IMD 1.17: 3/09/2012 11:43:52 VISION 1050 CP/M Plus Additional Files SN CP2768-1 VN 3.0    FMT1 P  ( +1"̀* " ! "+! "O!"! !!! "~# ´ !  ":"g:" :" g:" !~$ #~B)!1"ɷW|g !!%  "+! "z! "vCPM3 SYS CPMLDR error: failed to open CPM3.SYS $ CPMLDR error: failed to read CPM3.SYS $ CP/M V3.0 Loader Copyright (C) 1982, Digital Research $021182.>!Y1^.!61^.O:41(>`0 >z8y &y0(8:41 ( y> ( ˹> (ý.(~FO< w>2.~.-!Y1.!61.Fh.Vpր( =( =(>:41:41 241r~F>.--A/((/!21~wӍA/(y/ӑ>ӓӓA/(yӅ>Ӈ<Ӈ~FW< w>2?/qG/-#ۆ>!|1V~<^  ے (ے(  DISPLYRS232 KB LPT ۈW($ D/!W0N/Q/(#/ېOӐ>Ã*>Ӕ>>*)%_#ҋ#-*)MDͺ%")::)2^)ɯ2H)R(>G=O*_)~~w#~2H)~w%n%~R(~p2<)!"J)>2a)*_)~=2:)v(~2J)('>*_)w!")2^)=2B)!"\)&('"("'ͧ(+&v%~<·(w@)(÷':^)e#"\)&:b)(:>)2^):a)(*_)6:J)(w#:H)wn%:<)w*"*#}D>n)Ö%$*)q)* )):C)_2K){2C)"L)%" ))Ҝ)Ϳ#ʬ))>))#6:K)<!=¶)* ))" )*\)*:5)G/O*L)B)*L)Z$=3$)##N)"_)y%"2b)27):^)2>){2:)!"#"a)9""1#!(y2J"K!\"O"d'_^#V*_)h#h#;#h#h#h#h#h#h#_#h#h#h#(((h#h#h#h#(h#h#h#h#((h#h#h#h#h#h#h#h#h#h#h#h#h#h#h#h#h#h#h#h#h#h#h#:n##͌*y!Z)4 5~y5#5 6y # #:Z)A#![) O;#O#MDO#2#>e# BDOS ERR: $Select$Perm.$o#O#|#à#o#O##O#v{_zW{_zW )ø## ÿ# w##J͛*|^#V###")##")######"8)!) #*)!% :51 251O/;z!61V~e/ѷ ͢0#J(/!31ր(= ~ ~wgۉ(|ӈ&1cۄW> Ӈ<Ӈz 251W!41~0w!31~0wӰ>ۉ(!31~ӈwۉ(:31ӈۍ0-یWۍ_( :21ӍӍ?!Y1V~e/(1J(/=!|1. ۍ(!21~wӍ#h.ۍ ӌ?~ ~=W7/>HH 11M-)557424(41 >2)557424(42 >2(#8*+,H+T+N+,Ã8T8Æ8Ì8Ò8é8ÿ8À+Þ8t++z+@+è-D+88,59Ó,Ú8,**>22!*"*b"!/!1*$W+*(W+**)m+͚+_+.|Y+*$Ã+*(Ã+**)>ܚ+|…+h&)))/~A/,+~+¾+>+>w+́.A/-*"+*&)>+|+)#**)|!=)6$67͘**)w#w*)w#w#w!C)^#V#F*$ͧ*Oڗ#×#*c)ͦ%!C)s#r#p*)N#F*)^#V#F*C):E)O}|y҇$*%)ͥ#+p$*%)ͮ#}|yڞ$#Ç$*%)ͥ#*2)DM"N)͞**)s#r*)s#r#pyoxg$DM*8)Ͱ*MD"P)͡** )MDä*:4)Oæ%!')N:A) $G>O:@) %%*_)% :=)(%n` ~#fo$2;)O%"C)}:')O*C)ͷ#"C)2E)"F):()O:A)G26)!C)w*_) *_)n%!v%~2A)~2?)f%:))2@)v%:A)w:?)w |g}oç% )ô%:^)O!ͳ%yoxg:^)Oͦ%}* ):I)o$f%~w{ozg ^#VF$ ( 2(2*" ,*&)>+ ,| , ,-~6,O͌*#',a,>/<L,33A,O͌* _ W{?,!8%,:9AO͌*!8%,*99,!8%,*99,2,=->C,:,2,:,G ˇ2,s,1,",S,C,*,}(-*,[5K,:,=-",*5[,K,:,=-S,:,*{, < > 23~ -AD  :41ӈh&)))/n&/ ےӒ>@Ӎ~NNӍ>$ӍیӍ221>8h&):5)&>h)&!&" )Z$3$*\)'&*)%" )!c)~#Oͦ%E:))|&f%N/*_)"e)y2g)4&$;&+&'*e)%:g)O~&y'x ' '& 'Nc&&# &2#G>Ge#ͺ&f%~%*_) #t&Ow!X'xR'>Fwx2<)2<)~:;):b)6:<)}'w2<)f%~O c&ʡ'>wͺ&('%2A)e#4t&OҮ'5i#l'?'×'%:A)!?)'i#':#i#.%i#@%:5)R)&Z$3$Ö%:^)<ʋ#=!B)wW*    >Ӕ:K24>2K!(2"7!7[9W>w:9<2}7>2~727<277!"h!7"7>2|7ͥ5 X!(24 @4~0(1 4!]2~=G!32~G!`2~!H21:942# !4%,:42KFMT***WARNING - Disk format not recognized*** 7!"h!7>7!"h!7>"7G:927*9"7:8(:92|7!7[9W~7:9<t5G:927:8(:927(>G:7!88> Gx2}7 7ې:}7Ӑ@( !|=¼5+} :7!~7(:~7ӕ̕6:7͝6:72~7ӕ:7Ӗ!7[9W~7>^#V!=8"b>?8!a>s1!a>P2*[> DMv5*a>M1*[> DM͕6P2*[> DML5*b>!=8MͲ1*[>  *[> ͞8ҍ2*[>  *[> N#Fq#p *[> ~ڮ2*[> DMB5 *[> 61*[> N#F*[> *[> N#F͔51!e>p+q*[> N#F*d>?8^8*[>q#p*[>*[> 8+*[>##q#p*[>*[> N#F^#V?8*[> s#r *[> N#F`i"h>*[> N#F `i"j>*h>"f>j>f>͞8ڐ3*f>+*[> ^#V\8DM2_2*f>"f>\3*[> ^#V*j>\8DM2*[>  *[> ͞8Ҿ31*[> N#F*[> *[> N#F͏5!n>s+p+q*[>l>͠84 *[> ~K2-!=>2-!="}=*9"-*9"-*9"-*-!=N# (#z+ {H<##) 2-|2-:-2->2-:-*- >> <(E >!-< :-? +<:K<( k,*}=%,!7^#V#%, >!-<> !-2-K==<{ >>=/>h=/>!-͂-b= yw-Ă-b=/>2->h=>:->h= {=zl==, Read, Write Retry (Y/N) ?***WARNING*** Disk format not recognized ***WARNING*** MORE THAN 10 BAD TRACKS *7:|7627:77 ":7ĝ6 (y5>͝6͕6:7͝6ç5:K(1k,*7%,:7ʍ6!7^#V#%,b6!8%,Z7Yʥ5:7@>7<7!7%,:8÷6:8 ەӕӗ:8Ӕ> =»6۔ڿ6۔66:7ӕӔ> =6a۔6z6>Ӕ>۔7ەӗf!t7>Ӕ>Ӕ282828t7!f!"f"j!E"l>ӓ͆*(͉*͉*O͌*a , Read, Write777777777 Not ready, Protect, Fault, Record not found, CRC, Lost data, DREQ, Busy, Time ou4_2*l>DM2ͦ3Ê4*[>##l>͞8Ҋ4 *[> ~34_2*l>DM2:n>j4*[>  *[> N#FPY͹8d463g4ͦ3Ê4*[>  *[> ͞8҇41Ê4ͦ3!p>p+q*o>"[>!s>s+p+q*q>DM3*[> ^#V"]>*[> N#F*q>?8*]>:s>w *[> 6!u>p+q*t>DM3*[> ^#V"]>*[> N#F*t>?8*]>~   +5{>.+55OͲ5w66ͩ6́5;6<566́5͕6<>́5͕6<>645͜6<H66! w #ˆ5>Ö5>2,6""6"$6yo`"&6!"*6͋6-66*&6|6 "&6*"6MD6*$6DM:,65ͷ6g666Ͱ66**6|6U6*$6FMT >>t, Retry (Y/N) ? +ͨ- 8 9!1^#V#{K8++~29y29+V+^$, ,8*y29i&)1 ~#fo{‚8!~29!~#fo$,i`"9i`"9i`"9:,2 9i`z n&*9&)1~#fo8*9&)1~#fo~#fo292 9ɯ BIOS Error on : T-, S-!"$,!s,r, >ӝ>:!M-"1E945*"6""6**6#"*6ú56**6A\ABORTED$NO SPACE$NO FILE: $CANNOT CLOSE$DISK READ ERROR: $DISK WRITE ERROR$YYYP   YP6YPYPYPYPYPYP Ͳ ò!>6#6͐6">*>|$7>9ͫ8"|>##*|> ~!7!>6D7*>|?7!>66"|>D7!>6:>Y7!~>6#6#6Å7*|>~2~>*|> ~2>:>z7:>2>*|> ~2>!>6>!>ڰ7*>&v> ~/*>&: w!>4‹7:72"g:^ *:"|> *g:":*9My *9My *9My *~>My *>My *O[0*U>}O[0*9>!=8"W>*W>!=8!Y>s:h0:Y>2h\͕60\>645*W>!=8!|s2*9͗8"9>. \~9 -0:9 1*9>"9>\d5͍0C\͏5!Z>s*9>!=8C "9*9*|9s#r͍0C*Z>&\8DM\͔5:j2j\v5:9ҁ1*|9)8"|9:y9ZŠ1a9ҟ10ñ1g9ұ10!_>q.*[> :_>w*[> ~!`>q*[> :`>w*[> *[> ^#VN#FR* *[> 6*[:K2<>2K!E9"-!"-"-<;2-< 2=!"-&"-g< s*-~W e#~X _###~ ;=2-*< K!E9>;;~0(1 )!L9~2-!e9f-#<;!=%,!=%,:<2   MOVE ASM LDRWINCHASMe ENDER ASM DRIVES ASM LABEL ASMBIOSKRNLASM}CPM3 SS$ !"#$%&'()*CHARIO ASM1+,-./0123456LDRBOOT ASM7BOOT ASM89:;<=>?@APRIVATE ASMBCDRVTBL ASMDSCB ASMEFLDRDRV ASM'GHIJKLMNOPQLDRKRNL ASM{RSTUVWXYPORTS LIB0Z[\PATCH COM]^RMAC COMj_`abcdeRESBDOS3SPRfLIB COM8ghijLINK COM{klmnopqrMAC COM\stuvwxDIRLBL RSXyGENCOM COMtz{|}~BNKBDOS3SPRjBDOS3 SPRMGENCPM COM(DUMP COMCALLVERSASMECHOVERSASMRANDOM ASMVHIST UTL  title 'MOVE - bank select and move module for CP/M Plus' maclib ports maclib z80 cseg ; ; subroutines for other modules use ; public ?move,?xmove,?bank ; ; external areas and subroutines that we may need to use ; extrn @cbnk extrn @bnkbf extrn ?bnksl ; local save areas ; move$stat: db 0 ;flag to show next move is interbank src$des$bank equ $ src$bank: db 0 ;source bank number des$bank: db 0 ;destination bank number des$add: ds 2 ;destination address for inteTRACE UTL CPMLDR RELREADME TXT#HEXCOM COM XREF COMyCPM3 LIB Z80 LIB/WINCH ASMhCCP CMrbank move src$add: ds 2 ;source address for interbank move mov$cnt: ds 2 ;byte count for interbank move old$stk$save: ds 2 ;place to save users stack ds 16 ;place for out local stack local$stack equ $ tc$bank: db 0 ;conversion table used to translate ;CP/M's bank to ours ; ;local equates ; int$bnk$act equ 0 ;flag for interbank move active page ; ;set interbank move flag active for next call to ?move subroutines ;and save both the destination and source n   umbers ; ;at entry: ; ;b = destination bank ;c = source bank ; ?xmove: sbcd src$des$bank ;save source and destination lda move$stat ;get status byte setb int$bnk$act,a ;set interbank move active sta move$stat ;save status byte ret ;return to caller page ?move: lda move$stat ;test flag for interbank move bit int$bnk$act,a ;and go to appropriate routine jrnz int$bnk$mov ;* xchg ;we are passed source and dest in hl ldir ;use z80 block move instruction xchg  ; Table entry point public winc0 ; System Control Block variables extrn @ermde ; BDOS error mode ; Utility routines in standard BIOS extrn ?wboot ; warm boot vector extrn ?pmsg ; print message @ up to 00, saves & extrn ?pdec ; print binary number in from 0 to 99. extrn ?pderr ; print BIOS disk error header extrn ?conin,?cono ; con in and out extrn ?const ; get console status extrn ?bank ; Bank select page ; Extended Disk Parameter Heore source address ; lxi d,buffr ;point at intermediate save area lded @bnkbf lbcd mov$cnt ;remaining length to move lda src$bank ;get source bank number call ?bank ;find physical bank and swap it ldir ;move a segment shld src$add ;save new source address ; lxi h,buffr ;point at segment as source lhld @bnkbf lded des$add ;restore real destination address lbcd mov$cnt ;remaining length to move lda des$bank ;get destination bank number call ?bank ;find physical ;need next address in same registers ret ;return to caller ; ; this routine is improved over the DR example ; ; interbank moves of > 128 bytes can be made with one exception, ; a move cannot span a bank boundry int$bnk$mov: res int$bnk$act,a ;set off interbank move flag sta move$stat ;save status byte sspd old$stk$save ;save callers stack lxi sp,local$stack ;and load it with a local stack shld des$add ;save destination address sded src$add ;save source addressaders (XPDHs) dw w$write dw w$read dw w$login dw w$init db 0,0 ; relative drive zero winc0 dw tranw ; translate table address db 0,0,0,0,0,0,0,0,0 ; bdos scratch area db 000h ; media flag dw dpbw ; disk parameter block dw 0 ; checksum vector dw 0fffeh ; alloc vector dw winbcb ; dirbcb dw winbcb ; datbcb dw 0fffeh ; hash db 0 ; hash bank dseg winbcb: db 0ffh ;drv db 0,0,0 ; Rec # db 0 ; wflg db 0 ; scratch byte dw 0 ;  bank and swap it ldir ;move a segment sded des$add ;restore ending source address int$bnk$mov$ret: lda @cbnk ;load current bank number call ?bnksl ;find physical bank and swap it lspd old$stk$save ;restore callers stack pointer ret page ?bank: ral ; rotate into 1&2 ori 01h ; set bit 0 on out p$bank$select ; Select bank ret ;buffr ds 128 end  sbcd mov$cnt ;save length of move int$bnk$mov$a: lhld mov$cnt ;restore move length mov a,l ;check for zero length move ora h ;* jrz int$bnk$mov$ret ;* ; lxi b,128 ;segment length ; xra a ;clear carry flag ; db 0edh,042h ; SBC HL,BC ; jrc int$bnk$mov$last ;last move this time ; shld mov$cnt ;save remaining length ; lhld src$add ;restore source address ; lxi d,@bnkbf ;point at intermediate save area ; lxi b,128 ;segment length ; lda src$bank ;get source btrack dw 0 ; sector dw winbuf ; buffer address db 0 ; bank dw 0 ; link winbuf ds 512 cseg ; DPB must be resident dpb$w: dw 64 ; #128-byte records/track db 04 ; Block shift db 0fh ; Block mask db 0 ; extent mask dw 0983h ; maximum block number dw 1023 ; maximum dir entry number dw 0ffffh ; alloc vector for directory dw 08000h ; (Don't do checksumming) dw 0002h ; offset for system tracks db 01h ; db 01h ; tranw equ 0 page ;  title 'Winchester Handler Module' ; CP/M-80 Version 3 -- Modular BIOS ; Winchester I/O Module ; Initial version 0.01 ; Port Address Equates maclib ports ; CP/M 3 Disk definition macros maclib cpm3 ; Z80 macro library instruction definitions maclib Z80 cseg ; Variables containing parameters passed by BDOS extrn @adrv,@rdrv extrn @dma,@trk,@sect extrn @dbnk ; Other externals extrn u$conin$echo extrn error$table ank number ; call ?bank ;find physical bank and swap it ; ldir ;move a segment ; shld src$add ;save new source address ; lxi h,@bnkbf ;point at segment as source ; lded des$add ;restore real destination address ; lxi b,128 ;segment length ; lda des$bank ;get segment bank number ; call ?bank ;find physical bank and swap it ; ldir ;move a segment ; sded des$add ;save new destination address ; jr int$bnk$mov$a ;loop until complete int$bnk$mov$last: lhld src$add ;rest   called for first time initialization. dseg w$init: ret ; ;RESET AND CONFIGURE THE WINCHESTER ; w$login: lda @ermde ; Get error mode sta save$mode ; Save current value mvi a,0ffh ; Force to FF sta @ermde ; save it lxi h,winbuf shld dmaadr ; set up dma address lxi h,0 ; Zero shld wsect ; = sector shld wtrk ; and track CALL WINRES jnz bad$exit ;(RETURN A=5 IF TIME OUT ERROR) sta wrwf ; wrwf=0 to read label CALL WINRES jrnz bad$exit ;(RET IS ; REACHED. INR C MAPMOR: DCR C jrz MAPDONE ;(DONE IF OUT OF BAD TRACKS) INX H MOV A,D CMP M DCX H jrnz MAP$0 MOV A,E CMP M MAP$0: JC MAPDONE ;(DONE IF BADTRACK>TRACK) INX D ;TRACK+=1 (SKIPS BAD TRACK) INX H INX H ;POINT TO NEXT BAD TRACK jr MAPMOR MAPDONE: XCHG ;(HL=TRACK) ;ASSEMBLE "LOGICAL ADDRESS" XRA A MVI D,5 WWW: DAD H RAL DCR D jrnz WWW ;AHL:=TRACK*32 STA ADH ;(DRIVE ALWAYS 0) MOV A,H STA ADM LDA wsect ADD L S2 sta heds ; Store away lxi b,15 ; # bytes to move lxi h,winbuf+32 ; FROM address lxi d,dpbw ; TO address ldir ; move it inx h ; Skip skew ldi ; Then move in 2 more ldi ; ; CALL WINRES JNZ BAD$EXIT jr login$exit ; TOOBAD: push h lxi h,manybad ; Point to message call ?pmsg ; Print it pop h ret ; ; NOTOK: lxi h,nomatch ; Point to error message call ?pmsg Bad$exit: pop h ; pop return address pop d ; and DPH pointer lxi d,0 ; Set DPHURN A=5 IF TIME OUT ERROR) ;ASSIMILATE THE BAD TRACK TABLE XRA A STA BADTRACK-1 ;DEFAULT BAD TRACK COUNT TO 0 LXI H,0 SHLD ADH ;TRACK 0, SECTOR 0 MVI H,1 ;BLOCK COUNT OF 1 SHLD ADL ;XRA A CALL WAZ ;READ ABSOLUTE TRACK 0, SECTOR 0 JrnZ bad$exit ;(RETURN A=5 IF TIME OUT ERROR) LHLD dmaadr ;BAD TRACK TABLE FROM DISK IS SOURCE MOV A,M CPI 'W' ;"SIGNATURE" SHOULD BE "WXYZ" JRNZ notok INX H MOV A,M CPI 'X' ; BUT CHECK ONLY THE FIRST 2 BYTES JRNZ notok INX TA ADL ;AD(HML):=WTRK*32+WSEC MVI A,1 STA INTL ;SELECT OPCODE,DIRECTION LDA WRWF WAZ: LHLD dmaadr LXI B,0 ;B=0(=256) BYTE COUNT FOR DATA TRANSFER ;C=0 INPUT DIRECTION UNLESS CHANGED ORA A ; check wrwf jrnz wwrit1 ; non-zero means write WREAD1: MVI A,8 jr WACTR WWRIT1: MVI A,10 ;JMP WACTW ;WRITE DIRECTION TO IGNORE DATA JUST IN CASE WACTW: INR C ;=MVI C,1 ;SET WRITE DIRECTION WACTR: CALL WDOIT jrz w$exit ;(RETURN OK IF OK) CPI 0FEH jrNZ error pointer to 0 push d ; save it push h ; push return address Login$exit: lda save$mode ; Get saved value of @ermde sta @ermde ; restore ret save$mode ds 1 page DSEG ; ; Read entry point ; w$read: xra a ; A=0 sta wrwf ; Read/write flag=0 for read lxi h,read$msg jr w$common ; Join common code ; ; Write entry point ; w$write: mvi a,1 ; A=1 sta wrwf ; Read/write flag=1 for write lxi h,write$msg ; ; Common code for read/write operations ; w$common:H INX H INX H ;SKIP OVER THE "SIGNATURE" MOV A,M CPI MAXBAD+1 CNC Too$bad ;(ERROR FF IF MORE THAN (10) BAD) LXI D,BADTRACK-1;BAD TRACK TABLE IN MEMORY IS DESTINATION LXI B,(MAXBAD*2)+1 ;ROOM FOR BAD TRACK COUNT, (10) BAD TRACKS LDIR ;MOVE IT ; ; Now read LOGICAL track 0, sector 0 to get label info ; xra a ; A=0 sta wrwf ; for a read call w$1 ; Perform it jrnz bad$exit ; Jump if error ; ; Now, check that disk has one of our "signatures" ; lxi b,3 ; c$exit ;(RETURN ERROR (5/7) IF ERROR NOT STATUS BYTE) MVI A,3 ;"REQUEST SENSE STATUS" LXI H,LSTAT ;TO LSTAT LXI B,256*4;=MVI B,4/MVI C,0 ;4 BYTES IN CALL WDOIT jrNZ error$exit ;(RETURN ERROR STATUS (5/7/FE)) LDA LSTAT ANI 03FH CPI 4 ;IF THE CONTROLLER RETURNS 4 (DRIVE NOT READY) jrnz w$exit INR A;=MVI A,5/ORA A ; THEN CHANGE IT TO 5 error$exit: push psw ; Save error code lda @ermde ; Get error mode inr a ; Is it FF? jrz error$50 ; If yes, return hard error call ? shld operation$name ; Store "Read" or "Write" lhld @sect ; Get sector shld wsect ; store it lhld @trk ; Get track shld Wtrk ; store it lhld @dma ; Get dma address shld dmaadr ; store it W$1: ;TRACK MAPPING: SKIP RESERVED TRACK 0, NUMBER AROUND BAD TRACKS (IF ANY) LHLD WTRK XCHG ;DE:=TRACK INX D ;TRACK+=1 (TRACK 0 RESERVED) LXI H,BADTRACK-1 MOV C,M INX H ;C:=# OF BAD TRACKS, HL:=POINTS TO BADTRACK LIST ;SCHEME: SCAN BAD TRACK LIST. BUMP TRACK FOR EACH BAD TRACK # THATount = 3 lxi h,winbuf ; Point to info read from disk lxi d,signature ; and our signature w$log$01: ldax d ; Get signature character cci ; compare inx d ; Increment ptr jnz notok ; Jump if no match jpe w$log$01 ; if BC<>0, keep going mov a,m ; Now check final char cpi '0' ; For '0' jrz w$log$30 ; cpi '1' ; or '1' jrnz notok ; ; ; Disk is one of ours. Move info from label into DPB. ; w$log$30: lxi h,winbuf+7 ; Point to # heads mov a,m ; Get into A ral ; *   pderr ; Print message header lhld operation$name ; Get name of operation call ?pmsg ; Print that out pop psw ; Get status lxi h,error$table ; Point to table of msgs error$20: call errm1 ; Print out all errors lxi h,error$msg ; Point to ",Retry (Y/N)?" call ?pmsg ; Print it call u$conin$echo ; Wait for user response cpi 'Y' ; Yes? jz w$1 ; Try again jr error$51 ; No. Leave w/hard error error$50: pop psw ; Get error code error$51: mvi a,1 ; Set hard erro'RECEIVE B BYTES FROM WINCH TO (HL) WREC: mvi c,p$winch$data ; Set up port mvi a,2 ;(ONLY WORKS UP TO 256 BYTES) ;REPEAT WREC1: ;(HL):=IN(C) *HL+=1 *B-=1 DW 0A2EDH;"INI" ;[ACKNOWLEDGE] - (SHOULD BE AUTOMATIC WITH DATA) OUT p$winch$control ;UNTIL B=0 jrnz WREC1 ;END WREC RET ;PROCEDURE WSND(HL,B) 'SEND B BYTES FROM (HL) TO WINCH WSND: MVI C,p$winch$data MVI A,2 ;(ONLY WORKS UP TO 256 BYTES) ;REPEAT WSND1: ;OUT(C):=(HL) *HL+=1 *B-=1 DW 0A3EDH;"OUT,e ; Get low byte (LEL0384) ora d ; OR with hi byte (LEL0384) jrnz wdoit$4 ; Try again (LEL0384) ; ; Time out. Set error code = 7 and return. ; mvi a,7 ; Set error code = 7 (LEL0384) ora a ; reset Z-flag (LEL0384) ret ; Return (LEL0384) ;SELECT CONTROLLER WDOIT$6: MVI A,1 OUT p$winch$data ;p$winch$data:=DECODED CONTROLLER SELECTION (1) ;MVI A,1 OUT p$winch$control ;RAISE.. DCR A OUT p$winch$control ;..THEN LOWER.. THE SELECT LINE IN p$winch$cor w$exit: RET ;RETURN CONTROLLER'S ERROR CODE ; ; Print out message for each bit that is on ; errm1: mov e,m ! inx h ! mov d,m ! inx h ; get next message address add a ! push psw ; shift left and push residual bits with status xchg ! cc ?pmsg ! xchg ; print message, saving table pointer pop psw ! jrnz errm1 ; if any more bits left, continue ret page ;RESET AND CONFIGURE THE WINCHESTER WINRES: ; MVI A,080H ; (LEL0384) ; OUT p$winch$control ;PULSE THE RESET LINE (LEL0384)I" ;[ACKNOWLEDGE] - (SHOULD BE AUTOMATIC WITH DATA) OUT p$winch$control ;UNTIL B=0 jrnz WSND1 ;END WSND RET DSEG ;WAIT FOR WINCHESTER REQUEST WREQ: CALL WREQT jrnz WREQ RET ;WAIT FOR "REQUEST", RETURN Z=1 ; ; WAIT FOR WINCHESTER REQUEST ; TIME OUT IF TOO LONG. ; WREQT: PUSH D LXI D,0 WREQT1: IN p$winch$control ani 01 jz WREQT2 ;DONE IF REQUEST, RETURN Z=1 DCX D MOV A,D ORA E JNZ WREQT1 ;XRA A ORI 5 ;DONE IF TIME OUT, RETURN A=5, Z=0 WREQT2: POP D ntrol CMA ANI 2 MVI A,7 RNZ ;(RETURN ERROR 7 IF NOT BUSY) ;WAIT FOR REQUEST CALL WREQT RNZ ;(RETURN A=5 IF TIME OUT ERROR) IN p$winch$control CMA ANI 8 MVI A,7 RNZ ;(RETURN ERROR 7 IF REQUEST IS NOT COMMAND) ;JAM OUT COMMAND PUSH H PUSH B ;CALL WSND(WCB,6) LXI H,WCB MVI B,6 CALL WSND POP B POP H CALL WREQ ;IF REQ IS DATA IN p$winch$control ANI 8 jrnz NODATA ;THEN GET/PUT DATA MOV A,C ORA A PUSH PSW CZ WREC POP PSW CNZ W mvi a,01 ; Recalibrate (LEL0384) lxi h,wcb ; (LEL0384) mvi b,8 ; 8 chars (LEL0384) mvi c,1 ; Direction = out (LEL0384) call wdoit ; (LEL0384) rnz ; return if error (LEL0384) MVI A,12 ;SET DRIVE CHARS COMMAND LXI H,WCB1 ;FROM DRIVE CHARS DATA LXI B,256*8+1;=MVI B,8/MVI C,1 ;8 BYTES OUT ;JMP WDOIT;=CALL WDOIT/RET ;RETURN A=ERROR STATUS WDOIT: ;LOWEST LEVEL COMMAND HANDLER. ;INPUT: DATA: C: DIRECTION (0=IN,1=OUT) ; B: HOW MANY ; HL: WHERE TO GET/PUT T RET cseg maxbad equ 10 ; maximum # bad tracks WCB1: DW 256*(CYLS AND 255)+(CYLS/256) ;REVERSAL STORES HI-LO HEDS: Db 4 DW 256*(REDUCE AND 255)+(REDUCE/256) DW 256*(PRECOMP AND 255)+(PRECOMP/256) DB MAXECC cyls equ 306 reduce equ 307 ; (value > 306 means NEVER) (LEL0384) precomp equ 126 ; Precomp (LEL0384) maxecc equ 11 WCB: OP DB 0 ADH DB 0 ADM db 0 ADL DB 0 INTL DB 1 DB 4 WRWF: ds 1 ;Write/read/check/format flag WPT: ds 1 ; wsect ds 2 wtrk ds SND ;WAIT FOR REQUEST CALL WREQ IN p$winch$control CMA ANI 8 MVI A,7 RNZ ;(RETURN ERROR 7 IF REQUEST IS NOT COMMAND) ;FI NODATA: ;GET STATUS BYTE IN p$winch$data STA STAT MVI A,2 OUT p$winch$control ;THROW AWAY NULL STATUS BYTE CALL WREQT RNZ ;(RETURN A=5 IF TIME OUT ERROR) MVI A,2 OUT p$winch$control LDA STAT ANI 2 RZ ;(RETURN ZERO IF STATUS BYTE ZERO) MVI A,0FEH RET ;(RETURN 0FEH IF STATUS BYTE NOT OK) page CSEG ;PROCEDURE WREC(HL,B) HEM ; ; CMD: A: COMMAND BYTE ; ; ;RETURN: A: STATUS BYTE ;SETUP OPCODE STA OP ; ; Wait for not busy, but time out after 1 second ; lxi d,1099 ; 1099 *910us=1 second (LEL0384) WDOIT$4: ; (LEL0384) IN p$winch$control ; Get status ANI 2 ; Busy? JZ WDOIT$6 ; If not busy, do cmd (LEL0384) xra a ; (LEL0384) WDOIT$5: ; (LEL0384) dcr a ; (waste time) (LEL0384) jnz wdoit$5 ; 896us (LEL0384) dcx d ; Decrement (LEL0384) mov a   2 dmaadr ds 2 STAT: DS 1 ;COARSE STATUS BYTE (EVERYTIME) LSTAT: DS 4 ;FINE STATUS BYTES (FROM REQUEST SENSE STATUS COMMAND) DSEG Operation$name dw read$msg Read$msg db ', Read',0 Write$msg db ', Write',0 Error$msg db ' Retry (Y/N) ?',0 nomatch db '***WARNING***',13,10,'Disk format not recognized' db 13,10,0 manybad db '***WARNING***',13,10,'MORE THAN 10 BAD TRACKS',13,10,0 DB 0 ;NUMBER OF BAD TRACKS BADTRACK:DS MAXBAD*2 ;ROOM FOR (10) BAD TRACKS Signature db 'FMT'  public endtag dseg endtag equ $ n lda move$stat ;get status byte setb int$bnk$act,a ;set interbank move active sta move$stat ;save status byte ret ;return to caller page ?move: lda move$stat ;test flag for interbank move bit int$bnk$act,a ;and go to appropriate routine jrnz int$bnk$mov ;* xchg ;we are passed source and dest in hl ldir ;use z80 block move instruction xchg ;END OF WINCH END  title 'Diskette Handler Module' ; CP/M-80 Version 3 -- Modular BIOS ; Disk I/O Module ; Port Address Equates maclib ports ; CP/M 3 Disk definition macros maclib cpm3 ; Z80 macro library instruction definitions maclib Z80 ; Disk drive dispatching tables for linked BIOS public fddd0,fddd1,firq public trandd,tranrainbow public u$conin$echo, error$table, errm1 public motor$counter ; Variables containing parameters passed by BDOS extrn @adrv,@rdrv extrn @dma,@trk,@sect extrn @dbnk,@cbnk ; System Control Block variables extrn @ermde ; BDOS error mode ; Utility routines in standard BIOS extrn ?wboot ; warm boot vector extrn ?pmsg ; print message @ up to 00, saves & extrn ?pdec ; print binary number in from 0 to 99. extrn ?pderr ; print BIOS disk error header extrn ?conin,?cono ; con in and out extrn ?const ; get console status extrn ivect extrn ?bank cr equ 13 lf equ 10     bell equ 7 page ; Extended Disk Parameter Headers (XPDHs) CSEG dw fd$write dw fd$read dw fd$login dw fd$init db 0 ; relative drive zero db 2 ; TYPE field fddd0: fddd0$dpb equ $+12 dph trandd,dpbd0 dw fd$write dw fd$read dw fd$login dw fd$init db 1 ; relative drive one db 02 ; TYPE field fddd1: fddd1$dpb equ $+12 dph trandd,dpbd1 CSEG ; DPB must be resident dpbd0 dw 40 ;#12 a mov d,a ; Use it to clear d dad d ; add lxi d,old$track ; TO address fd$20 ldi ; move in track call set$up$8255 ; Set up 8255 command page more$retries: mvi c,04 ; allow 04 retries retry$operation: push b ; save retry counter ; ; Check to see whether the motor is being turned on cold, or ; whether it is still on from a previous access. ; call start$motor$timer ; Start timing in p$disk$bits ; Get previous status push psw ; save it lda select$mask ; Clear a (LEL0184) mov d,a ; Use it to clear d (LEL0184) dad d ; (LEL0184) mvi a,0ffh ; Use FF to force HOME (LEL0184) mov m,a ; Set to last trk used (LEL0184) ret ; (LEL0184) page ; disk READ and WRITE entry points. ; these entries are called with the following arguments: ; relative drive number in @rdrv (8 bits) ; absolute drive number in @adrv (8 bits) ; disk transfer address in @dma (16 bits) ; disk transfer bank in @dbnk (88 byte records/track db 4,0fh ;block shift mask (2K) db 1 ;extent mask dw 194 ;maximun block number dw 127 ;max number of dir entry - 1 db 0C0H,00h ;alloc vector for directory dw 0020h ;checksum size dw 2 ;offset for sys tracks db 2,3 ;physical sector shift (512 sector) dpbd1 dw 40  ; Get new status out p$disk$bits ; Send out (turns on motor) pop psw ; Get prev status ani 0100$0000b ; Was motor on jrz check$track ; bit 6=0 means it was on ; ; Motor was off. Wait 800 ms for it to come up to speed. ; lxi h,892 wait$0 xra a wait$1 dcr a jnz wait$1 ; Delay 896 uS dcx h ; mov a,l ; ora h ; jrnz wait$0 ; ; ; Check current track against desired one. ; check$track ; ; Access track ; lda trk ! lxi h,old$track ! cmp m jrz sa bits) ; disk track address in @trk (16 bits) ; disk sector address in @sect (16 bits) ; pointer to XDPH in ; they transfer the appropriate data, perform retries ; if necessary, then return an error code in DSEG fd$read: call read$setup ; Set up for read jr rw$common fd$write: call write$setup ; Set up for write rw$common: ; seek to correct track (if necessary), ; and issue 1797 command. shld operation$name ; save message for errors mov b,a ;#128 byte records/track db 4,0Fh ;block shift mask (2K) db 1 ;extent mask dw 194 ;maximun block number dw 127 ;max number of dir entry - 1 db 0C0H,00h ;alloc vector for directory dw 32 ;checksum size dw 2 ;offset for sys tracks db 2,3 ;physical sector shift (512 sector) trandd skew 10,1,1 tranrainbow me$track ; if same track, dont seek ; ; New track (different from last one accessed) ; new$track: ; lda old$track ; Get last track (LEL0184) CPI 0FFH ; First access? (LEL0184) jrnz New$trk$5 ; Jump if not (LEL0184) CALL HOME ; Else, home disk (LEL0184) XRA A ; Current trk is now 0 (LEL0184) new$trk$5: OUT P$DISK$TRACK ; out to current track (LEL0184) lda trk ; point to desired track call seeker ; and seek lda trk ; get track sta old$track ; put read or write into B lhld @dma shld dmaadr lda no$of$sides ; Get # sides ora a ; Check it jrz rw$26 ; Jump if single-sided lda @trk ; get track ani 01h ; low bit = side add a ; add a ; add a ; *8 rw$26 ora b ; OR in w/read or write sta disk$command ; save 1797 command page ; ; Will need to know info on last access to disk. Move info into ; old$track ; lxi h,fd0$access ; FROM address lded @rdrv ; Get relative drive xra a ; Clearskew 10,2,1 page ; Disk I/O routines for standardized BIOS interface ; Initialization entry point. ; called for first time initialization. DSEG fd$init: mvi a,fdc$reset ;reset out p$disk$control ;do it ret page fd$login: ; ; When this entry point is called, the last track accessed ; is set to 0FFH to flag a homing of the head before a new ; Read or Write operation. ; lxi h,fd0$access ; TO address (LEL0184) lded @rdrv ; get current drive (LEL0184) xra a     ; store as last track accessed jr get$sect ; Now, access sector. ; ; At same track as last access ; same$track: out p$disk$track ; give 1797 track ; ; Now, Get sector. ; get$sect: lda @sect out p$disk$sector ;and sector ; ; Save track info for drive ; lxi h,fd0$access ; TO address lded @rdrv ; get current drive xra a ; Clear a mov d,a ; Use it to clear d dad d ; lxi d,old$track ; FROM address xchg ; d$error: lda disk$status ; Get status byte cpi 0100$0000b ; Write protect error? mvi a,0ffh ; return hard error to BDOS jnz fd$exit ; Not write protect error mvi a,2 ; Write protect error jmp fd$exit err$timeout lxi h,time$out ; point to timeout message call ?pmsg ; Display message jr errm2 ; Ask for user response ; ; Print out message for each bit that is on ; errm1: mov e,m ! inx h ! mov d,m ! inx h ; get next message address add a ! push psw ; shift left and pu ani 0001$0000b ; see if record not found error cnz seeker ; if rec not found, may need to force seek dcr c ; decrement retry count jrz fd$error ; If failed 4 times, exit mov a,c ; cpi 02 ; If <2 retries jp retry$operation ; then retry ; ; If >2 retries have already been done, force a head restore. This ; is done by seeking track 5, then restore to assure head travel. ; This should cure persistent lint on the heads as well as seek ; errors. ; mvi a,5 ; ldi ; move in track JMP SEL$DMA CSEG ; ; Select DMA bank for transfer ; SEL$DMA: IF BANKED lda @dbnk ; Get DMA bank call ?bank ; Go to it ENDIF ; ; Now, set up for NMI to do command. NMI will use alternate regs ; so set them up with the apprpriate values. ; exaf ; exchange af and af exx ; and other prime regs push h ; save h (really h') push b ; save b (really b') push psw ; save a (really a') mvi c,p$disk$data ; load c with port addsh residual bits with status xchg ! cc ?pmsg ! xchg ; print message, saving table pointer pop psw ! jrnz errm1 ; if any more bits left, continue ret page DSEG ; ; Subroutine to seek to home track ; home: mvi a,08h ; home, hld, no verify jr seek$20 ; ; ; Seeker ; This routine seeks a track in A ; seeker: push psw ; Save destination track lda tpi ; Get TPI ora a ; Is it 48? jrnz seek$15 ; Jump if not ; ; Must double track info for  track 5 call seeker ; seek it call home ; home lda trk ; Get track back Call seeker ; seek it jmp retry$operation ; then retry page ; ; Error Handling... ; FD$ERROR: ; ; suppress error message if BDOS is returning errors to application... ; lda @ermde inr a ; Is it FF? jrz hard$error ; ; Had permanent error, print message like: ; ; BIOS Err on d: T-nn, S-mm, , Retry ? ; call ?pderr ; print message header lhld operatress lhld dmaadr ; get buffer address exaf ; put into prime regs exx ; lda disk$command ; get 1797 command call exec$command ; Start. Wait for IREQ & read status sta disk$status ; save status for error messages exx ; save regs for a second exaf ; pop psw ; restore a (really a') pop b ; restore b (really b') pop h ; restore h (really h') exx ; put back into prime regs exaf ; put af back too ; ; Operation completed. Status is in location di48tpi disks ; in p$disk$track ; Read in current track ora a ; Clear carry ral ; *2 out p$disk$track ; Set track reg pop psw ; Get desired track ora a ; clear carry ral ; *2 jr seek$16 ; Seek it seek$15: pop psw ; Restore track seek$16: out p$disk$data ; send out track mvi a,018h ; seek, hld, verify ; ; Routines for seek and home ; seek$20 out p$disk$control ; send command from A ; ; Delay at least 24 uSec after command ; mvi a,09 ; sion$name ! call ?pmsg ; last function ; then, messages for all indicated error bits lda disk$status ; get status byte from last error cpi 0ffh ; time out error? jrz err$timeout ; special message lxi h,error$table ; point at table of message addresses call errm1 ; Print out messages errm2 lxi h,error$msg ! call ?pmsg ; print ", Retry (Y/N) ? " call u$conin$echo ; get operator response cpi 'Y' ! jz more$retries ; Yes, then retry 10 more times ; ; Error noted. ; harsk$status. ; IF BANKED xra a ; Reselect bank 0 call ?bank ; ENDIF pop b ; recover retry counter lda disk$status ; get status ora a ; check status. jz fd$exit ; If no error, exit JMP CHK$ERROR DSEG ; ; Check error type. If write protect violation or time out, ; or not ready, don't bother retrying. ; CHK$ERROR: ani 1100$0000b ; Not ready or write protect? jrnz fd$error ; jump if yes lda disk$status ; get status again   eek$delay dcr a ;. jnz seek$delay ; ; ; Wait for completion ; seek$30 in p$disk$control ; get status byte rrc ; Ready? jc seek$30 ; loop until ready ; ; Return with A= status byte ; in p$disk$control ; read in status ; ; Delay 18mS to allow for settling time ; lxi d,01400h ; seek$delay2 dcr e ; jnz seek$delay2 ; 896 uS dcr d ; jnz seek$delay2 ; 20*896=18 mS push psw ; save status lda trk ; Get trk out p$disk$track ; Sa ; 1797 write ret ; ; Set up NMI ; NMI (non-maskable interrupt) occurs at fixed location 0066h. ; During normal run time NMI does not occur, so these locations ; are normal RAM. During diskette data transfers, NMI is ; triggered by the diskette Data Request signal, so the NMI ; locations are temporarily overlayed by intructions to process ; the interrupt. ; nmi equ 0066h nmi$setup: mvi a,fdc$reset ; Reset FDC out p$disk$control ; dcx d ; Point to TYPE field of XDPHr timer ; Start$motor$timer: di ; DI while changing counter mvi a,127 ; Start counter sta motor$counter ; ei ; EI RET ; ; Exit from routine. ; Must set up interrupts appropriately. ; fd$exit: push psw ; save status in p$disk$track ; read track out p$disk$data ; write out data ; ; Restore nmi locations ; IF BANKED lda @dbnk ; Point to bank call ?bank ; Switch to it ENDIF lxi d,nmi ; Point at nmi lxi h,nmibuf ; and at save buffer lxi ve in track reg pop psw ; Restore status ret page CSEG ; ; This routine actually executes the read or write command. An initial ; read (or write) is sent out to the controller. Since we are not ; doing multiple sectors, an interrupt will be generated at the end of ; the command. This invokes the NMI set up at the beginning of the ; routine. Either an INI or OUTI will be performed, depending on whether ; a read or write is invoked. This lets us read in an entire sector ; mo ldax d ; Get value push psw ; (save) ani 1 ; Mask # sides sta no$of$sides ; store pop psw ; Get type ani 0000$0010b ; Mask TPI field rar ; Rotate into bit 0 sta TPI ; store lxi d,nmibuf ; point to storage area lxi h,nmi ; original values lxi b,8 ; set up length ldir ; save them away lxi h,0d908h ; "EX AF,AF'" shld nmi ; beginning of nmi shld nmi+4 ; also, end of nmi lxi h,045edh ; "RETN" shld nmi+6 ; mvi a,3 ; Enable FDC inteb,8 ; load count ldir ; move saved data back IF BANKED xra a ; Point back to code bank call ?bank ; Switch back ENDIF in p$disk$bits ; Get disk bits ori 0000$1111b ; Deselect drive out p$disk$bits ; Send out mvi a,0d0h ; out p$disk$control ; Reset disk controller pop psw ora a ; set flags ret ; and exit!! CSEG read$setup: IF BANKED lda @dbnk call ?bank ENDIF call nmi$setup ; set up nmi (invarient part) lxi h,0a2edh re efficiently. ; exec$command: out p$disk$control ; send 1797 command ; ; Wait at least 24 usec after command before doing anything. ; mvi a,08 exec$delay dcr a jrnz exec$delay ; (delays 32 usec) ; ; Now, wait for completion, but TIME OUT after 1.2 seconds. ; lxi d,60000+1 exec$0 in p$disk$control ; get status rrc ; check not ready flag jnc exec$success ; if 0, successful completion inx d ; (waste time) dcx d ; inx d ; dcx d ; dcrrupt out p$8255$control ; ret CSEG ; ; Floppy completion interrupt. ; firq: push psw ; save A in p$disk$control ; relieve interrupt IF REAL$1050 mvi a,int$initial out int$port ; Init int port ENDIF pop psw ei ret page DSEG u$conin$echo: ; get console input, echo it ; and shift to upper case call ?const ! ora a ! jrz u$c1 ; see if any char already struck call ?conin ! jr u$conin$echo ; yes, eat it and try again u$c1: call ?conin ! push psw m ; "INI" shld nmi+2 ; store read portion IF BANKED xra a call ?bank ENDIF lxi h,read$msg ; point at " Read " mvi a,82h ; 1797 read ret write$setup: IF BANKED lda @dbnk call ?bank ; Switch banks ENDIF call nmi$setup ; set up nmi (invarient part) lxi h,0a3edh ; "OUTI" shld nmi+2 ; store write portion IF BANKED xra a ; Get CBANK back call ?bank ; restore it ENDIF lxi h,write$msg ; point at " Write " mvi a,0A2h x d ; decrement count mov a,d ; ora e ; adi 0ffh ; jc exec$0 ; 20 us*60000=1.2 seconds ; ; Time out. Set A=0FFH and exit. ; mvi a,0d0h ; Reset FDC out p$disk$control ; send it out mvi a,0ffh ; Set time out flag jr exec$exit ; ; Successful completion. Return w/status byte in A. exec$success in p$disk$control ; Get status byte exec$exit push psw ; Save status call start$motor$timer ; Start timer pop psw ; ret page ; ; Start up moto   ov c,a ! call ?cono pop psw ! cpi 'a' ! rc sui 'a'-'A' ; make upper case push psw ; Save character lxi h,cr$lf ; Send out CR LF call ?pmsg ; pop psw ; restore character ret ; ; Set up misc 8255 command ; ; Bit 7=0; Bit 6=0 means turn motor on. ; Set up drive select in bits 0-3. set$up$8255: lda @rdrv ; get relative drive inr a ; increment cpi 03 ; jm fd$40 ; ani 06 ; add a ; Double it fd$40 xri 0Fh ; bit=0 => on mov b,a ; save in b ;  old$track db 0ffh ; last track seeked to fd0$access fd0$trk db 0ffh ; last track accessed on A fd1$trk db 0ffh ; last track accessed on B ; error message components cr$lf db 13,10,0 read$msg db ', Read',0 write$msg db ', Write',0 operation$name dw read$msg ; table of pointers to error message strings ; first entry is for bit 7 of 1797 status byte error$table dw b7$msg dw b6$msg dw b5$msg dw b4$msg dw b3$msg dw b2$msg dw b1$msg dw b0$msg b7$msg db ; Set up Bit 4 (side select). ; If double sided, consecutive tracks use alternate sides ; of the disk ; lda @trk ; Get track sta trk ; store it lda no$of$sides ; Get # sides ora a ; Is it double sided? jrz fsel$1 ; Jump if not lda @trk ; get track push psw ; save it rar ; rotate into place sta trk ; store pop psw ; restore track ani 1 ; mask off other bits jrz fsel$1 ; If side 0, ok mvi a,010h ; Else, set side 1 bit ora b ; or w/b-reg mo EXTRN ENDTAG ; Label sector for disks for the Visual 1050 X EQU 0 ;ANCHOR 0 /SIGNATURE ;------------------------------------------------------------------------------ ; The following field said "FMT0" on the Amigo-formatted diskettes ;------------------------------------------------------------------------------ DB 'FMT1' ;ANCHOR 4 /FORMAT DW 512 ;SECTOR SIZE DB 10 ;# SECTORS DB 1 ;# HEADS DW 80 ;# TRACKS DB 3 ;TRANSPARENT SKEW ;------------------------------ ' Not ready,',0 b6$msg db ' Protect,',0 b5$msg db ' Fault,',0 b4$msg db ' Record not found,',0 b3$msg db ' CRC,',0 b2$msg db ' Lost data,',0 b1$msg db ' DREQ,',0 b0$msg db ' Busy,',0 time$out db ' Time out,',0 error$msg db ' Retry (Y/N) ? ',0 END des$add ;save new destination address ; jr int$bnk$mov$a ;loop until complete int$bnk$mov$last: lhld src$add ;restv b,a ; save in b again ; ; Set up bit 5 for write precompensation. (Write precomp is ; necessary for outer tracks, so check against constant specified ; by disk manufacturer.) ; fsel$1 lda trk ; get track cpi precomp$limit ; Compare with precomp (LEL0384) jrc fsel$2 ; jump if yes mvi a,020h ; set write pre-comp ora b ; or with other bits mov b,a ; store back in b ; ; All 8 bits of 8255 command have been set up. Save them. ; fsel$2 mov a,b ; get b reg------------------------------------------------ ; The following field (TPI) was not used on FMT0. Since the byte was unused, ; it had a value of 0. A value of 0 will be interpreted to mean 48 TPI. ; A value of 1 will be interpreted to mean 96 TPI. ;------------------------------------------------------------------------------ DB 1 ; TPI DB X,X,X,X DB X,X,X,X ;ANCHOR 20 /O.S. ; (Bytes 20-27 used by COPYSYS to generate bootable system) DW 2080h ;LOAD BEGIN ADDRESS DW ENDTAG-2080h ;L values sta select$mask ; save 8255 bits ret page CSEG IF REAL$1050 ivect2 equ 0fff8h ; ELSE ivect2 equ 0ffe2h ; address of ivect+2 ENDIF nmibuf ds 8 ; buffer to hold prev contents of nmi disk$command ds 1 ; current wd1797 command select$mask ds 1 ; current drive select code dmaadr ds 2 trk ds 1 ; track for current operation disk$status ds 1 ; last error status code for messages precomp$limit equ 43 no$of$sides db 0 ; # sides tpi db 0 motor$counter db 0 DSEG   OAD LENGTH DW 2080h ;JUMP ADDRESS DW 128 ;BYTE OFFSET TO SYSTEM DB 1 ;# HEADS DB X,X,X ;RESERVED ;ANCHOR 32 ;Copy of CP/M Plus DPB DW 40 ;# 128 BYTE RECORDS/TRACK DB 4 ;LOG2(2048/128) DB 15 ;(2048/128)-1 DB 1 ; EXM=1 DW 194 ;(390K/2048)-1 (HIGHEST BLOCK #) DW 127 ;(DIRS-1) DB 11000000B,00000000B ;2048/32=64 DIRS/BLOCK. DIRS/64=2BLOCK 2 BIT DW 32 ;(DIRS)/4 (GIVES CSV SIZE) DW 2 ;NUMBER OF SYSTEM TRACKS DB 1 ; non-transparent skew (this field not in DPB) lar system ; configuration. cr equ 13 lf equ 10 bell equ 7 ctlQ equ 'Q'-'@' ctlS equ 'S'-'@' ccp equ 0100h ; Console Command Processor gets loaded into the TPA cseg ; GENCPM puts CSEG stuff in common memory ; variables in system data page extrn @covec,@civec,@aovec,@aivec,@lovec ; I/O redirection vectors extrn @mxtpa ; addr of system entry point extrn @bnkbf ; 128 byte scratch buffer ; initialization extrn ?init ; general initialization and signon extrn DB 2 ;Physical Record shift factor DB 3 ;Physical Record Mask ;(HOST-MONITOR) DW 2 ;TRACK ORIGIN DB 0 ;HEAD ORIGIN DB 1 ;# HEADS DB X ; ;---------------------------------------------------------------------------- ; The following byte was unused on under FMT0. We will use it to tell ; how sides are to be read on a double-sided disk. A 0 will mean ; alternating heads. ;---------------------------------------------------------------------------- DB X ;ORDER (Not applicab ?ldccp,?rlccp ; load & reload CCP for BOOT & WBOOT ; private Bios calls extrn privcall ; user defined character I/O routines extrn ?ci,?co,?cist,?cost ; each take device in extrn ?cinit ; (re)initialize device in extrn @ctbl ; physical character device table ; disk communication data items extrn @dtbl ; table of pointers to XDPHs public @adrv,@rdrv,@trk,@sect ; parameters for disk I/O public @dma,@dbnk,@cnt ; '' '' '' '' ; memory cle since this is single sided disk) ;ANCHOR 56 /OPTIONS DB 0 ;STEP RATE (0=FAST..3=SLOW) ;--------------------------------------------------------------------------- ; The followwing field was unused in FMT0. In FMT1, it will be used to ; indicate the write precomp track. ;--------------------------------------------------------------------------- DB 0ffh ;Write precomp DB X,X,X,X,X,X,X,X, X,X,X,X,X,X,X,X,X,X DB X,X,X,X,X,X,X,X,X,X, X,X,X,X,X,X,X,X,X,X DB X,X,X,X,X,X,X,X,X,X, X,X,Xontrol public @cbnk ; current bank extrn ?xmove,?move ; select move bank, and block move extrn ?bank ; select CPU bank ; clock support extrn ?time ; signal time operation ; general utility routines public ?pmsg,?pdec ; print message, print number from 0 to 65535 public ?pderr ; print BIOS disk error message header maclib ports ; define mode bits ; External names for BIOS entry points public ?boot,?wboot,?const,?conin,?cono,?list,?auxo,?auxi publ title 'Root module of relocatable BIOS for CP/M 3.0' ; version 1.0 15 Sept 82 ; Copyright (C), 1982 ; Digital Research, Inc ; P.O. Box 579 ; Pacific Grove, CA 93950 ; This is the invariant portion of the modular BIOS and is ; distributed as source for informational purposes only. ; All desired modifications should be performed by ; adding or changing externally defined modules. ; This allows producing "standard" I/O modules that ; can be combined to support a particu,X,X,X,X,X,X,X DB X,X,X,X,X,X,X,X,X,X, X,X ;ANCHOR 128 END  dw 194 ;maximun block number dw 127 ;max number of dir entry - 1 db 0C0H,00h ;alloc vector for directory dw 32 ;checksum size dw 2 ;offset for sys tracks db 2,3 ;physical sector shift (512 sector) trandd skew 10,1,1 tranrainbow    ic ?home,?sldsk,?sttrk,?stsec,?stdma,?read,?write public ?lists,?sctrn public ?conos,?auxis,?auxos,?dvtbl,?devin,?drtbl public ?mltio,?flush,?mov,?tim,?bnksl,?stbnk,?xmov ; BIOS Jump vector. ; All BIOS routines are invoked by calling these ; entry points. ?boot: jmp boot ; initial entry on cold start ?wboot: jmp wboot ; reentry on program exit, warm start ?const: jmp const ; return console input status ?conin: jmp conin ; return console input character ?cono: jmp conout ; sen entry ret ds 64 boot$stack equ $ ; DEVTBL ; Return address of character device table devtbl: lxi h,@ctbl ! ret ; GETDRV ; Return address of drive table getdrv: lxi h,@dtbl ! ret ; CONOUT ; Console Output. Send character in ; to all selected devices conout: lhld @covec ; fetch console output bit vector jmp out$scan ; AUXOUT ; Auxiliary Output. Send character in ; to all selected devices auxout: lhld @aovec ; fetch aux outpor system startup. dseg ; this part can be banked boot: lxi sp,boot$stack mvi c,15 ; initialize all 16 character devices c$init$loop: push b ! call ?cinit ! pop b dcr c ! jp c$init$loop call ?init ; perform any additional system initialization ; and print signon message lxi b,16*256+0 ! lxi h,@dtbl ; init all 16 logical disk drives d$init$loop: push b ; save remaining count and abs drive mov e,m ! inx h ! mov d,m ! inx h ; grab @drv entry mov a,e ! ora d ! jz d$init$next d console output character ?list: jmp list ; send list output character ?auxo: jmp auxout ; send auxilliary output character ?auxi: jmp auxin ; return auxilliary input character ?home: jmp home ; set disks to logical home ?sldsk: jmp seldsk ; select disk drive, return disk parameter info ?sttrk: jmp settrk ; set disk track ?stsec: jmp setsec ; set disk sector ?stdma: jmp setdma ; set disk I/O memory address ?read: jmp read ; read physical block(s) ?write: jmp write ; write physical block(s) ?ut bit vector jmp out$scan ; LIST ; List Output. Send character in ; to all selected devices. list: lhld @lovec ; fetch list output bit vector out$scan: mvi b,0 ; start with device 0 co$next: dad h ; shift out next bit jnc not$out$device push h ; save the vector push b ; save the count and character not$out$ready: call coster ! ora a ! jz not$out$ready pop b ! push b ; restore and resave the character and device call ?co ; if device selected, print it pop b; if null, no drive push h ; save @drv pointer xchg ; XDPH address in dcx h ! dcx h ! mov a,m ! sta @RDRV ; get relative drive code mov a,c ! sta @ADRV ; get absolute drive code dcx h ; point to init pointer mov d,m ! dcx h ! mov e,m ; get init pointer xchg ! call ipchl ; call init routine pop h ; recover @drv pointer d$init$next: pop b ; recover counter and drive # inr c ! dcr b ! jnz d$init$loop ; and loop for each drive jmp boot$1 cseg ; followinlists: jmp listst ; return list device status ?sctrn: jmp sectrn ; translate logical to physical sector ?conos: jmp conost ; return console output status ?auxis: jmp auxist ; return aux input status ?auxos: jmp auxost ; return aux output status ?dvtbl: jmp devtbl ; return address of device def table ?devin: jmp ?cinit ; change baud rate of device ?drtbl: jmp getdrv ; return address of disk drive table ?mltio: jmp multio ; set multiple record count for disk I/O ?flush: jmp flush ; flush BIOS mai ; recover count and character pop h ; recover the rest of the vector not$out$device: inr b ; next device number mov a,h ! ora l ; see if any devices left jnz co$next ; and go find them... ret ; CONOST ; Console Output Status. Return true if ; all selected console output devices ; are ready. conost: lhld @covec ; get console output bit vector jmp ost$scan ; AUXOST ; Auxiliary Output Status. Return true if ; all selected auxiliary output devices ; are ready.g in resident memory boot$1: call set$jumps call ?ldccp ; fetch CCP for first time jmp ccp ; WBOOT ; Entry for system restarts. wboot: lxi sp,boot$stack call set$jumps ; initialize page zero call ?rlccp ; reload CCP jmp ccp ; then reset jmp vectors and exit to ccp set$jumps: if banked mvi a,1 ! call ?bnksl endif mvi a,JMP sta 0 ! sta 5 ; set up jumps in page zero lxi h,?wboot ! shld 1 ; BIOS warm start entry lhld @MXTPA ! shld 6 ; BDOS system callntained disk caching ?mov: jmp ?move ; block move memory to memory ?tim: jmp ?time ; Signal Time and Date operation ?bnksl: jmp bnksel ; select bank for code execution and default DMA ?stbnk: jmp setbnk ; select different bank for disk I/O DMA operations. ?xmov: jmp ?xmove ; set source and destination banks for one operation ?priv jmp privcall ; Reserved for system implementor jmp 0 ; reserved for future expansion jmp 0 ; reserved for future expansion ; BOOT ; Initial entry point f    auxost: lhld @aovec ; get aux output bit vector jmp ost$scan ; LISTST ; List Output Status. Return true if ; all selected list output devices ; are ready. listst: lhld @lovec ; get list output bit vector ost$scan: mvi b,0 ; start with device 0 cos$next: dad h ; check next bit push h ; save the vector push b ; save the count mvi a,0FFh ; assume device ready cc coster ; check status for this device pop b ; recover count pop h ; recover bit vector ora a ush d pmsg$loop: mov a,m ! ora a ! jz pmsg$exit mov c,a ! push h call ?cono ! pop h inx h ! jmp pmsg$loop pmsg$exit: pop d pop b ret ?pdec: ; print binary number 0-65535 from lxi b,table10! lxi d,-10000 next: mvi a,'0'-1 pdecl: push h! inr a! dad d! jnc stoploop inx sp! inx sp! jmp pdecl stoploop: push d! push b mov c,a! call ?cono pop b! pop d nextdigit: pop h ldax b! mov e,a! inx b ldax b! mov d,a! inx b mov a,e! ora d! jnz next ret table10: dw -10 ; has an available character. const: lhld @civec ; get console input bit vector jmp ist$scan ; AUXIST ; Auxiliary Input Status. Return true if ; any selected auxiliary input device ; has an available character. auxist: lhld @aivec ; get aux input bit vector ist$scan: mvi b,0 ; start with device 0 cis$next: dad h ; check next bit mvi a,0 ; assume device not ready cc cist1 ; check status for this device ora a ! rnz ; if any ready, return true inr b ; drop devic; see if device ready rz ; if any not ready, return false inr b ; drop device number mov a,h ! ora l ; see if any more selected devices jnz cos$next ori 0FFh ; all selected were ready, return true ret coster: ; check for output device ready, including optional ; xon/xoff support mov l,b ! mvi h,0 ; make device code 16 bits push h ; save it in stack dad h ! dad h ! dad h ; create offset into device characteristics tbl lxi d,@ctbl+6 ! dad d ; make address of mode byte mov a,00,-100,-10,-1,0 ?pderr: lxi h,drive$msg ! call ?pmsg ; error header lda @adrv ! adi 'A' ! mov c,a ! call ?cono ; drive code lxi h,track$msg ! call ?pmsg ; track header lhld @trk ! call ?pdec ; track number lxi h,sector$msg ! call ?pmsg ; sector header lhld @sect ! call ?pdec ; sector number ret ; BNKSEL ; Bank Select. Select CPU bank for further execution. bnksel: sta @cbnk ; remember current bank jmp ?bank ; and go exit through users ; physical bank e number mov a,h ! ora l ; see if any more selected devices jnz cis$next xra a ; all selected were not ready, return false ret ; CONIN ; Console Input. Return character from first ; ready console input device. conin: lhld @civec jmp in$scan ; AUXIN ; Auxiliary Input. Return character from first ; ready auxiliary input device. auxin: lhld @aivec in$scan: push h ; save bit vector mvi b,0 ci$next: dad h ; shift out next bit mvi a,0 ; insure zero a (nm ! ani mb$xonxoff pop h ; recover console number in jz ?cost ; not a xon device, go get output status direct lxi d,xofflist ! dad d ; make pointer to proper xon/xoff flag call cist1 ; see if this keyboard has character mov a,m ! cnz ci1 ; get flag or read key if any cpi ctlq ! jnz not$q ; if its a ctl-Q, mvi a,0FFh ; set the flag ready not$q: cpi ctls ! jnz not$s ; if its a ctl-S, mvi a,00h ; clear the flag not$s: mov m,a ; save the flag call cost1 ; get the actual ouselect routine xofflist db -1,-1,-1,-1,-1,-1,-1,-1 ; ctl-s clears to zero db -1,-1,-1,-1,-1,-1,-1,-1 dseg ; following resides in banked memory ; Disk I/O interface routines ; SELDSK ; Select Disk Drive. Drive code in . ; Invoke login procedure for drive ; if this is first select. Return ; address of disk parameter header ; in seldsk: mov a,c ! sta @adrv ; save drive select code mov l,c ! mvi h,0 ! dad h ; create index from drive code lxi b,@donexistant device not ready). cc cist1 ; see if the device has a character ora a jnz ci$rdy ; this device has a character inr b ; else, next device mov a,h ! ora l ; see if any more devices jnz ci$next ; go look at them pop h ; recover bit vector jmp in$scan ; loop til we find a character ci$rdy: pop h ; discard extra stack jmp ?ci ; Utility Subroutines ipchl: ; vectored CALL point pchl ?pmsg: ; print message @ up to a null ; saves & push b ptput status, ana m ; and mask with ctl-Q/ctl-S flag ret ; return this as the status cist1: ; get input status with and saved push b ! push h call ?cist pop h ! pop b ora a ret cost1: ; get output status, saving & push b ! push h call ?cost pop h ! pop b ora a ret ci1: ; get input, saving & push b ! push h call ?ci pop h ! pop b ret ; CONST ; Console Input Status. Return true if ; any selected console input device    tbl ! dad b ; get pointer to dispatch table mov a,m ! inx h ! mov h,m ! mov l,a ; point at disk descriptor ora h ! rz ; if no entry in table, no disk mov a,e ! ani 1 ! jnz not$first$select ; examine login bit push h ! xchg ; put pointer in stack & lxi h,-2 ! dad d ! mov a,m ! sta @RDRV ; get relative drive lxi h,-6 ! dad d ; find LOGIN addr mov a,m ! inx h ! mov h,m ! mov l,a ; get address of LOGIN routine call ipchl ; call LOGIN pop h ; recover DPH pointer not$firscessor operations end rack: out p$disk$track ; give 1797 track ; ; Now, Get sector. ; get$sect: lda @sect out p$disk$sector ;and sector ; ; Save track info for drive ; lxi h,fd0$access ; TO address lded @rdrv ; get current drive xra a ; Clear a mov d,a ; Use it to clear d dad d ; lxi d,old$track ; FROM address xchg ; d,-8 ! dad d ; point to read routine address jmp rw$common ; use common code ; WRITE ; Write physical sector from currently selected drive. ; Finds address of proper write routine from ; extended disk parameter header (XDPH). write: lhld @adrv ! mvi h,0 ! dad h ; get drive code and double it lxi d,@dtbl ! dad d ; make address of table entry mov a,m ! inx h ! mov h,m ! mov l,a ; fetch table entry push h ; save address of table lxi d,-10 ! dad d ; point to write routine adt$select: ret ; HOME ; Home selected drive. Treated as SETTRK(0). home: lxi b,0 ; same as set track zero ; SETTRK ; Set Track. Saves track address from ; in @TRK for further operations. settrk: mov l,c ! mov h,b shld @trk ret ; SETSEC ; Set Sector. Saves sector number from ; in @sect for further operations. setsec: mov l,c ! mov h,b shld @sect ret ; SETDMA ; Set Disk Memory Address. Saves DMA address ; from in @DMA and setACopyright (C) 1982, Digital Research BNKBIOS3 SPR F600 0A00 BNKBIOS3 SPR AD00 1300 RESBDOS3 SPR F000 0600 BNKBDOS3 SPR 7F00 2E00 60K TPA $$$$$1, BIOS Err on A: No CCP.COM fileCCP COM͙!:;>Q~>Qw# x Q:=_2ͅ!ͷ !>Q~>Qw# x Ӡ!45( 5 ې@Ӑ>>dress rw$common: mov a,m ! inx h ! mov h,m ! mov l,a ; get address of routine pop d ; recover address of table dcx d ! dcx d ; point to relative drive ldax d ! sta @rdrv ; get relative drive code and post it inx d ! inx d ; point to DPH again pchl ; leap to driver ; MULTIO ; Set multiple sector count. Saves passed count in ; @CNT multio: sta @cnt ! ret ; FLUSH ; BIOS deblocking buffer flush. Not implemented. flush: xra a ! ret ; return with no error s @DBNK to @CBNK ; so that further disk operations take place ; in current bank. setdma: mov l,c ! mov h,b shld @dma lda @cbnk ; default DMA bank is current bank ; fall through to set DMA bank ; SETBNK ; Set Disk Memory Bank. Saves bank number ; in @DBNK for future disk data ; transfers. setbnk: sta @dbnk ret ; SECTRN ; Sector Translate. Indexes skew table in ; with sector in . Returns physical sector ; in . If no skew table (=0) the22!f!"f"j!E"l>ӓ۔>!~(>>w2@2222͊<(J͏͔z>Ӕ>۔>2ەӗ:f!ېӐ>Ӕ:z!"h!>:z!"h!>>Ӕ( (    :*:2:!ԳӔ>= a۔:> :> 23~ E@2-E@2-q? ; error message components drive$msg db cr,lf,bell,'BIOS Error on ',0 track$msg db ': T-',0 sector$msg db ', S-',0 ; disk communication data items @adrv ds 1 ; currently selected disk drive @rdrv ds 1 ; controller relative disk drive @trk ds 2 ; current track number @sect ds 2 ; current sector number @dma ds 2 ; current DMA address @cnt db 0 ; record count for multisector transfer @dbnk db 0 ; bank for DMA operations cseg ; common memory @cbnk db 0 ; bank for pron ; returns physical=logical. sectrn: mov l,c ! mov h,b mov a,d ! ora e ! rz xchg ! dad b ! mov l,m ! mvi h,0 ret ; READ ; Read physical record from currently selected drive. ; Finds address of proper read routine from ; extended disk parameter header (XDPH). read: lhld @adrv ! mvi h,0 ! dad h ; get drive code and double it lxi d,@dtbl ! dad d ; make address of table entry mov a,m ! inx h ! mov h,m ! mov l,a ; fetch table entry push h ; save address of table lxi    Jm-$ML@ ~͊(1JM=! ۍ(!W~wӍ#͍ۍ ӌ?~ ~=W\>HH ۄW> Ӈ<Ӈz 2ZW!Y~0w!X~0wӰ>ۉ(!X~ӈwۉ(:Xӈۍ0-یWۍ_( :WӍӍ?!~VېOӐ>>Ӕ>>Q :Z 2ZO=;z![V~͊ѷ #JM!Xր(= ~ ~wgۉ(|ӈKcBB+"}{_}o>2~77ø~7"9:OG#Q{ozg# ""!2*%DM**ѵ+)) H~#+}#<:<ʲ<77:<ʢ-f(M!W~wӍf(y/ӑ>ӓӓf(yӅ>Ӈ<Ӈ~FW< w>2dql#ۆ>!yͦ(~FO< w>2~!~![F͍Vpր( =( =(>:Y:Y 2Yr~NNӍ>$ӍیӍ2W>8h&))>!~̓![̓O:Y(>`0 >z8y &y0(8:Y ( y> ( ˹> (moqsuwϼy޼{] _a*c9eHgWifkuKMOQSUлW߻Y[9 ;=+A:CIEXGgIv",!."*K6*}ʴ}<ʴ.}o|g "($Kt>=2(*f*(}DɯQ"(>QKQKQ>Q"%Q!*$K*"x!*!@$@hK\K:K ~#~ w*NK*NK^#V#N#F!x>QGQx3ڰbڼqҼo5p5"""*!yb! ~G*!NKկ2}!,"**NK6 :+OK2$^#V#N#FxNp:$p:Gjxj Y# A>QFQSACC*C}(-*A[KC:="A*[?KC:>S?:;Q{EAD  :Yӈh&)))n& ےӒ>@Ӎ~ͷ:AO !ͷ*!ͷ*2;C=:<2<:]|‚*Û*)>]²|žÛ$~O #ù>/<33O _ W{!ѭ|***)>,|h&)))~f+]~oP>W>wfͦf$*À*3579;º=Ѻ?57#%',);+J-Y/h1wùҹ!-< K Z ixKK{<<ʽ! ~6 69BK! OS$Nwy!"(9"f1f! Ҕ2! ~#foCOPYRIGHT (C) 1982, DIGITAL RESEARCH 1512822!"*"!!***),lwÒØn?qw}ÔêÉ} ˭ϭe%ÅXx1xF>Q>2Ã1Oj$|Ãà à à    ;Zx0N CP/M Version 3.0, BIOS version 1.3 ***BANKED VERSION***;C ۜO> ӟ>ӟ۞(D>ӟӜ> ӟ>ӟyӜ> ӟ> ӟ>ӟ>ӟ{ӟ>ӝ>xW!w q4 2b:O> :O> :b:O> :O> :b:O>:O>>ӟ>ӝ۞(D>ӟӜ> ӟ>ӟD>ӟ> ӟN2:(<m>nR,( 2:<2": <R(3I*+"*M!^#V#*Rg(Mx2y2 >2>2:|:w:ʴ>2d:#Ϫ>29ય2~2#!   )xð*}*}"*x"xm*^#V* s#r**s#r*:茶Y4Y̓**~#ng* s#r ^#V랍a##)0"xx!"""XC*~<Ω*":!::9*"x"*"g*3:= :Oi :=H:Gi a6:G/O**W :T=2!";&"=͇*~W#~X###~ 2J!L*ɰ~0ް1!S~24!l#:2":2#>22!L"!""2^#V: :#:_"ķy:O>O>:O>O>:O>O>*>2>!wѷ~w##!N#F#XF#N#ͣ2F#N#ͣ2F#Nͣ2>2!:Nķ(m: <2=(:=(=!_W!@""! "!"}!s,r, >G^!"!"!"!"!a"!~!![>ӝ>!ͷɯwwyª !#+>DPW Not ready, Protect, Fault, Record not found, CRC, Lost data, DREQ, Busy, Time out, Retry (Y/N) ? !"ҍ aʚ~¨6*:X)!:T>qk֨!:6>X*{Q:_2{2Ē"͂"X~<¨#cdfg!"()*N!r)!N!)z<*)"!":X*:w:w#:w*2*}D ?!B (<(< +s#r&r#~#fo !y(  !!}:;2i`z n&*&)~#foý*&)~#fo~#fo22ɯ BIOS Error on : T-, S-(F %y1 y!^#V#{6++~2y2+V+^Ͷ cy2i&) ~#fo{m!~2!~#foͶi`"i`"i`":ӕ(  O a !ͷ:<G:2:(:2(>G:+8> Gx2 , Read, Write *ͷ:(#!;!iͷ͈Yv:@>!>!!^ͷ^#V#ܷ >: ەӕӗ>Ӕ> =i۔m۔xxӐ@( !|=+} :!派(: Jӕ:N:2ӕ:Ӗ![Wü ":N (yx>NJ:Nx:<($THAN 10 BAD TRACKS FMT>Ӕ![W>wHa"G*":(:2![Wͪې:̓¡>2ͱԟߞ?~¾¾ʦƦ>w͙=2͜:wÚ~̓ʑpá!6NwͧBpͧȫÚgsr͐-͜ĎͤS)_ͤ̓~?w͐s-?F͜pN͆p# Þ͐*6!¿?~p*6 >2ͱݟԟߞͷw*oq͋"@6ȫ͚Xͤ͋͗wO~<: g~w#w#6##)͋@ * g~?G++9bڗ>2#×:#<֨2#*!""++"29Cw*{}<^#Vz!c!>c! Jw*q~69!͐=‡*":*}®:=::<>2*i^#V+ d!K*}@*)): K:) O "!w [O?WGzO:VxGyOGxwq*}}>=/>~/>!:x^yx/>2>~>:>~ 2>:* >> (G >! :? <:<( *ͷ!;!ͷ͈YJ>>!:> !22:K!ͷ!ͷ:"2:#22!>2!"*"*"*"*!N# (#z+ {h##) 2;|2<:2=>   !o#~>T}! 6**#K"G*~ xr͐-xą@˜7(͚Sʀw: :<RHͥ:>~c!o#~E^#V)G#~#~!~ b k##N#F#^#V#~#fo~o2{2g*wޒʪҢÞ+}*#}o|g:O*s#r#w!~w/~@w//Hͥ*e>=)_g:0"ök*w)*c)-}ͤÀk*s":;:r2͚Ώù͚Ώœ͚}/_|/*eW}_*c"e}o|g"c>2{( ȫˆʀHÈ2xą ):@ΖO~#w͚ʀô̓b_++V@* )͗Os++r~Gw#* #~$%+@*9>  #>? ;*~ w-xąH"0 *ĊHEʀ@~›:6¦w͚̋ȫÇPY*{zBKNyʺ Nú2: *~w *" ݓ2>ʄ@~k:(s~*9~Ês~ԟ~ͅ<:<œ. ʩ.ʩA܌rr##s܌<}rcN! ~态O>G~G!~G~o>_yG~.|°! w:ck[!x?[! ~ʤ͆[͗PPvqO-á=.:<ʰ! Vq##~_@wڧͶ:WMںʛ>úͶ >TJ:!ʷ͞x!Ǜw4 ϛPWޛP܌ÂՌÂ*!!~~#~O~#FsO s#r:(„y==„*!^W*y^#Vx7=2wͼկw#KWK*"J T͞*:["—>2—͇ͱ* «>2͙wBp+Ң:w͚AP{ 2W>O2ø}R*e):r͚Ώc2ZT͐-ږ3͗@YsY̓YןYͅ:ߞAsҢ:@Ң@Ң$͚̓A؏=:<~?¯ká?~?ʾZT͐ڡ*>o"͒"!Ñ:Oݓ"Ý}6͚ ~2Asv@NN~v$̓W+vw̚v$̓rrͅ:rߞ>2+A@2G:<ޔ2x# W:<­:22G?>Grx~:2Ô##~*$*">2̀2kºʺ**iҺ@:O~픯2~WW:2Ôyʛ?ʔx ʔ |̷ǔÔN:r:/GyOOA +¬ ¢y2:x¹o&:W>OͫE:ڟ?N/*"y2ͦ>2 ݓRXޒDM*w6# x *ow**ws#r̀*i6#6*}"j@*|<ď>!8>8> t>nͦv8 ~*own+SX:ڜq:ʺ!ʵ>2܌ͤ2њO ̎DM͸}ޚ>r""2:2* :::29:>:>*ڈ>F6:_/G:ʧ:ڨ|OͤG:_O̎̎zW{™|:*}|BKN™ zyG:!vq:vՌvMڂ?Ͷ >T͓Â!">Â:G:O:h=27ryy/W!:lr!Z2!"ög:2T͐-:ʹ>2<2ږ!w: >2*6ݓݖO~<w:*)@ u:G*g`~!x_<_@*oy<:/G?~##~? 6K@?F6##N6⟯2p##q:#*~w>2*p@! ~*"v@*w# ) 6#̟͙N#FxT]## #~ ȷ  *4# ' 4! *~^ ^33G# Pv:dv6 yT] KKͦޒ*w"wͦ"w@ :ÒNɒ N#Fyؒ*}|h#ð*ͫ# 6*q@!"@**#":&2͒:È0:+Òy<_W`iͫDM*w ~bNpwޒDM*we ^#V#~2>â9͆>!"*y³*X*ÿ͂"*g*K!~<:wb##>w#wĎ> r!~#w##~2 4~?ɘ̓¹:<ɘɘüޖAX2rK:w++~=wv4͗O5:2X!"*>o+"v *!b"ݓ": r#~?w#>r# L=J Lv wȫb܌?~O ͆ژ†wŒ~è# # x ͗w ٗڗٗڗw@ ~wb͐Úݑ!x>w~6:6~#+w#w+~;wɯ2KOFq-yl?Npg:ʓ~2@ !ק)#w*~"Ҟ!Fw䞨Ҟ̓Ҟ:w̚":>墯2̓*~wć"̀!~$6:03i"!~6*e>=)Q!QX@˜ >2 ˜!!q#p#w2wW*e_3ҫ-!s:!xQ*   ozg**|g͸*u* Ɛ ѐR>22Zw*q>ww:c *#*is#r*:!:)e:O!*c:Oͫ}@2æ ~á*g:o$*~K6?~wKw**i{#zir+s{O:w:Ғ4~:w?r##rp# ä |g}oì*g #G ¾1*q:*w***> r 2":O:G2!w*~zWw+ !z?#~*!* *G!O~2~m͗O~t>2?:2Ó*"r*r"ÿ<:g:!͐*f}D! ~6t!rͷւO(^ƂƂƂ  :Function = File = !,$"h!9"f! ͉:2t™:!=Hgo:O*;*͂:A2=/::0! dگ61#d ڸïp#:w#6 !6:6 *#!)6.#)͂ O(BDOS > wM  2*7w#6?#7 .,:;[]=<>|!?]45#Ra{i_p# l s s9ʌ^:—~x ):*:ňň>*(+"(w++2+2+Ʉp؄!" >2+2*jx.#NzW::!2W!5=^x^z:m:*;#wO:͂^2¢ů͠ć:!ڽ*(~ׅ݅5WèՇ؄jׅM2ͨx·*(+w"(j̓ !%"(^-:*$P:<\:W:2xM s:<9>2:*9x~+q’x2:*g͝DM*0MD"!*MD$:Oë!N: «G>O: Žù*Ď :ڎn` ~#foͤ2O̎"}:O*"!s#r#p*kN#F*m^#V#F*:O}|y9*+"*}|yP#9**DM"*ks#r*ms#r#pyox*kw#w*mw#w#w>2'å2*OͶyڲò<*eͲ:0!::ò2*>*ͫ"4#4#4)7 #  w#*J|^#V#"i##"k##"m###"o#"q##"!s )*s!)*|!6~67 l ls:¬MA2*2:*(:+w"(ͺ:G::+̜2 5*(~o#"(Mš*(~`Uoj*(~#"(Ñ!*~6s!+6:+‚xoڊ{2Ó#w:2.+:.2-!%"(2*!Š"&!*~4:2-Ԃ:Gͳͨ^2+>2:2*N#G2 2GH)+6:2,:!- ̓:,!̓+*(~L#Bxz:*:*(~ʓOrrorFile Exists? in Filenameòò>2a.":2:<:55;:2ɯ22{_zW{_zW )7CP/M Error On : Disk I/OInvalid DriveRead/Only FileRead/Only DiskPassword Er ̓ ̓! O(Ì*(~2**}ʷ!#¶!""÷:_:*(#w΄xH!Š)6"&:!Š x5~y 5 6y(^̓@O:=7:̓y ̓:I ̓:=e: zz#̓͂:! ̓ G:Ҏ>xʝʝw>ɯw̩z:»!>wɯ:=zxzz::G:=/ͽx:Āy!4 šn!6@G:x: P:<: P n6 t6! ^6 t6u:)<͠^!)"!z<~rs^#V#N#FxN:oʲ̀õ(# Þry< <<%zrͷr6r9rMDÌ:o!6!h: ʚnt2 r62>rz<*   kick it mvi a,com$default ; reset command parameters out p$aux1$control ; to its default push psw ; Save values (LEL0184) in p$aux1$data ; Read in anything (LEL0184) pop psw ; Restore command byte (LEL0184) out p$aux1$control ; OUT again in case 1st one missed (LEL0184) sta rspar ; Save RS232 parameters ei ; enable interrupts cinit$exit: ret page ; check$dev ; Assumes the address of a jump table in de, and a device in b. ; Preserves b and c. check$dev: mviced only by the DEVICE utility. ; ?cinit: lxi d,xfer$init ; jump table for ?cinit mov b,c ; needs b jr check$dev ; check for legality ; ; this table parallels @ctbl ; xfer$init: jr display$init ; init 6502 jr aux$init ; init rs-232 port jr kb$init ; init keyboard port jr lpt$init ; init parallel port kbinit: lda kmode ; Get keyboard bits (LEL0284) out p$kb$data ; Send out (LEL0284) display$init: lpt$init: ; ; Do nothing (set up in boot rom)  a,max$devices cmp b ; b > max$devices? jrc bad$device ; yes mov l,b ; device to l mvi h,0 ; make 16 bits dad h ; double it dad d ; entry in jump table pchl bad$device: xra a ret page ; ci (b) ; Character device input. This routine is called with the ; character device in register b. It returns an 8 bit ; character with no parity. ?ci: lxi d,xfer$in jr check$dev ; must parallel device table ; xfer$in: jr crtin jr auxin jr kbin jr lptin crtin: ; ret ; aux$init: ; ; get default baud rate, then set it, by setting the ; base baud rate in port c of misc. 8255, and baud rate ; factor in 8251 chip. ; mov l,b ; get device number mvi h,0 ; make into word dad h ! dad h ! dad h ; *8 (table entry size) lxi d,@ctbl+7 ; character device table dad d ; device baud entry mov l,m ; get baud rate mvi h,0 ; make word lxi b,baud$table ; settings to achieve baud rate dad b ; entry in table ; ; now have pointer to baud ta title 'Character I/O handler ' ; CHARIO.ASM ; Character I/O for the Modular CP/M 3 BIOS ; This module is organized into routines to do ; initialization, input, output, and status checks. ; ; Copyright (c) Visual Technology, 1983 ; ; Revision history ; ; Version 1.2.3 03-17-84 LEL ; maclib Z80 ; define Z80 op codes maclib ports ; define port addresses extrn ?pmsg extrn ?bnksl,?wboot extrn @cbnk public ?cinit,?ci,?co,?cist,?cost public @ctbl public aux$in$ptr,aux$out$plptin: mvi a,ctlz ; set to eof character ret auxin: lxix aux$in$ptr ; auxin buffer structure call bufin ; get character ei ; enable interrupts ret kbin: lxix kb$buf$in ; Point to keyboard buffer call bufin ; Get character ei ; reenable interrupts mov c,a ; Save character in C-reg ; ; Check caps lock ; lda kmode ; Get keyboard mode byte ani 010h ; check caps lock jrz kbin$20 ; Jump if not on mvi a,'a'-1 ; Check if >= 'a' cmp c ; jrnc kbin$20 ; Jump ible entry. set base rate. ; di ; disable interrupts in p$misc ; retain old settings xra m ; get new setting ani not misc$baudmask ; clear base rate bits xra m ; set new ones out p$misc ; reload it ; ; now set base rate factor in 8251 chip. ; mvi a,com$ir ; internal reset out p$aux1$control ; kick it mov a,m ; get new base rate xri mode$default ; default modes ani mode$baudmask ; use baud rate from table xri mode$default ; include defaults out p$aux1$control ; tr, kb$buf$in public dspint, kint, rsint, kmodei $*MACRO max$devices equ 3 ctlz equ 26 bdos equ 5 cseg page ; ; ?cinit ; This module is called for each of the 16 character devices, and ; initializes the devices. Register C contains the device number. ; The routine initializes the physical character device specified ; in register C to the baud rate contained in the appropriate entry ; of @ctbl. This routine need not be supplied if i/o redirection ; is not implemented. It is referen   f below range mvi a,'z' ; Check if <= 'z' cmp c ; jrc kbin$20 ; Jump if above range mov a,c ; Else, get character xri 20h ; Shift to upper case jr kbin$exit ; and exit ; ; Check numeric pad ; kbin$20 mov a,c ; Get keycode cpi 0bfh ; Numeric pad or less? jrnc kbin$50 ; Jump if no cpi 83h ; Enter key? jrz kbin$40 ; Jump if yes cpi 0a0h ; Low end of numeric pad? jrc kbin$50 ; Jump if less kbin$40 lda kmode ; Test num lock ani 20h ; jrz kbin$50 ; Jump  ret page ;inst(ix) ; Ix is the input buffer structure for a character device. ; This routine returns true if there is a character waiting, ; false otherwise. inst: ldx a,buf$empty ; next byte to empty ldx b,buf$fill ; next byte to fill sub b ; same? rz ; yes, it's empty mvi a,true ; return true ret page ; co (b) ; Character output. This routine is called with a device number ; in register b, and the character to be output in c. ; It waits until the device (or buffer)llel device table ; xfer$st: jr crtst jr auxst jr kbst jr lptst crtst: lptst: xra a ret auxst: lxix aux$in$ptr ; aux buffer structure di ; Disable interrupts call inst ; Anything in buffer? ei ; reeable interrupts ret ; and return page kbst: lxix kb$buf$in ; keyboard buffer structure di ; Disable interrupts call inst ; Check input status ei ; reenable interrupts rz ; If no character, return ; ; There is a character in the buffer, but in orderif not on mov a,c ; Get keycode cpi 83h ; Enter key? mvi a,0dh ; (assume yes) jrz kbin$exit ; Jump if true res 7,c ; Else change to number jr kbin$55 ; ; ; Test other special characters ; kbin$50 cpi 08ch ; Tab key? mvi a,09h ; Yes => Control-I jrz kbin$exit kbin$55 mov a,c ; Get keycode kbin$exit: ret page ; bufin (ix) ; Ix points to buffer data. ; Returns character in register a, after updating buffer ; management data structure. Buffer is circular. ; buf is ready to accept ; another character, and then sends the character. ; The character is 8 bits, no parity. ?co: lxi d,xfer$out jmp check$dev ; ; must parallel device table ; xfer$out: jr disp$out jr aux$out jr kb$out jr lpt$out kb$out: xra a ret aux$out: call ?cost ; device ready for output? jrz aux$out ; loop until ready di ; disable interrupts call bufout ; Put char into buffer lxi h,rspar ; Point to RS232 parameters (LEL0384) mov a,m ; Get them to know if ; it 'counts', we must get the exact character. ; ; lxix kb$buf$in ; Point to input buffer (LEL0384) di ; disable interrupts ldx b,buf$empty ; get empty pointer push b ; save it call buffer$in ; Get keycode ldx d,buf$empty ; Get new empty pointer pop b ; Get empty pointer stx b,buf$empty ; restore it ei ; reenable interrupts ; ; Now, check for 'non-characters', ie shift and num lock. ; sui 80h ; Caps lock? jrz kbds$1 ; jump if yes dcr a ; Num lo$empty is the offset of the next byte to return. bufin: spin: di ; push b call ?cist ; is there a character? pop b ei ; jrz spin ; no, wait for one di ; turn off interrupts buffer$in: ldx a,buf$empty ; offset of empty in buffer ldx b,buf$length ; length of buffer mov c,a ; save pointer ; ; add 1 mod length ; inr a ; increment buffer pointer cmp b ; did we go out of bounds? jrnz inbounds$i ; if not xra a ; else wrap around inbounds$i: stx a,buf$empty ;  (LEL0384) ori com$txe ; enables transmit mov m,a ; Store new params (LEL0384) out p$aux1$control ; aux1 control port ei ; reenable interrupts ret lpt$out: call ?cost ; busy jrz lpt$out ; yes, spin mov a,c ; get the character cma out p$printer mvi a,1 ; strobe the printer out p$8255$control ; to 1 xra a ; and back out p$8255$control ; to 0 ret disp$out: call ?cost ; busy? jrz disp$out ; yes, spin mov a,c ; get the character out p$disp$out ; send itck? jrz kbds$2 ; jump if yes dcr a ; Num lock up? jrz kbds$4 ; jump if yes mvi a,true ; Character is ok ret ; ; ; Handle caps and num lock ; kbds$1: lda kmode ; Get keyboard mode xri 010h ; toggle caps lock jr kbds$3 ; kbds$2: lda kmode ; Get keyboard mode xri 020h ; Toggle numlock bit kbds$3: sta kmode ; Store new settings kbds$4: di ; disable interrupts stx d,buf$empty ; store empty pointer ei ; reenable interrupts xra a ; a=0 for no charsave new emptying pointer mvi a,buf$buffer ; offset of buffer add c ; offset of character sta loc$i ; save in i-stream ldx a,$-$ ; load character loc$i equ $-1 ; disp. field of ldx ret page ; cist (b) ; Character device input status. This routine is called ; with a device number in register b and returns false ; if the specified device has no input character ready, ; and true if the device has an input character to be read. ?cist: lxi d,xfer$st jmp check$dev ; must para    out ; ; the following uses the bit set/reset feature ; of the 8255. mvi a,0000$1110b ; reset port c bit 7 out p$disp$control ; to shake hands inr a ; set port c bit 7 out p$disp$control ; to complete handshake ret page ; bufout (ix,c) ; This routine takes the character to be sent out and ; stuffs it into the buffer denoted by register ix. bufout: ldx a,buf$fill ; fill point in buffer ldx b,buf$length ; length of buffer mov d,a ; save fill point inr a ; next fill pointan error ; condition. ; Kint: Push psw ; Save A push h ; Save H (LEL0384) push d ; and d push b ; and b pushix ; and ix (LEL0384) ; ; Get keycode and check for warm or cold boot. ; in p$kb$data ; get keycode mov d,a ; save in d cpi 08ah ; Is it warm boot? jrz kint$6 ; jump if yes cpi 08bh ; Or cold boot? jrnz kint$7 ; jump if not page ; ; Key is cold boot. Jump to boot rom. ; kint$2 call reset$disks ; Reset floppy & wrz ost$false ; no. in p$misc ; if available ani misc$lpt$nobusy ; busy? jrz ost$false ; yes jr ost$true ; no page ; The entries in the following table are indexed by the ; values for baud rates in modebaud.lib ; baud$table: db baud$none ; none db baud$none ; 50 db baud$none ; 75 db baud$none ; 110 db baud$none ; 134.5 db baud$none ; 150 db misc$base01200 or mode$div64 ; 300 db misc$base02400 or mode$div64 ; 600 db misc$base01200 or mode$div16 ; 1200 db ba? cmp b ; outside? jrnz inbounds$o ; no. xra a ; yes, reset inbounds$o: stx a,buf$fill ; new fill point inbounds$5: mvi a,buf$buffer ; offset of buffer add d ; old fill point sta loc$o ; next byte to be sent stx c,$-$ ; store in buffer loc$o equ $-1 ret page ; cost (b) ; Character output status. This routine is called with a ; device number in register b. It returns with register ; a set to zero if the device specified cannot accept a ; character immediately, and retinch (LEL0384) lxi h,last$words ; Point to term. seq (LEL0184) mvi b,Last$length ; Load length (LEL0184) kint$3: push b ; Save B (LEL0184) push h ; Save H (LEL0184) mvi b,1 ; Device=1 (LEL0184) mov c,m ; Get character (LEL0184) call disp$out ; Send it out (LEL0184) pop h ; Restore h (LEL0184) pop b ; Restore B (LEL0184) kint$5: call disp$ost ; Wait till done (LEL1283) jrz kint$5 ; (loop if not) (LEL1283) inx h ; Point to next char (LEL0184) djnz ud$none ; 1800 db misc$base02400 or mode$div16 ; 2400 db baud$none ; 3600 db misc$base19200 or mode$div64 ; 4800 db baud$none ; 7200 db misc$base09600 or mode$div16 ; 9600 db misc$base19200 or mode$div16 ; 19200 @ctbl db 'DISPLY' ; device 0, 6502 CRT db mb$in$out db baud$none db 'RS232 ' ; device 1, RS-232 port db mb$in$out+mb$serial+mb$softbaud db baud$1200 db 'KB ' ; device 2, Keyboard db mb$input+mb$serial ; db baud$1200 ; (LEL0384) db baud$600 ; (LEL038urns with ff otherwise. ; B and C must be preserved. ?cost: lxi d,xfer$ost jmp check$dev xfer$ost: jr disp$ost jr aux$ost jr kb$ost jr lpt$ost kb$ost: xra a ret disp$ost: in p$disp$c ; port c ani disp$ready$rcv ; ready to receive? rz ; no. ost$true: mvi a,true ; return ready ret aux$ost: lxix aux$out$ptr ; aux xmit buffer di ; critical section ldx d,buf$empty ; next to read ldx a,buf$fill ; next to fill ei ; critical section buf$full$cond:  kint$3 ; Finish message (LEL0184) XRA A ; A=0 OUT P$BOOT ; ENABLE BOOT PROM jmp 0 ; ; Key is warm boot. ; kint$6 call reset$disks ; Reset floppy & winch (LEL0384) in p$disk$bits ; Get current settings ori 0100$1111b ; Turn off motor & deselect drvs out p$disk$bits ; Send out again mvi a,int$initial out int$port ei jmp ?wboot ; boot reset$disks: mvi a,fdc$reset ; Reset floppy (LEL0284) out p$disk$control ; send out (LEL0284) mvi a,wini$reset ; 4) db 'LPT ' ; device 3, Centronics parallel printer db mb$output db baud$none db 0 ; table terminator page ; ; Keyboard interrupt routine ; ; Takes incoming character, checks for warm or cold boot sequences. ; If it is either one, it performs them immediately. ; Otherwise, it stores the keycode in the buffer and performs the keyclick. ; If there is not enough room in the buffer to store the keycode, ; the key is discarded and the keyboard will beep to indicate ; this check is to see if the buffer was full. ; a full condition is the empty pointer one ; more than the fill pointer. Empty must always ; be ahead of fill (modulo buffer length since ; circular). inr a ldx e,buf$length ; need to wrap? cmp e ; if equal, wrap jrnz inbound$ost ; not equal xra a inbound$ost: cmp d ; is fill=empty? jrnz ost$true ; no. not full ost$false: xra a ; yes. full. ret lpt$ost: in p$misc ; printer status ani misc$lpt$avail ; available? j   Reset wini (LEL0384) out p$winch$control ; send out (LEL0384) mvi a,1 ; Select bank 1 (LEL0384) call ?bnksl ; for BDOS call (LEL0384) mvi c,0dh ; Reset disk system (LEL0384) call bdos ; perform call (LEL0384) ret ; (LEL0384) ; ; Key not cold or warm boot. ; kint$7: ; ; If screen is blanked, turn it back on & throw this key away. ; lda blank$flag ; Get blank flag (LEL0284) cpi 0ffh ; Screen blanked? (LEL0284) jrnz kins mov d,a ; store in d lxi h,kmode ; Get kmodes (LEL0384) mov a,m ; (LEL0384) ani 0011$0000b ; Keep leds only ora d ; OR in ani 7fh ; (not bell, tho) mov m,a ; Store new values (LEL0384) lxi h,kmodei ; (both) mov a,m ; ani 0011$0000b ; Keep leds only ora d ; mov m,a ; dspint$77: out clear$6502 ; Clear 6502 interrupt mvi a,int$initial ; Initialize out int$port ; Interrupt port ei ; enable interrupts dspint$87: in p$kb$control urn on/off keyboard leds. ; kint$90: mov m,a ; Store new num/caps lk (LEL0384) mov h,a ; store data kint$l: in p$kb$control ; Get status ani 01h ; Test Tx empty jrz kint$l ; loop if not mov a,h ; Get data back out p$kb$data ; Send to keyboard ; jr kint$99 ; then exit (LEL0384) ; ; Get ready to exit ; kint$99: jmp rs$exit ; (Same as other exit) (LEL0384) ; mvi a,int$initial ; Initialize ; out int$port ; Interrupt port ; popix ; start popping (LEL0384)t$9 ; Jump if not (LEL0284) xra a ; Clear A (LEL0284) sta blank$flag ; store as new flag (LEL0284) ; ; Send NULL to screen to turn it back on ; mvi b,1 ; Device #=1 (LEL0284) mov c,a ; C-reg=NUL (LEL0284) call disp$out ; Send to display (LEL0284) jr kint$99 ; Then exit (LEL0284) ; ; Screen not blanked. Put char into buffer. ; kint$9: mov a,d ; get keycode kint$11 push d ; save keycode lxix kb$buf$in ; point to buffer ldx d,buf$empty ; Get empty pointe; Get status ani 4 ; jrz dspint$87 ; ; Now do the actual out to the keyboard ; di lxi h,kmodei ; Get byte to send mov a,m ; out p$kb$data ; Send out ani 7fh ; (don't save beep) mov m,a ; ei ; ; Get ready to exit ; dspint$99: pop h ; Pop everything (LEL0384) pop d ; pop psw ; ret ; and return ; ; Beep routine ; beep: in p$kb$control ; Get status ani 4 ; Test Tx ready jrz beep ; Loop if not lda kmodei ; Get bits ori 80 ; pop b ; ; pop d ; ; pop h ; (LEL0384) ; pop psw ; ; ei ; enable interrupts ; ret ; and return Last$words: db 01bh,'c',00 last$length equ $-last$words page ; ; Display Interrupt routine ; ; Takes incoming character from 6502 code. This info is used for ; keyboard info only. ; Dspint: Push psw ; Save A push d ; and d push h ; and h (LEL0384) ; ; Get character ; in p$disp$in ; Get character r ldx a,buf$fill ; and fill pointer call buf$full$cond ; check full condition pop d ; restore keycode ora a ; (checking resultant flag) jrnz kint$30 ; jump if true ; ; Keyboard buffer is full. Beep rather than click and then exit. ; kint$23 call beep ; beep to indicate error jr kint$99 ; go to exit ; ; Keyboard buffer not full. Put char into buffer. ; kint$30 mov c,d ; Get char into C-reg push d ; call bufout ; put into buffer pop psw ; Get character intoh ; Set bell bit out p$kb$data ; Send it out ret page ;REC/SND (RS-232) INT ;SEE IF RECEIVER OR TRANSMITTER CAUSED INT. ; IF RECEIVER, ACCEPT CHR INTO RECEIVE FIFO. ; IF TRANSMITTER, OUT A CHR FROM TRANSMIT FIFO; ; IF FIFO EMPTY, TURN OFF TRANSMITTER. RSINT: PUSH PSW push h push D push b pushix ; (LEL0384) ;SEE IF REC OR SND CAUSED INT. in p$aux1$control ; read in status RAR RAR jrnC SINT ; ;REC INT: CHR TO FIFO. RINT: IN p$aux1$data ; read incoming mov d,a ; save it mvi a,12 ; Strobe out p$disp$control ; inr a ; then back out p$disp$control ; ; ; Get character. If it =FF, then it is really a signal that the ; screen has been blanked. ; mov a,d ; Get character (LEL0284) cpi 0FFH ; Is it FF? (LEL0284) jrnz dspint$44 ; Jump if not (LEL0284) sta blank$flag ; Else, store flag (LEL0284) jr dspint$77 ; and continue (LEL0284) ; ; Get info. Mask out the 2 leds. ; dspint$44: ani 1100$1111b ; minus led A ; ; Check for caps lock and num lock ; lxi h,kmodei ; Point to prev values (LEL0384) sui 80h ; Caps lock? (LEL0384) jrz kint$80 ; Jump if yes dcr a ; Num lock? (LEL0384) jrnz Kint$99 ; Jump if not either (LEL0384) ; ; Handle num lock ; mov a,m ; Get previos setting (LEL0384) xri 020h ; Toggle num lock jr kint$90 ; (LEL0384) ; ; Handle caps lock ; kint$80: mov a,m ; Get previous settings (LEL0384) xri 010h ; Toggle caps lock ; ; T    character MOV D,A ; save in D ; ; Check for parity error ; IN p$aux1$control ; get status bit 3,a jrz RINT0 ;Jump if ok ; Parity error. Reset error condition and replace char with '?' ; LDA RSPAR ORI 010H OUT p$aux1$control ANI 0EFH OUT p$aux1$control ;RESET ERROR MVI D,'?' ;REPLACE CHAR WITH '?' ; Processing continues here. ; RINT0: push d ; save character lxix aux$in$ptr ldx d,buf$empty ldx a,buf$fill call buf$full$cond ; buffer alreadytial ; Initialize out int$port ; Interrupt port popix ; (LEL0384) pop b POP D pop h POP PSW EI RET RSPAR: DS 1 ; ; The keyboard mode byte is kept twice. One (KMODEI) is used ; by the interrupt routine so that the led can be turned on ; as soon as the caps or num lock key is hit. The other ; (kmode) is used to actually effect the change to incoming characters ; as they are being processed. ; KMODEi: db 048h ; Initial keyboard 8251 values (LEL0284) kmode: db 048h ;  full? pop d ; (restore char) JrZ rs$error ; If yes, error mov c,d call bufout ; Else, put into buffer jr RS$EXIT ; ;SND INT: CHR FROM FIFO ; SINT: lxix aux$out$ptr ; Point to structure call inst ; Anything there? jrnz sint2 ; Jump if yes ; ; No characters in buffer. Turn off Xmit enable. ; sint$1: ; (LEL0184) in p$aux1$control ; Get status (LEL0184) ani 0000$0100b ; Transmitter empty? (LEL0184) jrz sint$1 ; Loop till it is (LEL0184) lxi h,rspar ; P (LEL0284) Blank$flag: db 0 ; (LEL0284) page ; ; Receive buffers kb$length equ 32 kb$buf$in: db kb$length ; length db 0 ; next character to take db 0 ; next character to fill ds kb$length ; buffer aux$length equ 32 aux$in$ptr: db aux$length ; length db 0 ; next character to take db 0 ; next character to fill ds aux$length ; buffer ; ; Transmit buffers aux$length$o equ 16 aux$out$ptr: db aux$length$o ; length db 0 ; next character to take db 0 oint to RS232 params (LEL0384) mov a,m ; Get current settings (LEL0384) ANI 0FEH ; Turn off xmit enable mov m,a ; Store new setting (LEL0384) OUT p$aux1$control ;SHUT OFF SND jr rs$exit SINT2: call buffer$in ; Get character from buffer PUSH PSW ; Save character (LEL0184) sint3: ; (LEL0184) in p$aux1$control ; Get status (LEL0184) ; ani 01h ; Xmit ready? (LEL0184) ; jrz sint3 ; Loop till it is (LEL0184) ani 05h ; Get Xmit ready & empty (LEL0384) cpi ; next character to fill ds aux$length$o ; buffer bootadd equ 0 end !*$K*"x!*!@$@hK\K:K ~#~ w*NK*NK^#V#N#F!x>QGQx3ڰbڼqҼo5p5"""*!yb! ~G*!NKկ2}!,"**NK6 :+OK2$^#V#N#FxNp:$p:Gjxj Y# A>QFQ05h ; Both must be set (LEL0384) jrnz sint3 ; To cure double char pblm (LEL0384) POP PSW ; Restore char (LEL0184) OUT p$aux1$data ; Send it jr rs$exit rs$error: mvi c,'?' ; Load question mark ldx a,buf$fill ; Point to fill location ora a ; Is it 0? jrnz rs$error$5 ; Jump if not ldx a,buf$length ; else,wrap jr rs$error$7 ; jump rs$error$5: dcr a ; decrement fill pointer rs$error$7: mov d,a ; call inbounds$5 ; Replace last char with '?' rs$exit: mvi a,int$ini    title 'Boot loader module for CP/M 3.0' public ?init,?ldccp,?rlccp,?time public nint, ivect extrn @civec, @covec, @aivec, @aovec, @lovec, @bnkbf extrn @dtbl,winc0 extrn ?pmsg,?conin extrn @cbnk,?bnksl extrn aux$in$ptr, aux$out$ptr, kb$buf$in maclib ports maclib z80 bdos equ 5 dseg ; init done from banked memory ?init: di ; disable interrupts lxi h,08000h ; hl <= device 0 shld @covec ; DISPLY = console output ; ; Set up interrupt vectors. Begin ,A" dw 05eedh ; "IM2" ENDIF ; ; Set up the interrupts that are implemented ; intset lxi h,firq ; Floppy completion IF REAL$1050 shld ivect+08 ELSE shld ivect+2 ; Point to vector ENDIF lxi h,kint ; Keyboard interrupt IF REAL$1050 shld ivect+10 ELSE shld ivect+4 ; Point to vector ENDIF lxi h,rsint ; RS232 interrupt IF REAL$1050 shld ivect+14 ELSE shld ivect+16 ; Point to vector ENDIF IF REAL$1050 ; display interrupt lxi h,dspint ;  title 'Boot loader module for CP/M 3.0' ; ; Updated to Version 1.2 03-02-84 LEL ; Updated to Version 1.3 03-29-84 LEL ; maclib ports maclib z80 public ?init,?ldccp,?rlccp,?time public nint, ivect ,empty$ptr extrn ?pmsg,?conin extrn @civec,@covec,@aivec,@aovec,@lovec extrn @cbnk,?bnksl extrn aux$in$ptr, aux$out$ptr, kb$buf$in extrn rsint, kint, firq, dspint extrn @date,@hour,@min,@sec extrn kmodei,motor$counter bdos equ 5 if banked tpa$bank eby pointing them all at a null ; interrupt routine so that every interrupt is satisfied in some way. ; lxi d,nint ; get address of null vector lxi h,ivect ; point to ivect table ini$vec: mov m,e ; store low byte of NINT inr l ; increment hl mov m,d ; store hi byte of NINT inr l ; increment hl jrnz ini$vec ; do for all IF REAL$1050 mvi a,0000$0000b ; Disable all interrupts out p$clk$portb ; Send it out mvi a,int$initial ; out int(from 6502 side) shld ivect+04 ; lxi h,vert$int ; Vertical retrace int shld ivect+06 ENDIF ; ; Initialize interrupt buffers ; lxix aux$in$ptr ; Point to aux input buff call empty$ptr ; fix pointers to empty lxix aux$out$ptr ; Point to aux output buff call empty$ptr ; fix pointers to empty lxix kb$buf$in ; Point to kbd buffer call empty$ptr ; fix pointers to empty IF REAL$1050 mvi a,all$ints ; Get interrupt mask out p$clk$portb ; Send qu 1 else tpa$bank equ 0 endif dseg ; init done from banked memory ?init: di ; disable interrupts lxi h,08000h ; hl <= device 0 shld @covec ; DISPLY = console output lxi h,04000h ; hl <= device 1 shld @aivec ; AUX = auxiliary input shld @aovec ; AUX = auxiliary output lxi h,2000h ; hl <= device 2 shld @civec ; KB = console input lxi h,1000h ; hl <= device 3 shld @lovec ; LPT = Centronics parallel ptr ; Set up interrupt vectors. Begi$port ENDIF ei ; reenable interrupts ; ; Check location C000H. If it has a value of 07, then we are booting ; from the winchester. Switch the addresses in LDRTBL to point to the ; winchester rather than the floppy. ; lda 0c000h ; Check value (LEL0284) cpi 07 ; Is it 7? (LEL0284) rnz ; Return if not (LEL0284) lxi h,winc0 ; Point to winchester (LEL0284) shld @dtbl ; Store into table (LEL0284) ret ?ldccp: ?rlccp: ?time: ret ; ; Null interrupt handler ; cse out mvi a,int$initial ; Initial value out int$port ; to int port ENDIF ei ; reenable interrupts ; ; Put up sign on message ; lxi h,signon$msg ; point to sign on msg call ?pmsg ; print it out ret ; ; Routine Empty$ptr ; ; "Empties" buffer by pointing empty and fill pointers to same ; location in buffer. ; empty$ptr: xra a ; Clear A stx a,buf$empty ; store in empty ptr stx a,buf$fill ; and fill ptr ret page cseg ; boot loading n by pointing them all at a null ; interrupt routine so that every interrupt is satisfied in some way. ; lxi d,nint ; get address of null vector lxi h,ivect ; point to ivect table ini$vec: mov m,e ; store low byte of NINT inr l ; increment hl mov m,d ; store hi byte of NINT inr l ; increment hl jrnz ini$vec ; do for all ; ; Set up interrupt mode 2 and select page ; IF REAL$1050 mvi a,ivect/256 ; get address of ivect dw 47EDH ; "LD Ig NINT: IF REAL$1050 push psw mvi a,int$initial out int$port pop psw ENDIF ei ret aseg org 0ffe0h ivect ds 32 ; 32-byte interrupt vector end is routine is called ; with a device number in register b and returns false ; if the specified device has no input character ready, ; and true if the device has an input character to be read. ?cist: lxi d,xfer$st jmp check$dev ; must para   most be done from resident memory ; This version of the boot loader loads the CCP from a file ; called CCP.COM on the system drive (A:). ?ldccp: ; ; In order to allow booting from the winchester OR the floppy disk, ; the boot program puts the drive code (01 for floppy A: drive or ; 07 for winchester C: drive) at location C000. We pick it up from ; there and use it to locate CCP.COM. ; lxi h,0c000h ; Point to C000 (LEL0284) mov a,m ; Get what is at C000 (LEL0284) cpi 07h ; I ; Store result inx d ; Increment reg inx h ; and storage area inxix ; and mask djnz time$25 ; Loop till done ; ; Get date data and translate to hex. ; lxi d,year ; Point to storage for result lxi h,clkvals ; Point to input values mvi b,3 time$27: push b ; Save count mov c,m ; Get 1's digit inx h ; Point to next digit mov b,m ; Get 10's digit inx h ; increment call bcd$to$hex ; Convert to hex stax d ; Store result inx d ; Increment pop b ; get cousta scbpb+2 ; Store (LEL0284) lxi d,scbpb ; Point to parameter block (LEL0284) call scbcall ; Set it (LEL0284) pop d ; Restore drive (LEL0284) mvi c,14 ; Select disk (LEL0284) call bdos ; (LEL0284) ldccp$exit: ret ; no$CCP: ; here if we couldn't find the file lxi h,ccp$msg call ?pmsg ; report this... call ?conin ; get a response jr ?ldccp ; and try again ?rlccp: IF BANKED lxi h,0100h lxi b,1000h ; Moving in 4k from bank 2 rl$1: mvi a,2 s it the winch? (LEL0284) jrz ld$0 ; Jump if yes (LEL0284) mvi a,01 ; Else, force to A: (LEL0284) jr ld$4 ; (LEL0384) ld0: ; (LEL0284) mvi a,3 ; Force to C: (LEL0384) ld4: ; (LEL0384) mov m,a ; Store in C000 (LEL0384) sta ccp$fcb ; Store in FCB (LEL0284) adi 40h ; Make alphabetic (LEL0284) sta ccp$drv ; Store for error msg (LEL0284) ; ; Set up the FCB ; xra a sta ccp$fcb+15 ; zero extent sta ccp$fcb+12 nt back djnz time$27 ; Loop 3 times ; ; Get hours ; mov b,m ; Get H1 inx h ; mov c,m ; Get H10 inx h ; call pack$word ; Pack into word sta @hour ; Store hour ; ; Get minutes ; mov b,m ; Get M1 inx h ; mov c,m ; Get M10 inx h ; call pack$word ; Put it in sta @min ; store minutes ; ; Get seconds ; mov b,m ; Get S1 inx h ; mov c,m ; Get S10 call pack$word ; pack into word sta @sec ; store minutes ; ; Now, comput call ?bnksl ; select extra bank mov a,m push psw ; get a byte mvi a,tpa$bank call ?bnksl ; select TPA pop psw mov m,a ; save the byte inx h dcx b ; bump pointer, drop count mov a,b ora c ; test for done jrnz rl$1 ret ELSE jmp ?ldccp ENDIF IF REAL$1050 dseg ; ; This routine is called whenever the BDOS wants to either read ; or change the date and time. On entry, if C=0, a read is ; requested. If C=0FFH, a write is requested. DE and HL must ; ; Zero ex field sta ccp$fcb+32 ; Zero cr field lxi d,ccp$fcb ; Point to FCB call open ; open file inr a jrz no$ccp ; If not found, check again ; ; File found. Load into 100h. ; lxi d,0100h call setdma ;start of TPA lxi d,128 ; call setmulti ;Read 128 rec at a time lxi d,ccp$fcb call read ;load the thing IF BANKED ; ; Now, Copy CCP to bank to bank 2 for reloading ; lxi h,0100h lxi b,1000h ; move 4K lda @cbnk push psw ; save current bank ld$1e the number of days since 1 Jan 78. ; mvi a,2 ; 1978 is not leap year sta leap ; so start leap count at 2 lxi h,0 ; Initialize hl for # days lda year ; Get year sui 78 ; minus 78 jm time$exit ; if less, error jrz time$50 ; Jump if zero push psw ; save year count time$30: lxi d,365 ; # days in normal year lda leap ; Get leap count cpi 4 ; Leap year? jrnz time$40 ; Jump if not inx d ; 366 days in a leap year xra a ; reinit leap count time$40: dadbe preserved. ; ?time: push h ; Save h push d ; and d mov a,c ; Get entry switch ora a ; Is it 0? jnz time$set ; No. Check if setting time ; ; Requesting read of time and date ; First read in the clock data. ; time$20: mvi b,12 ; Load # regs to read lxi d,regorder ; Register order lxi h,clkvals ; Temp storage area lxix masks ; Mask for extra bits time$25: ldax d ; Get reg to read call getdata ; Get data ldx a,0 ; Get mask ana c ; AND with data mov m,a: mvi a,tpa$bank call ?bnksl ; select TPA mov a,m push psw ; get a byte mvi a,2 call ?bnksl ; select extra bank pop psw mov m,a ; save the byte inx h dcx b ; bump pointer, drop count mov a,b ora c ; test for done jrnz ld$1 pop psw call ?bnksl ; restore original bank ENDIF ; ; Set up default drive as G: or A: ; lda 0c000h ; Get value at C000H (LEL0284) dcr a ; A=0,etc (LEL0284) mov e,a ; Move to E (LEL0284) push d ; save (LEL0284)     d ; add # days in year inr a ; Inc leap count sta leap ; store new leap count pop psw ; Get year count dcr a ; decrement jrz time$50 ; jump if zero push psw ; else, save year count jr time$30 ; and loop again time$50: lda month ; Get month dcr a ; minus 1 jrz time$70 ; Jump if January dcr a ; Else, decrement push h ; save # days so far lxi h,month$table ; Point to month table mov e,a ; move month to E xra a ; mov d,a ; Move 0 to D dad d ; Add to be jrz time$98 ; jump if zero jm time$91 ; No offset if date is < lhld temp ; Else, offset by 1 dcx h ; shld temp ; time$91: mvi b,001h ; Start month at 1 lhld temp ; Get # days mov c,l ; Start # days lxi h,month$table ; Time$92: mov e,m ; Get # days in month inx h ; Increment mov d,m ; inx h ; push h ; Save table pointer lhld temp ; Get # days xra a ; Clear carry db 0edh,052h ; subtract jm time$95 ; Jump if negative jrz time$95 ; (or zero) o low byte rar ; rar ; rar ; ani 0fh ; Clear hi bits mov c,a ; move to C-reg mvi a,3 ; Send M10 call put$data ; ; ; Set seconds. ; lda @sec ; Get seconds push psw ; save it ani 0fh ; Clear hi bits mov c,a ; move to C-reg mvi a,0 ; Send S1 call put$data ; pop psw ; Get secs again rar ; rotate into low byte rar ; rar ; rar ; ani 0fh ; Clear hi bits mov c,a ; move to C-reg mvi a,1 ; Send S10 call put$data ; ; ; Convert date in ginning of table dad d ; (Twice for word entries) mov e,m ; Load DE with entry inx h ; mov d,m ; pop h ; Restore days so far dad d ; Add days in preceding months ; ; If year is a leap year and month is March or later, add 1 to ; number of days. ; lda leap ; Get leap count cpi 4 ; Leap year? jrnz time$70 ; Jump if not lda month ; Get month sui 3 ; March or >? jm time$70 ; Jump if no inx h ; Else, add 1 day ; ; Add in day of month ; time$70: ldamov c,l ; Save # days in C-reg inr b ; Increment month pop h ; restore table ptr jr time$92 ; loop time$95: mov a,b ; Get month sta month ; store mov a,c ; Get day sta day ; pop h ; Restore stack jr time$125 ; time$98: mvi a,2 ; Month = Feb sta month ; mvi a,29 ; Day = 29 sta day ; time$125: ; ; Send year to RTC ; lda year ; Get year call hex$to$bcd ; Convert to BCD lda ones ; Send Y1 mov c,a ; mvi a,11 ; call putdata ; ldays since 1 Jan 78 to calendar date. ; lhld @date ; Get date mvi a,2 ; Start leap count at 2 sta leap ; mvi a,78 ; Year starts at 78 sta year ; time$80: push h ; Save # days lda leap ; Get leap count cpi 4 ; Leap year? jrz time$85 ; Jump if yes inr a ; Else, inc leap count lxi d,365 ; # days in normal year jr time$87 ; time$85: mvi a,1 ; Reinit leap count lxi d,366 ; # days in leap year time$87: ora a ; Clear carry db 0edh,052h ; SBC HL,DE jm day ; Get day of month mov e,a ; Move to E mvi d,0 ; Clear D dad d ; add to date so far ; ; Update field in SCB ; shld @date ; Store SPB value jmp time$exit ; and exit ; ; Pack 2 bytes into BCD word ; pack$word: mov a,c ; Get into A ral ; Rotate into high byte ral ; ral ; ral ; ora b ; OR in w/H1 ret ; ; ; Set clock using values in SPB. ; time$set: ; ; Get hour from spb. ; lda @hour ; Get hour push psw ; save it ani 0fh ; Clear hda tens ; Send Y10 mov c,a ; mvi a,12 ; call putdata ; ; ; Send month. ; lda month ; Get month call hex$to$bcd ; Convert to BCD lda ones ; Send M1 mov c,a ; mvi a,09 ; call putdata ; lda tens ; Send M10 mov c,a ; mvi a,10 ; call putdata ; ; ; Send day. ; lda day ; Get day call hex$to$bcd ; Convert to BCD lda ones ; Send D1 mov c,a ; mvi a,07 ; call putdata ; lda tens ; Send D10 mov c,a ; mvi a,08 ; call putdata ;  time$90 ; until negative jrz time$90 ; (or zero) sta leap ; Store new LEAP value pop d ; pop lda year ; Get year count inr a ; Increment it sta year ; Store it again jr time$80 ; Loop time$90: pop h ; Restore day count shld temp ; save it ; ; If this is a leap year, special considerations for Feb 29. ; lda leap ; Get leap count cpi 4 ; Leap year? jrnz time$91 ; jump if not xra a ; Clear carry lxi d,60 ; Feb 29? db 0edh,052h ; Check against date i bits mov c,a ; move to C-reg mvi a,4 ; Send H1 call put$data ; pop psw ; Get hour again rar ; rotate into low byte rar ; rar ; rar ; ani 0fh ; Clear hi bits ori 08h ; Set 24 hour clock mov c,a ; move to C-reg mvi a,5 ; Send H10 call put$data ; ; ; Set minutes. ; lda @min ; Get minutes push psw ; save it ani 0fh ; Clear hi bits mov c,a ; move to C-reg mvi a,2 ; Send M1 call put$data ; pop psw ; Get mins again rar ; rotate int    time$exit: di ; disable interrupts mvi a,rtc$read ; Leave in READ state out p$clk$control ; mvi a,all$ints ; Set up int mask again out p$clk$portb ; ei ; pop d pop h ret ; ; This subroutine is called with bits 0-3 set up as address ; input. Return w/C register = data. Carry will be set if ; data changed on 2 successive reads. ; get$data: push d ; Save D push psw ; Save Read address get$3: in p$clk$portc ;Read busy bit port ani 08h ; Mask busy bit jrz ge 12 year ds 1 month ds 1 day ds 1 leap ds 1 tens ds 1 ones ds 1 temp ds 2 month$table: dw 31 ; January dw 59 ; February (non-leap) dw 90 ; March dw 120 ; April dw 151 ; May dw 181 ; June dw 212 ; July dw 243 ; August dw 273 ; September dw 304 ; October dw 334 ; November ELSE ; No external clock. ?time: ret ENDIF CSEG ; ; Vertical retrace interrupt. ; Counts down until MOTOR$COUNTER=0, at which point it ; turns off the motor and masks out this ina,c ; xfer data to A out p$clk$porta ; write it mvi a,write$hi ; Set data write high out p$clk$control ; push b ; save B mvi b,2 ; delay parameter put$33: djnz put$33 ; Loop for delay pop b ; Restore B mvi a,write$lo ; out p$clk$control ; mvi a,0eh ; Deselect RTC out p$clk$control ; pop d ; ret ; ; tofrom: di ; Disable interrupts push psw ; Save PSW mvi a,0eh ; Deselect RTC out p$clk$control ; mov a,e ; Get direction byte out p$clk$cont$3 ; Loop till not busy mvi e,rtc$write ; To RTC call tofrom ; Set port A direction mvi a,rtc$select ; Select bit command out p$clk$control ; Select RTC pop psw ; Get saved register address out p$clk$porta ; Send address to RTC mvi a,add$write$hi ; Set address write high out p$clk$control ; mvi a,add$write$lo ; Set address write low out p$clk$control ; mvi e,rtc$read ; From RTC call tofrom ; Set port A direction mvi a,rtc$select ; Select bit command out p$clk$cterrupt. ; VERT$INT: push psw ; Save A push h ; and H out vert$clear ; Clear interrupt lxi h,motor$counter ; Point to counter inr m ; Inc counter (LEL0384) dcr m ; Decrement jrz vert$50 ; Jump if already 0 (LEL0384) dcr m ; Else, decrement (LEL0384) jrnz vert$50 ; Do nothing till it hits 0 in p$disk$bits ; Get 8255 bits ori 0100$0000b ; Turn off motor out p$disk$bits ; Send it back out VERT$50: ; (LEL0384) vert$exit: mvi a,int$initial ; Reinitrol ; mvi a,all$ints ; Interrupt mask out p$clk$portb ; mvi a,int$initial ; Interrupt setup byte out int$port ; Re-init interrupt cont pop psw ; restore ei ; ret ; ; ; Enter with 10's digit in B, 1's digit in C. ; Exit with hex number in A. ; bcd$to$hex: push d ; Save D mov a,b ; Get 10's digit ral ; *2 mov d,a ; (save) ral ; *4 ral ; *8 add d ; *10 add c ; + 1's digit pop d ; restore D ret ; it's that easy! ; ; Enter with # to be coontrol ; Select RTC mvi a,read$hi ; Set read high out p$clk$control ; push b ; save BC mvi b,5 ; Set delay count get$33: djnz get$33 ; loop for delay pop b ; Restore BC in p$clk$porta ; Read RTC data ani 0fh ; Zero out upper nibble mov c,a ; Move data to C mvi a,read$lo ; Set read low out p$clk$control ; mvi a,0eh ; Deselect RTC out p$clk$control ; pop d ; Restore D ret ; Done!! ; ; Write to RTC ; put$data: push d ; save regs push b ; put interrupt controller out int$port ; pop h ; Restore H pop psw ; and A ei ; Reenable interrupts ret ; and return ; ; Null interrupt handler ; NINT: IF REAL$1050 push psw mvi a,int$initial out int$port pop psw ENDIF ei ret CSEG ; CP/M BDOS Function Interfaces scbcall: mvi c,49 ;Set/Get SCB jmp bdos open: mvi c,15 jmp bdos ; open file control block setdma: mvi c,26 jmp bdos ; set data transfer address setmulti: mvi c,44 jmp bdonverted in A. ; Result in ONES and TENS. ; hex$to$bcd: push psw ; Save A xra a ; Clear A lxi h,tens ; Point to tens mov m,a ; Clear TENS pop psw ; Restore A hex$10: sui 10 ; Subtract 10 jm hex$20 ; inr m ; Increment tens count jr hex$10 ; hex$20: adi 10 ; Add 10 back sta ones ; Store result in ONES ret masks db 0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,003h db 0ffh,0ffh,0ffh,0ffh regorder db 0bh,0ch,09h,0ah,07h,08h,04h,05h,02h,03h db 00h,01h clkvals dssh psw ; Save address for write put$3: in p$clk$portc ; Read port busy bit ani 08h ; Mask busy bit jrz put$3 ; Loop till not busy mvi e,rtc$write ; Writing call tofrom ; Set port direction mvi a,rtc$select ; chip select out p$clk$control ; pop psw ; Restore write address out p$clk$porta ; Send out address mvi a,add$write$hi ; Set up address write out p$clk$control ; mvi a,add$write$lo ; Clear address write out p$clk$control ; pop b ; restore saved data mov    s ; set record count read: mvi c,20 jmp bdos ; read records DSEG signon$msg db 13,10,10,'CP/M Version 3.0, BIOS version 1.3 ' IF BANKED db 13,10,'***BANKED VERSION***' ENDIF db 27,';C' db 13,10,0 CSEG ccp$msg db 13,10,'BIOS Err on ' ccp$drv db 'A' db ': No ' db 'CCP' db '.COM file' db 0 ccp$fcb db 01 destin db 'CCP ','COM',0,0,0,0 ds 16 db 0,0,0 scbpb: ; (LEL0284) db 013h ; Offset into SCB (LEL0284) db 0ffh Get operation. Move low byte into A and L, move high byte into H. ; GET$op: Mov a,m ; Get low byte inx h ; increment mov h,m ; Move high byte to H mov l,a ; Move low byte to L jr priv$exit ; exit page ; ; A=2 is a private call which returns in HL the address of the ; requested translate table. ; C=1 if V1050 translate table requested ; C=2 if RAINBOW translate table requested ; priv$2: cpi 02 ; Is it 2? jrnz priv$80 ; See if another type lxi h,0 ; HL=0 if neither mo; Private BIOS call ; ; This routine is entered by making a BDOS call 50 (Direct BIOS ; call) to Bios entry point 30. ; ; When called, A is a subfunction identifier. (0 is illegal) ; Values in other registers depend upon particular subfunction. ; public Priv$call maclib Z80 extrn trandd,tranrainbow dseg PRIV$CALL: ora a ; Check value in A jrz bad$exit$2 ; Jump if 0 (illegal) cpi 01 ; Is it 1? jrnz priv$2 ; Jump if not ; ; A=1 is a private call which gives the user a ; Setting a byte (LEL0284) db 0 ; Value to set to (LEL0284) ; ; The locations starting at ; 0FFF0h are reserved for interrupt vectors ; ASEG org 0fff0h IVECT: ds 2 ; Expansion interface A ds 2 ; Expansion interface B ds 2 ; Display processor interface ds 2 ; Vertical Clock ds 2 ; Floppy disk interface ds 2 ; Keyboard interface ds 2 ; Winchester interface ds 2 ; Async Interface end v a,c ; Get C reg cpi 01 ; Is it 1? jrz V1050 ; If yes, 1050 table cpi 02 ; Is it 2? jrnz priv$exit ; Jump if not Rainbow: lxi h,tranrainbow ; load Rainbow address jr priv$exit ; exit V1050: lxi h,trandd ; Load V1050 address jr priv$exit ; exit page ; ; Other functions can be implemented here: ; Priv$80: jr priv$exit ; ; Error exit ; Bad$exit: pop b bad$exit$2: ; ; Exit point ; Priv$exit: ; ; Apparently, the A register gets moved on top of the L register ccess to flags located ; in memory. Register values are as follows: ; ; C = # of byte to be accessed ; B =0FFH if setting a byte ; =0FEH if setting a word ; =000H if a GET operation ; (else, ignored) ; DE = word value to be set ; or D = byte value to be set ; ; Upon exit, A or HL will contain the byte or word on a GET operation. ; priv$1: push b mov a,c ; Get OFFSET CPI MAX ; > MAX? JP BAD$EXIT ; Yes => error lxi h,bytetbl ; Point to bytetbl mvi b,0 ; Clear B DAD  ; sometime after leaving this routine. To make sure HL is the ; desired result, move L to A. ; mov a,l ; ret BYTETBL: DB 0 DB 0 DB 0 DB 0 DB 0 DB 0 DB 0 DB 0 DB 0 DB 0 MAX EQU $-BYTETBL end$out$ptr ; Point to aux output buff call empty$ptr ; fix pointers to empty lxix kb$buf$in ; Point to kbd buffer call empty$ptr ; fix pointers to empty IF REAL$1050 mvi a,all$ints ; Get interrupt mask out p$clk$portb ; Send B ; Add to get address within tbl pop Psw ; Move B into A ORA A ; Check SET JRZ GET$op ; 0 => Get operation inr a ; Increment jrz set$byte ; FF => Set Byte inr a ; Increment jrnz bad$exit2 ; If not FE, error ; ; Set word in bytetbl to VALUE ; Set$word: mov m,e ; Move Move lo byte into table inx h ; Increment mov m,d ; Move hi byte into table jr priv$exit ; Exit ; ; Set byte in Bytetbl to VALUE. ; Set$byte: mov m,d ; Store it jr priv$exit ; ; ;    ; Vector (word, r/w) @AIVEC equ scb$base+26h ; Auxiliary Input Redirection ; Vector (word, r/w) @AOVEC equ scb$base+28h ; Auxiliary Output Redirection ; Vector (word, r/w) @LOVEC equ scb$base+2Ah ; List Output Redirection ; Vector (word, r/w) @BNKBF equ scb$base+35h ; Address of 128 Byte Buffer ; for Banked BIOS (word, r/o) @CRDMA equ scb$base+3Ch ; Current DMA Address ; (word, r/o) @CRDSK equ scb$base+3Eh ; Current Disk (byte, r/o) @VINFO equ scb$base+3Fh ; BDOS Variable "INFO" ; (word, r/o) @RESEL equ scb$base+41h ; FCB Flag (byte, r/o) @FX equ scb$base+43h ; BDOS Function for Error ; Messages (byte, r/o) @USRCD equ scb$base+44h ; Current User Code (byt public @dtbl extrn fddd0,fddd1 extrn winc0 cseg @dtbl dw fddd0 ; A drive = floppy dw fddd1 ; B drive = floppy dw winc0 ; C drive = winch dw 0 ; D drive dw 0,0 ; E & F drives dw 0 ; G drive dw 0,0,0,0,0,0,0,0,0 ; drives H-P end ts time$25: ldax d ; Get reg to read call getdata ; Get data ldx a,0 ; Get mask ana c ; AND with data mov m,ae, r/o) @MLTIO equ scb$base+4Ah ; Current Multi-Sector Count ; (byte,r/w) @ERMDE equ scb$base+4Bh ; BDOS Error Mode (byte, r/o) @ERDSK equ scb$base+51h ; BDOS Error Disk (byte,r/o) @MEDIA equ scb$base+54h ; Set by BIOS to indicate ; open door (byte,r/w) @BFLGS equ scb$base+57h ; BDOS Message Size Flag (byte,r/o) @DATE equ scb$base+58h ; Date in Days Since 1 Jan 78 ; (word, r/w) @HOUR equ scb$base+5Ah ; Hour in BCD (byte,  title 'System Control Block Definition for CP/M3 BIOS' public @civec, @covec, @aivec, @aovec, @lovec, @bnkbf public @crdma, @crdsk, @vinfo, @resel, @fx, @usrcd public @mltio, @ermde, @erdsk, @media, @bflgs public @date, @hour, @min, @sec, ?erjmp, @mxtpa scb$base equ 0FE00H ; Base of the SCB @CIVEC equ scb$base+22h ; Console Input Redirection ; Vector (word, r/w) @COVEC equ scb$base+24h ; Console Output Redirection    r/w) @MIN equ scb$base+5Bh ; Minute in BCD (byte, r/w) @SEC equ scb$base+5Ch ; Second in BCD (byte, r/w) ?ERJMP equ scb$base+5Fh ; BDOS Error Message Jump ; (word, r/w) @MXTPA equ scb$base+62h ; Top of User TPA ; (address at 6,7)(word, r/o) end ap year? jrnz time$40 ; Jump if not inx d ; 366 days in a leap year xra a ; reinit leap count time$40: dade drive one db 02 ; TYPE field fddd1: dw trandd ; Translate table address db 0,0,0,0,0,0,0,0,0 ; Bdos scratch area db 0 ; Media flag dw dpbd1 ; Disk parameter block dw 0fffeh ; Checksum vector dw 0fffeh ; Allocation vector dw dirbcb dw datbcb dw 0fffeh ; Hash db 0 ; Hash bank cseg ; DPB must be resident dpbd0 dw 0028h ; #128 byte records/track db 04,0fh ; block shift and mask db 1 ; extent mask dw 194 ; maximum block number  title 'Diskette Handler Module' ; CP/M-80 Version 3 -- Modular BIOS ; Disk I/O Module ; Port Address Equates maclib ports ; CP/M 3 Disk definition macros maclib cpm3 ; Z80 macro library instruction definitions maclib Z80 ; Disk drive dispatching tables for linked BIOS public fddd0,fddd1 public u$conin$echo, error$table ; Variables containing parameters passed by BDOS extrn @adrv,@rdrv extrn @dma,@trk,@sect extrn @dbnk,@cbnk  dw 127 ; maximum dir entry # db 0C0h,00h ; alloc vector for directory dw 32 ; checksum size dw 2 ; offset for sys tracks db 2,3 ; physical sector size shift dpbd1 dw 0028h ; #128 byte records/track db 04,0fh ; block shift and mask db 1 ; extent mask dw 194 ; maximum block number dw 127 ; maximum dir entry # db 0C0h,00h ; alloc vector for directory dw 32 ; checksum size dw 2 ; offset for sys tracks db 2,3 ; physical sector size shift dseg ; ; Dire; System Control Block variables extrn @ermde ; BDOS error mode ; Utility routines in standard BIOS extrn ?wboot ; warm boot vector extrn ?pmsg ; print message @ up to 00, saves & extrn ?pdec ; print binary number in from 0 to 99. extrn ?pderr ; print BIOS disk error header extrn ?conin,?cono ; con in and out extrn ?const ; get console status extrn ivect extrn ?bank cr equ 13 lf equ 10 bell equ 7 page ; Extended Disk Parameter Headers (XPDctory buffer control block ; dirhead dw dirbcb dirbcb: db 0ffh ; DRV - Drive with record in buf db 0,0,0 ; Rec # db 0 ; wflg db 0 ; Scratch byte dw 0 ; Track dw 0 ; Sector dw dirbf ; Buffer address db 0 ; Bank dw 0 ; Link dirbf: ds 512 cseg ; ; Data buffer control block ; dathead dw datbcb datbcb: db 0ffh ; Drive db 0,0,0 ; Record # db 0 ; Wflg db 0 ; Scratch byte dw 00 ; Track dw 0 ; Sector dw datbf ; Buffer address db 0 ; Bank dw Hs) cseg dw fd$write dw fd$read dw fd$login dw fd$init db 0 ; relative drive zero db 2 ; TYPE field fddd0: dw trandd ; Translate table address db 0,0,0,0,0,0,0,0,0 ; Bdos scratch area db 0 ; Media flag dw dpbd0 ; Disk parameter block dw 0fffeh ; Checksum vector dw 0fffeh ; Allocation vector dw dirbcb ; dw datbcb ; dw 0fffeh ; Hash db 0 ; Hash bank dw fd$write dw fd$read dw fd$login dw fd$init db 1 ; relativ   0 ; Link datbf: ds 512 trandd skew 10,1,1 page ; Disk I/O routines for standardized BIOS interface ; Initialization entry point. ; called for first time initialization. fd$init: mvi a,fdc$reset ;reset out p$disk$control ;do it ret page fd$login: ; This entry is called when a logical drive is about to ; be logged into for the purpose determining what type ; of disk is in use. ; It may adjust the parameters contained in the disk ; parameter headmode ds 1 no$of$heads equ 53 ;Offset into label step$offset equ 56 ; tpi$offset equ 11 ; signature db 'FMT' nomatch db '***WARNING - Disk format not recognized***',13,10,0 page cseg ; disk READ and WRITE entry points. ; these entries are called with the following arguments: ; relative drive number in @rdrv (8 bits) ; absolute drive number in @adrv (8 bits) ; disk transfer address in @dma (16 bits) ; disk transfer bank in @dbnk (8 bits) ; disk track address in @t jpe back ; if bc<>0, keep going mov a,m ; Get next character cpi '0' ; Is it '0'? jrz login$30 ; If yes, it's ok cpi '1' ; Is it '1'? jrnz notok ; If not, it's bad ; ; Set up fields in TYPE field as follows: ; ; Bit 0 : 1=2 sides ; 0=1 side ; Bit 1 : 1=96 TPI ; 0=48 TPI ; Bit 2 : unused ; Bit 3 : unused ; Bit 4 : unused ; Bit 5 : unused ; Bits 6-7: step rate ; login$30: pop d ; Restore address of XDPH dcx d ; Point to type field lxier pointed at by ; The value of XDPH-1 (TYPE field) is adjusted to reflect ; the type of disk. This is determined by reading the ; disk label. push d ; Save address of XDPH lda @ermde ; Get error mode sta save$mode ; save it mvi a,0ffh ; Force to not display msgs sta @ermde ; store lxi h,datbf ; point to dma area shld dmaadr ; store lxi h,fd0$access ; assume A drive lded @rdrv ; Get drive xra a ; a=0 mov d,a ; Clear D dad d ; Point to corrrk (16 bits) ; disk sector address in @sect (16 bits) ; pointer to XDPH in ; they transfer the appropriate data, perform retries ; if necessary, then return an error code in fd$read: call nmi$setup ; set up nmi (invarient part) lxi h,0a2edh ; "INI" shld nmi+2 ; store read portion lxi h,read$msg ; point at " Read " mvi a,82h ; 1797 read jr rw$common fd$write: call nmi$setup ; set up nmi (invarient part) lxi h,0a3edh ; "OUTI" shld nmi+ h,datbf+no$of$heads ; mov a,m ; Get # sides dcr a ; Decrement mov b,a ; Save in B lxi h,datbf+tpi$offset ; Get tpi from label mov a,m ; ora a ; clear carry ral ; Move to bit 1 ora b ; OR with # sides mov b,a ; Save in B lxi h,datbf+step$offset ; Get step rate mov a,m ; db 0fh ; Into bits 6&7 db 0fh ; ora b ; OR with others stax d ; store in TYPE field ; ; Move label info into appropriate DPH ; lxi b,15 ; # bytes to move lxect flag pop d ; Restore address of XDPH login$10: mvi a,0ffh ; flag=ff mov m,a ; reset last track lda @rdrv ; Get relative drive inr a ; increment xri 0fh ; bit=0 => on sta select$mask ; save command mvi a,0ffh ; Clear "last" flags sta old$track ; xra a ; a=0 sta trk ; Going to Track 0 inr a ; a=1 sta sect ; Sector 1 ; ; Set up for reading the label ; push d ; Save addr of XDPH call nmi$setup ; set up nmi (invarient part) lxi h,0a2edh ; "INI" shld nm2 ; store write portion lxi h,write$msg ; point at " Write " mvi a,0A2h ; 1797 write rw$common: ; seek to correct track (if necessary), ; and issue 1797 command. shld operation$name ; save message for errors mov b,a ; put read or write into B lda @sect ; Get sector sta sect ; save it lhld @dma shld dmaadr lda no$of$sides ; Get # sides ora a ; Check it jrz rw$26 ; Jump if single-sided lda @trk ; get track ani 01h ; low bit =i h,datbf+32 ; FROM address lxi d,dpbd0 ; Assume drive 0 lda @rdrv ; check it ora a ; jz login$67 ; Jump if drive 0 lxi d,dpbd1 ; Set to drive 1 login$67: ldir ; move inx h ; skip skew ldi ; Then move in 2 more ldi ; jr login$exit ; exit notok: pop b ; Restore stack lxi h,nomatch ; Error, print message call ?pmsg jr login$exit bad$exit: pop b login$exit: lda save$mode ; Get saved value of @ermde sta @ermde ; restore it xra a ; Clear A ret save$i+2 ; store read portion lxi h,read$msg ; Point to "Read" shld operation$name ; store for error msg mvi a,82h ; Store read sta disk$command ; as command to execute call more$retries ; do it jrnz bad$exit ; Jump if problem ; ; Check that disk has our "signature" ; lxi b,0003 ; count =3 lxi h,datbf ; Point to signature on disk lxi d,signature ; and our recognized one back ldax d ; get signature char cci ; compare inx d ; increment de jrnz notok ; jump if no match     side add a ; add a ; add a ; *8 rw$26 ora b ; OR in w/read or write sta disk$command ; save 1797 command page ; ; Will need to know info on last access to disk. Move info into ; old$track ; lxi h,fd0$access ; FROM address lded @rdrv ; Get relative drive xra a ; Clear a mov d,a ; Use it to clear d dad d ; add lxi d,old$track ; TO address fd$20 ldi ; move in track ; ; Set up misc 8255 command ; ; Bit 7=0; Bit 6=0 means turn motor on. up for NMI to do command. NMI will use alternate regs ; so set them up with the apprpriate values. ; exaf ; exchange af and af exx ; and other prime regs push h ; save h (really h') push b ; save b (really b') push psw ; save a (really a') mvi c,p$disk$data ; load c with port address lhld dmaadr ; get buffer address exaf ; put into prime regs exx ; lda disk$command ; get 1797 command call exec$command ; Start. Wait for IREQ & read status sta disk$tart$motor$timer ; Start timing in p$disk$bits ; Get previous status push psw ; save it lda select$mask ; Get new status out p$disk$bits ; Send out (turns on motor) pop psw ; Get prev status ani 0100$0000b ; Was motor on jrz check$track ; bit 6=0 means it was on ; ; Motor was off. Wait 800 ms for it to come up to speed. ; lxi h,892 wait$0 xra a wait$1 dcr a jnz wait$1 ; Delay 896 uS dcx h ; mov a,l ; ora h ; jrnz wait$0 ; ; ; Check current track ; Set up drive select in bits 0-3. lda @rdrv ; get relative drive inr a ; increment cpi 03 ; jm fd$40 ; ani 06 ; add a ; Double it fd$40 xri 0Fh ; bit=0 => on mov b,a ; save in b ; ; Set up Bit 4 (side select). ; If double sided, consecutive tracks use alternate sides ; of the disk ; lda @trk ; Get track sta trk ; store it lda no$of$sides ; Get # sides ora a ; Is it double sided? jrz fsel$1 ; Jump if not lda @trk ; get track pushstatus ; save status for error messages exx ; save regs for a second exaf ; pop psw ; restore a (really a') pop b ; restore b (really b') pop h ; restore h (really h') exx ; put back into prime regs exaf ; put af back too ; ; Operation completed. Status is in location disk$status. ; pop b ; recover retry counter lda disk$status ; get status ora a ; check status. jz fd$exit ; If no error, exit ; ; Check error type. If write  against desired one. ; check$track ; ; Access track ; lda trk ! lxi h,old$track ! cmp m jrz same$track ; if same track, dont seek ; ; New track (different from last one accessed) ; new$track: ; lda old$track ; get last track accessed out p$disk$track ; send it out cpi 0ffh ; first access? cz home ; if yes, home lda trk ; point to desired track call seeker ; and seek lda trk ; get track sta old$track ; store as last track accessed jr get psw ; save it rar ; rotate into place sta trk ; store pop psw ; restore track ani 1 ; mask off other bits jrz fsel$1 ; If side 0, ok mvi a,010h ; Else, set side 1 bit ora b ; or w/b-reg mov b,a ; save in b again ; ; Set up bit 5 for write precompensation. (Write precomp is ; necessary for outer tracks, so check against constant specified ; by disk manufacturer.) ; fsel$1 lda trk ; get track lxi h,precomp$limit ; and precomp limit cmp m ; is it 4 retries have already bee$sect ; Now, access sector. ; ; At same track as last access ; same$track: out p$disk$track ; give 1797 track ; ; Now, Get sector. ; get$sect: lda sect out p$disk$sector ;and sector ; ; Save track info for drive ; lxi h,fd0$access ; TO address lded @rdrv ; get current drive xra a ; Clear a mov d,a ; Use it to clear d dad d ; lxi d,old$track ; FROM address xchg ; ldi ; move in track ; ; Now, setjrc fsel$2 ; jump if yes mvi a,020h ; set write pre-comp ora b ; or with other bits mov b,a ; store back in b ; ; All 8 bits of 8255 command have been set up. Save them. ; fsel$2 mov a,b ; get b reg values sta select$mask ; save 8255 bits page more$retries: mvi c,10 ; allow 10 retries retry$operation: push b ; save retry counter ; ; Check to see whether the motor is being turned on cold, or ; whether it is still on from a previous access. ; call s!   n done, force a head restore. This ; is done by seeking track 5, then restore to assure head travel. ; This should cure persistent lint on the heads as well as seek ; errors. ; mvi a,5 ; track 5 call seeker ; seek it call home ; home lda trk ; Get track back Call seeker ; seek it jmp retry$operation ; then retry page ; ; Error Handling... ; FD$ERROR: ; ; suppress error message if BDOS is returning errors to application... ; lda @ermde cpi 0FFh  ; routine. Either an INI or OUTI will be performed, depending on whether ; a read or write is invoked. This lets us read in an entire sector ; more efficiently. ; exec$command: out p$disk$control ; send 1797 command ; ; Wait at least 24 usec after command before doing anything. ; mvi a,09 exec$delay dcr a jnz exec$delay ; (delays 31 usec) ; ; Now, wait for completion, but TIME OUT after 1.2 seconds. ; lxi d,60000+1 exec$0 in p$disk$control ; get status rrestination track lda tpi ; Get TPI ora a ; Is it 48? jrnz seek$15 ; Jump if not ; ; Must double track info for 48tpi disks ; in p$disk$track ; Read in current track ora a ; Clear carry ral ; *2 out p$disk$track ; Set track reg pop psw ; Get desired track ora a ; clear carry ral ; *2 jr seek$16 ; Seek it seek$15: pop psw ; Restore track seek$16: out p$disk$data ; send out track lda step$rate ; Get step rate ori 018h ; seek, hld, ve jrz hard$error ; ; Had permanent error, print message like: ; ; BIOS Err on d: T-nn, S-mm, , Retry ? ; call ?pderr ; print message header lhld operation$name ! call ?pmsg ; last function ; then, messages for all indicated error bits lda disk$status ; get status byte from last error cpi 0ffh ; time out error? jz err$timeout ; special message lxi h,error$table ; point at table of message addresses errm1: mov e,m ! inx h ! mov d,m ! inx h ; get nc ; check not ready flag jnc exec$success ; if 0, successful completion inx d ; (waste time) dcx d ; inx d ; dcx d ; dcx d ; decrement count mov a,d ; ora e ; adi 0ffh ; jc exec$0 ; 20 us*60000=1.2 seconds ; ; Time out. Set A=0FFH and exit. ; mvi a,0d0h ; Reset FDC out p$disk$control ; send it out mvi a,0ffh ; Set time out flag jr exec$exit ; ; Successful completion. Return w/status byte in A. exec$success in p$disk$contrify ; ; Routines for seek and home ; seek$20 out p$disk$control ; send command from A ; ; Delay at least 24 uSec after command ; mvi a,09 ; seek$delay dcr a ;. jnz seek$delay ; ; ; Wait for completion ; seek$30 in p$disk$control ; get status byte rrc ; Ready? jc seek$30 ; loop until ready ; ; Return with A= status byte ; in p$disk$control ; read in status ; ; Delay 18mS to allow for settling time ; lxi d,01400h ; seek$delay2 ext message address add a ! push psw ; shift left and push residual bits with status xchg ! cc ?pmsg ! xchg ; print message, saving table pointer pop psw ! jnz errm1 ; if any more bits left, continue errm2 lxi h,error$msg ! call ?pmsg ; print ", Retry (Y/N) ? " call u$conin$echo ; get operator response cpi 'Y' ! jz more$retries ; Yes, then retry 10 more times hard$error: ; otherwise, lda disk$status ; Get status byte cpi 0100$0000b ; Write protect error? mvi a,1 ; returrol ; Get status byte exec$exit push psw ; Save status call start$motor$timer ; Start timer pop psw ; ret page ; ; Start up motor timer ; Start$motor$timer: RET ; ; Exit from routine. ; Must set up interrupts appropriately. ; fd$exit: push psw ; save status in p$disk$track ; read track out p$disk$data ; write out data ; ; Restore nmi locations ; lxi d,nmi ; Point at nmi lxi h,nmibuf ; and at save buffer lxi b,8 ; load count ldir ; m dcr e ; jnz seek$delay2 ; 896 uS dcr d ; jnz seek$delay2 ; 20*896=18 mS push psw ; save status lda trk ; Get trk out p$disk$track ; Save in track reg pop psw ; Restore status ret page ; ; This routine actually executes the read or write command. An initial ; read (or write) is sent out to the controller. Since we are not ; doing multiple sectors, an interrupt will be generated at the end of ; the command. This invokes the NMI set up at the beginning of then hard error to BDOS jnz fd$exit ; Not write protect error inr a ; Write protect error jmp fd$exit err$timeout lxi h,time$out ; point to timeout message call ?pmsg ; Display message jr errm2 ; Ask for user response page ; ; Subroutine to seek to home track ; home: lda step$rate ; Get step rate home$0 ori 08h ; home, hld, no verify jmp seek$20 ; ; ; Seeker ; This routine seeks a track in A at the given step rate ; seeker: push psw ; Save d"   ove saved data back mvi a,0d0h ; out p$disk$control ; Reset disk controller pop psw ora a ; set flags ret ; and exit!! ; ; Set up NMI ; NMI (non-maskable interrupt) occurs at fixed location 0066h. ; During normal run time NMI does not occur, so these locations ; are normal RAM. During diskette data transfers, NMI is ; triggered by the diskette Data Request signal, so the NMI ; locations are temporarily overlayed by intructions to process ; the interrupt. ; nmi equ 0error status code for messages fd0$access fd0$trk db 0ffh ; last track accessed on A fd1$trk db 0ffh ; last track accessed on B ; error message components read$msg db ', Read',0 write$msg db ', Write',0 operation$name dw read$msg ; table of pointers to error message strings ; first entry is for bit 7 of 1797 status byte error$table dw b7$msg dw b6$msg dw b5$msg dw b4$msg dw b3$msg dw b2$msg dw b1$msg dw b0$msg b7$msg db ' Not ready,',0 b6$msg db ' Protec066h nmi$setup: mvi a,fdc$reset ; Reset FDC out p$disk$control ; dcx d ; Point to TYPE field of XDPH ldax d ; Get value push psw ; (save) ani 1 ; Mask # sides sta no$of$sides ; store pop psw ; Get TYPE again push psw ; Save db 07h ; Rotate 6&7into 0&1 db 07h ; ani 0000$0011b ; Mask bits sta step$rate ; store step rate pop psw ; Get type ani 0000$0010b ; Mask TPI field rar ; Rotate into bit 0 sta TPI ; store lxi d,nmibuf ; poin title 'Root module of relocatable BIOS for CP/M 3.0' ; version 1.0 15 Sept 82 true equ -1 false equ not true banked equ false mb$xon$xoff equ 0001$0000b ; XON/XOFF protocol ; Copyright (C), 1982 ; Digital Research, Inc ; P.O. Box 579 ; Pacific Grove, CA 93950 ; This is the invariant portion of the modular BIOS and is ; distributed as source for informational purposes only. ; All desired modifications should be performed by ; adding or changing externally definedt,',0 b5$msg db ' Fault,',0 b4$msg db ' Record not found,',0 b3$msg db ' CRC,',0 b2$msg db ' Lost data,',0 b1$msg db ' DREQ,',0 b0$msg db ' Busy,',0 time$out db ' Time out,',0 error$msg db ' Retry (Y/N) ? ',0 precomp$limit db 43 no$of$sides db 0 ; # sides step$rate db 0 tpi db 0 motor$counter db 0 end ; Leap year? jrnz time$91 ; jump if not xra a ; Clear carry lxi d,60 ; Feb 29? db 0edh,052h ; Check against date t to storage area lxi h,nmi ; original values lxi b,8 ; set up length ldir ; save them away lxi h,0d908h ; "EX AF,AF'" shld nmi ; beginning of nmi shld nmi+4 ; also, end of nmi lxi h,045edh ; "RETN" shld nmi+6 ; mvi a,3 ; Enable FDC interrupt out p$8255$control ; ret cseg u$conin$echo: ; get console input, echo it, and shift to upper case call ?const ! ora a ! jrz u$c1 ; see if any char already struck call ?conin ! jr u$conin$echo ; yes, eat it modules. ; This allows producing "standard" I/O modules that ; can be combined to support a particular system ; configuration. cr equ 13 lf equ 10 bell equ 7 ctlQ equ 'Q'-'@' ctlS equ 'S'-'@' ccp equ 0100h ; Console Command Processor gets loaded into the TPA cseg ; GENCPM puts CSEG stuff in common memory ; variables in system data page extrn @covec,@civec,@aovec,@aivec,@lovec ; I/O redirection vectors extrn @mxtpa ; addr of system entry point extrn @bnkbf ; 128 byt and try again u$c1: call ?conin ! push psw mov c,a ! call ?cono pop psw ! cpi 'a' ! rc sui 'a'-'A' ; make upper case ret cseg IF REAL$1050 ivect2 equ 0fff8h ; ELSE ivect2 equ 0ffe2h ; address of ivect+2 ENDIF nmibuf ds 8 ; buffer to hold prev contents of nmi disk$command ds 1 ; current wd1797 command select$mask ds 1 ; current drive select code old$track db 0ffh ; last track seeked to dmaadr ds 2 sect ds 1 trk ds 1 ; track for current operation disk$status ds 1 ; last #   e scratch buffer ; user defined character I/O routines extrn ?ci,?co,?cist,?cost ; each take device in extrn ?cinit ; (re)initialize device in extrn @ctbl ; physical character device table ; disk communication data items extrn @dtbl ; table of pointers to XDPHs public @adrv,@rdrv,@trk,@sect ; parameters for disk I/O public @dma,@dbnk,@cnt ; '' '' '' '' ; memory control public @cbnk ; current bank extrn ?xmove,?move ; select move bankpoint to init pointer mov d,m ! dcx h ! mov e,m ; get init pointer xchg ! call ipchl ; call init routine pop h ; recover @drv pointer d$init$next: pop b ; recover counter and drive # inr c ! dcr b ! jnz d$init$loop ; and loop for each drive jmp boot$1 cseg ; following in resident memory boot$1: call set$jumps ; ; ; call ?ldccp ; fetch CCP for first time ; jmp ccp ret ; WBOOT ; Entry for system restarts. wboot: call set$jumps ; initialize page zero ; ; ?conos: jmp conost ; return console output status ?auxis: jmp auxist ; return aux input status ?auxos: jmp auxost ; return aux output status ?dvtbl: jmp devtbl ; return address of device def table ?devin: jmp ?cinit ; change baud rate of device ?drtbl: jmp getdrv ; return address of disk drive table ?mltio: jmp multio ; set multiple record count for disk I/O ?flush: jmp flush ; flush BIOS maintained disk caching ?mov: jmp ?move ; block move memory to memory ?tim: jmp ?time ; Signal Time and , and block move extrn ?bank ; select CPU bank ; clock support extrn ?init extrn ?time ; signal time operation ; general utility routines public ?pmsg,?pdec ; print message, print number from 0 to 65535 public ?pderr ; print BIOS disk error message header ; External names for BIOS entry points public ?boot,?wboot,?const,?conin,?cono,?list,?auxo,?auxi public ?home,?sldsk,?sttrk,?stsec,?stdma,?read,?write public ?lists,?sctrn public ?conos,?auxis,?auxos,?d call ?rlccp ; reload CCP ; jmp ccp ; then reset jmp vectors and exit to ccp ret set$jumps: if banked mvi a,1 ! call ?bnksl endif mvi a,JMP sta 0 ! sta 5 ; set up jumps in page zero lxi h,?wboot ! shld 1 ; BIOS warm start entry lhld @MXTPA ! shld 6 ; BDOS system call entry ret ds 64 boot$stack equ $ ; DEVTBL ; Return address of character device table devtbl: lxi h,@ctbl ! ret ; GETDRV ; Return address of drive table getdrv: lxi h,@dtbl ! ret Date operation ?bnksl: jmp bnksel ; select bank for code execution and default DMA ?stbnk: jmp setbnk ; select different bank for disk I/O DMA operations. ?xmov: jmp ?xmove ; set source and destination banks for one operation jmp 0 ; reserved for future expansion jmp 0 ; reserved for future expansion jmp 0 ; reserved for future expansion ; BOOT ; Initial entry point for system startup. dseg ; this part can be banked boot: mvi c,15 ; initialize all 16 character devices c$inivtbl,?devin,?drtbl public ?mltio,?flush,?mov,?tim,?bnksl,?stbnk,?xmov ; BIOS Jump vector. ; All BIOS routines are invoked by calling these ; entry points. ?boot: jmp boot ; initial entry on cold start ?wboot: jmp wboot ; reentry on program exit, warm start ?const: jmp const ; return console input status ?conin: jmp conin ; return console input character ?cono: jmp conout ; send console output character ?list: jmp list ; send list output character ?auxo: jmp auxout ; send auxill ; CONOUT ; Console Output. Send character in ; to all selected devices conout: lhld @covec ; fetch console output bit vector jmp out$scan ; AUXOUT ; Auxiliary Output. Send character in ; to all selected devices auxout: lhld @aovec ; fetch aux output bit vector jmp out$scan ; LIST ; List Output. Send character in ; to all selected devices. list: lhld @lovec ; fetch list output bit vector out$scan: mvi b,0 ; start with device 0 ct$loop: push b ! call ?cinit ! pop b dcr c ! jp c$init$loop call ?init lxi b,16*256+0 ! lxi h,@dtbl ; init all 16 logical disk drives d$init$loop: push b ; save remaining count and abs drive mov e,m ! inx h ! mov d,m ! inx h ; grab @drv entry mov a,e ! ora d ! jz d$init$next ; if null, no drive push h ; save @drv pointer xchg ; XDPH address in dcx h ! dcx h ! mov a,m ! sta @RDRV ; get relative drive code mov a,c ! sta @ADRV ; get absolute drive code dcx h ; iary output character ?auxi: jmp auxin ; return auxilliary input character ?home: jmp home ; set disks to logical home ?sldsk: jmp seldsk ; select disk drive, return disk parameter info ?sttrk: jmp settrk ; set disk track ?stsec: jmp setsec ; set disk sector ?stdma: jmp setdma ; set disk I/O memory address ?read: jmp read ; read physical block(s) ?write: jmp write ; write physical block(s) ?lists: jmp listst ; return list device status ?sctrn: jmp sectrn ; translate logical to physical sector $   o$next: dad h ; shift out next bit jnc not$out$device push h ; save the vector push b ; save the count and character not$out$ready: call coster ! ora a ! jz not$out$ready pop b ! push b ; restore and resave the character and device call ?co ; if device selected, print it pop b ; recover count and character pop h ; recover the rest of the vector not$out$device: inr b ; next device number mov a,h ! ora l ; see if any devices left jnz co$next ; and go find them... ret ; input device. conin: lhld @civec jmp in$scan ; AUXIN ; Auxiliary Input. Return character from first ; ready auxiliary input device. auxin: lhld @aivec in$scan: push h ; save bit vector mvi b,0 ci$next: dad h ; shift out next bit mvi a,0 ; insure zero a (nonexistant device not ready). cc cist1 ; see if the device has a character ora a jnz ci$rdy ; this device has a character inr b ; else, next device mov a,h ! ora l ; see if any more devices jnz ci$next ; board has character mov a,m ! cnz ci1 ; get flag or read key if any cpi ctlq ! jnz not$q ; if its a ctl-Q, mvi a,0FFh ; set the flag ready not$q: cpi ctls ! jnz not$s ; if its a ctl-S, mvi a,00h ; clear the flag not$s: mov m,a ; save the flag call cost1 ; get the actual output status, ana m ; and mask with ctl-Q/ctl-S flag ret ; return this as the status cist1: ; get input status with and saved push b ! push h call ?cist pop h ! pop b ora a ret costCONOST ; Console Output Status. Return true if ; all selected console output devices ; are ready. conost: lhld @covec ; get console output bit vector jmp ost$scan ; AUXOST ; Auxiliary Output Status. Return true if ; all selected auxiliary output devices ; are ready. auxost: lhld @aovec ; get aux output bit vector jmp ost$scan ; LISTST ; List Output Status. Return true if ; all selected list output devices ; are ready. listst: lhld @lovec ; get list ogo look at them pop h ; recover bit vector jmp in$scan ; loop til we find a character ci$rdy: pop h ; discard extra stack jmp ?ci ; Utility Subroutines ipchl: ; vectored CALL point pchl ?pmsg: ; print message @ up to a null ; saves & push b push d pmsg$loop: mov a,m ! ora a ! jz pmsg$exit mov c,a ! push h call ?cono ! pop h inx h ! jmp pmsg$loop pmsg$exit: pop d pop b ret ?pdec: ; print binary number 0-65535 from lxi b,table10! 1: ; get output status, saving & push b ! push h call ?cost pop h ! pop b ora a ret ci1: ; get input, saving & push b ! push h call ?ci pop h ! pop b ret ; CONST ; Console Input Status. Return true if ; any selected console input device ; has an available character. const: lhld @civec ; get console input bit vector jmp ist$scan ; AUXIST ; Auxiliary Input Status. Return true if ; any selected auxiliary input device ; has an avautput bit vector ost$scan: mvi b,0 ; start with device 0 cos$next: dad h ; check next bit push h ; save the vector push b ; save the count mvi a,0FFh ; assume device ready cc coster ; check status for this device pop b ; recover count pop h ; recover bit vector ora a ; see if device ready rz ; if any not ready, return false inr b ; drop device number mov a,h ! ora l ; see if any more selected devices jnz cos$next ori 0FFh ; all selected were ready, return true ret lxi d,-10000 next: mvi a,'0'-1 pdecl: push h! inr a! dad d! jnc stoploop inx sp! inx sp! jmp pdecl stoploop: push d! push b mov c,a! call ?cono pop b! pop d nextdigit: pop h ldax b! mov e,a! inx b ldax b! mov d,a! inx b mov a,e! ora d! jnz next ret table10: dw -1000,-100,-10,-1,0 ?pderr: lxi h,drive$msg ! call ?pmsg ; error header lda @adrv ! adi 'A' ! mov c,a ! call ?cono ; drive code lxi h,track$msg ! call ?pmsg ; track header lhld @trk ! call ?pdec ; trackilable character. auxist: lhld @aivec ; get aux input bit vector ist$scan: mvi b,0 ; start with device 0 cis$next: dad h ; check next bit mvi a,0 ; assume device not ready cc cist1 ; check status for this device ora a ! rnz ; if any ready, return true inr b ; drop device number mov a,h ! ora l ; see if any more selected devices jnz cis$next xra a ; all selected were not ready, return false ret ; CONIN ; Console Input. Return character from first ; ready console  coster: ; check for output device ready, including optional ; xon/xoff support mov l,b ! mvi h,0 ; make device code 16 bits push h ; save it in stack dad h ! dad h ! dad h ; create offset into device characteristics tbl lxi d,@ctbl+6 ! dad d ; make address of mode byte mov a,m ! ani mb$xonxoff pop h ; recover console number in jz ?cost ; not a xon device, go get output status direct lxi d,xofflist ! dad d ; make pointer to proper xon/xoff flag call cist1 ; see if this key%    number lxi h,sector$msg ! call ?pmsg ; sector header lhld @sect ! call ?pdec ; sector number ret ; BNKSEL ; Bank Select. Select CPU bank for further execution. bnksel: sta @cbnk ; remember current bank jmp ?bank ; and go exit through users ; physical bank select routine xofflist db -1,-1,-1,-1,-1,-1,-1,-1 ; ctl-s clears to zero db -1,-1,-1,-1,-1,-1,-1,-1 dseg ; following resides in banked memory ; Disk I/O interface routines ; SELDSK ; Spost it inx d ! inx d ; point to DPH again pchl ; leap to driver ; MULTIO ; Set multiple sector count. Saves passed count in ; @CNT multio: sta @cnt ! ret ; FLUSH ; BIOS deblocking buffer flush. Not implemented. flush: xra a ! ret ; return with no error ; error message components drive$msg db cr,lf,bell,'BIOS Error on ',0 track$msg db ': T-',0 sector$msg db ', S-',0 ; disk communication data items @adrv ds 1 ; currently selected disk drive @rd ; SETBNK ; Set Disk Memory Bank. Saves bank number ; in @DBNK for future disk data ; transfers. setbnk: sta @dbnk ret ; SECTRN ; Sector Translate. Indexes skew table in ; with sector in . Returns physical sector ; in . If no skew table (=0) then ; returns physical=logical. sectrn: mov l,c ! mov h,b mov a,d ! ora e ! rz xchg ! dad b ! mov l,m ! mvi h,0 ret ; READ ; Read physical record from currently selected drive. ; Finds address oelect Disk Drive. Drive code in . ; Invoke login procedure for drive ; if this is first select. Return ; address of disk parameter header ; in seldsk: mov a,c ! sta @adrv ; save drive select code mov l,c ! mvi h,0 ! dad h ; create index from drive code lxi b,@dtbl ! dad b ; get pointer to dispatch table mov a,m ! inx h ! mov h,m ! mov l,a ; point at disk descriptor ora h ! rz ; if no entry in table, no disk mov a,e ! ani 1 ! jnz not$first$select ; examine login rv ds 1 ; controller relative disk drive @trk ds 2 ; current track number @sect ds 2 ; current sector number @dma ds 2 ; current DMA address @cnt db 0 ; record count for multisector transfer @dbnk db 0 ; bank for DMA operations cseg ; common memory @cbnk db 0 ; bank for processor operations end ing the label ; push d ; Save addr of XDPH call nmi$setup ; set up nmi (invarient part) lxi h,0a2edh ; "INI" shld nmf proper read routine from ; extended disk parameter header (XDPH). read: lhld @adrv ! mvi h,0 ! dad h ; get drive code and double it lxi d,@dtbl ! dad d ; make address of table entry mov a,m ! inx h ! mov h,m ! mov l,a ; fetch table entry push h ; save address of table lxi d,-8 ! dad d ; point to read routine address jmp rw$common ; use common code ; WRITE ; Write physical sector from currently selected drive. ; Finds address of proper write routine from ; extended dibit push h ! xchg ; put pointer in stack & lxi h,-2 ! dad d ! mov a,m ! sta @RDRV ; get relative drive lxi h,-6 ! dad d ; find LOGIN addr mov a,m ! inx h ! mov h,m ! mov l,a ; get address of LOGIN routine call ipchl ; call LOGIN pop h ; recover DPH pointer not$first$select: ret ; HOME ; Home selected drive. Treated as SETTRK(0). home: lxi b,0 ; same as set track zero ; SETTRK ; Set Track. Saves track address from ; in @TRK for further operationsk parameter header (XDPH). write: lhld @adrv ! mvi h,0 ! dad h ; get drive code and double it lxi d,@dtbl ! dad d ; make address of table entry mov a,m ! inx h ! mov h,m ! mov l,a ; fetch table entry push h ; save address of table lxi d,-10 ! dad d ; point to write routine address rw$common: mov a,m ! inx h ! mov h,m ! mov l,a ; get address of routine pop d ; recover address of table dcx d ! dcx d ; point to relative drive ldax d ! sta @rdrv ; get relative drive code and s. settrk: mov l,c ! mov h,b shld @trk ret ; SETSEC ; Set Sector. Saves sector number from ; in @sect for further operations. setsec: mov l,c ! mov h,b shld @sect ret ; SETDMA ; Set Disk Memory Address. Saves DMA address ; from in @DMA and sets @DBNK to @CBNK ; so that further disk operations take place ; in current bank. setdma: mov l,c ! mov h,b shld @dma lda @cbnk ; default DMA bank is current bank ; fall through to set DMA bank &   ; PORTS.LIB ; I/O Port addresses for Visual 1050 ; ; Copyright (c) Visual Technology, 1983 ; ; Standard equates ; true equ 0ffh ; self explanatory false equ 0 ; ditto real$1050 equ true banked equ true ; Boot Mode flip-flop ; p$boot equ 0D0h ; Boot prom enable/disable p$bank$select equ 0d0h ; Select bank ; ; Interrupt vectors ; int$port equ 0C0h int$initial equ 010h all$ints equ 1111$1111b ; All interrupts enabled vert$clear equ 0A0h ; Clear vert interrupt vib ; char length low mode$b2 equ 0000$0010b ; baud rate factor high mode$b1 equ 0000$0001b ; baud rate factor low com$eh equ 1000$0000b ; enter hunt mode com$ir equ 0100$0000b ; internal reset com$rts equ 0010$0000b ; request to send com$er equ 0001$0000b ; error reset com$sbrk equ 0000$1000b ; send break com$rxe equ 0000$0100b ; receive enable com$dtr equ 0000$0010b ; data terminal ready com$txe equ 0000$0001b ; transmit enable ; some common values ; mode$eig00b ; ready to xmit disp$req$rcv equ 0100$0000b ; req rcv from display disp$req$xmit equ 1000$0000b ; req xmit to display disp$portc$cons equ 0001$0100b ; port c constants ; Lpt masks ; misc$lpt$strobe equ 0000$0001b ; handshake strobe misc$lpt$avail equ 0010$0000b ; lpt available misc$lpt$nobusy equ 0001$0000b ; finished printing ; equates for mode byte bit fields mb$input equ 0000$0001b ; device may do input mb$output equ 0000$0010b ; device may do output mb$in$out equ mb$input+mb$outd$vert$int equ 0a0h ; vid$disp$int equ 0B0h ; ; ; Display section 8255 parallel interface ; p$disp$in equ 84h ; port a from display p$disp$out equ 85h ; port b to display p$disp$c equ 86h ; port c from/to display p$disp$control equ 87h ; control port for display clear$6502 equ 0b0h ; Keyboard 8251 - keyboard input, loudspeaker output ; p$kb$data equ 88h ; in= kb data, out= loudspeaker data p$kb$control equ 89h ; kb control/status ; RS-232 8251 ; p$aux1$data equ 8Ch ; rs-232 xmit/recv datht equ 0000$1100b ; eight data bits mode$onestop equ 0100$0000b ; one stop bit mode$div16 equ 0000$0010b ; 16x baud rate factor mode$div64 equ 0000$0011b ; 64x baud rate factor mode$baudmask equ 0000$0011b ; to get baud bits from port c mode$default equ mode$onestop or mode$eight or mode$div16 ; one stop, eight data, no parity, 16x com$default equ com$rts or com$rxe ; request to send and receive enable ; port c base baud rate definitions ; misput mb$soft$baud equ 0000$0100b ; software selectable ; baud rates mb$serial equ 0000$1000b ; device may use protocol mb$xon$xoff equ 0001$0000b ; XON/XOFF protocol ; enabled baud$none equ 0 ; no baud rate associated ; with this device baud$50 equ 1 ; 50 baud baud$75 equ 2 ; 75 baud baud$110 equ 3 ; 110 baud baud$134 equ 4 ; 134.5 baud baud$150 equ 5 ; 150 baud baud$300 equ 6 ; 300 baud baud$600 equ 7 ; 600 baud baud$1200 equ 8 ; 1200 baud baud$180a p$aux1$control equ 8Dh ; rs-232 control/status ; Miscellaneous 8255 ; p$disk$bits equ 90h ; diskette bits p$printer equ 91h ; printer bits p$misc equ 92h ; miscellaneous bits p$8255$control equ 93h ; 8255 control port ; MB8877 Floppy disk formatter/controller ; p$disk$control equ 94h ; mb8877 status/command p$disk$track equ 95h ; mb8877 track p$disk$sector equ 96h ; mb8877 sector p$disk$data equ 97h ; mb8877 data ; Winchester Interface to Xebec Controller ; p$winch$data equ 0E0h ; Wc$base01200 equ 0000$0000b ; port c 1200 baud misc$base02400 equ 0000$0100b ; port c 2400 baud misc$base19200 equ 0000$1000b ; port c 19200 baud misc$base09600 equ 0000$1100b ; port c 9600 baud misc$baudmask equ 0000$1100b ; mask for port c base baud rate ; ; Display 8255 Modes ; disp$model equ 0B4H ;mode: A=1&IN, CH=OT, b=1&OT, CL=XX disp$set2c equ 005H ;set bit 2 of port c disp$set4c equ 009H ;set bit 4 of port c disp$set6c equ 00DH ;set bit 6 of port c disp$s0 equ 9 ; 1800 baud baud$2400 equ 10 ; 2400 baud baud$3600 equ 11 ; 3600 baud baud$4800 equ 12 ; 4800 baud baud$7200 equ 13 ; 7200 baud baud$9600 equ 14 ; 9600 baud baud$19200 equ 15 ; 19.2k baud ; 8251 Modes ; mode$s2 equ 1000$0000b ; stop bit high mode$s1 equ 0100$0000b ; stop bit low mode$ep equ 0010$0000b ; even parity mode$pen equ 0001$0000b ; parity enable mode$12 equ 0000$1000b ; char length high mode$11 equ 0000$0100inchester data p$winch$control equ 0E1h ; Winchester control ; ; Real time clock ; p$clk$porta equ 09Ch ; Port A p$clk$portb equ 09Dh ; Port B p$clk$portc equ 09Eh ; Port C p$clk$control equ 09Fh ; Control port add$write$hi equ 09h add$write$lo equ 08h read$hi equ 0DH read$lo equ 0CH write$hi equ 0BH write$lo equ 0AH rtc$select equ 0fh rtc$read equ 91h rtc$write equ 81h ; Display masks ; disp$ready$rcv equ 0000$0001b ; ready to receive disp$ready$xmit equ 0000$10'   et7c equ 00FH ;set bit 7 of port c ; ; Keyboard 8251 mode bytes ; kb$default equ mode$onestop or mode$eight or mode$div16 ; one stop, eight data, no parity, 16x kb$ir equ 0100$0000b ; internal reset kb$sig equ com$er or com$rxe or com$txe ; err reset, RxE, TxE kb$click equ 0101$0101b ; keyboard click ; ; Miscellaneous 8255 ; lpt$mode0 equ 088H ; Mode:A=0&OT, CH=IN, B=0&OT, c=OT lpt$baud equ 0000$1100b ; 1200 baud motor$on eq {2 x < <͍ C?C C >2% % :' YPyPtz\ V xw <͍ <:$ ڶҏکÜ:$ 2) >:$ 2) >:$ 2) >:$ =2) >2* ! :* O "+ !9 :) O F*+ ~w x <͍: > > 2}!"~"\ʽtS \ _" 2 ~ B* : #=I" 2 ^C* : #=b<* }B* | B!]>I.C!e>I<:\̹@B:C<: 0B C:" 2( :" 00B:( 0B C: 9u 0eh ; Motor on motor$off equ 0fh ; Motor off ; ; Floppy disk controller modes ; fdc$reset equ 1101$0000b ; Reset ; ; Winchester controller modes ; wini$reset equ 080h ; Reset ; ; Buffer data structure definitions: buf$length equ 0 ; length of buf$buffer buf$empty equ 1 ; offset of next char in buffer buf$fill equ 2 ; offset of next free location ; (empty=fill means buffer empty) buf$buffer equ 3 ; start of buffer :<!e>b  9O9$9p<!>b9f<:] ͍ͣ9<!m>I#   <9ͣ< <9͍9<:\@B:C|zʒt< <1Q ̓ͮUtͳr CP/M 3 PATCH - Version 3.0$ ERROR: $PATCH requires CP/M 3$Invalid file type: .$Serial number mismatch$No file: $False password: $Invalid patch number: $Drive $ is R/O$ on $Illegal drive: $ Enter File: $ Enter Password: $ Do you want to indicate that patPATCH VERSION3.0 PATCH.COM COPYRIGHT 1982, DIGITAL RESEARCH151282654321:o2! *m" -< |#}0#:] <>2   : : :3! ]~. a{ ##e~ a{ ##~ 2m#~2n*m" : aB{B @2\! :\Ҥ!e~ #Z!CO"e>M2g>2 zÖ: *e}C|O:gM>2 *e}P|R:gL>2 \2 |: @: ,?<2 L*>2 ó!>2 ch $ Valid file types: COM or PRL$ Valid patch numbers: 1-32$ Current patches for $ WARNING: Patches greater than $ exist for $ has been installed$ already exists for $ Patch $None$ for $ Patch installed$ Patch not installed$ $ $: $ COMPRL151282 @ first time ; jmp ccp ret ; WBOOT ; Entry for system restarts. wboot: call set$jumps ; initialize page zero ; ;6 =++w: #<: +=6 ?>!6 #=D!~a_{_ w#Q: Ƃ2 * 6 : ʝʯ>2 '0: =„>2 '0:S ʂ>2 '0: =±! 3 #:! ]* } 1]:]>2 >2 A: N* | :02# }0 _'_:# 2$ !]}02$ * " * " ? <͍ <ͭ* |́* }́* |́* }́2 >:" '2" {2 z2 : 2 ܻ: WÈ* |}* |}: _:$ d:$ G* |}* |}2 :(   è COPYRIGHT (C) 1980 DIGITAL RESEARCH @: 5@%15252'5h+U"!""*"5j"2u3>2v3*5"3-ͩ-:5Z!""$"5"5"5"5"5" " 522>2 5:4 b:4$M:(5-C+C*M:(5!,5M[!35PMp%M(ʡͣ#v#ƒ$:5}% }!"&:5ʦ>%*#5}| V AX*|:5(#$*#5"A*#5"&#v#% RØV AR*&*ͻIH'd ! ^#V#*"0}o|gF 9"":!`x=`y0l2!!4^4!4q/:4:4,; *5͉: 5ª|}$ªo͕Ͱ8Oͻy0H͕H͉: 5në:4:4,>C0:4M:4  ;C:4#:4 ! #! #{ozgBB**}j!]~ } #ymy>2(>2v3͖*5|EB"#5>%0,# ^#VÕJB*50MB*50!".*5} "#5^#V"5*.5",:4M:'5M*,~#T :5T !4N*5*,s#r+"%5yP  ͫ%> ͫ%%g >v % 222:4¦ :4 – ì !ʬ ¦ À :4:4€ ( :4 :4:€ :4€ (€ € x !4À  :€ :>S %2 !~5€ :%j B !4À € !~5€ úG!~4_!p!~5^!~>À >2)5:4 *5" +"%5:4ڥ >ͫ%ͫ%[%:4 :4, V :4  + !4N#~ͫ% > ͫ%ͫ%*5"#5:)5R"A*5"%5!4NA#~ͫ% p"5*5N"%5!4q#͢%w 3:4(x *#5:,5o"#5V%2*5Ô; !:V :4:4{%͉"">2!:4:424*o,kÊo:4:4{,ʊ:k*%5#!(5~́ w23@:2(4y""3"323>2v3 :u3L!P46+(0>24:u3:v3"U24͋$͇%ͩ$!5*}*#5":4:4: =X!^#fk:Vj&AW y ~   8 ; C :4:4=s#r+".*."5:u32'5!5~4P!"*|"#5>%*5%"".o!P46 !L4*>2(>2v3͖>2(>2v3͖NB:O* 0:+5ʘ0*5*!5S*5*!5S\gr!P4w#þH USE FACTOR !M4** "5A1z{*5~2*"#5v#!":5(%! 5%n25%%%>%n2G:5x:L4 o:x_*5#"5:5ʽ*5|ʉIB0>%%O%O: 5%*55%ý:5ʽ: 5O*5*5ESS͎2O=>O͎2N=#y{- :)5%͉}*5" +"%5ͫ%ͫ%*5"#5>@:2(4:(5 H 23y"*5"3*%5! {#zt ~+"%5*5+"5wT #"5*5"3:)5ʑ N]T s#r+*#5* {_zW"3:)52v3 > > >2 5n2"5 %: 5*#5* 5"#5*55%"#5:5KBn2: 5O0!*", ++ *5:K4 0@:5Ĩ/ú>2) :u3ʭ :4­ *5+"%5[%2!<24*$#"$""*:40!??"4͋$"5+"%5͇%ͩ$+:4­ :4,J "*} :*5 :5%:4 +:25Ĩ/:4 :4  @G!4F#I ,*5͘EIr,o͉n2"5~2 r,Yo :K4 ͉:K4 " : 52> 2K4::4M:4 Mg %U!P46+:v3Ϳ$ý*3*3"3Ϳ$"3½:v3*3^#V{ʽr+s*3^#V ʽ-:v3:r+s!46#w4> 24͋$í!94~6!(5~6"3~,_#!4w͋$ÏV *3o6͋$*3~6 Þ*3:4,"3~ š62:4*3s#r2(5294*3#"%5͇%ͩ$@*3"5":(42:32(5Ģ >24*3"32(5 ͉r!Q4wM#* 5* 5 "#5" 5͎21͎2=HÎ2Î20:G!^4!K4wOOn2!6z_{_4A_A?*!5"#5*#5*5{z*/5+"%5**+"%5% V%=͇%͢%*%5#þ!v3ʲ:(O! ^#V4@B%GFB>%%O0*#5##~<##ò*#5"|3#"%5͇%:15^:4^!4~?^#ʲ:4͆!~3"z3^#V"#5}ʝ##~2v32w322(!~38w# ͖!~3"z3>2y3*z3^#V#"z3"#5*#5}S+ >2):4„ ͣ#v#: :5$:)%k %G I k :)%:)c %k %+:4„ :4, " :4 :4/ :4 :5 $*#5^#V*S"s#r*5*#5s#r+"5 |#v#*#5" 5:4 :4/ !"5:5> %AB,#*#5 :4:4 !;*M_!Q^#fkox Iͻ8ʗy0IͻGͰͻHIͻ(yIͰͻͻy0>=n2*5~2%! 5%~2͉:K4 v }>v S M:5p*#5*gu>%"u> %2 :5O%:4©:5[%! 4:4©:4,ʀ>:5: O%% 2)5:4:4 !*%5"-5>2'5*%5"&:4:4(:)5N:5N:4=N N*&"%52)ͫ%:(5ī%x;c!'54!'55:)5ž!":*5ʍ!5%Ù*5%*#5":5*%5~ *%56 ͫ%<͉:K4 "5~2o M%(>@%>#*55%!".!/)   ʩ##~<2x3G*#5###"%5:w37> ͺ!w3~w7>w> ͺ:w3Pd!5^!K4~ B!~624(02w3%!>%|_}_> ͺ!w3~w:x3ʜ=͢%ͺ!w34È*#5^#V"#5!y35:24(0!^4!K4w>R0>V0>D>P>L>O>B>S>N0!u~ڇK6N4!E s#r!U :mw* 5!] s#r!t~ ڹ6K^4!1w!;p!u~K!5N!E ~#fo!U ~2n!] ^#V"p~wN#Fq#p>B0!4"%*%F# #2P"*#5##~G=#w#6#w]$*5!4n& {ozg"#5!5{#z$"5f$*5!4N#yʦ$ ~Ù$f$!U3"Q"/$:P"%*5!3{#z"#5%_!U3*#5~#~&%~#$"5ÿ$&%!%*A1>623y"!v36*5"3$"32:4*W"#5GJ2:42942(524> 2S(0>24ɯ242T!4~@`65!^4#:(5O:4yD(w~$w:(50 |:(5D(A:(5?ʱ@ʱD(Aɷ͙| ;!Cͻ2(5:'5:)5:5:(5ͫ%:(5 !J24:(5 ʞ;{>24:'5ʋ:)5.:5‹;Ž*-5*%5++{Iz]~ T++]!]+?"%5:'52'5hͫ%2'5ä:(5*—:S —ʤË ¤24͙ʳ>|ʾ>:(5'2(5> :u3>+2P4(0!K46 >24>24:(52SR:K2oo&) ^#fkN]ivKzV{K>ɯo>g"!6ů{_zW5>)D*OxGғ !?uDM!xGyOڱò)â͝ddJ)=J|g}o=2o2o*p"rOxKxGyKxGy0KG*p*r}|K\\z{W¢Ü}|ڜâWʜllyWœâ!!#Qzg{ozg{ozg{ol&:oO:n2m*p" 52n2ox:4SYMBOL TABLE OVERFLOW *#5###w*#5###~,#*#5_####&%s#r&%^#V&%##"%5F%wF%~#!4~l%6~=ͫ%ͫ%!4N#~ͫ% y%͢%͢%2P"I!LTM>!GT:(5=M!GE2(5"4!44>24!(5:4ruͳ u͇:(5D(OʓQ˜>ßH©>2T2(5:SD(B¹>D> !452T!"4!4N#~#A07O!T/!~*4! ) "4 :(5 5!'':(5 :(5,;%:(5 !:(5; ,J242Z$ l ` / ‰ >24#!:(52S:4; ¡ :4/!:Z/!)!:4 :(5'#!R:(5'z 24É :(5' >24#!^ :(5 #! #!;!)!<!!Z~4z :4 ;!,ɯ2t2u2 52o=20!"5" 52m{!t~Q5_!1~9:uK:K4 *E"5:U2 5*]" 5*v"#5:K4 $:4§:4KK!4^#=ʣV²*4(—ҌV :4:4V !!*/O:0K>20y_j:t:_!;~:!ts!1~y_!t~X=w_!1~[Kdͪ>20$y$zU0!%2m*#5"v:mP>U0%4XXCHGXTHLENDIFEXITMEXTRNLOCALMACROSTKLNTITLECOMMONINPAGEMACLIBPUBLIC7 PF FPA A A* A A A(#&&#&2#/?&#' '( v'( %:P!@"<& #*)&# PP%27&#(&#  $ %*%"$  NZZ NCC POPEP M a{xʑ(_BH!f(4D(#ƒ( p({ڍ(KR(CR(<:4 JCR:4(ʿ((!46 4(!4(# ( ɯ<:4O=_.)!D'F!%V#fjQM()#!>!!Z~#!5z #!:Z#!G )!Rz >24>VG!>OG!>IG!>BG!0!P!w#w#["!"#5!U3w#w#p"!u3~#4^!v3~w!3ͷ"!3ͷ"!3ͷ"!3~w!3ͷ"!4~w!(4~wN#Fp+q!u3~#^!v3"!3#!3#!3#!3"!3#!4"!(4"5>%:m!>2m*202m!" 5/:0Kx*#5DM*5" 5}|^#V<>E0:u3ʛ*3~Œ:v3ʁ!\4>A!(0":3]#"3,ž"3Þ-2\  :4x_<24!K4w:94͜:94ɯ2:4284]294:4:94K)2:4;4~#!͜,!:4~*4!;4_:94w]294ɯ<*#5"W͉#4#*W"#5ɯ2[![4Y5!!:46"3!:4~q5!84^4!;4~â:u3:94†G³]âʻ^¨^·:94&·!:44#wó&G294xâG:94&:4G/G&ʷ/&ʷG/G!94~&*   2%!%^#Vo&)O~#F͔(ͨ(xGyѯ*ÿ*:?*ÿ*:@*ÿ*~x/~# *> x/\ ʨ/0!s*6S#6Y#6M#w!*w:>*2=*!"*%,ʨ/26**j*կ ,,0:?*1::*Z1ͬ2L1͎2**}1}w1>B/a1}|Gd/:?*ʓ1**+![2*CP/M RMAC ASSEM 1.1 NO SOURCE FILE PRESENT NO DIRECTORY SPACE SOURCE FILE NAME ERROR INVALID PARAMETER: SOURCE FILE READ ERROR OUTPUT FILE WRITE ERROR CANNOT CLOSE FILES UNBALANCED MACRO LIB END OF ASSEMBLY : 5O!5 ~#fo: 5O!5 s#r:?*yʟ2š2ͬ2Ž2G:9*29*!:*4>6:9*L/29*2%#333/3 3333#332E3 3 ?-$-w#+!\64 #+>GO#w %+>O # <+6 2+6L#6I#6B#w2|*\+>2*5!"B*!(5~2A*w͹*!1*>826*27*!"/5*"5!5"h*"*"*#"5"!5\, _#~ͨ+ ¶+:;*Aͨ+>:ͨ+Ͷ+>.ͨ+Ͷ+>-ͨ+*!1+!32*!1+:=* D,> D,:D*6,_!D* W,6 4ɯ2D*2*522521528*:\ -2;*2@*O:\ʋ,=Ì,y!<*w#w#w#w#>2+52,5:m$>-!~#$ª,~>-# ʱ,<*A-P-S-R-L-*,+,-,-+5~S-M$Nwy!"(9"f1f! Ҕ2! ~#foCOPYRIGHT (C) 1982, DIGITAL RESEARCH 151282KK{<<ʽ<K : >! ~6 69BK! OS  MXList WAITING FOR PRINTER $PRINTER READY $-25L-15Q-8*1,-x#ñ,~A,-#ñ,#6 !1*!*!E**e !N*+-!j**%,r-6* ,,:=*ʂ-:>*…-2:?*ʨ-!***ѯ2:*29* ,,!3*60#60#60#>235!"*:5ͨ/-!"f*2Q*2e**E*+!1*z{:*5G.*B*-.!"B**\..*B*#"B*+~¤.:u32*5G.*\!F2+*f*-•.*!"f**h*ʹ*E*€.a.Ò.Ҫ.ʒ.6# ‹.͹**h**f*#"f*~!2*G:=*..xx/.x.1,..****w#"*!-*!"***}!,"**NK6 :+OK2$^#V#N#FxNp:$p:Gjxj Y# A>QFQx>QGQx3ڰbڼqҼo5p5"""*!yb! ~G*!NKկ2!*$K*"x!*!@$@hK\K:K ~#~ w*NK*NK^#V#N#F!",!."*K6*}ʴ}<ʴ.}o|g "($Kt>=2(*f*(}DɯQ"(>QKQKQ>Q"%Q flag call cost1 ; get the actual output status, ana m ; and mask with ctl-Q/ctl-S flag ret ; return this as the status cist1: ; get input status with and saved push b ! push h call ?cist pop h ! pop b ora a ret costj*!*-/~5/ʹ*9//͹*!2*1L/****w#"*!-*!"****/_!5*~ ͳ.27**/5}!1~ /ͳ.#/> ͳ.>#ͳ.ͅ/> ͳ.*/5~/ͳ.#/> ͳ.> ͳ.> ó.}26*!7*è/Oͳ.:K4 :5:=*yx/:8*!5I0:25!*5—0~0:K4 0!K4~ —0:350:P4+—0:,50ʗ0:Q4#0:L4 0:,5=ʗ0!K4~ ʇ0!4s!7*~!6*Ԩ/4:4!K4ʺ0G~ 0#x=ë0> 0> 024!K4>x6 #=0G!K4~ p%,**}0>ͳ.0*j*+:+5+   !2*%DM**ѵ+)) H~#+}#<:<ʲ<77:<ʢ2~77ø~7"9:OG#Q{ozg# ""BB) >>l!C9 < ,*3&+) ^#V*3M  ,!iq*# :iw*#"!͛o #*DMu{!"*!*"D*!s*D!s*D!s!6*!*"D*!s*D!s*D!s!6*M: *M: *M: O`iN928 "92;!j6:;!jU :j=O!< Hq!j40 *8M*9 !k6:;!kڇ :k=O!< N,!k4g  ,!lq*' :lw*#"!͛ '*DMT{*!*"!"!ns+q: ͪ :n!O> !>O:n2n'*DMT{T:lͪ : >>l?: &#*DMu{:2:2u͉Tp*>@O>*>@*w*~!s+q*&%*& *&%*2& "*DMT*+"*DM3T"!p+q!\#s>!s:+&:2̀&ͣ :22ͧ!s+q+q*M*͍"̀̀Hm*DM̀%*& "!6|*#:w*##:w* :w!6!6\2!:!H÷:!!6l+6**͍!6\Ãà à ÃÃ1j$|@ "H$UUT$$ $I D$BA@! B$$A IA $!"  @$@$BI!!@""$DA  $I$@!O!mT!w& 8 !w:o2% & *M͍ !6!6:n!2oK :m!o>O!mC!pq*pM !rp+q*q}OY *q|OY *8M *9DMg *;M !s6:;!sھ :s=O!< NY !s4ž !t6:;!t :t=O!< N: !t4 : 2u: :* *uMi  ,*3&+) N#F+q#p!C6:? *uMY !vq "w:R:ҕ *vM*w *3&+) N#F+q#p*3&+) >>l2C:Ҵ *vM *wDMg !yq:y/:yH >!y# :y::* ^#V""!3"$"!o2ͣ :< J.< -B3!6#6!6*#s#r!6\wl!6!6!6\ʒÇ.  -›!&6:!&:&=O! N,:&<2&©**pH*#N*##* ^N0Jͭ1 Gͤͣ  <_1D**M*0G!'q:w**M0*"!6}!6:'҄Çͭ1Ҙ**͇H* >͘ҿ:'/**M*0} <_1K!6ÞCOPYRIGHT (C) 1980 DIGITAL RESEARCH RELIRLFATAL ERROR$l$l1 ͺ!"!6͓*~=:!ͣ !6:/::!ͣ !6:!!/ͣ < ͧv! s+p+q> ͍"̀ځ*>! q** DM* 1q>> ͍+s#r=>!r+s+q+q+p+q> ͍"!6> !*&*6!4¦:! *w* * * DM -* *s#r*"::y8*;< -*:;2:@:<!C6*y&>) N#FG>!ykb :y/:yH҅V :y ¦:823*3&+) *9s#r:y!"+"-"/"1!36<::y<@ Gb :!:y<b :I:y/ *yM :y#~ >!y/͐ :yI:I 7:[:y[Ϳ o >á2zO>Ҏ*zM@:zá2z*zM͵:z,=>)-,),>,=*#"!|p+q*{~**{ >*{#"{>ʹ*~>~,H#6#6:  . - 12(:( T}L :2:2!:y :2̀y ͣ :22!""*"!6!6: *")*"*K: *: !6#6l: *)"ï !6l+6!6͔ :  G. - !"!\"!"*^#V" $!^q> !^] :^0O,h :^ AO,!_q:_OD :_OD !ap+q>`Mi !`\Mi !cp+q*bDMG!ep+q!d\+J<!hr+s+q*f&4 N,*gDM͵ DM̈́  ,*3&+̀*":*. Tu -". u -2:~ l:\.~ -Ql.~ -dup. du -zT!"u*M: *M: !6>}!: :<2¨#u{u>!͘,T>͍)*DMTT"*%DMu{̀+s#r;'*DMu{̀N*"'ͅ>v":2T2u:ҙu͟!6>!ڙ: :<2:ҦT͟:!/Ҵ:͍ >>l͍ >!͘:/H*!*",    !6)!\""!o)ͣ !6!6ʹͼi**& w:<2cͣ ʹ7*~-w!6*~)…!6:ғͣ !6*"*~)*:º!6***̈́:*:!6!6lͼͣ Þ!6*~>ʤ*#"}!6*:3ͣ *~=X!6*#"}:X!"}**Ҁ* *}s#r*>wÑ**}̈́ͼҡͣ ʹ*~]*~D!6*~I!6*~M!6*~P!6ͣ ʹèogDM!>))덑o|g = DM!>))4 =,_{ozg~ D^#V) N~ U^#V|g}o `_{ozgO{ozgi`N#Fogo&og_{_z#WLIB 1.1 $REL $$$IRL $$$INDEX ERROR$NO MODULE: $SYNTAX E!q!6!6*"ʹ!""!o8ͣ >͍J!"ͼҍ*~(c͆Ç*~_[],()!q: > :a/>z!/H:_2:!p+q*^#V"*##^#V"!6 !6+6:W: Q!6l<*6+: m+_Ax!!6Aڙ:ڐ!l+}::*~:Hھ!*#~A<*wO>!*&*6 '!6:.+A: çCOPYRIGHT (C) 1980 DIGITAL RESEARCH ? OVL LINKING $ $ 1L9M9!96w:o9!9D:!""!""!"9*9^#V"9"q::u9 ͥ6**=;"`:"b:q:b:͞8.96`:q:͞8"9|!96wj1:9R,v! !i*& :b>!4F>:<2O* :w:!4~ʶ 6*#"*{zڶ!"ͧ*!~2xG:2G:p ˆx!4~ 6*#"*{z!"*!~2xG:2G x{_ C#5>ɯ$!p+q!6> !ڌ*&*~ x*&*N,:….,!4Q!r+s+p+q*DMG*DMFEͣ !s+p+q+p+q+p+qWͣ !">͍+s#r!oM*DM`:$*D;*; ";*+":*"::,*;*;":3*.:#":*+":*":**:":*+" ;*" ;**:";*+"9;*";;**;"=;!]:6>!]:ڤ*]:&f;) N#F͋41!]:4:u92:2:2;2E;2u;2;2;2;!D:6+6!E:6!"p9!"m9}2o9!z962v92x92w9!t96X!"y:"{:"}:":":":":":":":":":":":":":"i:"k:"m:"o:}2:!:6#6#6*9"q:2C:2D:2E:2R:!"X:o&"Z:|!"s:!"p;";";";":":";"7;*+":*+":*+" ;*+"9;!":":";"?;!":":";"A;:9*b::9=o&))9  ^#V!!<4*<&^<) M͐O>!>͍ ͣ !9*DM͠O>9ͣ *"*#"`!r+s+p+q+p+q***DMͮ*!r+s+p+q+p+q***DMͮ!p+q*DMp!6 > !*&*6!4²*DMͰͣ !p+q * 6 * 6*DM̀*͍!p+q*DM+ͣ !q*& , ,!p+q*  !p+q*!p+q*!p+q*! p+q*! p+q* ! p+q* !p+q`*!p+q*_{ozg_-   <͞8-*<&^<) ^#V"d:M*<&^<) q#p!<4*9&))9  *`:s#r*A:)8"p9*9&))9 q#p:9<29O>D:9=29D:9ڗ*9&))9 ^#V"p9  ^#V"`:*`:DM!96#~ͬ . ":\ -:+: .+: -:9":5*.:~=ͬ :9('*.:~(*.:~)H^*.:~,NDͬ :9['(:9vC()!o96>5!B".:ͬ . ":\ -ˆ*.:~=Ÿͬ ï.+: -§:9ҹ'*.:~*.:~(H*.:~,Dͬ :9'ù:w92y9:9F:9DMͪͮDMͪDMͪͺ"u:![<4!"i:"k:"m:"o:*d:##6*d: 6*d:^#V!`=p+q*d:*_=s#r*d: >!a=q*d: :a=w*d:##>?!b=q*d:##:b=w*d:##~*d:##>w*d:##~*d:##>w*d: ~!c=q*d: >:c=Hẅ́d:8++"\<*\<^#V!e=p+q̈́d:8++"\<*\<*d=s#r*d: ^#V!g=p+q*d: *f=s#r*d: ~!h=q*d: >:h=Hw!k=s+p+q!^=6:k==2k=ʱ*i=:^=2^=*i=#"i=Ñ:^=2^=!n=s+p+qͽ"d:`:d:͞8͹h!n=*l=*d: DM*n=>*>:DM9͏5*:@ ~ !92(< !92)<7 :)<ր2) >!:*!^:6+":^:$t 8'> *0< ~L*0< DMB5*0< 6*0w#6!4:o929*p9"95*.:~(*.:~ʐn*.:~)p̀^*.:~*.:~(HҍDO:9ʛD*Ͳ!6~̈́6*& 6:[],()?$! : @: <_2 <: !#<ڲ*#<& :<«>!#<4>*.:#".:*.:N2<&õ͵:< ͵!<6 !%<6+6:%< :%<  !̈́d:8+s#r!r=s+q+p+q*o=DM*q=̈́*^=&^<) ^#V"d:>d:ͫ8ʆh!q=}*o=*d: DM*q=>*}U!r=}>M"d:<>!|=r+s+q+q+q+p+q+q+p+q:u=2}=:z=Һ!}=44*`:"d:*}=& "`:q:ͮ896<*s=DM*u=̈́*^=&^<) N#FU*^=&^<) *d:s#r*}=M͍*v=DM>*y=M*u=Ms*x=Mf*u=*d: *s=DM -B:z=Y*{=DM*d: ~#k!{96 MODULE TOP $UNDEFINED START SYMBOL: $YY???? $$$XX???? $$$RQST$ UNDEFINED SYMBOLS: $ABSOLUTE $CODE SIZE $DATA SIZE $COMMON SIZE $U0<##>w#6*0<##N#F*.< ~O`i~8p8!6Ͷ8ikS*0< DMv5*0< DMd5*0< *0<##N#Fq#pä*0<##q#p*u:#^#V*u: ^#V*u: ^#V*u:~*u:~*u:>*u:~*u: ^#V*w: ^#V!8:=<Hw!>:><Hw!?:?<Hw!@:@<Hw!B͔8>ͥG<<6͸ !\6͊ !!%<6͊> :%<5 !͸ ͵" :<:„ :\:%<Hb !:]A<2\O>v !*%<&\ 6 ô !%<6:<.° ͵͊ڰ :%< ڧ !͸ ͵Ô ! :%<<2% :<02<> : :>!"&<͵͊6 - *&<))))*<& "&<0 D͵ *&<:/͵: W :ZD͵:ڎ : !=8:=0OͲC:= AOͲ!=q:=O:=O!=p+q!=̈́8MD>=08MD:;!t;!;!;:u;2\. ] -Ÿ\ͩ6!t;6!;6!;6!;6!=6+6>!=*=&f;) ^#V"= *= ~ *= DMv5 *= 6!=6:=<2=:=7::2\. ] -)\ͩ6*p9###H:ͮ8!D:U!\:6*p9###F:ͮ8!C:r!\:6*p9###X:ͮ8҉!\:6:R:>S:ͫ8:U:H:C:/HҼ!\:6!\:6:E:!C:!\:6!\:6:C:*F:"::\:*p9###":8'*u:"w:*E<#"E<ͺ"u:>͔8$>ͥG<ͮ8!TJ<ͫ8:P<Hr:Q<ҁ!U<6 Æ!U<6:U<q:ͫ8+s#r!`:͹8ң96:T<Һ*JE<ͫ8*P<&i:) N#F,DM,*LE<ͫ8F*P<&i:) *q:s#rN*q:DMͷ!V<6>!V<ڷ!"Y<*V<&i:) ^#V"u:>u:ͫ8ʝͺ"W<*Y![<,*[<&i:) ^#V"u:*[<&<) N#F.>u:ͫ8%Okͥ:Ý :!Q: D*Q:&J: :!=ڞ*=&y:) >Ͷ8Ҕͥ:=<2=v!":::2=!=6:=#w:==2= *=&:) *=&: N!: ͠8*=&: ~2=*=& :=w:=2=:=<2=õ*=&: :=w::<2:*b:"d:`:d:͞8q͜/!9H`2UO!: 8DM>ͪ̈́d:8+s#r&!]:6>!]:7*]:&f;) N#F͋4:*]:&<) N#F.B2=:="="=:=O>"=n2=ð-*]:&i:) ^#V"u:>u:ͫ8 '*+>M%('͕".>:^:('*.>DM*,>^%:+>&7','!0:6&H'='!0:6!"1:"7::!:'*:͗8"1:"7:. 9\ -u')29!hʦ':92h\͕6¦'\=45)2|29!:6*7:"1:!"9"9^ :_:/2^::!:!_:' ',':e (.e -'e>*2!:\d5I'}/B(}͉ͽ"d:`:d:͞8)͹(:v92\!0>6>!0>گ(h!0>҈(*0>&\ 6 å(:0>=O! *d:*0>&\ w:0><20>g(!!:6.e -¼(\W5/(!!:6.e -(\d5*d:"1>!_:6I'*1>"d:̈́*>DM*>h!ͮ"!>2>:>>!>ͫ8HA!ͱ!">G!*!>">*>DM*>MC:>e!*]:M͋!*>*>*]:*>*>5:=Ҭ!ͱ!"!>>͔8ž!*!>">!>6í!!:]:2%>*>M^ *>DM4*>#DM4O`i~8p8"#>*%>M^ *#>*b:"d:`:d:͞8%"*d: ~#"*d: 6̈́d:8+s#r!!{96:*:MH"H"!^:6:*:Mi"2"g:͜2f:o"=6*:::: -y"::29:*::ͺ/Ҵ":*:͉:*:M"!:͹8"/Ͳͯ/Ͳ Ͳ=6#:*:*:*:-2=ͥ"=ͮ"=!"=nͺ"u::]:<2]:w!=r+s+p+q*=}*=_DM͘4*=#*=|_͘4!=p+q*="d:2:=2=:=O>Ґ*=DM^"=ã*=&:) =8"=:=O>:=O>==͞8UO!: ͹8"=*=*="=*=DM*=8*d: ~*d: :!z9/H!"=ͽ"d:`:d:͞8HҴ>=08>͔8S6!~=6U`/wUp/>=08 \8 M`͹ҖÞ2DM_   *=#"=̈́d:8+s#r >!=Ͷ86!=6>#w#62~=ͽ"d:`:d:͞8N/=:=d:8+s#rI(.: -)!:6!:6^ ͽ"d:`:d:͞8)/)*{:DM>fy ^%y !":y y *d:"4>#*4>"d:!3>6>!3>)h!3>ڶ):3>=O! *d:Ny û) y :3><23>Œ)*:"::)͸*9"q:̈́d:8+s#r5)!0:4~ (*6*1:#"1:*7:{z*!"1:/ *1:!>~26>xG:6>26>G )x{_ P*#B*>ɯ`iq#zV*COMPRLRSPSPROVLSYM!;>q*5:> :;>w*5:#"5:!3:͹8ڦ*>*3:DM\͔5!"5:!<>q:8>!<>28>:7><27>*!7>6*8>Mq*!8>6!=>q*=>Mq**A:#"A:!?>p+q*>>}O**>>|O*:*:͉*:*:"::*:M/I#:*:͉*d:DM :*:Mҟ#{#=ͯ6Ü#*:&:) :8DM>*:Mf#:*:*:&:) :8*:͉*]:&y:) N#F*]:*:DM5!=6#!=6*:":*:M^ :]:$$*g:*:":C$*]:&:) :8*]:&y:) q#p:]:P$!=6*]:&y:) N#F *:":>!:Ͷ8::HҲ$:R:Ҕ$=6ò$*:&:) :8"S:::2U:!R:6:0:$)$ò$!&>6>!&>%%*&>&:) *&>&:) 8*&>&:) q#p*&>&!=6>=08>͔8'6!~=6w*=#"=>&8)))M`̈́d:8+s#r>!=Ͷ8\66!=q!=:~=v d!=6h!=ڤ:==O! *d:N:=<2=|:E:J:*Q:M2"V:!"V:|!=6:Q:!=:==O!J: NͲ:=<2=6D:R:*U:&:) S:8"V:D>!{:Ͷ81*:"V:DX:ͣ8D*X:"V:Z:X:͞8mX:Z:͞8#DM*X:v6*:DM*:6*:DM*:6*:DM*:6`:s:͞89ͮ8*9|=ͫ8:+:o9+h,*p9"A::\:,+**V:DM**X:":!@>6::=!@>q+*@>&: N!: p9͞8j+*@>&: N͍+!@>47+:o9:o9HҌ+ -!C>q:C>¢+*X:"D>ó+*C>&:) ^#V"D>D>A:͞8+96D>A:͞8+*+*C>&f;) N#F͋4*C>&y:) >Ͷ8,:C>,*X:DM',,',|9A:͞8&,*A:"|9!G>p+q*F>"H>*C>&y:) F>8+!H>͹8g,*H>DM4O**H>"H>3,::=O!: N!: !y: 8*p9͗8"A>**A>DM**:o9,***p9DM*,*m9DM****:r9,*:DM*,*!J>6>!J> -y:) q#p*&>&:) >w#6:&><2&>$s:q:͞87%*q:"s::G%͸*9"q:^ :_:/2^::{9]%!!)>s+p+q:)>ˆ%*g:*'>"'>:f:҅%!)>6Ý%*)>&:) '>8+s#r*]:&y:) N#F*]:%*'>DM*)>M͋%*]:&y:) N#F*'>*)>*]:5y y !*>q:*> &>!*>&:*>#&+"ÿ&:*>1&p"ÿ&:*>?&k$ÿ&:^:ҿ&:*>=O!& ^#VI"ÿ&ÿ&͈"ÿ&>ÿ&͵"ÿ&#ÿ&T#ÿ&#ÿ&#ÿ&$ÿ&$ÿ&Q$ÿ&d$ÿ&W&]&`&f&o&u&{&&&&&&&!+>6)&)2->:^:&*->My (')2,>')2+>:+> Ͳ(Ͳ*=DM_-Ͳ*=*=+DM_)Ͳl*|9DM_68f ͥOr:t9Z^E.:n~:x9ZyU/?OVLAY?OVLA0RELIRLIRLREL))O`i~8p8>!:!>6::!>:>=O!: NͲ!>4½)2:͕":)2::: !:6!>6::!>. ):>=O!: Hq!>4 *h&\8*|& "9>*7:DM\͏5*9+"9!>q:>2]:*]:&f;) N#F͋4!>q:]:!f:Ҏ *]:&y:) N#F*>͘4:]: Z:y:͞8Ҽ *y:"Z:X:y:͞8 *y:"X:*]:&y:) N#F+q#p!>s+p+q::2>O!: :8">/   *!J>4,*p9"A::\:(-ͦ-ͦ-ͦ-!L>6::=!L>|-*L>&: ~2K>u-*K>&:) A:͠8e-ͦ-J-:r-.u--!L>4--*p9*A>A:ͮ8ҕ-ͦ-|-:7>ʥ-ͦ-Õ-!O>q*O>Mͧ**A:#"A:M>A:͞8-ͦ-ù-ͦ-*K>&i:) ^#V"u:>u:ͫ8.ͥ*K>&:) 8"M>͹-ͺ"u:-*K>&<) N#F.*0< ~R.*0< DMd5*0< *0<##N#Fq#p].*0<##q#p2P>:P>ʤ.*K>&:) 8"M>"9:P>O>Ҙ."9͹-2P>c.>5:08>͔8ʾ.q*å.>*5:DM\͔5\v5:w9Z.. \": -.:e /.*o9&XXDATA $$$XXCOMM $$$::;7;YYABS $$$YYPROG $$$YYDATA $$$YYCOMM $$$n;;;; N#F*t>?8*]>~   +5{>.+55OͲ5w66ͩ6́5;6<566́5͕6<>́5͕6<>645͜6<H66! w #ˆ5>Ö5>2,6""6"$6yo`"&6!"*6͋6-66*&6|6 "&6*"6MD6*$6DM:,65ͷ6g666Ͱ66**6|6U6*$645*"6""6**6#"*6ú56**6ABORTED$NO SPACE$NO FILE: $CANNOT CLOSE$DISK READ ERROR: $DISK WRITE ERROR$YYYP   YP6YPYPYPYPYPYP Ͳ ò!>6#6͐6">*>|$7>\8_* DMe - /:w9#/:w92\\B5:9 A/. ~9\ -9/!"5:}28>27>*ͥ.:x9Z^/. \": -f/.en* -v/:x9ʌ/:x92\\B5!"5:}2R>ͽ"d:`:d:͞8(0͹/H02DMv0 q*!Q>6h!Q>/:Q>=O! *d:Nq*:Q><2Q>/:R><2R>0 q* q*0 q*̈́d:8+s#râ/ q* q*ͥ.!S>q> !S>O0:S>0Oq*Z0:S> AOq*!T>q:T>O60:T>O60!V>p+q*U>|O[0*U>}O[0*9>!=8"W>*W>!=8!Y>s:h0:Y>2h\͕60\>645*W>!=8!|s2*9͗8"9>. \~9 -0:9 1INDEX ERROR$MULTIPLE DEFINITION: $MAIN MODULE ERROR$FIRST COMMON NOT LARGEST$COMMON ERROR$UNRECOGNIZED ITEM $llyWœâ!!#Qzg{ozg{ozg{ol&:oO:n2m*p" 52n2ox:49ͫ8"|>##*|> ~!7!>6D7*>|?7!>66"|>D7!>6:>Y7!~>6#6#6Å7*|>~2~>*|> ~2>:>z7:>2>*|> ~2>!>6>!>ڰ7*>&v> ~/*>&: w!>4‹7:72"g:^ *:"|> *g:":*9My *9My *9My *~>My *>My *>My *|>":i`N#Fog_og_{ozg_ogDM!>))덑o|gV8 =D8DM!>))k8 =c8_{ozg^#V) ~8^#V|g}o ˆ8_{ozgi`N#Fogo&og_{_z#W*9>"9>\d5͍0C\͏5!Z>s*9>!=8C "9*9*|9s#r͍0C*Z>&\8DM\͔5:j2j\v5:9ҁ1*|9)8"|9:y9ZŠ1a9ҟ10ñ1g9ұ10!_>q.*[> :_>w*[> ~!`>q*[> :`>w*[> *[> ^#VN#FR* *[> 6*[>^#V!=8"b>?8!a>s1!a>P2*[> DMv5*a>M1*[> DM͕6P2*[> DML5*b>!=8MͲ1*[>  *[> ͞8ҍ2*[>  *[> N#Fq#p *[> ~ڮ2*[> DMB5 *[> 61*[> N#F*[> *[> N#F͔51!e>p+q*[> N#F*d>?8^8*[>q#p*[> LINK 1.31 $01/04/83?MEMRY$MEMRYX MEMORY OVERFLOW, USE [A] SWITCH$INSUFFICIENT MEMORY$OVERLAPPING SEGMENTS$ XXABS $$$XXPROG $$$*[> 8+*[>##q#p*[>*[> N#F^#V?8*[> s#r *[> N#F`i"h>*[> N#F `i"j>*h>"f>j>f>͞8ڐ3*f>+*[> ^#V\8DM2_2*f>"f>\3*[> ^#V*j>\8DM2*[>  *[> ͞8Ҿ31*[> N#F*[> *[> N#F͏5!n>s+p+q*[>l>͠84 *[> ~4_2*l>DM2ͦ3Ê4*[>##l>͞8Ҋ4 *[> ~34_2*l>DM2:n>j4*[>  *[> N#FPY͹8d463g4ͦ3Ê4*[>  *[> ͞8҇41Ê4ͦ3!p>p+q*o>"[>!s>s+p+q*q>DM3*[> ^#V"]>*[> N#F*q>?8*]>:s>w *[> 6!u>p+q*t>DM3*[> ^#V"]>*[>0   ( COPYRIGHT (C) 1977 DIGITAL RESEARCH 112O02Z0̀%!"K2.>2.*M0"$/̓%!"":g0i!"P0"R0"2:0v: 0$  :[0-ʬ+ʬ* :[0!_0M!f0P p  !   :O0Ĝ!":O0*V0}|<r ͪ*|Ĵ:O0_͑H *V0"Ù*V0"E V» ͪ»**»"Ù*K0"X0!0NA#~' ~p"K0*K0N"X0!0q#*w œ:0!x ͜ *V0*R0:_0̍"V02*M0r; !:r 0Ģ*R0̜*R0ĜG:O0xě%:/ *R0̍:xz*P0#"P0E2D20:b!^4!/wjj*R0!6zz{z4A_A?ɯ2.2*T0"V0!.8w# *V0*K0{zҤ*b0+"X0 =$**X0#Þ!.*V0".#"X0$:d0<:0<! 0~?<#ʐ: 0͡!.".^#V"V0}{##~2.*.^#V#"."V0*V0}d##~<2.G*V0##"X0:.> u!.~w>w> u:.:0!4 :0& : 0::0!xI !4̨ e ::̮>͞ } !~5:Į ͵ !4̨!~5 G!~Ҩ4_!p!~ʮ5^!~> >2\0:0N *K0"+"X0:0 >''!:0N : 0,N :0 >  > !0N#~' ) > ''*K0"V0:\0x ʹ:\0" m }*K0"+"X0''*K0"V0>"4ͬ:2T/:[0 “ 2/-*M0"$/*X0!{#zڿ ~+"X0*M0+"M0wß #"K0*M0".:\0 N]T s#r+*V0*{_zW".:\02.R  :0F: 0e%;m ">2:0b: 020 W,F:0b: 0e,ʹ:re*X0#![0~ʇww2/ͬ:2T/-"."$/2/>2.v:.ʸ!/6+͕%>20:.ʮ:.0209$<!5*}Ģ*V0":0y: 0:yv! X! ^#fkX _~ 0^ Z   2 5 8  :0‰:0=ʉG! 0ʃF#2sÖ*I0| E2V ,[ ͊m *R0"R0"P0 m E2D2V ,ʾ ͊:/ m :/ "> 2/:ĮP'!5^!/~ !~620͕%2.|z}z> u!.~w:.W=*u!.4C*V0^#V"V0ý!.5¯:20͕%!^4!/w>R͘%>V͘%>Dý>Pý>Lý>Oý>Bý>Sý>N͘%*6".~ 6-!2~B6~44O!! s#r!1~ _6^4! w!p!2~~!55N!! N#fiooo&)^#fk9BIO[ov ͌z{>ɯo>g͌"!6ů{_zW5>   % *I0:/ ͪ% ͬ:O0ĭ%  :.ʢ :0¢ *K0+"X0!2<20*#"" : 00Ĩ!??" 09"K0+"X0$< :0¢ : 0,? ʹ  *} :]0 :O0 :0 ͤ%:e0ĭ%:0 : 0  ͬͧ%vʹ   ͺ :0: 0 !;* _!5 ^#fkS \ h n 2 ͠ ͻ ͵ ͠ ͖ 8{ Ăy0 2͵ ͖ Gͻ ͋ ͖ 1ͻ ͯ 2ͯ ͖ (Ăy 2͵ ͋ ͖ ͖ Ăy0 ͖ 2ͯ 1:0 : 0 -Ͳ !/6+:.;?*$/*."$/?"$/:.l*.^#V{r+s5*.^#V ʓ:. r+s!06#wÚ> 209!e/~6![0~6".~,#!0w9 9*.~6 *: 0,Ĵ2f/*.s#r2[02e/*.#"X0$<5ͬ*$/"M00:T/2:/2[0 v>20*.".2[0v*R0m "R0͍"R0!/w >=G*R0*I0"R0"R0 m :/ }>͞ ¥͢ :O0*V0*ʿ͜">2:O0:0:O0!!4:0: 0,)D*OxG !?DM!xGyO23)#͌)=R|g}o=^͌͌roz{͉͌͌}|͉͌Þ͌Þ͌ë͉͌!!o#Ã͌zg{o͌zg{o͌zg{oolo&3:0: 0 ;!,ɯ2122=2 !"I0&q!1~\5_! ~͔D:2:/ *!"I0:/ :0:0! 0^#=ʙV¨*0!҂ :0:0& !!>O: > 'd ! ^#V#*0}o|g*  ":D x=D y0P 2!0^4! 0q :0Ė: 0,; Ė*I0m |}$† ͌oy Ԍ͋ 8O͖ Ăy01y 1m X:0 : 0, >C͘%:0 : 0 v;:0 : 0 v-!v !v-ʹ {ozg:.7ͮ2Z0!O0~4l!"*|>"V0*""J͊!/6 !/͒%:^0ʏ>2.͡%ͱ*K0*T0&*M0*T0&\ ͍!/w#õH USE FACTOR !/͒%*"P0Þ%z{*P0"R0*"V0 !":O>"4:O0: 2\0:0=: 0 F!Fʹ%*X0"`0>2Z0*X0":0k: 0T!T:\0¦:O0¦:0=ʦ ʦ*"X0 !':[0'Tx»!Z04TT!Z05T:\0!":]0!**V0":O0*X0~ Ĵ*X06 '>#G*I0!" :0 :Z0 !0N*K0:O0Ÿ"b0+"X0yʛ 'É' Ͳ >ͮ 222:0: 0 !ͮ-:01   2 yU`:10_!~0!1s! ~͔ yU!1~N=w_! ~QZP>2 ypP͘% >U̘%>: 2 3>E͘%óf:.O*.~H:.=!4>͕%0:/#". ͆%2G:0xa{_ ʇ ʇ:0x҇_<20!/w:e/S:e/9ɯ2f/2d/2e/:0:e/ !2f/g/~#»S͉!f/~4!g/_:e/w2e/ɯ<*V0"36<& #*)&# PP%27&#(&#  $ %*%"$  NZZ NCC POPEP M x#_BH!™# 0#³# £#{ڽ#KÅ#CÅ#<: 0 JCR:0 $# $! 06 p#! 0$# # ɯ<:0O=_^$!"F!!V#fjQ̀#G$2!!!^#Vo&)O~#F##xGyѯ?>P?<=?>>=<<i;m=>c==>o>v<=<;8?N!Nw#w#W!"V0!.w#w#l2N!.~4^!.~w!.ͼ!.ͼ!.ͼ!/~w!$/ͼ!D/~w!T/~wN#Fp+q!.~^!.!. !. !. !/!$/ !D/!T/5~wN#Fq#p>BØ%!0" * F#%2NG*V0##~w*V0##~<͉:.t!.N!. yq~t +a62/-!.6*M0"$/B".2f/*"V0͗ 2f/2e/2[020> 2͕%>20ɯ202!0~@$6^4#:[0w~$w:[00 6:[0A:[0?e@eAɷP6 o2[0:Z0ʦ:\0 :O0¦:[0':[0 !20:[0 R;/>20:Z0?:\0:O0?́;B*`0*X0++{z~ 0000000000000000000@@@@@@@@@@@@@@@@AA AAQQQ"Q'Q,Q1Q6a *\ ?=)$=)w#Ž&!\60 ڱ&>GO#w ³&>O # &6 &6L#6I#6B#w2|r&\u'>2]0!"%![0~2%wG&!,x&>!0^*K0"V0*M0{z"K0!N"O1#w#w*V0!NN*O N#Fr+sq#p0U>G=#w#wY*M0!0n& {ozg"V0!K0{#z"M0b*M0!0N#yʢ ~Õb!."O1:N *M0!$/{#z"V0$ _!.*V0~#~1 ~#"M0û1 !͒%Þ%SYMBOL TABLE OVERFLOW G*V0##~w*V0##~=*V0_###1 s#r1 ^#V1 ##"X0P wP ~O!0~z 6~=ͼ !0N#~ͼ „ Ͳ O2Nyã6r>ã:[0'ƒ2[0>ã ¡:.ʔ>+2/͕%!/6 >20>20:[02́:0:Z0: 0=!EQ<!LT:[0=!LE>!GT:[0=!GE2[0" 0!04>20![0:0/ʦg¦´/ʦA¦:[0O<QA>HHR>22[0m:B_>fD> j!052!"0!0N#~#A҄0Æ7O!~*0!ʩң)Ú "0 x:[0 '¦́'æ:[0 :[0,;%:[0 !:[0; ,82%2%!"b0*"M0!1"%"&"@&#"K0"T0' _#~6' D':%A6'>:6'D'>.6'D'>-6'x&!,N'!k-x&!,N':% '> ':%'_!% '6 4ɯ2%2]02e02d02g02%:\ =)!%w#w#w#w#w#w#>2^02_0:m$(!~#$,(~(# 3(%Aʩ(Pʩ(Sʩ(Hʩ(Lʩ(*t(+t(-¶(^0~Sʣ(Mʣ(e0Lʣ(d0Qʣ(g0Rʣ(%1¶(x#3(~AҶ(#3(#6 !)-x&!x&!%͉&!%͉&ͳ'(`&͛'͠':%)!&͉&l&͛'&À# $b${$*!:!X!!M"p"""""4#\#j# ()*+,-/ABCDEHLMDBDIDSDWEIEQGEGTIFINLELTNEORSPACIADCADDADIANAANDANICMACMCCMPCPIDAADADDCRDCXENDEQUHLTINRINXIRPJMPLDALOWLXIMODMOVMVINOPNOTNULORAORGORIOUTPOPPSWRALRARRETRLCRRCRSTSBBSBISETSHLSHRSTASTCSUBSUIXORXRAXRIASEGCALLCSEGDSEGELSEENDMHIGHIRPCLDAXLHLDNAMEPAGEPCHLPUSHREPTSHLDSPHLSTAXXCHGXTHLENDIFEXITMEXTRNLOCALMACROSTKLNTITLEINPAGEMACLIBPUBLIC7 PF FPA A A* A A A(#&&#&2#/?&#' '( v'( %:P!@"202́/>20:[02́:0G:0::0l:[0'́:[0' 20/:[0'|>20^—́:[0  <¨!~4 >¼!~5 : >20>V>O>I>B͘%!QéÉ $ ? H Y ` e Ò ü ò ~ÏGÇåûfD?<==:e>?; ><>; ;<=R>>>F>;>G==<==>=s;=P=*>=$?P:-?]>*<<==<;=>>y> ;:2   ͠'!%60#60#60#>2f0!"&:O0*!"%2%2%2%Z&%u'!-x&z{:]0ʢ)*%F)w)!"%r&\‰)*%#"%+~):.2]0ʢ)r&\!~-N'*%F))Z&!"%*%B&%)¼))*)6# )G&*%*%#"%~!<-x&G:%7*$*x*7*x2*Ϳ'5*9**&*&w#"&!F)`&!"&*&%~ʅ*B&Œ*`*G&`*!S-x&ö,͟**>&*@&w#">&!F)l&!">&*@&&`*_!%~ DD  $$HD@" @@ $B $$H$H$HH$$! HD$D$D@AD HD$!A" 1:#"1:*7:{z*!"1:/ *1:!>~26>xG:6>26>G )x{_ P*#B*>ɯ`iq#zV*COMPRLRSPSPROVLSYM!;>q*5:> :;>w*5:#"5:!3:͹8ڦ*>*3:DM\͔5!"5:!<>q:8>!<>28>:7><27>*!7>6*8>Mq*!8>6!=>q*=>Mq**A:#"A:!?>p+q*>>}O**>>|O*:DIRLBL yd'* !9"1>"#2#:Og}**Ip2~w2i#1#":RͶ :O~!ʫ:<2Ž:"2"x2*# O:ļ:<:G>O*# :<t *2%*b0}!,~ +*#+> *>#**> **b0~>+*#2+> *> *> *}2%!%*O*:/ :O0:%y*:%!O0•+:e0!]0+~,:/ ,!/~ +:f0,:/++:_0,+:/#,:/ ,:_0=+!/~ +!0s!%~!%*4:0!/,G~Y+#x=+> Y+> Y+20!/>x6 #=,G!/~ pͳ'*&}?,>*/,`&%͈':^0*+,!&6S#6Y#6M#w!&w:%2%!"&ͳ'*2%`&%͛'͠'+,:%ʶ,:%.*P0"%.*>&}ʶ,>͕*æ,:%,l&&͈'!-x&CP/M MACRO ASSEM 2.0 NO SOURCE FILE PRESENT N1n$'CP/M Version 3.0COPYRIGHT 1982, DIGITAL RESEARCH151282654321!`i^#V#~#foͽ{¡y#wG:xA##6?)@w){#{s333333.;;33,;;#wD{_#6 sO O ڹ.:;=,/[]<>a{Ҷ_#  ý Copyright (c) 1982, Digital Research 11/02/82tIw!/>!/>!*6 #:_#:*Y" Y" Y" >*Y"#####Y"##Y"Y"Yz2*Kg"ɯ22!"*DM6:O* 2~ ~ †:<~:2>2:<** "_?:<2>!/:<}:2* ~b W6 y2> # vwm>2>!/ N *~O²+—">2>!/*:< "~G # p *~w#  :O DIRECTORY SPACE SOURCE FILE NAME ERROR INVALID PARAMETER: SOURCE FILE READ ERROR OUTPUT FILE WRITE ERROR CANNOT CLOSE FILES UNBALANCED MACRO LIB END OF ASSEMBLY G:%x-!%~--.-*P0*%O {-z-.*P0"%!%^4!%w..WƐ'@'Õ*>:͕*!%^Ww*%{-|-}--{?.!%~#-6.-> ͕*> ͕*͞*> ͞*ws @ @NULL0LOADER0SCB []=, :;<>%\|"()/#!@&+-*? COMHEXRSX1###~ERROR: FILE: File not found.No directory space.Invalid file name.First submitted file must be a COM file.Duplicate input RSX...Duplicate RSX in header. Replacing old by new.Invalid RSX type.No more RSX files to be used.Error on copy.There are not enough available RSX slots.Disk read.Disk write.Total file size exceeds 64K.COM file found and NULL option.No header or RSXs to strip. *8*:*8yO:O*}O= ~ w#P^#V#ɷ{ozg |g}oh:<͉̉O<OBKBK$'-*!*^#V"3   Invalid FCB.Media change occurred.Disk I/O error.Invalid drive error.Invalid SCB offsetMissing right parenthesis.Missing SCB value.Missing left parenthesis.Unrecognized option.No modifier for this option.OPTION: This file was not used.GENCOM completed.Requires CP/M 3 or higher.1n$1n$" %* %|<Ó* %}0HÓ::$]Ç:$jZÇ:$wÇ:$҄ZÇer ͺv!n$q*n$& ͤ!p$p+q*o$~*o$Nͤ*o$#"o$  ͤ ͤ&9 :)w!)6!)6!)6%͛2$!"$$*$*$"$!<4:$GT*<$#ã!!<ڸ*<&: 6!<4!\"<$w#s#r!n"<$w#s#r.:[ -!<6>!:H!<6::=!!;S*;&/% 6!;48!/%6 !;6#6:; *;&*(~ HҞ*;&*(*;&/% w!;4#4`*;&/% 6.!;6 :; *;&*(~ H!;4#N*( *;&/% w!;4î!;p+q3r*;D ( w*<&') ^#V"(!<6>!!%(z:$/H!"$$#͞%U!$6̓!"<6:"<#ڀ*"<&( 6:"<<2"<_!"<6:$!"<ک*"<&$) >w#6:"<<2"<…!(" (* (:Ow:%/* ( :Ow* ( 6* ( :$w!"$:%:O2)x* (DM;#"$Q !;p+q*;DM*O>0*;"( !;p+q*;DM:O>R*;"( !;p+q*;DMJ2$>!$y*;"( *( >Š*(DMͻO>ҟ*("(!;p+q*$"%*;"%*$"'%̀"$$#*'"( !;q!;6>!;*;&)))=% *;& *;& w!;4!;6 >!;F:;2;*;&; 6*;& 6!;4!;6> !;ڍ:;2;*;&% *;&; w*;&*(*;& w!;4K;ͫ2$>!$ҥ*'"(!;p+q!;6 >!!;*;&*;6!;4±!*;&1 :;© :;!;4 !;r+s+p+q+p+q !;6. *;~ *;~2;*;My 2$!;6:$ L :;  *;My 2$ ! . :;2$͌ :;2$2;*;~2;!;6*;~2;. *;~L ç *;N! *;*; =2;!;› !;6!;6:;!;ژ L :;ڑ 6 !;4z Þ 6 *;6͌ *;:;w:$$͂#+s#r :$ *$#"$ :L2$:;2;O*; ~2;*;&*;:/( !;4*%͛2$>!$!%"( ):%/i:$R%͛2$*("(!"$$fx%͛2$!"$o!"$*$*$"$/!##"$*$DM*#w#6!)" (%͛2$* (##"*<**̓#+s#r!<5&*<$T :{$]*(DMZ!#:Q! <#:Q2<* !<ړ*<&* (6!<4w* (" (!<6*<&') ^#V"(x*(DM͋2$!)"<*<*<&$) N#Fq#px*(DM͋2$:)!)6*<;:;w*;&*;:; *;&*;~2; *;6*$~2; :;2;!;6*$#~2;!;4N*; :0f !;6| *;&*;:;| !;6!;4N*$ ~2;*;&*$~2;*;My 2$:$:$H:$H:$H !;4N*$ ~2;*;My 2$ä :;2$$͂##+s#r*$Ny 2$!L *$#"$ :$$#+";!;6:$!;P *;Nͤ*;#";!;41 !;p+qr*;DMͺ!;r+s+p+q*;DM͗ *;DM͗ *;~w*;*;~!;p+q*;>9Ұ *;~7w÷ *;~0w!;r+s+q+q*;:;~!;H IQ !;60!$6!;6*$#"$;4    w!$:&<*<-*$**<"*<*$DMi*&<&9) *'<&) N#Fq#p!(<6>!(<ڋ*&<&)))9 *(<& *'<&)))9 *(<& w:(<<2(!(!%< *%<& * (*$<&)))9 *%<& Ÿ :3<<23<0 !$:$ !9!3<6!$:3<҄!*3<&$ ~24<:$=2$:4<26<:$!6!$ҹ! !O:) ":$!!$6!:%!%!!$6!!$6:)"!$6.;) -!2":$"!$62":%!%,"!$62" :"!$6:$/^"%ͦ%ͻ2$*(~2%%S!*3<&ͮ#% "(*3<&') q#p!4<6> !4<ڱ"!*3<&ͮ#% *4<& 6:4<<24<…" *$&$ :3 !6<#*5<&*7<*6<&*(  w:%<<2%<!)" (!$6!,<6:$!,<*,<&$ 6!-<6:$!-<ں*-<&') ^#V"(!.<6>!.<ڑ*.<& * (*.<& *(ʇð:.<<2.!$:$_!)" (!,<6:$!,<r:,<<2,<* (#^#V"0<:$5~ *( 6x*(DM͋2$!0<#"$%͛2$*$DMi*0<"$/>>!)" (* ( ~2$ʃ҃* ( :$* ( w*("(* ( >Ҭf %͛2$:$~!"$$!"$$#*$"$*(DM1͞%U̓!)"w:5<<25<:6<<26<"!: !6:5<<25<:6<<26<:#>i`N#Fog_ogDM!>))덑o|gҨ# =–#DM!>))ҽ# =µ#^#V) #^#V|g}o #O{ozgi`N#Fogo&og_{_z#W (*("(!"$:%N:%/!$N!)6 *( 6*(DM͛2$:$H !"$:%1:$d~õ:$ʚ x*(DMZ:$ʚ:{$$͂#+s#r*(DMZy:{$$͂#+s#r!$#+s#r*(DMU:$/1*(DM1x*(DMͦ*(DM*(DM͋2$.)$ -:% !)6:O2) *( 6*(DM͛2$:$1 *(DM1!"$!3<6>$#_"*(DM͠*$~[h*( ~25<>!5<!6<6!4<6:5<=!4<*6<&*(*3<&)))=% *4<& w:6<<26<:4<<24<†*3<&% :5!%**(DM*O>S:%/P o:%o*( >o :% :$<2$23<!*3<&ͮ#% *3<&') q#p!4<6:$=!4< !5<6> !5<:3<=o&!ͮ#% *5<& !*3<&ͮ#% *5<& w:5<<25<³:3<=23<:4<<24<£R"*'"(X">!$҉!!$6!3<6:$!3< !*3<&') ^#V"(X#/b 'Ͳ"!*3<&% >x *3!$Ҙ Ͳ"!:3<<24<:$!4<!*4<&') ^#V"'!6<6>!6< *6<&*(*6<&*' :6<<26<¿ Ͳ":4<<24<5   6   ."y2;!"(:2(=2(:=;!~;4#.{2(!" "9"2!;(y3]K!o\b!,_^#V* !J ^#V̀:#!"(COPYRIGHT (C) 1982, DIGITAL RESEARCH 151282/(  + 1 7 = }!!!!"""""# ####$$CP/M Error On : Disk I/OInvalid DriveRead/Only FileRead/Only DiskPassword ErrorFile Exists? in Filenameò ò >2(a." :(2:<:5(5(;(:(2ɯ2(2{_zW{_zW ) 74#4#4)7( #  w#*J|^#V#"i(##"k(##"m(###"o(#"q(##"(!s( )*s(!()*(|!(6~67*k(w#w*m(w#w#w>2('å2(*OͶyڲ ò <*e(Ͳ:0!(:(:(ò 2*(>*ͫ"(:+ ̜2 5*( ~o#"( M š*( ~`Uoj*( ~#"( Ñ!* ~6s!+ 6:+ ‚xoͳ*& ~2+ o#"& !+ 6M : W:2 x ͺ*( +"( w  : >2* 2 :*( : +w"( ͺ:G:  !% "( ^-:* $P:<\: W:2 xM s:<9>2 :* 9x~+q ’x2 :* ͂^2 ¢ů͠: !ڽ*( ~5WèjM 2 ͨx*( +w"( j$$#$-$A$J$S$@Y$u u J$u u }$$$$$*%P%$%&'('d'''(('({ A g X J v !)$*^#V#^#Vw# ll l ls:¬MA wM  2*7w#6?#7 .,:;[]=<>|!?]45#Ra{i_p# l s s͂:(A2= / ::0! dگ61#d ڸïp#:w#6 !6:6 *#!)6.#)͂ O(BDOS !(s#r#p*k(N#F*m(^#V#F*(:(O}|y9*( +"*( }|yP#9*( *(DM"(*k(s#r*m(s#r#pyoxg͝DM*(0MD"(!*MD$:(Oë!(N:( «G>O:( ù* :(n` ~#foͤ2(O"(}:(O*( "(2("(:(O:(G2(!(w*~zWw+ !z?#~*!* *G!O~2(~m͗O~t>2(?:(2(O:(w:Ғ4~:(w?r##rp# ä |g}oì*g( #G ¾1*q(:(*w***> r >2+ 2* jx. #NzW:  : !2 W! 5= ^x^ z: m :* ;#wO: 9ʌ ^:— ~x  ) :* :   >*( +"( w++2+ 2+ p!" r y< < <% zr ͷr 6r 9r MDÌ:o !6!h : ʚnt2 r 62 >r z<*)$"!z<~r s^#V#N#FxN:oʲ ̀õ (# Þ Function = File = !,$-"h!9"f! ͉:2(t™:! =Hgo:O*;*Ó*"r*r"ÿ<:g:!͐*f}D! ~6t!r ͷO(^  : šn!6@G:x: P:<: P n6 t6! ^6 t6u:)<͠^! G:Ҏ>xʝʝw>ɯw̩z:»!>wɯ:=zxzz: :G:=/ͽx:Āy!4 )e(:(O!*c(:(Oͫ}@2æ  ~á *g(:(o$*~K6?~wKw**i({#zir+s{ozg*(*(|g͸*u(*(  R>22Z$w*q(>ww:(c( *(#*i(s#r*:(!(:G~#<*q(#~!;(!(!(!~6k!"2(*q(N1q*{(]*{([*y(}<^#V(t6 ^#V}e ^#V#~2(>â9͆>!"(*y(³*(X)*ÿ͂"*g(*K! ~<:wb##>w#w> r !~#<5~y 5 6y(^@O:=7:y :I :=e:  zz#͂:!  r  ! O(Ì*( ~2* *}ʷ!#¶!""÷:_:*( #wxH! )6"& :!  x2 GH)+6:2, :!-  :, !+*( ~L#Bxz:* : *( ~ʓOڊ{2Ó#w:2. +:. 2- !% "( 2* ! "& !* ~4:2- Ԃ: Gͳͨ^2+ >2:2 *N#G2  7   !"@*(*#":&2(͒:È0:+Òy<_W`iͫDM*w( ~bNpwDM*w(T] KKͦ*w("w(ͦ"w(@ :(N N#Fy*(}|h#ð*(ͫ# 6*q(@-RXDM*w(6# x *o(w*(*w(s#r̀*i(6#6*}("(j-@*(|<ď+>!8>8> t>nͦv8 ~*o(wn:(r :(/GyOOA +¬ ¢y2(:(x¹o&:(W>OͫE:(ڟ?N/*"(y2ͦ+>2( )@ u :G*g(`~!x_<_@!*o(y<:(/G?~##~? 6!K@?F6##N6 2 p##q:r !Z$2!"ög:(2T͐-:ʹ!>2<2(!!(w: >2(*6!O~2(+A@2! ͚A=: <%~?¯"k"?~?ʾ"ZT͐"*>o"͒"!:O"(Ý"}-6͚:(2(9:(>#:(>#*+S!X:(ڜq: ʺ!((ʵ>2( ͤ2(O DM͸}>r "("(2(:(2(* :(:(FsO s#r:(„y==„*(!(^W*y(^#Vx+7=2(wͼկw#KWK*("(J T͞*(:(["(Ͷ:(WMںʛ>(úͶ >TJ:(!(ʷ͞x!(w4 PWP  Â*!!~~#~O~#̀2(k,ºʺ*(*iҺ@:O~2(~WW:2(Ôyʛ?ʔx ʔ |̷ÔN͆G:(<2(x# W:(<­:2(2 G?>Gr x~:(2(Ô##~*$*">2>2: *(~w *" 2(>ʄ@~k:((s~*9~Ês~ ~ͅ<Eʀ@~›:(6!¦w͚̋,ÇPY*({zBKNyʺ Nú2—#͇ͱ * «#>2(͙ wB p'+!#:(w͚AP{" 2! W>O2 ø }-R*e()$:(r "ök*w()$*c()$-}-ͤÀk*s(" :(;$:r 2͚ù͚͚}/_|/*e(W}_*c("e(}o|g"c(>2({2{2g*w(ʪ$Ң$Þ$+}$*(#}o|g:(O *s#r#w!~w/~@w//Hͥ*e(>=)%_g:0%G~.|°! w:ck[!x?[! ~ʤ͆[͗PPv qO-á=.: <ʰ! Vq##~_@w: <œ. ʩ.ʩA r r##s <}r cN! ~态O>G~G!~G~o>_yW#x#W{s+p+q7r#r#r>@ >2  !!q#p#w2(wW*e(_3ҫ -!(s:(!(xQ*q(~wɯ2(2(ù*~2(~w#~2(~wZ!""2(=2*~2(=2(2(k:*wX/ 6X*~Gw#* #~$%+@*9> # #>? ;*~ w-xąH"(0 *(#ĊH( ,ˆʀHÈ2(xą ):(@O~#w͚ʀô̓-b_++V@* )͗Os++r!x>w~6:(6~#+w#w+~;wɯ2 K,OFq-yl?Npg&:(ʓ~†wŒ~è# # x ͗w w@ ~wb͐Úw:- %:(<%R$Hͥ:(>(~c!o#~E%^#V)$G#~#~!%~ b%% k%%##N#F#^#V#~#fo~o!o#~>T}! 6**#K" G*~ xr ͐-xą@7(͚S!ʀq&&͋"&@6,͚%Xͤ͋&͗wO~<:( g&~w#w#6##)͋&@ * g&~?G++N͆p# Þ&͐*6!¿&?~p*6 &>2ͱ ! ! ͷ w*ò!~$6:03i"!~6*e(>=)Q!(QX<k*{(}<^#V{!~! _*o(~s̓  2@ !()#w*~"!!(Fw̓ :(w̚":>#2(̓ *~wć"#Fx T]## #~ ȷ   *4 # '  4 !( *~^ ^ 33G# P v :dv 6 y #*~w>2 *p@! ~*"v@*w# ) 6# ͙   !N!"*>o+"v- *!b("": r#~?w#>r# L=J! Lv w,b ?~O ͆=: <>w##~2( 4~?̓-¹:(<üAX2(r K:(w++~=wv 4͗O5:(2(X:(!(v q: v v Mڂ?Ͷ >T͓Â!"(>(Â:(G:(O:(h=2(7ryy/W!(:(lڈ>F6:(_/G:(ʧ:(ڨ|OͤG:(_OzW{|:(*(}|BKN zyG8   (w'ͧ B pͧ ,Úgsr ͐-ͤ͜!S')_'ͤ̓ ~?w͐s-?F͜p!'̓ ¡'>2ͱ ?~¾'¾''''>w'͙ =2(͜!:(wÚ~̓ ʑ'pá'!(6NN!(r )!(N !)z<*)$"!" :X(*:(w:(w#:(w*2* }D#cdfg!"()*!!$$HH !"BB$HHDA! "D"H $B!$!AI!$ $ H  H A$I! I" $$BD"$H "AHD @ I  B"$$H @@@@" BHB  !I$ @ $@$"$AI$$IBI$I H@@I!$DA $ $@$ !$!!" !$I@I $@ $ @!H"BI"HI DIHA DD$HH $  B D$ "I$I$H$ I !  $I$I$I $@HD${(X)^#V!"(:(<)!~<<)^#V*(<)"("(x+)!(*(>X)*{()Q*:(_2({2(Ē*"(͂"X*~<)ҍ) -)a*ʚ)~)6*(:(X*)!(:(T>q*k)!(:()-6>)ʴ+>2d,:+#++>29+2~2#! , , ,)x,) ,O +"!w [,O?WGzO:(V,xGyOG,xwq*}(}2*i(^#V+ d,!(K*}(@+*)):( K:(+5(.7@ U&%*gy&&%2GP+QB4``l!*^#V#^#Vw# ͒͒ ͒ ͙͒:sA ws  X*]w#6?#] .,:;[]=<>|!eʃ45#xa{ҏ_p# ’ ʙ ʙ:A2'!%"!9"1!>%:25:!=g$D$ $I"B IIBB"$B@DH"$$ IH $$ !I"AD B!B  BI$A$"@$I$!!""@H! $!@I$1:#"1:*7:{z*!"1:/ *1:!>~26>xG:6>26>G )x{_ P*#B*>ɯ`iq#zV*COMPRLRSPSPROVLSYM!;>q*5:> :;>w*5:#"5:!3:͹8ڦ*>*3:DM\͔5!"5:!<>q:8>!<>28>:7><27>*!7>6*8>Mq*!8>6!=>q*=>Mq**A:#"A:!?>p+q*>>}O**>>|O*:ڗ>2#-×:#-<)2#-*(!""++"(29-C-%w*{(}<^#Vz!(c-!>c-! J-w*q(~69!͐9bBI$"" HB@ UUUUUUUUUUUUUUUUUAPDA$! @I !@D@BDI@!B$ @$I$$ "@$$@@HHBD"D$H D@!IB@ A"B HBIB$$ "$ D$!"D$H$D$I@D BD" H$BHHBDHB"H!"9   o:O*7*/*"*"[ <:g:!,*}D!~6 !S͌rOͨ͠bbb  :G:xͨ›:ͨ: !6 :<!G: >xw>ɯw% :7!>wɯ:= x :r:G:=Ľ9xr:y!4 5~y‰5 6y͌Ҡ^I@O:=ʯ:Iy I I:µ  #I:! I I I! O͠wɯ2z ̈́ ʹOFqy3 Np͆ͯ:Z~MwS~¹o¹#¹ # ? -Ϳw ʠʡڠ¡w  ~w 2 > y &!"*>o+"1͗ *!"s͙" r#~?w#>r# =J̧ 4  wͶ ~O ʙ:z<>w##~2_4~?ʈ>x:<ʈʈ{ͥ  2 :w++~=w4-Oҫ5:<4{͊ >2 :!3:z͞ Ͱ @ R _@ !">:o$*~ 6 ~w w**{#z' r+s{ozg**|g= v ** ʄ ʏ  >22ͦ w*>ww: *#*s#r*  :!:G~# <*#~!d!ͼ ʷ !ͼ &!~6̀!"2*N q* * *}<6 ^#Vͳ>F D >!"**[ + "**K!z~<:w ##>w#w͂ × ̈́ > !~#2:2*N#G2H  W W|:<ʈ:W:H2xy“:z<*"!z<~s^#V#N#FxN:@ :G:O:=27)yy/W!:#?>F6:_/G:^:_|OfKyp!VuWy/2&:ʌͺR g[ |OE w @~@w>2 :>* ͊  :3:z͞ !>2Ob 2O ͊ DM͠}>""2:2* ::E sMO s#rͰ :(±y==±*!^W*=2wX կw#|W|*" j*:Œ"R :W>R  :!jx!w4 ͚̚͡@   w:͆ DM*T] KKN :@͆ *"N "  :k Nq N#Fyʀ *}| #X *i # 6  ͆ DM*6# x£ *w**s#rL*6#6͝ *"ͤ ͔  *|<>! > > >N 4  ~*w::/GyO A +B 8y2:xOo&:W>Oi E:5 N/*"y2>2Í s͝ ͳ L2 ͤ ͔ *'  :O~Sy? x  - NG:<o ͠# CP/M Error On : $Disk I/O$Invalid Drive$Read/Only File$Read/Only Disk$File Exists$? in Filename$ÍÍ>2a."z:2:<:^^d{_zW{_zW ) 4#4#4 #  w#J|^#V#"##"##"###"#"##"! *!*|!6J67*w#w*w#w#w>2'q2*O͂yڍÍ<* p :0!:® :Í2*i "!s#r#p*N#F*^#V#F*:O}|y*Ͱ+*͹}*!!~~#~O~#G~.|! w:cʇ̈́ w!x?w! ~ʽw-llqOý.:z<! Vq##~_@w͡:z<¸. . r##s}̴̭N! ~态O>G~G!~G~o>_yW#x#W{s+p+q r#r#r͋S "͙>2z4 !!q#p#w2wW* _҆-!s:!f͐ *~wĦ ɯ2*#~2~w !"2=2*~2=22̀:*wͳ  6 D2x™# 22zG?S͝ >Gx™~™:ʙ2 ##~[*$a*" ͋ʄ *!~Ê͙l͋ 6> - Ͷ ͙ÇPY*{zBK yʢ â< yº! > ~Gw#* #~$ + *!>  #>? #*~ w0" *y͐}0͋  Ͷ ͙^ 2͋ :@ʕ ~#w> ͙{> _++V * -Os++r!x>w~6:6~#+w#w+~|y #*Ͱ*DM"*s#r*s#r#pyoxg[ DM*0MD"!*MD$:Oi !N: i G>O: ʀ w *͂ :ʘ n` ~#fob 2O͊ "}:O*"2":O:G2!w*~zWw+ z #~*!* * ! ~2~+ -O~2 >2 :2 :w:P 4~:w r##rp# b |g}oj * # G | *ġ :*w**= ҵ * >  )ý :O!ͼ *:Oi } Á ~ |*:   6 *L͝ ͪ !~+6:0 ' "!~6*>=)X!f_CÀ*}<~*~{ͧ> N Ä:G*`~!x_<_*y <:/G ~##~?  @ F6##N6͆y2zp##q:!2!"R |:2 ͥ:N>2<2͡|!w:>2*6s͙ͤ|͔ ~<Œw:ҧ* ~§2& @t ͬ ͖ :z<ô~?̀ ~?  ͥ *>$NK"ɷ J>">2:N#=N>2!N2~2#! Œ t t)xu) O _"!w O?WGzO:xGyOõxwq*}<:<:*^#V=*"*DM**= ѵ+)) P ͞ g #+} ͔ ͳ >2*^#V+:<ʐ <' ͞ ' ~' *+"}{_}o= :<̝ ~' ") :OG#!K* N*))KKBI"B" $$@"o"6 "!_ ʍ:OsÙ*"8cͬ͌ ôͬ͌ í  ͔ͥ͡ `-}͔ Pͬ yá>O2{&Ó8:*:"R ̀**8q̀*"z::2ͬ͌ ͬ͌ ͬ(}/_|/*W}_*"}o|g">2{&&2{2|*͆ D<8+}7*#}o|g:O*s#r#w!~w~@w6Hq*>=)ү_|:0ʠ êͺ:<­ ‡Hq:>~c!o#~^#VG#~#~!##N#F#^#V#~#fo~1TdCP/M Version 3.0COPYRIGHT 1982, DIGITAL RESEARCH1512826543210123456789ABCDEF ERROR: $Reading file: $Writing file: $Directory full$Reading file: $Writing file: $Invalid drive.$) ? $) ? $) ? $Bad character, re-enter $ $ Disk read error: $File cannot fit into GENCPM buffer: $Unable to open: $BDOS3 BIOS3 Setting up directory hash tables: $ Enable hashing for drive $: $Unable to allocate space for hash table.$ SUUUUUUUUUUUUUUUUUAHBI$"@!@HII D"BB"$ "H BD!$ H$BD!!$D  D $"BHD! $ HHAII "!!!!B"D !B"I$$A"D$!!$H $$! H  BBD$A DBAHD$IH$ B!$$H!H"$! A$A "$B"D$$$@D DB!$@H@$$DD!$$I$DH"H$A@!@ !$ " $$ @DD! !$!$$A DD"@$BD"$"I$HBI !  $$D $@I$Ho!o#~*ͥ&  && > ͋͹d- j 6Ͷ > ͙F b -w ~<: ͯ~w#w#6##- a * ͯ~?G++Np# |mͥZ ͆͂ b ͧb !B6NN!B!z<*"!"z:{*:w:w**z}D#cdfg!"()etting up Allocation vector for drive $ Setting up Checksum vector for drive $ *** Bank 1 and Common are not included *** *** in the memory segment table. *** $Number of memory segments $ CP/M 3 Base,size,bank ($) $ Enter memory segment table: $ Base,size,bank $Zero length segment not allowed.$Bank one not allowed.$ ERROR: Memory conflict - segment trimmed. $Memory conflict - cannot trim segment.$ ERROR: Memory conflict - segment trimmed. $ ERROR: Memory conflict - segment trimmed. " BH$DH@$ @A$ I"I$$DDH$I$ @ BD$DII !$$BD$$ @BB$H I $B IDI"@ !@$ A ! B$A@ $$ A$ $@" B"@ D! A$$D! I"!BI$ ! @"$I!$I$H H$I"I$I$BHDI $@@HHI$H"H $I$I$ B!I"" BDBA$@BB"$B@D! !  $$@@!!DD@@@I!@$"$ABD$*:_2{2"+ "~̀~!:҈6>Ë2$-:$<~2$*!""++ !ͥ Æ1${;   $ CP/M 3 Sys $ Memseg No. $ Bank $ Accept new memory segment table entries $Default entries are shown in (parens). Default base is Hex, precede entry with # for decimal $ Use GENCPM.DAT for defaults $Create a new GENCPM.DAT file $Display Load Map at Cold Boot $Number of console columns $Number of lines in console page $Backspace echoes erased character $Rubout echoes erased character $Initial default drive ($:) ? $Top page of memory $Bank switched memory $Common memory base page $Long error messages !U q:V 2V*T&+S"!U$-U RUW !T6#6#6:.Q2U:/Q2UTqT TyT Uͧ pT !T6Uͧ pT pT :;Rһ!;R6:%V2.Q:4Q/24QTT TT L!U6N!Vr+s+p+q*V6 *V#6 *V|O! *V## w*V|O! *V w*V}O! *V w*V}O! *V w!T:TO`iPSW "V*V :0Qw*V :2Qw*V :1Qw.*V :3Qw*V :4QwX*V   :+Q/ҼW*V >*V w:@*V wW*V >*V w^*V :/Qw!)X"V*V6? ͜*VDMN*V~  (7*VN !V6>!Vn *V#"V:V:-Q/HX *V6d ,7*VN :V<2V, *V++"VNÊ *VN*V !V6!V6Te!Vr+s+q:-Q/Ү >!V6#q#p!V6:5Q!Vڳ*V&+SFQ  VzSک:VM*V&+SFQ  ~*V&+SFQ  VzSHJ:V2V*V&+SFQ  ^#V"Vé*V&+SFQ  ~*V&+SFQ  VzSHҩ:V2V*V&+SFQ  ^#V"V:V<2V¿ :V:VH`!V6:5Q!V`*V&+SFQ  VzS/*V&$Double allocation vectors $Accept new system definition $ CP/M 3.0 System Generation Copyright (C) 1982, Digital Research $ BNKBIOS3 SPR$BIOS3 SPR$BNKBIOS3 SPR$BDOS3 SPR$RESBDOS3 SPR$BNKBDOS3 SPR$ 64K TPA Copyright (C) 1982, Digital Research *** CP/M 3.0 SYSTEM GENERATION DONE ***$!Tq:UM*T&!Tp+q:Ud*T !Tp+q*T#6:UҀ:Tڀ*T *T#N! *T6 7 7!Tr+s+q+q!U6N*TDMN:TTN͜:T.:T/!U!]6 !m6 !TpVN#F!W "V*V"V*V͕S(!$V6-!$V6*VSD*VWR!"&V!V6&VS!V6>!Vڷ*V&)*&V>͒Sʭ*V&)*&VWR"(V*(V ͕Sʭ!V6:V<2Vf:-Q/!V!$V6!$V6V>X W*V"V*V~>>!Vs+p+q+p+q%N*VDMN 7*VDM$  7*VME :,QҨ *V&U *VDM :V 2V*V&U DM*V:V2V*V&U *V&+S:V2V*V&U ) :V2V!Vp+q*V"TͣN,ͧ*VDM !Vr+s+p+q*V^#V"T*V##^#V"T*V ^#V"T+SFQ  ~H*V&+SFQ  VzSHV:V2V*V&+SFQ  ^#V"V:V<2V:V!$V6!U6ͬ#Q$!H> U͇Sʔ* U|2Uß*U|2U!U:.Q2T*U|!UO:/Q2T*U|O:T2TUTI:-Q/!$V>O:T2T* U|O:T!$V2T:T=2T* U|O:T2TҮ:-Qқ*nV*U*V |!UO:/Q2T*U|O:T2T2Uͬ:U/Ҙ!!V6>!!Vژ*!V&$SQ  6:!V<2!Vsà!U6:V/ҫ*:U2T:T2TTͩ:-Q*T&+SDM*U*T&+SDM*U:-Q/+q *T 6 *T 6*T!Tp+q*T!Tp+q*T!Tp+q*T] ͧ!Tp+q*T} ͧ!Tp+q*T ͧ *T 6!Tp+q*T!Tp+q*T! ͧ!Tp+q*T" ͧ!Up+q*T$!Vr+s+p+q+q:V *V*VDM*V -- !Vs+p+q:VJ *V*VM!VLS!Vq:V e > :Va/>z!V/H҄ :V_2V:V!Vq:V/>!V/HҦ >ͧ>!Vp+q(7*V~ Y7 N7NTe:T *TMV Y*Vw!Vq:*V#DMT  *VDMT *TZSU͊S@?ͧ*T+ZS}<2V!V6!V:V҆*V&+SW "TDMͧ *VDM> :V<2VS*TDMO W*T"T!Vr+s+q:VGTqT TyT *Vn}2T*V#~2TpT WTS}pS}TR+s#r*V&)+!Vs+6:V!V4>T͇S+s#rBKͧ pT^ :V<2VpT *VT :-Q/k)Tw T z!LT"V!U"V͙!T"V!U"V͙!(T"V! U"V͙*V#DMT  *VDMT *VDMeͧWͧ *VDM> *V*Ws#r*V##*Ws#r*V&:U2!V!""V*!VM"V͟:!V2U! U6Û*U|!U2!V* U|!Uo&)##""V*T&+SDM*!V*!VM"V͟:!V2 U:U2!V!""V>T͇S+s#r*!VM"V͟:!V2U* U|!$V2T:T2T U(T(TͩC*$V&+ST͊S+s#r* U|!$V2!V:-Q/ *T&+SDM*!V"*T&+SDM*!V*!VM"V͟:!V!Uw:-QҢ!T6:T2TULTLTͩ*U|2!V*U|!Uo&)*"V""V*T&+SDM*!V*!VM"V͟:!V! Uw:,Q/Ҳ:V2V *V&U  :T2T*T&! S!0*V& U q*T&! S0*V&VO! N7:VO! N7!Vp+q 7*V|O *V}O H7!Vq*V&+SDM$ !Vp+q!V6!V60!'"V>V͇S† *VM7 !V6>!V VVzSڽ !V6:V<2VVVzS+s#rÔ :V *VM7!V60*V! S"V:V<2V‹ !Vs+q(7:V  #7*V&DMZ  *VM N!Vs+p+q+p+q :T: ͜*V6:V<2VO!T NV 2V  :V,u *V#"V*V6!V6 :V#… !V6  :V02V:V> !VHҽ >!VҸ :V2Vý !V6!V:V *V^*V&+S*V& *Vq !V6*V6ͧ *<    *Ws#r*VDM> !V6&VS(>!V6>!V*V&)*&V>͒S*V&)*&VWR"(V *(V## *(V ͕S*(V ͕SH*(V ͕SH*(V ͕SH*(V ͕SH!V6:V<2V-:V!V6!V6!V6>!V*V&)*&VWR"(V*V&)*&V>͒S*(V S?!V6*(V ͕S:V/c!V6N:VO!=R ~2T *(V WR"*V**V N#F`i))"VN:VAO7N*V&6Q DMʹ ͜*V&6Q ~/*(V q#p:-Q/!V6*V&,V) *Vs#r*V*Live $: $ Number of directory buffers for drive $: $Minumum number of buffers is 1. $ Number of directory buffers for drive $: $ *** Maximum number of directory buffers *** *** for the current drive is$. *** *** Number of directory buffers reduced *** *** accordingly. *** $ Share buffer(s) with which drive ($:) ? $ *** Data buffer required and *** *** allocated for drive $: *** $ Overlay Data buffer for driveN!N:V=O *V&+SFQ NE *V&+SFQ  NE :-Qb!N*V&+SFQ  N ͜:V<2V !T6!V6%NVʹ ͜PNT2V!TT TT N!V6Vʹ ͜:V!FT !!U6+6!W6͌!:W/җ#:R2T͜N;Rʹ :=R2T͜͜N,Qʹ ͜͜:>R2T:2Q<22Q  2Q :2Q=22Q:?R2T:1Q<21Q' 1Q :1Q=21Q:@R2THN3Qʹ ͜:AR2TkN4Qʹ ͜͜:BR2TN:0QAO7NTe:T"*TMV A2W*WM͈ /"Þ":W20Q͜͜:CR2T.Q *.Q&V"LV*V͛ 2V'ͧ*V&+SFQ  *(V w*V&+SFQ N`iPS*V&+SFQ  N`iPS*V&+SFQ  ͕S *(V q#p*V&+SFQ  VzS*V&+SFQ  q#p:V<2V:-Q/!V!$V6:T<<2T:T<<2T!V6>!V8*V&NV) >w#6*V&pV) >w#6:V<2V:!Vڡ*V&)*&V>͒Sʗ*V&)*&VWR"(V *(V WR"*V*(V ͕SN:VAO7:7!V6**V ^#V!S*V&+S*V&NV) q#p* $: $ Number of data buffers for drive $: $Minumum number of buffers is 1. $ Number of data buffers for drive $: $ Share buffer(s) with which drive ($:) ? $ Allocate buffers outside of Common $ Accept new buffer definitions $!W6>!W**W&)*&V>͒S**W&)*&VWR"(V ͕S*(V ͕SHҸ* *(V WR"*V**V ^6 *W&$SQ q#p*W&$SQ  6*(V ͕S*%ͧ!W4*!W6>!W+!"HW}2W>!W=+*W&PS"U:DR2TN-Qʹ ͜:-Q/2T:-Q[#:ER2T/Q ͜:FR2TN+Qʹ ͜x#:R2T͜N!W#*W&U 6:W<2W#!W6>!W $*W&U 6$:W<2W#!V6*V&U  !V6TqT TyT Wͧ pT^ pT^ WS#ZS"U!W6>!Wڋ$*W&,V) >w#6:W<2Wh$!"LV:]A$!U6#6!W6>!W$*W&=R 6:W<2W¦$$!U6#6:mD$!U6!T6 Available space in 256 V&NV) nVR+s#r*(V ͕S—'N:VAO7:7!V6**V >R!S*V&pV) s#r*V&) VR+s#r **V R*V&pV) CS **V q#p:V<2Vk:Vҫ͜:T2FQ!T:/Q2GQ!"IQ!HQ6!V6ON:GR2T 5Q N*FQM ,7*GQM ,7*HQM N:V/҈!N!V6:5Q!V !V6:V/ :V =O!=R ~2T*V&+SFQ DM *V&+SFQ  N`iPS*V&+SFQ  q#p*V&+SFQ  ~ͧ *V&+SFQ  ~7ͧ *V&+SFQ ~2V*V&$SQ HW|S ~H6+*W&$SQ ^#V"HW!W4**W&))lW *HWs#r*W&))  >w#6!W6>!W+*W&$SQ HW|S>͇SH+*W&))lW  *W6 DS+s#r*W&$SQ  6!W4h+!W4*!W6>!W7,*W&+SFQ  *W&W) N#Fq#p*W&+SFQ  *W&7W w!W4+:-QF,!fW6K,!fW6 !W6:W4:fW=2iW!"gW"dW}2 W! W6*T&PS*LViS"bW:-Qڞ,nVbWzS*ViS"bW!W6>!W,*W&W) *W&+SKQ  N#Fq#p*W&$SQ  6!W4£,!W6! W6#6!W6n&byte pages: $TPA =$, Bank 0 =$, Other banks =$Unable to allocate Dir deblocking buffer space.$Unable to allocate Data deblocking buffer space.$Unable to allocate Data deblocking buffer space.$Drive specified has not been defined. $0FFFFH is an invalid value in the DPH directory BCB address field.$ Setting up Blocking/Deblocking buffers: $ The physical record size is$: $ *** Directory buffer required *** *** and allocated for drive $: *** $ Overlay Directory buffer for dr*V&+SFQ  N "V*V|*V}O:/QH҆MN!V:/Q*V&+SFQ  Hq!V:/QO`iPS*V&+SFQ  q#p *V}2V!V6!V6!V:V# *V&+SFQ ~2V*V&+SFQ  :V2V*V&+SFQ  *V&+SFQ  !V:V/+~!V/H+ |ͧ!V6 :V!V+~!VHc N*V&+SFQ :Vw!V6 :V!V+~!VH N!V:V*V&+SFQ  Hq!V:VO`iPS*V&+SFQ  q#p!V6:V<2V×1:V<2V"͜!V6:5Q!Vo!:V!=   ))lW  ^#V"JW*W&))lW >͒S:WH3:WE-1&N!W6]&N*W&))lW N#F$ {&N!W6>JWR>fS:WHҚ-!JWVS+s#r!W4g-!JWVS+s#r:W3*W&)*&VWR"(V WR"*V >RZS"^W **V ͕S-!W6-!W6*(V ͕Sc0bB*W&$SQ  >w:-Q.: Wd.! W6*W&$SQ  6&N:WAO7&N.:W{O!=R ~2T&N:WAO7'N*W&$SQ  DMʹ ͜*W&$SQ  ~.*W&$SQ  6.*W&$SQ  6t/:W;O!=R ~2T'N:WAO7|O:/Q2T*U}pS}URW"\W*T&PS"XW*T&PS*U "VWÇ;*RW*`W|O:/Q2TW*U"\WO`iPS*`W "XW*T&PS* U "VW*RW*\W"T*U|O:T2T*W&)*\W"jW*XW"ZWWTS"U*T"`W*`WW !T͕S;*`WW 6*`W#"`W;!W6!W6!W6:5Q!WS<*W&+SFQ  2W!FQ  ~:W!WHL<:W2W:W2W!W4;:T2FQ!T:/Q2GQ:W<*W&+SFQ  O:T<*W&+SFQ  N`iPS!͕S"`W!FQ :T w*W&+SFQ  N`iPS*`WiS!q#p!W6n&)) ~,5*W&$SQ !^N#F-S*TW"TWT5*W&$SQ !^N#F-S*TW"TW*W&$SQ  ^*PW"PW!W4#4*fW&*PW+S*W&) "RW:-Q9W*U"jW*RW*U*TW *LV *V *nV |O:.QO:T2UO:T2T:T2T:T2T|2U!T2.QW"T*T&PS*U "ZW*RW "VW*T"`W*`WW !T͕SC6*`WW 6*`W#"`W6!W6n&))lW  ^#V"JW*W&))lW >͒S:WH9!W6>JWR>fS:WHҶ6!JWVS+s#r!W4Ã6!JWVS+s#r:W8*W&)*&VWR"(V*W&$SQ  >«7*W&$S>'*W&$SQ  DM  : Wt/! W6*W&$SQ  ~t/A'ͧb'N:WAO7'*W&$SQ  DM  &/*W&$SQ  ~^W͇Sҹ/'N*^WDM$ 'N*W&$SQ  *^Ws*W&$SQ  ~R0:W[O!=R ~2TM(N*W&$SQ  ~AO7(NTe:TL0*TMV A2 W* WM͈ *0/* WMF80/*W&$SQ  : Ww͜c0*WMTCc0 4*(V ͕Sn3!W6*W&$SQ >͒S°0*(V q#p*W&$SQ  6n3bB*W&$SQ  >w:-Qګ1: W1:W1! W6!W6*W&$SQ  6(N:lW  ^#V"JW*W&))lW >͒S:WHғA!W6>JWR>fS:WHh=!JWVS+s#r!W45=!JWVS+s#r:WxA*W&)*&VWR"(V*W&$SQ  >0?*W&$SQ  ~>*(V"LW*W&$SQ  n&)*&VWR"(V ^#V"NW*LW"(V *NWs#r0?*\W*ZWs#r*(V *XWs#r*XW##"XW*\W##"\W!W6*W&$SQ  ~!W ?*W&$SQ ^#V͛ 2W*jW6*W&+SFQ N`iPS!N`iPS!͕S  *jW q#p *jW 6*W&+SFQ  *W&$SQ |S+s#r:fWZWR+s#r *jW s#r:fWjWR+Q  ~h7*jW6 *jW *VWs#r*W&$SQ VWR+s#r*(V *ZWs#r:fWZWR+s#r:fWjWR+s#rë7*(V"LW*W&$SQ  n&)*&VWR"(V ^#V"NW*LW"(V *NWs#r*W&$SQ  >£8*W&$SQ  ~48*jW6 *jW *VWs#r*W&$SQ VWR+s#r*(V *ZWs#r:fWZWR+s#r:fWjWR+s#rã8*(V"LW*W&$SQ  >o&)*&VWR"(V!Q  >ʂ8*(V ^#V"NWÐ8*(V ^#V"NW*LW"(V *NWs#r!W4>JWR>fS:WH8!JWVS+s#r!W4ç8!JWVS+s#r6!W4n&))lW  ^#V"WAO7(N1: W1!W6! W6:Wʨ1:WƋO!=R ~2T(N:WAO7)N*W&$SQ  DMʹ ͜*W&$SQ  ~ґ1*W&$SQ  6è1*W&$SQ  6! W6S2:WKO!=R ~2T)N:WAO76)*W&$SQ  DM  *W&$SQ  >w: WS2! W6*W&$SQ  ~S29)ͧZ)N:WAO7)*W&$SQ  DM  2*W&$SQ  ~$3: WҌ2! W6*W&$SQ  :Ww 3:WkO!=R ~2T)N*W&$SQ  ~AO7)NTe:T 3*TMV A2 W* WM͈ 2Ü2* WMF2Ü2*W&$SQs#r!W46>:fWjW͇S+s#r! >w#6:fWjWR+s#r*W&$SQ  >1A*W&$SQ  ~¤?*(V"LW*W&$SQ  n&)*&VWR"(V ^#V"NW*LW"(V *NWs#r1A*\W*ZWs#r*(V *XWs#r*XW##"XW*\W##"\W!W6*W&$SQ  ~!W A*W&$SQ  ~ҩ@*W&$SQ ^#V͛ 2W*jW6*W&+SFQ N`iPS!N`iPS!͕S  *jW q#p*W&+SFQ   *jW w*W&+SFQ  *W&$SQ |S+s#r@*jW6 *jW *VWs#r*W&$SQ VWR+s#r *jW 6:fWZWR+s#r *jW s#r:fWjWRJW\6!W6>!Wc9*W&,V) >͒S\9*W&)*&VWR"(V *VWs#r*W&,V) VWR+s#r!W4 9!W6>!W9*W&)*&VWR"(V*W&NV) >͒Sʽ9*(V *VWs#r*W&NV) VWR+s#r*W&pV) >͒S9*(V *VWs#r*W&pV) VWR+s#r!W4h9aB!W6>!W::*W&W) *W&+SFQ  N#Fq#p!W4:*V*RW*nV "RW> U͇SUzSH҇:*TW*U|O:.QO:T2Uá:*TW* U|O:.QO:T2U!U:T2T:T2T:T2T:.Q2.Q* U}pS} URU͊S"`W> U͇SUzSHB;*RW  : Ww͜*W&$SQ  :Wwn3:U!W]3:W+O!=R ~2T)N*W&$SQ  DMʹ ͜*WMTCn3 4! W6*W6 dWDS+s#r!W4>JWR>fS:WHҿ3!JWVS+s#r!W4Ì3!JWVS+s#rç-!W4n&))lW  ^#V"JW-!T6!W6:W 4bB)NWʹ ͜P,!"PW}2Wo&"TW2W>!Wu5*W&$SQ  ~n5*W&$SQ  ~ >Hһ4:-Q|4!W4á4*W&$SQ !^N#F-S*TW"TW*W&$SQ  ^*PW"PW*W&$SQ  ~ >Hn5:-Q/5!W4*W&$SQ >   +s#r!W4?:fWjW͇S+s#r! >w#6:fWjWR+s#r!W4>JWR>fS:WHhA!JWVS+s#r!W45A!JWVS+s#ru=!W4n&))lW  ^#V"JW=!W6>!WA*W&7W *W&+SFQ  w!W4˜A!W6>!WaB*W&)*&VWR"(V*W&NV) >͒S"B*(V *ZWs#r*W&NV) ZWR+s#r*W&pV) >͒SZB*(V *ZWs#r*W&pV) ZWR+s#r!W4A!"W"W!W6:5Q!WB*W&+SFQ  ~¶B*W&+SFQ  VS*W"WB*W&+SFQ  VS*W"W!W4pB$N%N!bWVSDM$ :-QMC%O†O~#o}o|O<O:TzO<.O:TƜzO<8O:TzO:TzO:TotOzO:TgN!|!|PRTMSG ,QPAGWID 2QPAGLEN 1QBACKSPC 3QRUBOUT 4QBOOTDRV 0QMEMTOP .QBNKSWT -QCOMBAS /QLERROR  +QNUMSEGS  5QMEMSEG00 KQHASHDRVA6QALTBNKSA +QNDIRRECA ;QNDTARECA KQODIRDRVA [QODTADRVA kQOVLYDIRA  ItG2WHGtG2W!W6!T:W:W H:W/H[I*W&T :Ww!W4~`i+wtG2WI:W :W/HxItG2W[I!W6#6>!W҇K *W&+S P  ^#V"W! P  ~2WJ:WI:WA2WI:W0/>9!W/HI:W02WI:WA 2W *W&+S P  ^*W&+S*W"W*W&T ~?[J *W&+S P  :WO!=R 6!U6!W4!T5>!T҇K:WʧJ*W&T ~A/>P/HҜJ*W&T ~A*WwäJF GÇK:WJ*W&T ~Y*WwÇK!W6*W6!W6:T=!WڇK:W!WO!T ~2W, K*W#"W6N*WDM$ :U C$%N*WDM$ >W͇S>W͇SHHC!W6MC!W6͜͜!Ws+q*W&$SQ ^#V"W:-QڋC:fWWRbW͊S+s#rF!iW55:W®D*W&$SQ  ~2W!W6:W!WګD!fW:iWYD!iW6*gW#"gW!W6!W6!W6:5Q!W7D*W&+SFQ  2W!FQ  ~:W!WH0D:W2W:W2W!W4C*W&+SFQ  S+s#rcD!fW:iW2iW*W͛ 2W…D4%ͧ>äD*W&+SFQ  WzS+s#r!W4±CF*W&$SQ  ~2W!W6:W!WF!fW:iWoE!iW6*gW#"gW!W6!W6!W6:5Q!WME{QOVLYDTAA QCRDATAF ;RDBLALV  !WHQK>!WLK:W2WQK!W6!W:WxK*W^*W&+S*W& sÀKF G!W4J!W6!W6:W:W/HK!W6:W *W&+S P *W& *W&W HK!W4éK:WK!W6K!W4ÒK:WL>:WWͧ T. T~ !W6!W6>!WN!W6#n& +S P  ~2W!W6:W:W/H N!W6>!WڞL'N *W&+S P *W& *W&W w!W4gL:W°L!W6L:WL:WA*W&W wL:W L:W0*W&W wL:WA *W&W w'N*W&*W&+SFQ  2W!FQ  ~:W!WHFE:W2W:W2W!W4D*W&+SFQ  S+s#ryE!fW:iW2iW*W&$SQ  ~ڼEWbWzS+s#rYS:/QpSҹEd%ͧ>E*W͛ 2WE%ͧ>E*W&+SFQ  WzS+s#r!W4D>!Wq*W6 dWR>fS'F>%ͧ>ERROR: $ at line $Missing parameter variable$Equals (=) delimiter missing$Invalid drive ignored$Invalid character$Invalid parameter variable$!"WWͧ !W6!W6:W GG:WG͈K2W:WFIGDM!>))덑o|gS =S^#V))) DM!>)):S =2S_og^#V) PS^#V|g}o ZS_{ozgO{ozgi`N#Fogo&og_{_z#WBNKBIOS3SPRRESBDOS3SPRBNKBDOS3SPRCPM3 SYSGENCPM DAT . $W 6 'N*W&W 6='N*W&W 6  *W&+S P  !^*W&+SR"W:WmM'N*W~A*W&W wM:WʞM'N*W~ҐM*W&W 6YÛM*W&W 6NM*WNbN:WM'N*W&W 6,*W#"W*WNbN'N*W&W 6,*W#"W*WNbN'N*W&W 6 'N*W&W 6 !W4PL!W4'L>!W NT^ T :W]NT^ !W6>!WUN*W&W 6!W4:N!W6aN!W4!Wq'N:WO! *W&W w'N:WO! *W&W wO*TDM}oN*T†O]!O> 2 PW:TgxʀO { O: PO*T!F GF!Wr+s+q:U2W!U65FN*WDMN>FN*WDMZ :WCG.͜:W2U:WoG!W6TlG!W6sG!W4MG*W&W ~2W:W :W H:W HG:W ·G*W#"WMG*W&W ~2WÄG:Wa/>z!W/HG:W_2W:WG!W6:W!W6:W/:W/HI!W6>!W/H*W&W 6 !W4HtG2W!W6:W:W=H:W H:W/H~H*W&W :WwtG2W!W4:H:W=:W H:W/HҧHtG2W~H:W I:W=>!WHH!W6 I:W=HHF GH:WHcF G:W :W/H?   0 jmp bdos call$msg: db cr,lf,'**** CALLVERS **** $' curvers db 0 end ʭ*V&)*&VWR"(V*(V ͕Sʭ!V6:V<2Vf:-Q/!V!$V6!$V6V>X W*V"V*V~>>!Vs+p+q+p+q%N*VDMN 7*VDM$  7*VME :,QҨ *V&U *VDM :V 2V*V&U DM*V:V2V*V&U *V&+S:V2V*V&U ) :V2V!Vp+q*V"TͣN,ͧ*VDM !Vr+s+p+q*V^#V"T*V##^#V"T*V ^#V"TDUMP VERSION 3.0 DUMP.COM COPYRIGHT 1982, DIGITAL RESEARCH151282654321Ҋ ҏ>.Ï_ Ҧ0Ï7Ï͜Ü\2|::Iͺ>2 :2f>2>û>!6 #=!~a1{1 w##:Ƃ2*6 2fl:<2!G\:>2 *|ͫ}*ͫ>:Ï:> ͏> Ï> Ï:_:<2>2ͺ >Ï*}o| ; CALLVERS program bdos equ 5 ; entry point for BDOS prtstr equ 9 ; print string function vers equ 12 ; get version function cr equ 0dh ; carriage return lf equ 0ah ; line feed org 100h mvi d,5 ; Perform 5 times loop: push d ; save counter mvi c,prtstr lxi d,call$msg ; print call message call bdos mvi c,vers call bdos ; try to get version # ; CALLVERS will intercept mov a,l sta curvers pop d dcr d ; decrement counter jnz loop mvi c,*!""ͮͷ͇*"͛~ͫ#*}#"%"*̀*}K|K*ͺ-m121=2#\:}mͺ2>o:  /\ͺ 1gn~ͻ͙D.:ܰg+":>2 CP/M 3 DUMP - Version 3.0$ ERROR: File Not Found $ Enter Password: $ Password Error$ ERROR: No Records Exist$ Press RETURN to continue $,@    ; ECHOVERS RSX pstring equ 9 ; string print function cr equ 0dh lf equ 0ah ; ; RSX PREFIX STRUCTURE ; db 0,0,0,0,0,0 ; room for serial number jmp ftest ; begin of program next db 0c3H ; jump dw 0 ; next module in line prev: dw 0 ; previous module remov: db 0ffh ; remove flag set nonbnk: db 0 db 'ECHOVERS' space: ds 3 ftest: ; is this function 12? mov a,c cpi 12 jz begin ; yes - intercept jmp next ; some other function begin: lxvi c,version call bdos cpi 31h ;version 3.1 or better? jnc versok ; bad version, message and go back lxi d,badver call print jmp reboot ; versok: ; correct version for random access mvi c,openf ;open default fcb rdname: lda fcb+1 cpi ' ' jnz opfile lxi d,entmsg call print call parse jmp versok opfile: lxi d,fcb call bdos inr a ;err 255 becomes zero ;*************************************************** ;* * ;* sample random access program for cp/m 3 * ;* * ;*************************************************** org 100h ;base of tpa ; reboot equ 0000h ;system reboot bdos equ 0005h ;bdos entry point ; coninp equ 1 ;console input function conout equ 2 ;console output function pstring equ i h,0 dad sp ;save stack shld ret$stack lxi sp,loc$stack mvi c,pstring lxi d,test$msg ; print message call next ; call BDOS lhld ret$stack ; restore user stack sphl lxi h,0031h ; return version number = 0031h ret test$msg: db cr,lf,'**** ECHOVERS **** $' ret$stack: dw 0 ds 32 ; 16 level stack loc$stack: end S*V&+SFQ  q#p*V&+SFQ  ~ͧ *V&+SFQ  ~7ͧ *V&+SFQ ~2V*V& jnz ready ; ; cannot open file, so create it mvi c,makef lxi d,fcb call bdos inr a ;err 255 becomes zero jnz ready ; ; cannot create file, directory full lxi d,nospace call print jmp reboot ;back to ccp ; ;*************************************************** ;* * ;* loop back to "ready" after each command * ;* 9 ;print string until '$' rstring equ 10 ;read console buffer version equ 12 ;return version number openf equ 15 ;file open function closef equ 16 ;close function makef equ 22 ;make file function readr equ 33 ;read random writer equ 34 ;write random wrtrzf equ 40 ;write random zero fill parsef equ 152 ;parse function ; fcb equ 005ch ;default file control block ranrec equ fcb+33 ;random record positi * ;*************************************************** ; ready: ; file is ready for processing ; call readcom ;read next command shld ranrec ;store input record# lxi h,ranovf mov m,c ;set ranrec high byte cpi 'Q' ;quit? jnz notq ; ; quit processing, close file mvi c,closef lxi d,fcb call bdos inr a ;err 255 on ranovf equ fcb+35 ;high order (overflow) byte buff equ 0080h ;buffer address ; cr equ 0dh ;carriage return lf equ 0ah ;line feed ; ;*************************************************** ;* * ;* load SP, set-up file for random access * ;* * ;*************************************************** lxi sp,stack ; ; version 3.1? mA   becomes 0 jz error ;error message, retry jmp reboot ;back to ccp ; ;*************************************************** ;* * ;* end of quit command, process write * ;* * ;*************************************************** notq: ; not the quit command, random write? cpi 'W' jnz notw ; ; this is a random write, fill buffer urs lxi h,buff ;next to get wloop: mov a,m ;next character inx h ;next to get ani 7fh ;mask parity jz ready ;for another command if 00 push b ;save counter push h ;save next to get cpi ' ' ;graphic? cnc putchr ;skip output if not pop h pop b dcr c ;count=count-1 jnz wloop jmp ready ; ;***racters lxi h,buff ;destination rloop1: ;read next character to buff push b ;save counter push h ;next destination call getchr ;character to a pop h ;restore counter pop b ;restore next to fill cpi cr ;end of line? jz erloop1 ; not end, store character mov m,a inx h ;next to fill dcr c ;counter goes down jnz ntil cr lxi d,datmsg call print ;data prompt mvi c,127 ;up to 127 characters lxi h,buff ;destination rloop: ;read next character to buff push b ;save counter push h ;next destination call getchr ;character to a pop h ;restore counter pop b ;restore next to fill cpi cr ;end of line? jz erloop ; not end, store character ************************************************ ;* * ;* end of read command, all errors end-up here * ;* * ;*************************************************** ; error: lxi d,errmsg call print jmp ready ; ;*************************************************** ;* * ;* utility subroutines for console i/o * rloop1 ;end of buffer? erloop1: ; end of read loop, store 00 mvi m,0 ; ; write the record to selected record number mvi c,wrtrzf lxi d,fcb call bdos ora a ;error code zero? jnz error ;message if not jmp ready ;for another record ; ;*************************************************** ;* * ;* end of write commands, process read  mov m,a inx h ;next to fill dcr c ;counter goes down jnz rloop ;end of buffer? erloop: ; end of read loop, store 00 mvi m,0 ; ; write the record to selected record number mvi c,writer lxi d,fcb call bdos ora a ;error code zero? jnz error ;message if not jmp ready ;for another record ; ; ;********************************************** ;* * ;*************************************************** getchr: ;read next console character to a mvi c,coninp call bdos ret ; putchr: ;write character from a to console mvi c,conout mov e,a ;character to send call bdos ;send character ret ; crlf: ;send carriage return line feed mvi a,cr ;carriage return call * ;* * ;*************************************************** notf: ; not a write command, read record? cpi 'R' jnz error ;skip if not ; ; read random record mvi c,readr lxi d,fcb call bdos ora a ;return code 00? jnz error ; ; read was successful, write to console call crlf ;new line mvi c,128 ;max 128 characte********** ;* * ;* end of write command, process write random zero fill * ;* * ;******************************************************** notw: ; not the quit command, random write zero fill? cpi 'F' jnz notf ; ; this is a random write, fill buffer until cr lxi d,datmsg call print ;data prompt mvi c,127 ;up to 127 chaB   putchr mvi a,lf ;line feed call putchr ret ; parse: ;read and parse filespec lxi d,conbuf mvi c,rstring call bdos lxi d,pfncb mvi c,parsef call bdos ret ; print: ;print the buffer addressed by de until $ push d call crlf pop d ;new line mvi c,pstring call bdos ;print the string ret ; readcom: ;read the next command line to the conbuf lxi  'type data: $' errmsg: db 'error, try again.$' prompt: db 'next command? $' entmsg: db 'enter filename: $' ; ;*************************************************** ;* * ;* fixed and variable data area * ;* * ;*************************************************** conbuf: db conlen ;length of console buffer consiz: ds 1 ;resulting size d,prompt call print ;command? mvi c,rstring lxi d,conbuf call bdos ;read command line ; command line is present, scan it mvi c,0 ;start with 00 lxi h,0 ; 0000 lxi d,conlin;command line readc: ldax d ;next command character inx d ;to next command position ora a ;cannot be end of command rz ; not zero, numeric? sui '0' cp4!y~=W!x# ~#bxE {8~#o}oA'.`28!Ip+q*HT!J6J T ` T!p+q*T> >/Ҥ×!p+q*DM͛:̀ ̀:2:!!K:*&L Ǹ!4!K6 ͐uëYALPSID'TCELLOC$LAITINI!%cCOPYRIGHT (C) 1977 DIGITAL RESEARCH {{ { {zb{b{*9 {_zW}l&))o> \> \\ß*"!" ͟#͟Prںºx"x#"̀ں͇"1!6# yafter read conlin: ds 32 ;length 32 buffer conlen equ $-consiz ; pfncb: dw conlin dw fcb ; ds 32 ;16 level stack stack: end d value in the DPH directory BCB address field.$ Setting up Blocking/Deblocking buffers: $ The physical record size is$: $ *** Directory buffer required *** *** and allocated for drive $: *** $ Overlay Directory buffer for dri 10 ;carry if numeric jnc endrd ; add-in next digit push psw mov a,c ;value = ahl dad h adc a ;*2 push a ;save value * 2 push h dad h ;*4 adc a dad h ;*8 adc a pop b ;*2 + *8 = *10 dad b pop b adc b pop b ;+digit mov c,b mvi b,0 dad b aci 0 mov c,a jnc readc jmp readcom endrd: ; end of read, restore value in a adi '0' ;command cpi 'a' ;translate case? rc͟!h͟$h͟'h*̀`*̀`*1̀I ?! ^#Vr+sz`>>!@^#V#̀{ k͇#"/<͟h2**̀`i~#!~6͟*1Þ6͔h*1^#V#Þ͔{> \*/̀>*\ ERROR - FORM IS X,Y TYPE HISTOGRAM BOUNDS HISTOGRAM: ADDR RELATIVE FREQUENCY, LARGEST VALUE = .INITIAL = .COLLECT = .DISPLAY = .... !6 ` !6 ` !6 ` *&T` !6 ` !6 ` !60 ` *& ; lower case, mask lower case bits ani 101$1111b ret ;return with value in chl ; ;*************************************************** ;* * ;* string data area for console messages * ;* * ;*************************************************** badver: db 'sorry, you need cp/m version 3$' nospace: db 'no directory space$' datmsg: dbC   T` !6* ` !6* ` !6* ` *& @AA I$DBD $I$BHA"DH!""@f>2>û>!6 #=!~a1{1 w##:Ƃ2*6 2fl:<2!G\:>2 *|ͫ}*ͫ>:Ï:> ͏> Ï> Ï:_:<2>2ͺ >Ï*}o| ^Ȋ l9O/J7ps[F՛/xFV][^+vz@W ]+z@t"^+zEW Tz@W ^+z@W ^+z@W ^)jcv;cv;cv;cv;cv;cv;cv;cv;cv;cv8-Vx ͡LȆ?쁣@¶CVK'%dm]0p@" _2lR{6݁0Xw< M"0xʄGAD"!< "Ce6LgA!@r6а0 f a0 f f'/v{BH»@Y{La0`5;l:JfѰՐ^b1b+$ @@ I$B$!!D!$"H@* ͡. ;ͣW!E# ¡ # ¬# ·@ʴʥzʖ=ʐ=|zJz?4)z zp+q%N*VDMN 7*VDM$  7*VME :,QҨ *V&U *VDM :V 2V*V&U DM*V:V2V*V&U *V&+S:V2V*V&U ) :V2V!Vp+q*V"TͣN,ͧ*VDM !Vr+s+p+q*V^#V"T*V##^#V"T*V ^#V"T#b1En6`  fԐ1Uum(@8"ͩ bT|Ёnʲc`ݒͣJU;$wgvHea͵@lNd6Xt\ Ux&m&bsgHdf(eaUpW }IGÕAV!I@.1[|V!K'ԙ4yL6#Fr8#* Jj\U +ͣMU9Lg!yI ;6 pfiEt(Ub F$ [@{m8A8upBk  >/Ҥ×!p+q*DM͛:̀ ̀:2:!!K:*&L Ǹ!4!K6 ͐uÇYALPSID'TCELLOC$LAITINI!ÓCOPYRIGHT (C) 1977, DIGITAL RESEARCH g gzd{ *9 Wl> W> W*"!"^l!]kl$]xl']::>2l!6!"!~4*s,r,"!~Od>g>:N ,:h : Rxf0V jo<- 'i0)d`@!M#%y`ݒ{JI;%%Ydn0ڄ-V<|fހfQfݠ6m]YmrXHk!W!*UC6(9``* º`+`1YbGV ^G< E`Y jV_0H05O#+v: s خSx:q$Of`R(Ԅ.- ͼ{>X0Y""f@VmjYVlUyBlڰ :0rP1nʲLJ5cAU %Ja`ͼ` `@k+T$ dp#t f`C՛V]b3jH6'p0!!*WH|#+x[݀:a v@SPhhP8ͱ HFlh8` nx*l6ǀ3ll8 ~ `4fPp$#`?ٶ4u`Lͮ`eU8kFo&ePJܮwXڮVmfP DJ¯@ pic@Y FՀ3lh #~K6ƀHP&Y)AD24D) #: Id ynјY)AB@h(P&!r7Bi6L@r2L@3%0h(H @P( @P( @P( !Xf. rfi3A R G!`i3N`e9L'#  Cd l [ -"ڴ#+[p[@l!F2y* "*xT-V-^yA!~4x]> WO" Q>2y*"  INITIAL = COLLECT = DISPLAY = "-A" IN EFFECT, ADDRESS BACKTRACE READY FOR SYMBOLIC BACKTRACE BACKTRACE:%B 2!4þ *%"%:/ ͩ!4¡ :$ !4!"%!q: O !{4>!O :!{O :2*'M!8 ^#V%!t ͫ *%B :w*%#"%` Ø Ø Ø Ø Ø ͩ` *M6` !6 ` !6 ` !6 ` *&T` !6 ` !6 ` !60 ` *&D   ?쁲[*@`^2K6meRq}Bwٴj^2! ;4f@RzKƬ;ͽ~ â:!~mU0wz@uB@+͵͸ja] mfݠ6ma`Q2XCp̃\Ub4f07 JYM"3i(2GV ew*a q='@DuO#?(W ;k+6 ~PV BP@2!~sǣ+t9erl[U;D +Wx z2AEwvlfuhٶI,V f`CMa 2YMWx!y@b+ó`@ @-U Uw[AF: c6B*OU > 0"[-Ke%ـl Setting up Allocation vector for drive C: *** Bank 1 and Common are not included *** *** in the memory segment table. *** Number of memory segments (#3) ? 2 CP/M 3 Base,size,bank (83,3D,00) Enter memory segment table: Base,size,bank (00,80,00) ? 01,82,00 Base,size,bank (00,C0,02) ? 11,2F,02 CP/M 3 Sys 8300H 3D00H Bank 00 Memseg No. 00 0100H 8200H Bank 00 Memseg No. 01 1100H 2F00H Bank 02 Accept new memory segment table entries (Y) ? Y Setting up direc ***************************************************************************** The procedure for generating the system is as follows: 1. Assemble necessary files using RMAC: RMAC SCB RMAC BIOSKRNL RMAC CHARIO RMAC MOVE RMAC PRIVATE RMAC BOOT RMAC DRIVES RMAC WINCH RMAC DRVTBL RMAC LDRDRV RMAC LDRWINCH RMAC LDRKRNL RMAC LABEL RMAC LDRBOOT RMAC ENDER 2. Create the BIOS by linking the appropriate files together as follows: LINK BNKBIOS3[B]=BIOSDp"[<-Ki%pm@D"[T-Kl%A@mD"[n-Kn%ЉmD"[-?帡`n@D$"[-Ks% {tX$@UaUzjH+{P@3k(3jK4K6`JYG&ml fհmIW, x@(dz¦.U _6J XKUw(A^Od`@F*K՛v#ץf@#sFI' *** Directory buffer required *** *** and allocated for drive $: *** $ Overlay Directory buffer for drtory hash tables: Enable hashing for drive A: (Y)? Y Enable hashing for drive B: (Y)? Y Enable hashing for drive C: (Y)? Y Setting up Blocking/Deblocking buffers: The physical record size is 0200H: Available space in 256 byte pages: TPA = 00F0H, Bank 0 = 0082H, Other banks = 000BH Number of directory buffers for drive A:? #32 Available space in 256 byte pages: TPA = 00F0H, Bank 0 = 0040H, Other banks = 000BH Number of data buffers for drive A:? #35 Allocate buffKRNL,SCB,PRIVATE,MOVE,CHARIO,DRVTBL, WINCH,DRIVES,BOOT 3. Create a CPM3.SYS file using GENCPM. When GENCPM is invoked, it will ask a series of questions which should be answered as follows: CP/M 3.0 System Generation Copyright (C) 1982, Digital Research Default entries are shown in (parens). Default base is Hex, precede entry with # for decimal Create a new GENCPM.DAT file (N) ? N Display Load Map at Cold Boot (Y) ? Y Number of console columns (#80) ? #80 ers outside of Common (Y) ? Y Available space in 256 byte pages: TPA = 00F0H, Bank 0 = 0002H, Other banks = 0001H Number of directory buffers for drive B:? #0 Share buffer(s) with which drive (A:) ? A: Available space in 256 byte pages: TPA = 00F0H, Bank 0 = 0002H, Other banks = 0001H Number of data buffers for drive B:? #0 Share buffers with which drive (A:) ? A: Available space in 256 byte pages: TPA = 00F0H, Bank 0 = 0002H, Other banks = 0001H The physical recor Number of lines in console page (#24) ? #25 Backspace echoes erased character (N) ? N Rubout echoes erased character (Y)? N Initial default drive (A:) ? A: Top page of memory (FF) ? FF Bank switched memory (Y) ? Y Common memory base page (C0) ? C0 Long error messages (Y) ? N Accept new system definition (Y)? Y Setting up Allocation vector for drive A: Setting up Checksum vector for drive A: Setting up Allocation vector for drive B: Setting up Checksum vector for drive B: E   d size is 0100H: Available space in 256 byte pages: TPA = 00F0H, Bank 0 = 0002H, Other banks = 0001H Number of directory buffers for drive C:? #0 Share buffer(s) with which drive (A:) ? A: Available space in 256 byte pages: TPA = 00F0H, Bank 0 = 0002H, Other banks = 0001H Number of data buffers for drive C:? #0 Share buffers with which drive (A:) ? A: Available space in 256 byte pages: TPA = 00F0H, Bank 0 = 0002H, Other banks = 0001H Accept new buffer definitions (Y)*cN,*cN{zҽ{,*c*e{ozg ~*c#"c> :[ >  X N*c>:> !:q#G*eDM*h ERROR: $DISK READ$LOAD ADDRESS LESS THAN 100$DISK WRITE$LOAD ADDRESS $ERROR ADDRESS $INVALID HEX DIGIT$CHECKSUM ERROR $FIRST ADDRESS $LAST ADDRESS $BYTES READ $REC? Y BNKBIOS3 SPR xxxxH xxxxH BNKBIOS3 SPR xxxxH xxxxH RESBDOS3 SPR xxxxH xxxxH BNKBDOS3 SPR xxxxH xxxxH *** CP/M 3.0 SYSTEM GENERATION DONE *** At this point, a new CPM3.SYS file has been created. If you have a disk that is already bootable, you can simply PIP the new CPM3.SYS file over to it. Otherwise, continue with steps 4-5. 4. Create a loader bios at the correct address to be loaded in by the boot rom by: LINK BOOTLDR[L2000]=LABEL,CPMLDR,LDRKRNL,SCB,LDORDS WRITTEN $CANNOT OPEN SOURCE FILE$DIRECTORY FULL$CANNOT CLOSE FILE$HEXCOM VERS: 3.00 $command line ; command line is present, scan it mvi c,0 ;start with 00 lxi h,0 ; 0000 lxi d,conlin;command line readc: ldax d ;next command character inx d ;to next command position ora a ;cannot be end of command rz ; not zero, numeric? sui '0' cpRBOOT,MOVE, LDRWINCH,CHARIO, DRVTBL, LDRDRV, ENDER 5. Put system onto target disk by: COPYSYS BOOTLDR.COM and copy CPM3.SYS and CCP.COM to the target disk as well. **************SYSTEM GENERATION COMPLETE***************** not the quit command, random write? cpi 'W' jnz notw ; ; this is a random write, fill buffer uÀCP/M Version 3.0COPYRIGHT 1982, DIGITAL RESEARCH251082654321!9"k1G \!m!w# š!v6H#6E#6X!e6C#6O#6M<<&:g.".g"?S:2n!`w #4o"c*e{ozg"hj:]@*c"\y!5C*^N{zb+"^*^*`*h"!j4&"h"y:b<5*kG!gwxS0  F   i!v"/!Q/+>c!K-6*/K>XG!+>yC!Q/+>c!+Q/>r–!}o|g}ʖ!#"/!/–!/ʖ!/+>c!/ͷ~g"B,U"G-!,,> c!o0ͷX:F-!,,> c!q0ͷ~*G-w#w:F-X!s0͡!F-6*G-*G-^#V#)))"I-*B,*G-^#V))W+"B,*B,>og"@,:F-f!,,> c!y0ͷ~!{0!+Q/>r2K-*I-w#w2P/>2O/2N/!/(,>t!"N-:F-X!D,LG!),>y :#!#6!Q/D,>_:O/!N/:N/2O/2N/!P/4!}0!/3>XG!3>y.!/3>X3t!/3>XG!3>y[!/3>X3t*3!3>}23:3ʐ!/3>S*3:3<_Lt*3"3!3ö*33>_*3"3!3!;3"93!3*3>!t!<3"53!L33>Gt!Q33>Gt!"'32.3*'3*#3^#VW*'3#"'3*#3*'3)))^#V!<3>p!")3*)3 |*53+*)3"73*73~ ]Æ*73~_n*736?|*73~`|*736@*)3#")38*#3*'3)))!M3>Gt*#3*'3)))^#V")32-3!)3~#ʖ:-3 ͟!<33>t!M33>t2-3!-34*%3++*)3))^#V"gw!0>1xy :B12!1!A14ì*00>c*0"D1!D1ͷ~^#V"F1*F1^#V> ͍!H1 *!H1> XÓ1~# s !9"2!1"1!16*1w#w*1ng | *1KLG!1>yº !1**1~ogQ1~og)1^#V*1^#V#r+sH !11>c !1*>22*1~ogQ1~Y !11xyK !24H :2K !1!1> !1* *1*1^#Vͯ1>_ *1~ogQ1~ !1*{ !1*!11xy !1*é !1**1~ogQ1~ !1* *2:1!0*L-#"L-!0A !/*!/>X!/>Xt!D,KLG!.,>y:O/!N/f:N/2O/2N/!/>X!.,!,@!D,KL(,tî!N/4!,/>c!0!0!0n !N-~#!0̓ ã!0ͬ!D,/,>c!0~U!9"0:#Z!#6!#"/r*/>$Gt!##>Gt!#0,>Gt!#6!#6!#"0!0T!F-6!"#!D,6!06:0}͐3>!D,ͧd*0!F-6!#6*##"#*# |.!"0}20!0>!#*0"0!0U!#"0!0+!#*06*0 "0!04í!"#:+3:,31!Q3:-3ogͯ3>Gt*+3O"+3M!Q3:-3ogͯ3>Gt!3A !/3*!/3>S!L3:-3ogͯ>t*%3*)3))^#V")3ø͟!.34*3~!.3!t:-3ogͯ}!;3w!;3~w*93:;3=_L3t*93!3>_!3^#V"<:F4!F46*<KLG!H<>y+!E46ð!E46!4"$Gt!'4I<>Gt!*46!>46z"!4*<@*<"r2<:E4:<>2<>2<*Ó*1~og |c !1>ߦw !1~?t !16_ !1~@‚ !16`Y2 ~# ˆ *_2^#V"e2*c2^#V"g2!"2*[2^#V"2*2*2W *]2*2ͯ"2!2 :2 *e2*2)))~# *g2^#V#*e2*2)))s#rc *e2*2)))^#V"2*g2*2))~#K *g2*2))^#V"2% *g2^#V#*g2*2))s#r*g2^#V#r+s*a2^#V*g2^#VW !i272>!c!2ͷ~*2+|´ *Y2^#VO"2þ *Y2^#V"2*2*g2++*g2^#V))s#r*g2*g2^#V))w#w*2#"2ô 2~# +.!+6:# :# :#.~!#*#~20:0 20:0Q~:0Þ:K-z"/!0Ur"/*/ 3,>Gt!0#!D,6,> c!0ͷ~Ͳ"0~# ¦*0^#V"0*0^#V"0͕!1"1!216>261251:!12:1::1!51!!1:51og~271:21!216{:71!61281*0:61o:81OLG!1>c:81og>og}281*0:81ogW"0*0:81og####"0*0*0W*00>c*0";1!;1ͷ~>291!1n&}2=1:=1!91*1:91og"1*1~og |*1>ߦw*1~?*16_*1~@*16`!914å:Gt!^<<xy;!<8!<5!<͛#E!<͛!<5:22%^}2<:!4*<@*<"!4*<@*<"2<*t!<͆!<4!<͆ *26*2LG!X2>yC *2"3*3#~>!3w:3og2~C :2 !26*e2^#V#"3!3"323!3> *3++| !"3Ñ *3>og"3*3:3og)2s#r!34d !" 3*e2^#V" 323*2"3!3"3* 3* 3W_!34:3og)2^#V" 3*e2*3)))^#V"3*2*3j/*3+" 3* 3* 3"3!36\*3*2jY*3#" 3* 3* 3W"3!36\Û :3o* 3"3u* 3"3*e2*3)))^#V"3*2*3jʛ*26*3*2s#r3 ~# ±*3^#V"#3*!3^#V"%3! ÷>2.3*3~ʟ*34*3~og"3!3A !/3**0++*0)"1*11>_*0^#V"31*0^#V#r+s*1*0*0^#V)))s#r*0:61_L*0*0^#V)))>t*0*0^#V)))w#w!31#`*0*31)))^#V1j`*0*0^#V)))"1*1!1>Gt*0*31)))"1*1*1>Gt*31+"31*0*31)))^#V1j!31#T*1"1*0*31)))"1*1*1>Gt*31+"31*11>Gt:71%^}2C1:C1!A1$ *0:A1_LG!>1>t!0>1xy!0>1xy !B14:A1!!1:B1oG   ^#V^#V  $ "/  Later CP/M or MP/M Version Required$*#=**#={ozgY|g}o!\!l!ÍÝ3>Ý!*3>K* !*   >    !"#$%(^#V^#Vnd of Execution$#dd(Copyright (c) 1980 Digital Research V1.3MXList SYMi`~sw#r##q#p i`N#F#^#V~;q4#p+i`##s#rA"]" FREE Request Out-of-Range$ Free Space Overwrite$GKҜMbkÜiFhNhN#Fh^#V"#y2#xүi&ͩ x>!J#{#z*#*# xyxM_!^#VͤG>(Iỳ>)I|*<|6<ͤͶò">,IG> _O! O! O!0:IIWWG|e}e ڐdԒ ͒ڝÔxWN #~Iæ!wͤ*=!9{_z{ G>#I*=>=^#V#qF3O3*# 72gl*<"?'w#-!9~sG~#s4! 9~.Y+60e0e6 #M+r>o&9y>o&90w+Š6./G! >0 >-3T]))>: >?I!oͤͤ>=I^#V|A}8.))ä#F>A> #\~ >.~ =M^#V# File: Traceback: ERROR FIXED OVERFLOW OVERFLOW UNDERFLOW ZERO DIVIDE END OF FILE UNDEFINED FILE KEYNULCONCONRDRPUNLSTBADG!]#~8  " Condition Stack Overflow$4Ox!< w#s#r#s#r!9!^# s#r!]#N!< +++++q #{Š #zʏ ++~q ++!]#5!~# ž Ú !]#N!< +++++¹ #~# +{ #z ++~ù #^#V=!L#~9!5:L#_!M#^iO>`G>0 <  DM0 > Ew#E~#X~#W #Ý!9Oo>gy~#o>gxGGtwF#"WObk++~+ y~#/w!/x"yʞ" >O6# x" h"=ɯ ~#fo++"!=~#"*!="²""""  Insufficient Memory$ Invalid I/O List E ) )  ) z|ODM|O)Ox>~!>)< D=M)6ɯo>g{ozg!dÄlmnpr Conversion2!Ä*%=|^#V"%=###^#V#N#Fxʿ #~ò*%=|^#V#N#F!9yx"%=:L# !9!#{z#  !!9:]#O!^# {#z!]#5#}OD*#=~r##~#fo9!NÄVWXZ\ Free Space Exhausted##^#V#{_zW;{_zW>4z˜{##^#V# ##s#rs#r#s#r+++~sw#r####}*#=}|5*{z5+F+N+V+5^{;{z;}|;{H    { *$'symbol table reference overflow 22i2d$PlPRINTER busy XREF 1.3 no SYM file no PRN file CP/M PRNXRFABORTED. V́ + 1@+> 0# +333  FG1"z*QS cE5T @lXRF.XRF make error  '.XRF close error .XRF write error <<<_<<b2>û>!6 #=!~a1{1 w##:Ƃ2*6 2fl:<2!G\:>2 *|ͫ}*ͫ>:Ï:> ͏> Ï> Ï:_:<2>2ͺ >Ï*}o|ecords per track db ?bsh,?blm ; block shift and mask db ?exm ; extent mask dw ?dsm ; maximum block number dw ?drm ; maximum directory entry number db ?al0,?al1 ; alloc vector for directory dw ?cks ; checksum size dw ?off ; offset for system tracks db ?psh,?psm ; physical sector size shift ; and mask endm ; gcd macro ?m,?n ;; greatest common divisor of m,n ;; produces value gcdn as result ;; (used in sector translate table generation) ?gcdm set ?m ;csv ; checksum vector else dw 0FFFEh ; checksum vector allocated by endif ; GENCPM if not nul ?asize dw ?alv ; allocation vector else dw 0FFFEh ; alloc vector allocated by GENCPM endif dw 0fffeh,0fffeh,0fffeh ; dirbcb, dtabcb, hash alloc'd ; by GENCPM db 0 ; hash bank if not nul ?csize ?csv ds ?csize ; checksum vector endif if not nul ?asize ?alv ds ?asize ; allocation vector endif endm dpb macro ?psize,?pspt,?trks,?bls,?n;variable for m ?gcdn set ?n ;;variable for n ?gcdr set 0 ;;variable for r rept 65535 ?gcdx set ?gcdm/?gcdn ?gcdr set ?gcdm - ?gcdx*?gcdn if ?gcdr = 0 exitm endif ?gcdm set ?gcdn ?gcdn set ?gcdr endm endm skew macro ?secs,?skf,?fsc ;; generate the translate table ?nxtsec set 0 ;;next sector to fill ?nxtbas set 0 ;;moves by one on overflow gcd %?secs,?skf ;; ?gcdn = gcd(?secs,skew) ?neltst set ?secs/?gcdn ;; neltst is number of eldirs,?off,?ncks local ?spt,?bsh,?blm,?exm,?dsm,?drm,?al0,?al1,?cks,?psh,?psm local ?n ;; physical sector mask and physical sector shift ?psh set 0 ?n set ?psize/128 ?psm set ?n-1 rept 8 ?n set ?n/2 if ?n = 0 exitm endif ?psh set ?psh + 1 endm ?spt set ?pspt*(?psize/128) ?bsh set 3 ?n set ?bls/1024 rept 8 ?n set ?n/2 if ?n = 0 exitm endif ?bsh set ?bsh + 1 endm ?blm set ?bls/128-1 ?size set (?trks-?of; Macro Definitions for CP/M3 BIOS Data Structures. ; dtbl - drive table ; dph translate$table, - disk parameter header ; disk$parameter$block, ; checksum$size, (optional) ; alloc$size (optional) ; skew sectors, - skew table ; skew$factor, ; first$sector$number ; dpb physical$sector$size, - disk parameter block ; physical$sectors$per$track, ; number$tracks, ; block$size, ; number$dir$entries, ; track$offset, ; checksum$vec$size (optional) ; Dements to generate ;; before we overlap previous elements ?nelts set ?neltst ;;counter rept ?secs ;;once for each sector db ?nxtsec+?fsc ?nxtsec set ?nxtsec+?skf if ?nxtsec >= ?secs ?nxtsec set ?nxtsec-?secs endif ?nelts set ?nelts-1 if ?nelts = 0 ?nxtbas set ?nxtbas+1 ?nxtsec set ?nxtbas ?nelts set ?neltst endif endm endm f)*?spt ?dsm set ?size/(?bls/128)-1 ?exm set ?bls/1024 if ?dsm > 255 if ?bls = 1024 .'Error, can''t have this size disk with 1k block size' exitm endif ?exm set ?exm/2 endif ?exm set ?exm-1 ?all set 0 ?n set (?ndirs*32+?bls-1)/?bls rept ?n ?all set (?all shr 1) or 8000h endm ?al0 set high ?all ?al1 set low ?all ?drm set ?ndirs-1 if not nul ?ncks ?cks set ?ncks else ?cks set ?ndirs/4 endif dw ?spt ; 128 byte rrive Table. Contains 16 one word entries. dtbl macro ?list local ?n ?n set 0 irp ?drv, ?n set ?n+1 dw ?drv endm if ?n > 16 .' Too many drives. Max 16 allowed' exitm endif if ?n < 16 rept (16-?n) dw 0 endm endif endm dph macro ?trans,?dpb,?csize,?asize local ?csv,?alv dw ?trans ; translate table address db 0,0,0,0,0,0,0,0,0 ; BDOS Scratch area db 0 ; media flag dw ?dpb ; disk parameter block if not nul ?csize dw ?J   ; @CHK MACRO USED FOR CHECKING 8 BIT DISPLACMENTS ; @CHK MACRO ?DD ;; USED FOR CHECKING RANGE OF 8-BIT DISP.S IF (?DD GT 7FH) AND (?DD LT 0FF80H) 'DISPLACEMENT RANGE ERROR - Z80 LIB' ENDIF ENDM LDX MACRO ?R,?D @CHK ?D DB 0DDH,?R*8+46H,?D ENDM LDY MACRO ?R,?D @CHK ?D DB 0FDH,?R*8+46H,?D ENDM STX MACRO ?R,?D @CHK ?D DB 0DDH,70H+?R,?D ENDM STY MACRO ?R,?D @CHK ?D DB 0FDH,70H+?R,?D ENDM MVIX MACRO ?N,?D @CHK ?D DB 0DDH,36H,?D,?N ENDM MVIY MACRO ?N,?D @CHK ?DH ENDM BITX MACRO ?N,?D @CHK ?D DB 0DDH,0CBH,?D,?N*8+46H ENDM BITY MACRO ?N,?D @CHK ?D DB 0FDH,0CBH,?D,?N*8+46H ENDM SETX MACRO ?N,?D @CHK ?D DB 0DDH,0CBH,?D,?N*8+0C6H ENDM SETY MACRO ?N,?D @CHK ?D DB 0FDH,0CBH,?D,?N*8+0C6H ENDM RESX MACRO ?N,?D @CHK ?D DB 0DDH,0CBH,?D,?N*8+86H ENDM RESY MACRO ?N,?D @CHK ?D DB 0FDH,0CBH,?D,?N*8+86H ENDM JR MACRO ?N DB 18H,?N-$-1 ENDM JRC MACRO ?N DB 38H,?N-$-1 ENDM JRNC MACRO ?N DB 30H,?N-$-1 ENDM JRZ MAC ?D @CHK ?D DB 0DDH,8EH,?D ENDM ADCY MACRO ?D @CHK ?D DB 0FDH,8EH,?D ENDM SUBX MACRO ?D @CHK ?D DB 0DDH,96H,?D ENDM SUBY MACRO ?D @CHK ?D DB 0FDH,96H,?D ENDM SBCX MACRO ?D @CHK ?D DB 0DDH,9EH,?D ENDM SBCY MACRO ?D @CHK ?D DB 0FDH,9EH,?D ENDM ANDX MACRO ?D @CHK ?D DB 0DDH,0A6H,?D ENDM ANDY MACRO ?D @CHK ?D DB 0FDH,0A6H,?D ENDM XORX MACRO ?D @CHK ?D DB 0DDH,0AEH,?D ENDM XORY MACRO ?D @CHK ?D DB 0FDH,0AEH,?D ENDM ORX MACRO ?D @C DB 0FDH,36H,?D,?N ENDM LDAI MACRO DB 0EDH,57H ENDM LDAR MACRO DB 0EDH,5FH ENDM STAI MACRO DB 0EDH,47H ENDM STAR MACRO DB 0EDH,4FH ENDM LXIX MACRO ?NNNN DB 0DDH,21H DW ?NNNN ENDM LXIY MACRO ?NNNN DB 0FDH,21H DW ?NNNN ENDM LDED MACRO ?NNNN DB 0EDH,5BH DW ?NNNN ENDM LBCD MACRO ?NNNN DB 0EDH,4BH DW ?NNNN ENDM LSPD MACRO ?NNNN DB 0EDH,07BH DW ?NNNN ENDM LIXD MACRO ?NNNN DB 0DDH,2AH DW ?NNNN ENDM LIYD MACRO ?NNNN DB 0FDH,2AH RO ?N DB 28H,?N-$-1 ENDM JRNZ MACRO ?N DB 20H,?N-$-1 ENDM DJNZ MACRO ?N DB 10H,?N-$-1 ENDM PCIX MACRO DB 0DDH,0E9H ENDM PCIY MACRO DB 0FDH,0E9H ENDM RETI MACRO DB 0EDH,4DH ENDM RETN MACRO DB 0EDH,45H ENDM INP MACRO ?R DB 0EDH,?R*8+40H ENDM OUTP MACRO ?R DB 0EDH,?R*8+41H ENDM INI MACRO DB 0EDH,0A2H ENDM INIR MACRO DB 0EDH,0B2H ENDM IND MACRO DB 0EDH,0AAH ENDM INDR MACRO DB 0EDH,0BAH ENDM OUTI MACRO DB 0EDH,0A3H ENDHK ?D DB 0DDH,0B6H,?D ENDM ORY MACRO ?D @CHK ?D DB 0FDH,0B6H,?D ENDM CMPX MACRO ?D @CHK ?D DB 0DDH,0BEH,?D ENDM CMPY MACRO ?D @CHK ?D DB 0FDH,0BEH,?D ENDM INRX MACRO ?D @CHK ?D DB 0DDH,34H,?D ENDM INRY MACRO ?D @CHK ?D DB 0FDH,34H,?D ENDM DCRX MACRO ?D @CHK ?D DB 0DDH,035H,?D ENDM DCRY MACRO ?D @CHK ?D DB 0FDH,35H,?D ENDM NEG MACRO DB 0EDH,44H ENDM IM0 MACRO DB 0EDH,46H ENDM IM1 MACRO DB 0EDH,56H ENDM IM2 MACRO DB 0EDH,5DW ?NNNN ENDM SBCD MACRO ?NNNN DB 0EDH,43H DW ?NNNN ENDM SDED MACRO ?NNNN DB 0EDH,53H DW ?NNNN ENDM SSPD MACRO ?NNNN DB 0EDH,73H DW ?NNNN ENDM SIXD MACRO ?NNNN DB 0DDH,22H DW ?NNNN ENDM SIYD MACRO ?NNNN DB 0FDH,22H DW ?NNNN ENDM SPIX MACRO DB 0DDH,0F9H ENDM SPIY MACRO DB 0FDH,0F9H ENDM PUSHIX MACRO DB 0DDH,0E5H ENDM PUSHIY MACRO DB 0FDH,0E5H ENDM POPIX MACRO DB 0DDH,0E1H ENDM POPIY MACRO DB 0FDH,0E1H ENDM EXAF MACRO DB M OUTIR MACRO DB 0EDH,0B3H ENDM OUTD MACRO DB 0EDH,0ABH ENDM OUTDR MACRO DB 0EDH,0BBH ENDM RLCR MACRO ?R DB 0CBH, 00H + ?R ENDM RLCX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 06H ENDM RLCY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 06H ENDM RALR MACRO ?R DB 0CBH, 10H+?R ENDM RALX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 16H ENDM RALY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 16H ENDM RRCR MACRO ?R DB 0CBH, 08H + ?R ENDM RRCX MACRO ?D @CHK ?D DB 0DDH, EH ENDM BC EQU 0 DE EQU 2 HL EQU 4 IX EQU 4 IY EQU 4 DADC MACRO ?R DB 0EDH,?R*8+4AH ENDM DSBC MACRO ?R DB 0EDH,?R*8+42H ENDM DADX MACRO ?R DB 0DDH,?R*8+09H ENDM DADY MACRO ?R DB 0FDH,?R*8+09H ENDM INXIX MACRO DB 0DDH,23H ENDM INXIY MACRO DB 0FDH,23H ENDM DCXIX MACRO DB 0DDH,2BH ENDM DCXIY MACRO DB 0FDH,2BH ENDM BIT MACRO ?N,?R DB 0CBH,?N*8+?R+40H ENDM SETB MACRO ?N,?R DB 0CBH,?N*8+?R+0C0H ENDM RES MACRO ?N,?R DB 0CBH,?N*8+?R+8008H ENDM EXX MACRO DB 0D9H ENDM XTIX MACRO DB 0DDH,0E3H ENDM XTIY MACRO DB 0FDH,0E3H ENDM LDI MACRO DB 0EDH,0A0H ENDM LDIR MACRO DB 0EDH,0B0H ENDM LDD MACRO DB 0EDH,0A8H ENDM LDDR MACRO DB 0EDH,0B8H ENDM CCI MACRO DB 0EDH,0A1H ENDM CCIR MACRO DB 0EDH,0B1H ENDM CCD MACRO DB 0EDH,0A9H ENDM CCDR MACRO DB 0EDH,0B9H ENDM ADDX MACRO ?D @CHK ?D DB 0DDH,86H,?D ENDM ADDY MACRO ?D @CHK ?D DB 0FDH,86H,?D ENDM ADCX MACROK   0CBH, ?D, 0EH ENDM RRCY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 0EH ENDM RARR MACRO ?R DB 0CBH, 18H + ?R ENDM RARX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 1EH ENDM RARY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 1EH ENDM SLAR MACRO ?R DB 0CBH, 20H + ?R ENDM SLAX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 26H ENDM SLAY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 26H ENDM SRAR MACRO ?R DB 0CBH, 28H+?R ENDM SRAX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 2EH ENDM SRAY MACRO ?D ETURN A=5 IF TIME OUT ERROR) ;ASSIMILATE THE BAD TRACK TABLE XRA A STA BADTRACK-1 ;DEFAULT BAD TRACK COUNT TO 0 LXI H,0 SHLD ADH ;TRACK 0, SECTOR 0 MVI H,1 ;BLOCK COUNT OF 1 SHLD ADL ;XRA A CALL WAZ ;READ ABSOLUTE TRACK 0, SECTOR 0 JnZ bad$exit ;(RETURN A=5 IF TIME OUT ERROR) LHLD dmaadr ;BAD TRACK TABLE FROM DISK IS SOURCE MOV A,M CPI 'W' ;"SIGNATURE" SHOULD BE "WXYZ" JNZ notok INX H MOV A,M CPI 'X' ; BUT CHECK ONLY THE FIRST 2 BYTES JNZ notok INX H ; Extended Disk Parameter Headers (XPDHs) dw w$write dw w$read dw w$login dw w$init db 0,0 ; relative drive zero winc0 dw tranw ; translate table address db 0,0,0,0,0,0,0,0,0 ; bdos scratch area db 000h ; media flag dw dpbw ; disk parameter block dw 0 ; checksum vector dw 0fffeh ; alloc vector dw 0fffeh ; dirbcb dw 0fffeh ; datbcb dw 0fffeh ; hash db 0 ; hash bank dseg winbuf ds 512 cseg ; DPB must be resident dpb$w:  @CHK ?D DB 0FDH, 0CBH, ?D, 2EH ENDM SRLR MACRO ?R DB 0CBH, 38H + ?R ENDM SRLX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 3EH ENDM SRLY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 3EH ENDM RLD MACRO DB 0EDH, 6FH ENDM RRD MACRO DB 0EDH, 67H ENDM W !i272>!c!2ͷ~*2+|´ *Y2^#VO"2þ *Y2^#V"2*2*g2++*g2^#V))s#r*g2*g2^#V))w#w*2#"2ô 2~#  INX H INX H ;SKIP OVER THE "SIGNATURE" MOV A,M CPI MAXBAD+1 CNC Too$bad ;(ERROR FF IF MORE THAN (10) BAD) LXI D,BADTRACK-1;BAD TRACK TABLE IN MEMORY IS DESTINATION LXI B,(MAXBAD*2)+1 ;ROOM FOR BAD TRACK COUNT, (10) BAD TRACKS LDIR ;MOVE IT ; ; Now read LOGICAL track 0, sector 0 to get label info ; xra a ; A=0 sta wrwf ; for a read call w$1 ; Perform it jnz bad$exit ; Jump if error ; ; Now, check that disk has one of our "signatures" ; lxi b,3 ; co dw 64 ; #128-byte records/track db 05 ; Block shift db 31 ; Block mask db 1 ; extent mask dw 0989h ; maximum block number dw 2047 ; maximum dir entry number dw 0ffffh ; alloc vector for directory dw 08000h ; (Don't do checksumming) dw 0002h ; offset for system tracks db 01h ; db 01h ; tranw equ 0 page ; called for first time initialization. dseg w$init: ret ; ;RESET AND CONFIGURE THE WINCHESTER ; w$login: lda @ermde ; Get error mode title 'Winchester Handler Module' ; CP/M-80 Version 3 -- Modular BIOS ; Winchester I/O Module ; Version 1.1.3 Updated 02-15-84 LEL ; Port Address Equates maclib ports ; CP/M 3 Disk definition macros maclib cpm3 ; Z80 macro library instruction definitions maclib Z80 cseg ; Variables containing parameters passed by BDOS extrn @adrv,@rdrv extrn @dma,@trk,@sect extrn @dbnk,@dtbl ; Other externals extrn u$conin$echo eunt = 3 lxi h,winbuf ; Point to info read from disk lxi d,signature ; and our signature w$log$01: ldax d ; Get signature character cci ; compare inx d ; Increment ptr jnz notok ; Jump if no match jpe w$log$01 ; if BC<>0, keep going mov a,m ; Now check final char cpi '0' ; For '0' jz w$log$30 ; cpi '1' ; or '1' jnz notok ; ; ; Disk is one of ours. Move info from label into DPB. ; w$log$30: lxi h,winbuf+7 ; Point to # heads mov a,m ; Get into A ral ; *2  sta save$mode ; Save current value lda @dbnk ; Get Data bank (LEL0384) sta save$bank ; Save it (LEL0384) mvi a,0ffh ; Force to FF sta @ermde ; save it xra a ; move 0 to data bank sta @dbnk ; for reading of label lxi h,winbuf shld dmaadr ; set up dma address lxi h,0 ; Zero shld wsect ; = sector shld wtrk ; and track CALL WINRES jnz bad$exit ;(RETURN A=5 IF TIME OUT ERROR) sta wrwf ; wrwf=0 to read label CALL WINRES jnz bad$exit ;(Rxtrn error$table,errm1 ; Table entry point public winc0, dpbw ; System Control Block variables extrn @ermde ; BDOS error mode ; Utility routines in standard BIOS extrn ?wboot ; warm boot vector extrn ?pmsg ; print message @ up to 00, saves & extrn ?pdec ; print binary number in from 0 to 99. extrn ?pderr ; print BIOS disk error header extrn ?conin,?cono ; con in and out extrn ?const ; get console status extrn ?bank ; Bank select pageL    sta heds ; Store away lxi b,15 ; # bytes to move lxi h,winbuf+32 ; FROM address lxi d,dpbw ; TO address ldir ; move it inx h ; Skip skew ldi ; Then move in 2 more ldi ; ; CALL WINRES ; Set up for correct # heads jnz bad$exit ; Exit if error jmp login$exit ; TOOBAD: push h lxi h,manybad ; Point to message call ?pmsg ; Print it pop h ret ; ; NOTOK: lxi h,nomatch ; Point to error message call ?pmsg Bad$exit: pop h ; pop return addressit for user response cpi 'Y' ; Yes? jz w$1 ; Try again jr error$51 ; No. Leave w/hard error error$50: pop psw ; Get error code error$51: mvi a,1 ; Set hard error jr w$exit ; (LEL0284) good$exit: xra a ; Zero means good (LEL0284) w$exit: ora a ; Set error code (LEL0284) RET ;RETURN CONTROLLER'S ERROR CODE page ;RESET AND CONFIGURE THE WINCHESTER WINRES: ; MVI A,080H ; (LEL0384) ; OUT p$winch$control ;PULSE THE RE"LOGICAL ADDRESS" XRA A MVI D,5 WWW: DAD H RAL DCR D jrnz WWW ;AHL:=TRACK*32 STA ADH ;(DRIVE ALWAYS 0) MOV A,H STA ADM LDA wsect ADD L STA ADL ;AD(HML):=WTRK*32+WSEC MVI A,1 STA INTL ;SELECT OPCODE,DIRECTION LDA WRWF WAZ: LHLD dmaadr LXI B,0 ;B=0(=256) BYTE COUNT FOR DATA TRANSFER ;C=0 INPUT DIRECTION UNLESS CHANGED ORA A ; check wrwf jrnz wwrit1 ; non-zero means write WREAD1: MVI A,8 jr WACTR WWRIT1: MVI A,10 ;JMP WACTW ;WRITE D pop d ; and DPH pointer lxi d,0 ; Set DPH pointer to 0 push d ; save it push h ; push return address Login$exit: lda save$mode ; Get saved value of @ermde sta @ermde ; restore lda save$bank ; Get saved data bank (LEL0384) sta @dbnk ; restore it (LEL0384) ret save$mode ds 1 save$bank ds 1 page DSEG ; ; Read entry point ; w$read: xra a ; A=0 sta wrwf ; Read/write flag=0 for read lxi h,read$msg jr w$common ; Join common code ; ; Write entry pSET LINE (LEL0384) mvi a,01 ; Recalibrate (LEL0384) lxi h,wcb ; (LEL0384) mvi b,8 ; 8 chars (LEL0384) mvi c,1 ; Direction = out (LEL0384) call wdoit ; (LEL0384) rnz ; return if error (LEL0384) MVI A,12 ;SET DRIVE CHARS COMMAND LXI H,WCB1 ;FROM DRIVE CHARS DATA LXI B,256*8+1 ;=MVI B,8/MVI C,1 ;8 BYTES OUT ;JMP WDOIT ;=CALL WDOIT/RET ;RETURN A=ERROR STATUS WDOIT: ;LOWEST LEVEL COMMAND HANDLER. ;INPUT: DATA: C: DIRECTION (0=IN,1=OUT) ; B: HOW MANY IRECTION TO IGNORE DATA JUST IN CASE WACTW: INR C ;=MVI C,1 ;SET WRITE DIRECTION WACTR: CALL WDOIT jrz good$exit ;(RETURN OK IF OK) CPI 0FEH jrNZ error$exit ;(RETURN ERROR (5/7) IF ERROR NOT STATUS BYTE) MVI A,3 ;"REQUEST SENSE STATUS" LXI H,LSTAT ;TO LSTAT LXI B,256*4;=MVI B,4/MVI C,0 ;4 BYTES IN CALL WDOIT jrNZ error$exit ;(RETURN ERROR STATUS (5/7/FE)) LDA LSTAT ANI 03FH CPI 4 ;IF CONTROLLER RETURNS 4 (DRIVE NOT READY) JRNZ error$exit ; (LEL0284) INRoint ; w$write: mvi a,1 ; A=1 sta wrwf ; Read/write flag=1 for write lxi h,write$msg ; ; Common code for read/write operations ; w$common: shld operation$name ; Store "Read" or "Write" lhld @sect ; Get sector shld wsect ; store it lhld @trk ; Get track shld Wtrk ; store it lhld @dma ; Get dma address shld dmaadr ; store it W$1: ;TRACK MAPPING: SKIP RESERVED TRACK 0, NUMBER AROUND BAD TRACKS (IF ANY) LHLD WTRK XCHG ;DE:=TRACK INX D ;TRACK+=1 (TRACK 0 RESERVED); HL: WHERE TO GET/PUT THEM ; ; CMD: A: COMMAND BYTE ; ; ;RETURN: A: STATUS BYTE ;SETUP OPCODE STA OP ; ; Wait for not busy, but time out after 1 second. ; lxi d,1099 ; 1099 * 910us=1 second (LEL0384) WDOIT$4: ; (LEL0384) IN p$winch$control ; Get status ANI 2 ; Busy? JZ WDOIT$6 ; If not busy, do cmd (LEL0384) xra a ; Do loop 256 times (LEL0384) WDOIT$5: ; (LEL0384) dcr a ; (waste time) (LEL0384) jnz wdoit$5 ; 896us (LEL0384) dcx d  A;=MVI A,5/ORA A ; THEN CHANGE IT TO 5 error$exit: push psw ; Save error code lda @ermde ; Get error mode inr a ; Is it FF? jrz error$50 ; If yes, return hard error call ?pderr ; Print message header lhld operation$name ; Get name of operation call ?pmsg ; Print that out pop psw ; Get status lxi h,error$table ; Point to table of msgs error$20: call errm1 ; Print out all errors lxi h,error$msg ; Point to ",Retry (Y/N)?" call ?pmsg ; Print it call u$conin$echo ; Wa LXI H,BADTRACK-1 MOV C,M INX H ;C:=# OF BAD TRACKS, HL:=POINTS TO BADTRACK LIST ;SCHEME: SCAN BAD TRACK LIST. BUMP TRACK FOR EACH BAD TRACK # THAT IS ; REACHED1OR PASSED. INR C MAPMOR: DCR C jrz MAPDONE ;(DONE IF OUT OF BAD TRACKS) INX H MOV A,D CMP M DCX H jrnz MAP$0 MOV A,E CMP M MAP$0: JC MAPDONE ;(DONE IF BADTRACK>TRACK) INX D ;TRACK+=1 (SKIPS BAD TRACK) INX H INX H ;POINT TO NEXT BAD TRACK jr MAPMOR MAPDONE: XCHG ;(HL=TRACK) ;ASSEMBLE M    ; Decrement (LEL0384) mov a,e ; Get low byte (LEL0384) ora d ; OR with hi byte (LEL0384) jrnz wdoit$4 ; Try again (LEL0384) ; ; Time out. Set error code = 7 and return. ; mvi a,7 ; Set error code = 7 (LEL0384) ora a ; reset Z-flag (LEL0384) ret ; Return (LEL0384) ;SELECT CONTROLLER WDOIT$6: MVI A,1 OUT p$winch$data ;p$winch$data:=DECODED CONTROLLER SELECTION (1) ;MVI A,1 OUT p$winch$control ;RAISE.. DCR A ; OUT p$winch$control ;..THEMMAND) Operation$name dw read$msg Read$msg db ', Read',0 Write$msg db ', Write',0 Error$msg db ' Retry (Y/N) ?',0 nomatch db '***WARNING***',13,10,'Disk format not recognized' db 13,10,0 manybad db '***WARNING***',13,10,'MORE THAN 10 BAD TRACKS',13,10,0 DB 0 ;NUMBER OF BAD TRACKS BADTRACK:DS MAXBAD*2 ;ROOM FOR (10) BAD TRACKS Signature db 'FMT' ;END OF WINCH END  RET ;PROCEDURE WSND(HL,B) 'SEND B BYTES FROM (HL) TO WINCH WSND: if banked lda @dbnk ; Get bank for transfer call ?bank ; select it endif MVI C,p$winch$data MVI A,2 ;(ONLY WORKS UP TO 256 BYTES) ;REPEAT WSND1: ;OUT(C):=(HL) *HL+=1 *B-=1 DW 0A3EDH;"OUTI" ;[ACKNOWLEDGE] - (SHOULD BE AUTOMATIC WITH DATA) OUT p$winch$control ;UNTIL B=0 jrnz WSND1 if banked xra a ; Point to Bank 0 call ?bank ; Reselect it endif ;END WSND RET DSEG ;WAIT FON LOWER.. THE SELECT LINE IN p$winch$control CMA ANI 2 MVI A,7 RNZ ;(RETURN ERROR 7 IF NOT BUSY) ;WAIT FOR REQUEST CALL WREQT RNZ ;(RETURN A=5 IF TIME OUT ERROR) IN p$winch$control CMA ANI 8 MVI A,7 RNZ ;(RETURN ERROR 7 IF REQUEST IS NOT COMMAND) ;JAM OUT COMMAND PUSH H PUSH B ;CALL WSND(WCB,6) LXI H,WCB MVI B,6 CALL WSND POP B POP H CALL WREQ ;IF REQ IS DATA IN p$winch$control ANI 8 jnz NODATA ;THEN GET/PUT DATA MOV A,C R WINCHESTER REQUEST WREQ: CALL WREQT jrnz WREQ RET ;WAIT FOR "REQUEST", RETURN Z=1 ; ; WAIT FOR WINCHESTER REQUEST ; TIME OUT IF TOO LONG. ; WREQT: PUSH D LXI D,0 WREQT1: IN p$winch$control ani 01 jz WREQT2 ;DONE IF REQUEST, RETURN Z=1 DCX D MOV A,D ORA E JNZ WREQT1 ;XRA A ORI 5 ;DONE IF TIME OUT, RETURN A=5, Z=0 WREQT2: POP D RET cseg maxbad equ 10 ; maximum # bad tracks cyls equ 306 reduce equ 307 ; (value > 306 means NEVER) (LEL0384) precomp equ 126 ;ORA A PUSH PSW CZ WREC POP PSW CNZ WSND ;WAIT FOR REQUEST CALL WREQ IN p$winch$control CMA ANI 8 MVI A,7 RNZ ;(RETURN ERROR 7 IF REQUEST IS NOT COMMAND) ;FI NODATA: ;GET STATUS BYTE IN p$winch$data STA STAT MVI A,2 OUT p$winch$control ;THROW AWAY NULL STATUS BYTE CALL WREQT RNZ ;(RETURN A=5 IF TIME OUT ERROR) MVI A,2 OUT p$winch$control LDA STAT ANI 2 RZ ;(RETURN ZERO IF STATUS BYTE ZERO) MVI A,0FEH RET ;(RETURN 0FEH IF STATUS BYTE NOT OK) Precomp (LEL0384) maxecc equ 11 WCB1: DW 256*(CYLS AND 255)+(CYLS/256) ;REVERSAL STORES HI-LO HEDS: Db 4 DW 256*(REDUCE AND 255)+(REDUCE/256) DW 256*(PRECOMP AND 255)+(PRECOMP/256) DB MAXECC WCB: OP DB 0 ADH DB 0 ADM db 0 ADL DB 0 INTL DB 1 DB 4 DSEG WRWF: ds 1 ;Write/read/check/format flag WPT: ds 1 ; wsect ds 2 wtrk ds 2 dmaadr ds 2 STAT: DS 1 ;COARSE STATUS BYTE (EVERYTIME) LSTAT: DS 4 ;FINE STATUS BYTES (FROM REQUEST SENSE STATUS CO page CSEG ;PROCEDURE WREC(HL,B) 'RECEIVE B BYTES FROM WINCH TO (HL) WREC: IF banked lda @dbnk ; Get bank for transfer call ?bank ; Select it endif mvi c,p$winch$data ; Set up port mvi a,2 ;(ONLY WORKS UP TO 256 BYTES) ;REPEAT WREC1: ;(HL):=IN(C) *HL+=1 *B-=1 DW 0A2EDH;"INI" ;[ACKNOWLEDGE] - (SHOULD BE AUTOMATIC WITH DATA) OUT p$winch$control ;UNTIL B=0 jrnz WREC1 if banked xra a ; Point to bank 0 call ?bank ; Reselect it endif ;END WRECN   LOADER y; !91""|0!~ʞz=_: _* ""*og*%|}D S#N#F:ʒ#4ʝ^#V{‚:¿*.~w*DM!&_*.& >k s#rr+6.""1*D`.45. F.~. ^#Vx>`. s#rz 6#N#fi%$g1:=<@v_}v=p{_3;{<g"T=X3*j ~P#~R#~L{gbk#N#Fk$&Zcx {~#o}o1!.~ .w#w~?w; ; ! ~#49 w#~$ A  < > _I  ! 6 ! ~#Ͱ 6 m   _  ! 6=  { *.pѯ:r x , \<=!Ͱ =ɯ2 \s 2 ! D ;! : .44 #4"l ~[* 2 a7 {7 w!Y #! *l "l " ~ U #D ]T!̷ 6*%.w#w!} 6 r 6 #w.6#6 #t#6.wo*.s#r.rͧ ̧ m . ^#V45+ w#w.f.5\A "l " l |F# !( |;!"Ï:= w*wWx ~#&*.~s*"ѷ\ Cannot load Program 221282 COPYR '82 DRI <bHA$@DH   A@!" $$@X X X S 1-! j 1".~2.~2 :Xck*kͮ  b < .~=>$.w.6#w.6#w.61.~  .~~w@.p T~º>+~.~~! yͮ Ë.~~w2g !PROF !( : x. +"l ! ͮ   ͮ ~!G8 * ~;#1 կA *l ~:g #I ѯ*l  *l ~0څ :҅ q X x<Ü AX QX X ~@#~:k #^ *jT~# ® wy#ù ! 4 : !Ͱ ~@*h~ yw y/w*hw*h~I E> ͦ > æ % 0  < : ~ȹͦ #* A !g ~6*  * >? A *l " ~0: :: q "l x~0 xG#Gs : &͘ ͤ &ͦ %˜ >  Ʌo$>?· !  > # ͮ x> # ~ Enter User #:ILE.S !+2 !  +~d {   O! w+w+: =w! 5 c ʋ  :p  m>> ͧ  N Ĩ –.~+w.~2  9 : ! ~##~ !7 : !Կ : x*l " !ZXچ! 6  zz: 6 : %2p  ͆ : =̀ 2r  DIR TYPE ERASE RENAME DIRSYS USER u"Q}:\=p:r Aæ R ÂN ͙ʸ} !M 545 x ]  ̵ 6 : oG! ~怹>2M  xf>:ͦ ͤ ͍ ͤ f ¹2  $No File$ required$ERASE $ (Y/N)? $ Press RETURN to Continue $ (User 0)$NON-SYSTEM FILE(S) EXIST$: $$$ SUB,?D ENDM SUBY MACRO ?D @CHK ?D DB 0FDH,96H,?D ENDM SBCX MACRO ?D @CHK ?D DB 0DDH,9EH,?D ENDM SBCY MACRO ?D @CHK ?D DB 0FDH,9EH,?D ENDM ANDX MACRO ?D @CHK ?D DB 0DDH,0A6H,?D ENDM ANDY MACRO ?D @CHK ?D DB 0FDH,0A6H,?D ENDM XORX MACRO ?D @CHK ?D DB 0DDH,0AEH,?D ENDM XORY MACRO ?D @CHK ?D DB 0FDH,0AEH,?D ENDM ORX MACRO ?D @Clf   ͫR  L͞L I *  *  A }_Yl !ͮ ͒6 \&đ %* "l ͍  ûȷ45: w ? A I N   SUBMIT COM ! ͮ ! 6 #"l  !cͿ  O!:r :ͦ ͍ !~B I !pͰ ^#VCOM SUB PRL y!cͰ  î !" * %.2P#ͮ !g 4*l +"l ͷ 2 "Qx2Sl "Tx2V!q ~ :p ͆ .ڶ2* og$2| .w#w#w#wO