IMD 1.17: 29/05/2011 18:22:53 unlabeled  >o:~W!{> " OC > S>O:31!2|}N#Fx2CN#FC$#^#V^#VS#~2#~2<2###~2#^#VSN#FCC*KB0KC:( [0!'}#"* (,*#"+))[R#}! !!Ax͎qput+[[R8 utx7?R#|(/ sr +utwwNFqpnf^:(#~W#:G)[7?K R0! !;NFx(ENF C$7?KnfB8C[0MD!' {:m!;!NFnfB#>,(0W}_nfRut;RDM!A76! [36:G6!w0 ͖!2͖ !͗>O3F#Nů  SYS: Which .SYS file to load 0 = CPM 1 = OSLOAD ? SelectReadFile not found error: file *+":*+"/:*+"^:*+":!":"5:"d:":!":"7:"f:"::8*9:8=o&))8  ^#V!q;p+q!r;6>!r;2*r;&;) p;3>L ~ÒÃG3x(OxAG:xG~ > 2v:nO y~ 8 q!*z~(ͭ8͏ͷ:q2t>2>2yKc> 2v> :yG /_~(!` *k:t{  _!c(  :v= L{((ZZ:nhZ:thZ:xhZZ>2v ~  ( w:q2rF8 <2ty2x:qW:j*mKoB(7:rGz?"|*m"o:qG2rxG![k2jG!> z{2n2xw<2q*k!` "kͱ"k: (8 ~Zd>w(>>w~Can't recognize density of disk in$Read$Write$Seek$ error on track $ sector $ side $ drive $ $!\6͂ !!y;6͂6 :y;- !Ͱ ͭ :s;:| :\:y;HZ !:]A<2\O>n !*y;&\ 6 ì !y;6:s;.¨ ͭ͂ڨ :y; ڟ !Ͱ ͭÌ ! :y;<2y;O!\ :s;w:s;0O> :s;02s;> :s;AO> :s;A 2s;>>!"z; :s;<:s;]:s; HҀ :s;S¸ !96ͭ} :s;P !96 "9} :s;D !96 "9} :s;L "8} :s;M *M8):[ͱ!N5!6ñ:5!6#6>!ڰ!6:<2O>/:!O!T *M͡H~K:¡!6[–ͱ!N5:2:2!4=:[¼ͱ4:!6:.2O8: :* ͇g;[ ͱ!N5!6:%:<2*6 * 6å!q!6> !d*&I :]>!4A>:<2O* :w:?†!6!q!6?!:ҠgÐ!q*&*~!6:22: :]Hں:A2O>: 2ͯ :S:QHI:N<22: H@"2Í202O> c!6Í202O> ڍ*&O*IPLGEN00MACGSTAT COM) PIP COM: IOMEGHD MAC]IOMEGHD RELCPM SYSHBIOS2200MAC !BIOS2200MAC>"#$%IPLGEN00REL &IPLGEN00COM 'BIOS2201PRN()*+,-./BIOS2201PRN0123789:BIOS2200REL 4README DOC56BIOS2201PRNV;<=>?@BIOS2201HEXABBIOS2201REL CBIOS2201SYMDBIOS2201ASMEFGHIJKLBIOS2201ASM8MNOPIPLGEN01MACGQRSTUIPLGEN01PRNVWXYZ[\]IPLGEN01PRN ^IPLGEN01ASME_`abcIPLGEN01REL dIPLGEN01SYMeBIOS2201MACfghijklmBIOS2201MAC>nopqIOMEGA MAC^rstuvwIOMEGA RELxINDEX COM ySUPRBIOSLIBz{|}~et z ; return if so ld e,a ; else e = character ld c,2 ; console output code call 0005h ; do the bdos stuff jp txout ; and repeat ;* ;** ;* ;+ ci:: ;- ld c,1 call 0005h ret ;* ;** ;* ;+ make$system:: ;- call txout .xlist defb cr,lf,lf defb 'Please Enter Name of GEN''ed CP/M System --->',eom .list ld hl,line$buffer ; hl @ line buffer ld (hl),80 ; max. line size = 80 characters ex de,hl ; de @ line buffer ld c,10 ; read console buffer call 0005h ; ld hl,fcb ; clear out fcb ld de,fcb+1 ; ld bc,33 ; ld (hl),00 ; prime the routine ldir ; perform the operation ld de,fcb+1 ; de @ filename ld hl,line$buffer+1 ; hl @ filename line ld c,(hl) ; c = size of line inc hl ; point to data part of line ld b,8 ; b = size of filename ms010:: ld a,(hl) ; a = data from line cp '.' ; is it a dot?? jp z,ms020 ; brif so ld (de),a ; else stuff to fcb inc hl ; inc de ; increment pointers djnz ms010 ;SUPRBIOSLIBDISKDEF LIB1Z80 LIBNDREQUATELIBM80 COMM80 COML80 COMTQUADBIOSMACQUADBIOSMACQUADBIOSMACQUADBIOSMAC@DCON COMNDU COMNSETRX COMNQUADBIOSORGQUADBIOSORGQUADBIOSORGQUADBIOSORGQUADBIOSORG title 'Initial Program Loader and Generator V1.1" name ('iplgen') ; date 21-Jun-83 ; ; .z80 ; Z-80 coding is used ; ; aseg ; ; *** ASCII Constants *** ; cr equ 0dh lf equ 0ah bell equ 07h eom equ '$' retry equ 10 ; ; ; ; ; *** Port Assignments *** ; SCSI$base equ 0050h ; SCSI Interface board base QUAD$eia equ 0010h ; Base port for QUAD. eia board crtstatus equ QUAD$eia+4 ; Status port for console crtdata equ QUAD$eia+5 ; Data port for console ; txrdy equ 0001h ; Tx. Ready bit in 8251 usart rxrdy equ 0002h ; Rx. Ready bit in 8251 usart ; ; *** SCSI Port assignments *** ; ; * bit,byte and port assigments for * ; * SCSI host interface adaptor * ; datai equ SCSI$base ; data in register datao equ SCSI$base+2 ; data out register bstat equ SCSI$base+1 ; bus status selport equ SCSI$base ; select port adr. clrint equ SCSI$base+1 ; clr. intrrupt port dmaport equ SCSI$base+3 ;  ms030:: ld a,(hl) ; skip past '.' cp '.' ; jp z,ms020 ; brif found inc hl ; jp ms030 ; and countine ;* ms020:: inc hl ; point past '.' ld a,b ; see if all filename is filed or a ; jp z,ms040 ; brif so ms050:: ld a,' ' ; pad with spaces ld (de),a ; inc de ; djnz ms050 ; ms040:: ld bc,3 ; ldir ; trnsfr rest of file name ld de,fcb ; try to open ld c,15 ; call 0005h ; cp 0ffh ; check for error jp nz,ms060 ; brif ok call txout ; defb cr,lf,lf defb 'ERROR: Cannot Open File ',eom ld de,(line$buffer+1) ld hl,line$buffer+2 ld d,0 add hl,de ld (hl),'$' ld de,line$buffer+2 ld c,9 call 0005h jp make$system ;* ms060:: call txout defb cr,lf defb 'Loading File ...',eom ld hl,buffer ms070:: ex de,hl ; de @ dma buffer push de ; save ld c,26 ; set dma call 0005h ; ld de,fcb ; de @ fcb ld c,20 ; go read a record call 0005h ; perform the read or a ; check for errors jp nz,ms080 ; dma address port cparity equ SCSI$base+4 ; clear parity port busy equ 80h ; controler busy bit cd equ 40h ; command/data bit direc equ 20h ; directon bit req equ 10h ; request bit msg equ 08h ; end message bit perr equ 04h ; perr error bit bdack equ 02h ; board ack. signal lint equ 01h ; interupte bit ; ; cseg ; start:: ld sp,stack ; set up the stack pointer call txout .xlist defb cr,lf defb 'IPLGEN00 -- Initial Program Booter and' defb ' System Generator V1.1' defb cr,lf,lf defb 'For 60k Systems',cr,lf,lf,lf defb 'L)oad or M)ake System Track --->',eom call ci ; get answer cp 'M' ; see if make system jp z,make$system ; brif so cp 'L' ; see if load system jp z,load$system ; brif so call txout defb cr,lf,lf defb 'ERROR: Please Type "M" or "L"' defb cr,lf,lf,eom jp start ;* ;** ;* ;+ txout:: ;- ex (sp),hl ; hl @ data ld a,(hl) ; a = data inc hl ; put back pointer ex (sp),hl ; cp eom ; end of message??? rbrif done pop hl ; increment dma ld de,128 ; add hl,de ; jp ms070 ; ;* ms080:: call txout ; defb cr,lf,'OK',cr,lf,eom call get$drive ; go get the proper drive code ld hl,buffer+0880h ; start = buffer ld (begin),hl ; pop hl ; end = last dma ld (last),hl ; ld a,03 ; command is write ld (command),a ; call doio ; and do the i/o call txout defb cr,lf,lf defb 'Operation Completed',cr,lf,eom jp 0000 ;* ;** ;* ;+ get$drive: ;- call txout defb cr,lf defb 'Enter 0 (Drive #0) or 1 (Drive #1) -->',eom call ci cp '0' jp z,gd99 cp '1' jp nz,gd010 ld a,20h ld (drive),a gd99: call txout defb cr,lf defb 'OK',cr,lf,eom ret ;* gd010: call txout defb cr,lf defb 'ERROR: Please Enter Either 0 or 1',cr,lf,eom jp get$drive ;* ;** ;* ;+ load$system:: ;- call txout defb cr,lf,lf defb 'Load System Function Selected',cr,lf,eom call get$drive ld hl,0d400h ld (begin),hl ld hl,0f700h ld (last),hl ld a,1 ld (command), wait5: ld hl,(lcmd@) ; recover last command jp dcmd1 ; and try again ;* wait2: out (clrint),a ; clear interrupt or a ; exit with non-zero ret ; and exit ;* ;** ;* ;+ ?putdma: ;-op: send dma address to host adapter ;-pp: rpntr has dma address ;- ld a,(hidma) ; set hi-byte out (dmaport),a ; high byte always zero ld de,(dma) ; de @ dma address ld a,d out (dmaport),a ; send byte 1 ld a,e out (dmaport),a ; send byte 2 ret ; and exit ;* ;** ;* ;+ ?select: ;-op: select controler ;- in a,(bstat) ; is controler busy?? and busy ; wait for not busy jr z,?select ; wait if so sel2: ld a,01h ; select controler #1 out (datao),a ; out (selport),a ; and select controler sel1: in a,(bstat) ; wait for req and req ; jr nz,sel1 ; ld d,a ; d=0, mark first command ; ;* now fall on thru to output command bytes * ; ;+ ?outcmd: ;-op: issue command bytes to host adaptor ;-pp: hl @ command bytes ;- in a,(bstat) ; grab 3 Copyright (c) 1979, Digital Research????????????CON:RDR:PUN:LST:DEV:VAL:USR:DSK:TTY:CRT:BAT:UC1:TTY:PTR:UR1:UR2:TTY:PTP:UP1:UP2:TTY:CRT:LPT:UL1:R/OR/WSYSDIRR/O R/W SYS DIR ** Aborted **Active User :Active Files: Drive Characteristics65536: 128 Byte Record CapacityKilobyte Drive Capacity32 Byte Directory EntriesChecked Directory EntriesRecords/ ExtentRecords/ BlockSectors/ TrackReserved Tracks is Temp R/O Disk: d:=R/OSet Indicator: d:filename.typ $R/O $R/W $SYS $DIRDisk Status : DSK: d:DSK:User Status : USR:Iobyte Assign: =Bad DelimiterInvalid AssignmentBad Delimiter: Bytes Remaining On R/, Space: Invalid File Indicator** Too Many Files **File Not Found Size Recs Bytes Ext Acc65536 set to R/O Invalid Disk AssignmentWrong CP/M Version (Requires 2.0)!9"2!T OË!]6:\:] Hr3 Ë:\ʀË͇ /ҋͺ *2!"q*"&L ͐ ͐ ͐!$p+q*#~*#N͐*##"#÷!&p+q͠*%DMͱ O O!(q*(&a call txout defb cr,lf,lf defb 'Loading System ...',eom call doio jp 0ea00h ;* ;** ;* ;+ doio:: ;- ld hl,command ld a,(drive) or (hl) ld (hl),a ld de,(begin) ld (dma),de ld a,1 ld (command+2),a ld (command+4),a doio10:: ld hl,command call docmd jr z,doio20 call txout defb cr,lf,lf defb 'ERROR: Disk I/O Error Detected, Operation Aborted' defb cr,lf,eom jp 0000 ;* doio20:: ld hl,command+2 inc (hl) ld hl,dma+1 inc (hl) ld hl,(dma) ld de,(last) or a sbc hl,de jp c,doio10 ret ;* ;** ;* ; ;* start of protocal handling routnes * ; ;+ docmd: ;-op: issue command to SCSI host adaptor ;-pp: hl @ command bytes to send ;- @actsec & @rpntr are valid ;-rc: no - zero : error in command (a = error bits) ;- zero : command was executed successfully ;- ld (lcmd@),hl ; save command @ ld a,retry ; get retry count ld (trycntr),a ; reset counter out (cparity),a ; reset parity error dcmd1: push bc ; save counter calbuss status ld c,a ; save status and cd ; see if data ret nz ; exit if data ld a,c ; check for direc and direc ; ret z ; exit if input ld a,req+bdack ; bit 0,d ; see if first cmd. jr nz,?oc5 ; brif not ld a,req ; else just check for req. ?oc5: and c ; check for ready jr nz,?outcmd ; brif not (1.75/1.17) ?oc1: ld a,(hl) ; get command byte (1.75/1.17) out (datao),a ; send to controler (2.75/1.83) inc hl ; point next (1.5/1.0) ld d,1 ; mark not first command jr ?outcmd ; and do it again! ;* ;** ;* ; ; dseg line$buffer:: defs 80+2 last:: defw 00 begin:: defw 00 hidma:: defw 00 drive:: defw 00 dma:: defw 00 lcmd@:: defw 00 trycntr:: defw 00 command:: defw 00,00,00,00 fcb:: defs 36 defw 100 stack:: buffer:: end mmand bytes * ; ;+ ?outcmd: ;-op: issue command bytes to host adaptor ;-pp: hl @ command bytes ;- in a,(bstat) ; grab L!*p+q*)O2'!,p+q*+O2'O2'O!.p+q*-LRRLR\LR" O!/q*/& L!1p+q*0#L~*##N!ͽ͞"T!Vq*VMͳ!Xp+q!W* >Wr#MͲ!_p+q!`6>!`6*`&*^*`&Y />!`4 >*]& ~ O!]49!a6:a*]& ~2bO>z*bM >!b/~,H~:H~*H~.H~>H~<H~=H*]& 6!]4T!]4!cq*a&Y :cw!a4!gr+s+p+q!h6>fr*d*f!is*d́"dPY! "f>!h#~Haͫo!h6:i0O͐!mr+s+p+q*lTZs#r*lڶ*l+s#r*jN#F+q#pÌ!nq!"o"q}2uo&"s* s:n*sDM2u:uqos*s"s*o͊O !v6>!vQ*v&w 6`i+46)A*:'ʓ:'O!) ~2vʍ:vO!w 6,]!v6>!v*v&w ~һ*vM !v4˜8AO͐:͐ͱ*##N!ͽ"* N#F*͠"l ?putdma ; set dma address call ?select ; go select controler pop bc ; recover bc ; wait: ; ;* here we must wait for execution * ; in a,(bstat) ; a <--- buss status and cd+req ; check for data jr nz,wait ; brif still data in a,(datai) ; a <-- completion status push af ; save ending status wait1: in a,(bstat) ; wait for req. and msg. and req+msg ; jr nz,wait1 ; in a,(datai) ; get byte of zero pop af ; recover status and 00011111b ; mask out errors jr nz,wait4 ; brif not ok in a,(bstat) ; check for parity and perr ; out (clrint),a ; clear interrupt ld a,0ffh ; jr nz,wait4 ; brif error xor a ; exit with zero ret ; and exit ;* ;* wait7: pop af ; clear out stack wait4: bit 2,a ; hardware busy?? jr z,wait6 ; brif not call txout defb cr defb 'Please Wait, Drive is Spining Up',eom jr wait5 ; and continue ;* wait6: ld hl,trycntr ; see if retry up dec (hl) ; jr z,wait2 ; brif retry is up >!H% - *DM ͱͷDM  ͱ* N#F 9ͱ * ^#V))DM Tͱ* ~ *} *M!+s#r#4 !s+p+q!6!66:!ڄ !6!6>!r *&**&Y i !6!4+4A :} :!4- >!699 2¨ :!4: :2!6+6>! :O!9 DMi ͱ:!O!Y DMi :2:2͠!4 F :® )!6>!ګ ͠:O!9 DMi 8ͱ!6> !ڤ Å :2k ä  ͐:!O!Y DMi w !4C F :¿ >F : F :=229:Y= ;>9*&Y DM =2 I>!6:=28 :2:2 :!!29:Y T >:Y,e \>Ì !p+q*~:ʉ *N͐*#"o :͐!p+q!'"!6> **{2*́"PY! ">!+~H !6:0O͐à k͐!p+q* !q*& *M *M !p+q*!!p+q*"!p+q*$!6  !kp+q*j> >ڪ Þ !qp+q/ *pDM9: :M2r:N!r !:r *r& N!r4 !6:͔: :ͳ.!ws+p+q+p+q:w=2wN *s*u w*s#"s*u#"u' !"*M^7 !x6:!xھ **DM͆ 2yʭ :yʗ ͯ *"*6:2x÷ *"!x4d !"/ !j}=2| !"*KM^'_ !z6:|!z1 * "}*}DM͆ ' ͯ *"!z4 :e !"͆ !z6:|!z '? 2*H#"H!{6:{ր!Ң *{& :{4 2!{4m *":ڹ ͯ !z4I '2!"!q: !4>!S :S! :2*M! ^#V͎ * :w*#" = = = = = ͯ  *M !6q  !6q  !6q  *& !6à  !6 à  !60à  *& !6  !6  !6  *& . 1 4 7 : = F P [ f q  ͠Q" 8AO͐jͱͷDM͏ m  Z"l"!6>ʥ *}҆ *M ͱ*}x O͐} W͐ͱ !+s#r!+s#r#4D ͠:\ʹ :\=Oͳͩ !6!)6l :) :)=2) :] & !"}2\!h6?!j6?\:'C:'ƀo&")!)6!"):)/)HҘ]!)6> !)ڎ*)&*)*)&*) y!)6 Ä:) 2):)<2)M*)#")/:)ҩ*)+")`*")#"]!*)!/H!")!"]*)) *)s#r!)6> !).*)&*)*)&*) w:)<2)*)) >w#6*)) w#6*)!) w#6*)%) w#6*)) N#F*)) q#p*)%) *) ~e *) * ~o&͞ *)%) q#p!)6* >!)6!)6>!)=:)!)w=*)&*)~2):)*)& *):)2):):*)!) *)) s, >X\:)“>!d!")>!)d!")!")*++!)a*)) ^#V")]*)")*)) ^#V")]!)6> !)T*)&*)~2)*)&*)~2)O;*)) ^#V"(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE)(INP:/OUT:SPACE) COPYRIGHT (C) 1979, DIGITAL RESEARCH, PIP VERS 1.5$$$ SUB =.:,<> _[]INPIRDPTRUR1UR2RDROUTLPTUL1PRNLSTPTPUP1UP2PUNTTYCRTUC1CONNULEOFDISK READ ERROR$DISK WRITE ERROR$VERIFY ERROR$NOT A CHARACTER SINK$READER STOPPING $NOT A CHARACTER SOURCE$ABORTED$BAD PARAMETER$INVALID USER NUMBER$RECORD TOO LONG$INVALID DIGIT$END OF FILE, CTL-Z?$CHECKSUM ERROR$CORRECT ERROR, TYPE RETURN OR CTL-Z$INVALID FORMAT$HEX$$$$NO DIRECTORY SPACE$NO FILE$COM$START NOT FOUND$QUIT NOT FOUND$CANNOT CLOSE DESTINATION FILE$DESTINATION IS R/O, DELETE (Y/N)?$**NOT DELETED**$$$$$$$NOT FOUND$COPYING -$REQUIRES CP/M 2.0 OR NEWER FOR OPERATION.$UNRECOGNIZED DESTINATION$CANNOT WRITE$INVALID PIP FORMAT$CANNOT READ$INVALID SEPARATOR$1 :2L> ̈́M9  :2!q: " *M n :c4 *M n :2!c:Q !c:2: !:cw>!n !5 Y : { !6!q:!lwҙ  â :0O !q:O| :O| !6:]2l:o'2o:n'2n:m'2m*mMͣ *nMͣ *oMͣ :]:   *}2D" * * *&"!q:UY: Y:ҩ: ʩ:_2ʘ:€!6<:<2!ژ!6 >!]Ҥ; !6:Q::H: !6*M : !6!q:a/>z!/H:_2:!q:A/>Z!/H8: 2::=O>m:W!Q} Hmd>9>!6:2*M!E ^#V͎ڗO **~2*#"m2m͖ 2m!6m!6m!6 m2mͯ m!62m!62m!62m!62m'2:2:TҒ:2!6*ME:2::Ҳ:<22ý: 2:} >ͯ :i:2:d*M:[ )*)) *)) N#Fq#p*)) *)s#r*)#")!)6 J:)!)J!)6 :)<2)*)")҈q:tw͠ͱ!"))ҍ*)) ^#V")]͠.*)DM\ -°!\6:\ͣ:ͱ*}DM'ͫ*)%) N#F'ͫ*)!) N#F'k͐ͫ*)) N#FͫR͐/͐ *) ~IO͐NW͐ͫ8AO͐:͐ *) ~2)t(͐:)҃)͐*)#")Ã& \!"))\Ұ*)")]͠*)M! ^#V *) >*) w *) >*) w *) >*) w *) >*) w.*)DM\ -+!\6uͱ:)O! DMͱ*)#")Ù*))))))"):m w>.Yn -:YS:Z Hҧ!6> 2)½>!)6> !)*)&*)>2) :) .͐*)M͐:)<2)99:Y=/9&ͩ c,Hͩ 9 EHͺ i`N#Fog_og_ogDM!>))덑o|gҘ =†DM!>))ҭ =¥~ ³^#V) ½^#V|g}o _{ozgi`N#Fogo&og_{_z#W221@:2!o6+6+6!6#6!6#6:G*o .!N6:^*M^!K6!6!6+6' :$::=2K  :ʤ\:ҷ\x'Ͳ:!\͢  :͈'! Ͳ:$: $͈Ͳ!N6' :!Cwͯ !6:^͢c!6{:/>!/H{ͯ :<2Š ::=HҮͯ !6:Ҿ:2 !6::/H͈;!6:> !/>HHͯ :^!w:<2:0}:@E}:!S!W6: z!]6:cm!c6:_z!_6l ::,: HHҰͯ : 2ó:E:1:2v!q!*8!*6: >ͦ>ͦ!q:_  !p+q.*   !q*&!p+q*2!p+q*2!p+q*22!p+q*!p+q*!p+q*!p+q*2!p+q**M:>!(:=2%> >>!F!5+N! ~2!4<2T>>!b}*bMͭz:b2!b6:<2é>!`ҥ*`MͭҞ!`6!6> :é:(!q:!wO! ~2*& :w>!:!4!6>:N<2N!> *N& N2 !p+q!6!6+6 !6: S: M!6g8:N2M*M8p!6!6!6>!ڕ*&P 6!4z!6!6#6#6!6*M8:ھ:*͇g2ê::¿::,͡A<2O>*M8):[ͱ!N5!6ñ:5!6#6>!ڰ!6:<2O>/:!O!T *M͡H~K:¡!6[–ͱ!N5:2:2!4=:[¼ͱ4:!6:.2O8: :* ͇g:[ ͱ!N5!6:%:<2*6 * 6å!q!6> !d*&I :]>!4A>:<2O* :w:?†!6!q!6?!:ҠgÐ!q*&*~!6:22: :]Hں:A2O>: 2ͯ DM!  ::=H-\:N2O_og_{ozg^#V))) _{ozg^#V) d^#V|g}o n_{ozgO{ozgi`N#Fogo&og H ©=¨blocks db dir&dn ; Directory blocks db 2 ; Sector size 512 bytes dw 16*heads&dn ; Sectors per track dw cyls&dn ; Total tracks on disk dw hoff ; Reserved tracks .xall dstlen defl $-dst&dn endm ; ; ; scsi controller opcodes OPRDY EQU 0 OPZERO EQU 1 OPSENS EQU 3 OPFORM EQU 4 OPREAD EQU 8 OPWRIT EQU 10 OPSEK EQU 11 ;***************************************************** ; DTC-10 PORT ADDRESSES ;***************************************************** ; controller addresses CBASE EQU 050H BSTAT EQU CBASE+2 BCON EQU CBASE+1 DATAIN EQU CBASE+0 DATAOUT EQU CBASE+0 ;***************************************************** ; DTC -10 STATUS EQUATES ;***************************************************** ; controller status codes BUSY EQU 08H REQ EQU 80H SLCT EQU 40H DODATA EQU 02H ; ; ; ; ;*** Status and error bits ; secs equ 16 ;Physical sectors per track per head ; ; DSEG ;DATA STUFF ; DMXSPH: ;MUTUAL EXCLUSION SEMAPHORE DW 1 ;SE÷:S:QHI:N<22: H@"2Í202O> c!6Í202O> ڍ*&O*& !sc*&P :w:·>!ұͯ :22:_!6=!6>'!E!4!p+q*0 !r+s+p+q*~$7*>*>H&>*#"*#"> 2:R͎:!6!6=2:ʙ!6:“H9Ž>!6-e!6ͻ2=2ʺ-é:>>"ͻ2:!!5ͻ2ͬ!\-:>>!p+q:,!6*DM9:<!6:z 2W!6D*&L :w:<2Ov*:>=20O> ڒ:0:AO>Ҥ::A }}Hͬ!wͻO`idͻV[2O>2:!X!6:!:=O!L NE!4 E E:/.*&L 6$L9k9.Xͯ *KM^020 :020:121'ͳ':²ͯ !G6!"!"7 *M^n/ :a/:H!6:ͯ !&6 TITLE TURBODOS OPERATING SYSTEM - IOMEGA DTC-10 DISK DRIVER .Z80 ; NAME ('IOMEGADR') ;MODULE ID ;***************************************************** ; Comment: ; this driver package is constructed in a way that should make ; it easy to add other SCSI drives to this interface. ; ; It is however at this time restricted to IOMEGA. ; It will handle up to 4 subsystems by changing the ; equates in two places. Hd0,1,2,3 and hddsks. ; ; author: Peter H. Mack (805) 527-0737 ; date: July 15,1983 ; rev: ------------ ;***************************************************** ; INCLUDE DREQUATE.LIB ;O/S SYMBOLIC EQUATES ; FALSE EQU 0 ;DEFINE LOGICAL VALUES TRUE EQU NOT FALSE ; ; ;*** Hard Disk selection choices *** ; IOMEGA EQU 1 ; Iomega 8 inch cartridge ; ;*** IOMEGA Disk equates *** ; HOFF EQU 1 ; Number of reserved tracks for loader ; ;*** IOMEGA Physical drives *** ; hd0 equ IOMEGA ; Set to type of drive or false if not used hd1 equ false ; all drives musMAPHORE COUNT ..DMXH: DW ..DMXH ;SEMAPHORE P/D HEAD DW ..DMXH ; HDCSPH: ;HDC SEMAPHORE DW 0 ;SEMAPHORE COUNT ..HDCH: DW ..HDCH ;SEMAPHORE P/D HEAD DW ..HDCH ; dmaptr: ds 2 ;temporary dma pointer storage sector: ds 1 ;temporary sector storage seccnt: ds 1 ;temporary sector count storage drive: ds 1 ;temporary drive number storage ; ; cdb - command data block CDB: DS 1 ;(1) group/opcode DS 1 ;(2) lun/block msb (always 0) DS 1 ;(3) block addr msb DS 1 ;(4) block addr lsb DS 1 ;(5) number of data blocks DS 1 ;(6) special option (always 0) ; ;***************************************************** ; Main dispatcher routine ;***************************************************** ; CSEG ;CODE STUFF ; ; IOMEGA INITIALIZATION ; DSKIN@:: CALL DINIT ; RET ; DINIT: RET ; ; DISK CONTROLLER DRIVER BEGINS HERE ; DSKDR@:: LD HL,DMXSPH ;GET MUTUAL EXCLUSION SEMAPHORE CALL WAIT## ;DISPATCH IF NECESSARY CALL ..DD ;CALL DISK DRIVER P2*">!b!ͯ >!`0ͯ !q:E:24J!46*}a!44EJ *KM^'́:‚ͯ !36'n::0:f9OY#9.3'ͳ.:020' 'ͳ'7 6'!j>A+!s!"@͓1!"<**"͓n "Dn"":!Q2҂:X!Wғä:ڤ*MEÓ:ұ@@:O2Mc;!6#6>!)*&P ~"::H:H:H:H"!6!4:_jYO jM*"S*" 3@bl*M1͓!""7 *M^͆ \͔!":͎H*#"ͧÝ/ :>͛9ͯ .*#":_!' !'6!36' :1/!aE*#">z?C9IͲÁ.!6> !ڇ*&' ~2 ʀ: y.*M!4Q>!қ:=2á:2:Ҭ\>!ҿ:=2K:2K!:!:K\: \!p+q͈*t have same interface type hd2 equ false ; i.e. all SA1000 type or all ST506 type hd3 equ false ; TST MACRO DN ;physical hard disk defined IF HD&DN x defl 1 else x defl 0 endif endm hddsks defl 0 ;number of physical hard disk drives hdtst macro rept 4 tst %hddsks ;test all four physical drives iff x exitm endif .lall hddsks defl hddsks+1 .xall endm ;end rept endm ;end hdtst hdtst ;calculate number of physical hard disks ; ; dsktyp macro dn,typ .sfcond if typ eq IOMEGA strate&dn defl 10 ; 10 MS cyls&dn defl 306 heads&dn defl 4 fixed&dn defl false ;cartridge drive endif dks&dn defl heads&dn*(cyls&dn-hoff)*2 ;hard disk size in blocks ;dir&dn defl ((dks&dn / 128) + 1) ; DIR entries = blocks / 128 dir&dn defl 8 endm x defl 0 rept hddsks dsktyp %x,hd%x x defl x+1 endm dstdef macro dn ; Disk specifcation table defination macro .lall dst&dn: db 5 or (80h and fixed&dn) ; Block size 4K bytes dw dks&dn ; Total USH AF ;SAVE RETURN CODE LD HL,DMXSPH ;GET MUTUAL EXCLUSION SEMAPHORE CALL SIGNAL## ;SIGNAL PROCESS AS READY POP AF ;RESTORE RETURN CODE RET ;DONE ; ..DD: LD A,(IX+PDRFCN) ;GET PD REQ FUNCTION NUMBER OR A ;PD REQ FUNCTION NUMBER=0? JP Z,RDDISK ;IF SO, CONTINUE DEC A ;PD REQ FUNCTION NUMBER=1? JP Z,WRDISK ;IF SO, CONTINUE DEC A ;PD REQ FUNCTION NUMBER=2? JP Z,RETDST ;IF SO, CONTINUE DEC A ;PD REQ FUNCTION NUMBER=3? JP Z,RETRDY ;IF SO, CONTINUE DEC A ;PD REQ FUNCTION NUMBER=4? JP Z,FORMAT ;IF SO, CONTINUE RET ;ELSE, DONE ; ;***************************************************** ; Return ready - opcode 3 ; returns ACC = 0ffh = ok ; 0 = error ;***************************************************** ; retrdy: ld a,oprdy ;iomega opcode ld (cdb),a call setcdb ret z call docom call cmpstat cpl ret ; and leave ;***************************************************** ; Return disk specification table - opcode 2 ; returns ACC to be used, then this will have to be ; rewritten. ;***************************************************** selblk: ld L,(ix+pdrtrk) ld H,(ix+pdrtrk+1) call shftlh ;*2 call shftlh ;*4 call shftlh ;*8 call shftlh ;*16 call shftlh ;*32 call shftlh ;*64 ld E,(ix+pdrsec) ld D,(ix+pdrsec+1) add HL,DE ;add sectors call shftlh ;blocks = secs*2 ld A,H ld (cdb+2),A ld A,L ld (cdb+3),A ld A,(ix+pdrsc) ;sector count rlca ;mult * 2 ld (cdb+4),a ret ; ;***************************************************** ; set up cdb ; returns ACC = 0ffh = ok ; 0 = error ;***************************************************** ; setcdb: call seldrv ret z call selblk ld L,(ix+pdrdma) ld H,(ix+pdrdma+1) ld (dmaptr),HL or 0FFH ret ; ;***************************************************** ; select drive ; returns ACC = 0ffh = ok ; 0 = error ;***************************************************** ; seldrv: ld A,(IX+pdrdrv) ;get requested d CMPSTAT: in a,(datain) ;input completion status ld C,A ;place in c for further use. LREQ: in A,(bstat) ;looking for last req ld B,A ;save for checking and req ;check for req jr z,lreq ;loop until found in A,(datain) ;input last byte o A ;se i las byt no zero jr nz,seterr ;if last byte non zero ld A,C ;now check completion status and 09FH ;to see if it is zero jr nz,seterr ;if not zero xor a ret SETERR: ld a,0FFH ;set error flag ret ;***************************************************** ; read data from disk ;***************************************************** READDAT: ld HL,(dmaptr) ;load data pointer RDREQ: in A,(bstat) ;input bus status ld C,A ;store for further checking and req ;look for req jr z,rdreq ;else loop ld A,C and 10H ;check for com jr nz,cmpstat ;if com present must be complete in A,(datain) ;input data from controller ld (HL),A inc HL jr rdreq ;********************************************= 0ffh = ok ; 0 = error ;***************************************************** ; retdst: call retrdy ;is drive ready or A jr nz,dstrdy ;if so skip ld (IX+pdrdst),A ; otherwise zero dst pointer ld (IX+pdrdst+1),A ret ; and return dstrdy: ld A,(IX+pdrdrv) ;get requested drive ld B,A ;and save for mult add A,A ;*2 add A,A ;*4 add A,B ;*5 add A,A ;*10 add A,B ;*11 ld HL,dstbase ;get base address of dst tables ld E,A ;make offset 16 bits ld D,0 add HL,DE ; and put together ld (IX+pdrdst),L ;save for return ld (IX+pdrdst+1),H or 0ffh ;set valid return flag ret ; and leave ; ;***************************************************** ; read disk - opcode 0 ; returns acc = 0 ok ; 0ffh error ;***************************************************** ; rddisk: ld a,opread ;set up command ld (cdb),a call setcdb jr z,rds02 ;exit error ld B,10 ;retrys rds01: push BC ld HL,cdb call docom call readdat pop BC and A rive cp hddsks ;make sure valid drive number jp nc,selnrdy ;exit if not rlca ;put drive into proper place for command rlca rlca rlca rlca ld (cdb+1),a or 0FFH ;set worked flag ret selnrdy: xor 0 ;return not ready ret ;***************************************************** ; get controller ;***************************************************** GETCON: in a,(bstat) ;input from status port and busy ;mask select bit (busy) jr nz,getcon ;if busy, keep looping ld a,slct ;assert select out (bcon),a ;to get controller CBUSY: in a,(bstat) ;input bus status and busy ;look at busy jr z,cbusy ;loop until we aquire controller ld a,dodata ;data enable out (bcon),a ret ;***************************************************** ; do a command ;***************************************************** DOCOM: call getcon ;get controller call outcom ;output command ret ;***************************************************** ; output commands ;********* ; SHFTLH -- SHIFT LEFT HL 1 BIT POSITION ; CARRY CONTAINS MSB ;***************************************************** .8080 SHFTLH:: PUSH PSW ANA A ; CLEAR CARRY SHFL: MOV A,L ; SHIFT LOW RAL ; ROTATE 9-BIT ACC LEFT MOV L,A MOV A,H ; SHIFT HIGH RAL MOV H,A POP PSW RET .Z80 ;***************************************************** ; disk specification tables ;***************************************************** x defl 0 dstbase: rept hddsks ;define disk specification tables ; for all hard drives on controller dstdef %x x defl x+1 endm end ret z ;exit ok dec B jr nz,rds01 rds02: ld A,0FFH ret ;error exit ;***************************************************** ; write disk - opcode 1 ; returns acc = 0 ok ; 0ffh error ;***************************************************** ; wrdisk: ld A,opwrit ;set up command ld (cdb),A call setcdb jr z,wrts02 ;error ld B,10 wrts01: push BC ld HL,cdb call docom call writedat pop BC and A ret z ;exit ok dec B jr nz,wrts01 wrts02: ld A,0FFH ret ;error exit ;***************************************************** ; format routine Opcode - 4 ; (not applicable for iomega drive) ;***************************************************** ; format: xor A ; Otherwise set good return ret ; And leave ;***************************************************** ; load block cdb with block number and #blocks ; comment: the iomega drive system is addressed by block ; numbers this routine assumes a constant of 128 blocks per track ; If other drives are ***************************************************** OUTCOM: ld HL,cdb ;load cdb pointer COMREQ: in A,(bstat) ;input from bus status ld C,A ;store in reg(c) or A ;set status flags jp p,comreq ;wait for req and 10H ;check for com/data ret z ;return if data req. ld A,C ;also see if controller and 40H ;switched direction ret z ;if it wants to send data,return ld a,(HL) out (dataout),a ;write commands to controller inc HL jr comreq ;loop as long as commands are requested. ;***************************************************** ; write data to disk ;***************************************************** WRITEDAT: ld HL,(dmaptr) ;load pointer to data DAREQ: in A,(bstat) ;input bus status ld C,A and req ;set flags jr z,dareq ;loop for req ld A,C and 10H jr nz,cmpstat ;on receipt of command complete status ld A,M ;get data out (dataout),a ;output to controller inc HL ;increment controller jr dareq ;go back for another byte SQQ`dE4M-ISHFTLH Mce@ px@\". K% ` pA,f .hdO*YVzʨU/ $|amd3h 6,^ۧpct dO:C6[Pct {?#@3n$1D8DEYdD> 6 @`SC@XMX*v@@?*Ktnlͮ,ͮ,ͮ-VY2`іnqdoX!iSt `?_p8 =p)9(N`@>4,mfH6Dʐ ˘?40ðUe"{(|\(@)CP[2|@WGH6D2P<lwU9.o>H dE4E$DSKIN@4eDĈȘSIGNALEtIdoX!iSt `?_p8 =p)9 ! ~ 3#0 Wx x ڀ ڂ G ~ # 3x~#B!Y~ɯ2:߷=!߾ý:߷=!߾:ý^T!~  6?#ˆ:`O> K{͘A͒>:͒͢>:͒͢xK > K > ͒x  ͢ØÆ^ BRͧ9!5‚#~Y‚#"T<ÆALL (Y/N)?^ Tʧ͘!6!~ڇ ݯw4!Y~ʆ͌†t=ʆf ^ T ݯ2o&)|+!<ͧÆNO SPACE^ :Ty!B*O=?_s#"^sG!~Y޸psp2mÆÆf ͧÆFILE EXISTS _: É: :߷ʉ=2)ͽÉ T!@k!}|q=qf^!~2>`~2߯2\!!B!~> >#0~O#Cx2͘1)ͽÂf zͧÆBAD LOADCOMf^: !߶ Â$$$ SUB *C ^OT *C~wD -'  -@ͦ~^*C Ox! N!Fwyxʋ>ڋ>*Cw~#+w#w+ɯ2E22i^ *C :~w~͔͔# #  w ~>2!E5T*C!"C"C!w# F! w͌x2͢*C ~<wʃG:!ʎì 4~ʶ¬:<ʶ$ʶïZͻx>2>2ͻ:!Z2:Eẅ́͊Ͳ>2>2T*CGͻ:ẅ́n>2;O ^DM;}H>"*C ::ddslO s#r:E͊:==»y==»*Ww#*"͸*:G#š"͸:!w4!iw:Z!E~=262*C!!~~#~O~G#n,-.‹! w! yG!x͢.:E<ʄ! q!pQ:E<. ʄ$.:E<ʄi6}2ExN! ~态O>G~G!~G} *C!r#r#r ^ͥ_y#x#{g"C{2!"E9"1A22!ty)K!G_^#V*C~E ,&-AGMS!!ô!ô!Bdos Err On : $Bad Sector$Select$File R/O$:BA2!~6 O͐  :E B 2>: b# : y! 4 5~yy5 6yҐ^H@Oy H H: –ͬ  #H: !  Hù H H $O͐: 2 *CN# x: 2 p&x~+é72 H! >w_: ! 5ͤNkͱ¦ͱxʊ#Nx: ! 2 ͤ! 5™#wO~x½p Hy<< ʑ :!qMD#2E>! ^#V w#P:BO|^#V#"##"##"##"!O*!O*|!6ʝ6>*w#w*w#w'û*! J*""!N#F*^#V*~#foyx*{_zW+*s+p+q-*C ͥ!!q#p#w*:BOYG}*MD "ã:!Bw!>2*C~=2u:B2~2wE:A*Cw>"!""2B!"!rQQQâ~?ͦ~?rQ*"CQ-Q͜QüQrQ$Q*):B"*)*)Q;*"E:;:A2AQÓQÜQ*C}/_|/*W}_*"}o|g":ʑ*C6:ʑw:2E**E}DQ>2AÖÚÞâüpØtxØ|ÀæN   :!_zV#_~  :!):!!!1: !9:1d͘|^#VS*3!1NFx(BtNF C͘7?KnfB8C[MDx| #*5"!">22*3:OvWarm boot error-reset system $\X COPYRIGHT (C) 1979, DIGITAL RESEARCH _͌> ͒> Ò> Ò͘~#͌ì _2<د2 ه!߶2:2a{_:߷ʖ:߷>Ľʖ:=2–!B!6#5ʖ:߷Ľ!ͬʧ )!F#xʺ~0wëw!" !~6ͽ:ý(!#͘*~ "ڷ"͌#>?͌͘ =_.:;<> Oڅo$>!Y2*O"ʉ@G:ʐ:wÖx2p0ʹ#*©6?ëw˜0ï#6 ¹.0#*6?w0#6 #6" #~?  xDIR ERA TYPESAVEREN USERg!yO#< Ty#O 3ۯ21y_͸2y2ͽ:ط˜1͘A͌>>͌92^ :߷¥.!_~#fow]ݭގޥ!v"!çREAD ERRORçNO FILE^:߷yx#*DM*s#r*s#ryOxG*0MD!!N: EG>O: \S*C :qn& ^#V>O^"*}:*)=":O:o"*C *C!ͮ~2~2ͦ:2ͮ:O:w:w |g}o*# ):BO!yoxg*:BO}!N#F "*#*s#r^ ~!J! J*:o$*C~i6iw**{#zr+s{ozg**͕** ,w͜͸Ͳ!!N#F$**O!~#:A#~$=2Ek͌::/GyO>2!q*C"͡ʔ*JҔ^:Oyʃ?|x | s-|N-# S:2E!~Яw>T D^6k-äPYy 5*{zBK5*|>Gx((Ox& }<2~sT1T*$} ͌[! w}<2{TMAyx >/:(>>2>(y>ÌÝÎÓBÊ FLOPPY rErE8?@/ _      y2y2CG 8"~G:G:~ >2> !5 Um-͚ >> 2 :O :G:y~ :28 q*~(P>(=(!& :22ͺ>2 /E͙0zW: #͢8 /2:2 >2>2v /2{l: >2 /*>2>2**":̓v"2 *~(͙8ͺ {l:2 >2>2E> 2 > :G /_~(!*: { _{: # U-͚ >WJ(  m space: defb " ",eom skip: defb "Register Dump af, hl, de, bc" crlf: defb cr,lf,eom dr: endm ; .list ; ; ; subttl Equates and Constants page ; ; *** ASCII constants and User Options *** ; aseg bell equ 0007h ; sound console bell cr equ 000dh ; cariage return lf equ 000ah ; linefeed ffd equ 000ch ; formfeed xon equ 0011h ; ^q xoff equ 0013h ; ^s eom equ 0000h ; end of message marker false equ 0000h ; true equ not false ; retry equ 0010 ; Retrys before Hard-Error msize equ 0060 ; 60k system. ; ; ; *** Port Assignments *** ; SCSI$base equ 0050h ; SCSI Interface board base QUAD$eia equ 0010h ; Base port for QUAD. eia board crtstatus equ QUAD$eia+4 ; Status port for console crtdata equ QUAD$eia+5 ; Data port for console ; txrdy equ 0001h ; Tx. Ready bit in 8251 usart rxrdy equ 0002h ; Rx. Ready bit in 8251 usart ; ; *** SCSI Port assignments *** ; ; * bit,byte and port assigment: =2 W{((y~:: :U>: ~ ( w:2F8 <2 y2:W: *KB(7:Gz?"*":G2xG![2 G!zi` n&y P:ʋ>2*PY}(|˘A8g ѷ> :2z2g22w<2*!"f":(8 VU>w(>>wz2~: Â_Gy_()gD͂ <`G.͓|y2!$O͞Ɛ'@'OÞCan't recognize density of disk in$Read$Write$Seek$ error on track $ sector $ side $ drive $ The diskette in$ is write-protected. Remove the diskette and put on the write protect tab, then type any character.$ Type a control-C if you wish to abort the operation instead $ is not ready. Insert diskette, close drive door, and type any character to continue.$ title CP/M Ver 2.2 BIOS for SCSI Host Adaptor name ('bios22') ; date 20-Jun-83 ; by David Wagstaff ; copyright 1983 by Griffin Tech. All rights reserved ; ; .z80 ; z-80 coding is used aseg ; Absolute addressing is needed ; subttl Introduction, Externals, Internals and Macros ; ; ; This module contains the Basic Input/Output System for ; version 2.2 of the CP/M operating system. ; Portions of the Serial port I/O have not beened coded for ovious reasons ; therefore, this task is left to the customer of this product. ; The equate 'SCSI$BASE' has be equated to the base address for the SCSI ; interface board, the current value is 050h. ; The equate 'MSIZE' should be set to the size of the operating system ; to be gen'ed, typicaly this should be about 60k. ; ; ; ; ** >> Editing History << ** ; ; Ver. Date Modification ; ---- -------- ---------------------------------------- ; 00 06/20/83 1) Created. ; ; ; .xlist mdbe macro vals for * ; * SCSI host interface adaptor * ; datai equ SCSI$base ; data in register datao equ SCSI$base+2 ; data out register bstat equ SCSI$base+1 ; bus status selport equ SCSI$base ; select port adr. clrint equ SCSI$base+1 ; clr. intrrupt port dmaport equ SCSI$base+3 ; dma address port cparity equ SCSI$base+4 ; clear parity port busy equ 80h ; controler busy bit cd equ 40h ; command/data bit direc equ 20h ; directon bit req equ 10h ; request bit msg equ 08h ; end message bit perr equ 04h ; perr error bit bdack equ 02h ; board ack. signal lint equ 01h ; interupte bit ; ; *** Cartriage storage information for IOMEGA system *** ; ncyn equ 306 ; # track/drive nscyn equ 64 ; # sectors/track ?nbsct equ 2 ; # blocks/sector nbblk equ 256 ; # bytes/block nbrec equ 128 ; cp/m record size bls equ 2048 ; cp/m block size drm equ 512-1 ; # dir. entrys -1 bysct equ nbblk*?nbsct ; # bytes/sector nbcyn equ nscyn*bysct ; # bytes/track ï!1 !; !`|G^22y:??!H͞͞:"1O͞:*81O͞ Super Quad CP/M v X2.0 Typeahead installed $K CP/M 2.2 installed Default console is serial port $ Default printer is $parallel printer driver$serial port $ $ 00O>0GD`D ! ~ 3#0 Wx x ހ ނ G ~ # 3x~#B!Y~ɯ2:=!ý:=!:ý^T!~  6?#ˆ:`O> K{͘A͒>:͒͢>:͒͢xK > K > ͒x ue,sp ; macro to print version or date defb (value shr 12)+'0' defb ((value shr 8) and 0fh)+'0' defb sp defb ((value shr 4) and 0fh)+'0' defb (value and 0fh) +'0' endm ;*** debug macro mesg,values ; macro to debugging bios local dm,dr,space,skip ; 'mesg' is a ASCII string local hlx,dex,bcx,afx,ard ; to be printd, 'values' is local crlf ; a list of memory location jp ard ; to dump to the terminal. hlx: defw 00 ; A register dump will also bcx: defw 00 ; be printed on the console. dex: defw 00 afx: defw 00 ard: ld (afx),a ld (hlx),hl ld (dex),de ld (bcx),bc push af push hl push bc push de ifnb irp val, ld hl,(val) call ?pdec ld hl,space call ?prtmsg endm endif ld hl,dm call ?prtmsg ld hl,skip call ?prtmsg irp val, ld hl,(val) call ?pdec ld hl,space call ?prtmsg endm ld hl,crlf call ?prtmsg pop de pop bc pop hl pop af jp dr dm: defb mesg defb cr,lf,eonrsct equ bysct/nbrec ; # recs/sector nrcyn equ nscyn*nrsct ; # recs/track nrecbls equ bls/nbrec ; # recs/bls nblscyn equ nrcyn/nrecbls ; # bls/track dsma equ nblscyn*(ncyn/2); size of an logcal drive A: dsmb equ nblscyn*(152) ; size of B: offset equ 0001 ; track offset for System Track ; ; * IOMEGA command set * ; fmtztrk equ 10000b ; format z-track flgsct equ 10010b ; flag sector flgtrk equ 10100b ; flag track c?seek equ 00110b ; seek track c?home equ 01000b ; ?home drive reqst equ 01010b ; reqest status reqes equ 01100b ; reqest extended status ctest equ 01110b ; test contrl. status rddata equ 00001b ; read data rdid equ 10101b ; read id rddtof equ 11001b ; read data with offset rddiag equ 10001b ; read diagnostic wrtdata equ 00011b ; write data wrtid equ 00111b ; write id wrtdiag equ 10011b ; write diagnositc ; ; ; ; *** CP/M Enviroment Constants *** ; tpa equ 0100h ; Address of start of tpa bias eq defw drm defw 0ff00h ; debug = 0ffffh defw (drm/4)+1 defw 9ah ;**** ; ; ; *** >>> Disk Parameter header tables <<< *** ; dpbase: ; defw 0000,0000 ; Drive A: defw 0000,0000 ; defw dirbf,dpAblk ; defw chkA,allA ; ; defw 0000,0000 ; Drive B: defw 0000,0000 ; defw dirbf,dpBblk ; defw chkB,allB ; ; subttl Boot and Warm Boot Routines page ; ; ; *** >>> Start of BOOT and WARM BOOT Routines <<< *** ; ?boot: ;-op: Handle misc. initilization and signon message printing ;-pp: none ;-rc: none ;- xor a ; clear IOBYTE ld (iobyte),a ; ld (cdrive),a ; and current disk ld hl,signon ; go print sign-on message call ?prtmsg ; ?gocpm: ld a,0c3h ; a = op. code for 'jp' ld (0000h),a ; vector @ 0000h ld (0005h),a ;& vector @ 0005h ld hl,bios+3 ; location of wboot routine ld (00001h),hl ; save it ld hl,bdos ; location of BDOS ld (0006h),hl ; save to system vector ld a,(cdrive) ; get the current disk ld c,a ; to register c  and rxrdy ; ret z ; exit if not ready or 0ffh ; else with with true ret ;* ;** ;* ;+ ?conin: ;-op: get character from the console ;-pp: none ;-rc: a = character (parity bit striped, i.e. only 7-bits present) ;- call ?const ; Wait for character ready or a ; jr z,?conin ; ; ; >>> Supply Code here for your hardware configuration <<< ; >>> register a will receive character, port has character ready <<< ; Sample code is provided for a 8251 type usart. ; in a,(crtdata) ; grab the data byte cpl ; our hardware complements the data register ret ; and then exit ;* ;** ;* ;+ ?conout: ;-op: send character to console ;-pp: c = character ;-rc: none ;- ; >>> Supply code here for your hardware configuration <<< ; Sample code is provided for a 8251 type usart in a,(crtstatus) ; wait for tx. ready and txrdy ; jr nz,?conout ; remember our hardware ld a,c ; a = character to send out (crtdata),a ; eject the character ret ; and then exit ;* ;** ;* u (msize-20)*1024 ; ccp equ 3400h+bias ; Base of CCP bdos equ ccp+0806h ; Base of BDOS bios equ ccp+1600h ; Base of this bios iobyte equ 0003h ; Address of IOBYTE cdrive equ 0004h ; Current disk indicator nsects equ (bios-ccp)/128 ; # of sectors/ ccp ; ; ; *** IOmega blocking size equates *** ; bufsz equ 2048 ; Data blocking size mgablks equ bufsz/256 ; # of iomega blocks cpmblks equ bufsz/nbrec ; # of cp/m records mask equ 07h ; see following table ; ; ******************************************** ; * the value of "mask" determines the block * ; * buffer size of the deblocking routines. * ; * the value of "mask" are: * ; * bufsz mask * ; * ----- ---- * ; * 2048 07h * ; * 4096 0fh * ; * 8192 1fh * ; * 16384 3fh * ; ******************************************** ; ; ; ; org bios  jp ccp ; and pass control to the CCP ;* ;** ;* .xlist signon: defb cr,lf,lf,lf defb "BIOS220 --- CP/M Ver. 2.2 BIOS 20-Jun-83",cr,lf crlf: defb cr,lf,eom .list ;* ;** ;* page ;+ ?wboot: ;-op: Warm Boot CP/M system. ;-pp: System Tracks of Drive A: has a valid system on it. ;-rc: CCP is reloaded into core from system tracks ;- ld sp,0080h ; set-up the stack to free area call ?flush ; flush disk cache ld hl,-1 ; force new reads ld (@rblk),hl ; ld a,'W' ; mark as warm boot ld (@wrtact),a ; ld c,0 ; select drive A: call ?seldsk ; call ?home ; recalibrate drive ; ;* At this point we must reload in everything but the BIOS * ; ld a,(cdrive) ; a= current disk number wbt1: push af ; save current disk ld hl,0001 ; set to ready block 1 ld (@actsct),hl ; ld hl,ccp ; hl @ base of CCP wbt2: ld (@rpntr),hl ; save load adr. to dma pointer ld a,8 ; go read in 8 blocks (8*256) bytes call ?rdblk ; go do it jr nz,wbterr ; brif  ;+ ?list: ?punch: ;-op: handle output to list and punch devices ;-pp: c = character to send ;-rc: none ;- ; >>> Supply code here for your hardware configuration <<< ret ; This just acts as a bit-bucket ;* ;** ;* ;+ ?listst: ;-op: Return Status of Printer Ready ;-pp: none ;-rc: a = 00 : printer not ready ;- ff : printer is ready ;- ; >>> Supply Code Here for your hardware configuration <<< ; ld a,true ; this is just a default ret ; and then exit ;* ;** ;* ;+ ?reader: ;-op: handle input from a secondary input device ;-pp: none ;-rc: a = inputed character. ;- ; >>> Supply code here for your hardware configuration <<< ld a,'Z' and 3fh ; this just returns EOF ret ; ;* ;** ;* ; ; subttl Disk Support Routines page ; *** >>> Disk Support Routines <<< *** ; ;+ ?home: ;-op: This function performs no-operation in ;- this system. ;- ret ; just exit ;* ;** ;* ;+ ?seldsk: ;-op: Select a drive for further operations ;-pp:  ; start at bios cseg ; ; subttl Jump Vector Table for BIOS Functions page ; jp ?boot ; Cold Start jp ?wboot ; Warm boot jp ?const ; Console Status jp ?conin ; Console Input jp ?conout ; Console Output jp ?list ; Printer Output jp ?punch ; AUX: output routine jp ?reader ; AUX: input routine jp ?home ; Recalibrate Drive jp ?seldsk ; Select Drive jp ?settrk ; Set Track Number jp ?setsec ; Set Sector Number jp ?setdma ; Set DMA address jp ?read ; Read a Sector jp ?write ; Write a Sector jp ?listst ; Return Printer Status jp ?sectran ; Sector Translator routine ; subttl Comman Data Storage Definations page ; ; *** >>> Comman Data Storage Defination Area <<< *** ; ; *** Disk parameter block definations *** ; dpAblk: defw nrcyn ; DRIVE A: Type defb 4,15 defb 0 defw dsma defw drm defw 0ff00h defw (drm/4)+1 defw 1 ;**** dpBblk: defw nrcyn ; DRIVE B: Type defb 4,15 defb 0 defw dsmb error ld hl,(@rpntr) ; up-date dma pointer ld de,nbblk*8 ; de = transfer size add hl,de ; ld a,(@actsct) ; point next data block add a,08 ; ld (@actsct),a ; cp 11h ; see if the end has been reached jr nz,wbt2 ; brif not done ld a,false ; mark as not write active ld (@wrtact),a ; pop af ; recover current disk number ld (cdrive),a ; jp ?gocpm ; an pass control to CCP ;* wbterr: ld a,'W' ; a = code for warm boot error call ?dskerr ; go print the message pop af ; recover all old number jp wbt1 ; and try again ;* ;** ;* subttl Character I/O routines page ; ; *** >>> Start of Character I/O routines *** ; ?const: ;-op: See if console has character ready ;-pp: none ;-rc: a = 00 : no character ready ;- ff : character ready ;- ; >>> supply code here for your hardware configuration <<< ; Sample code is provided for a 8251 type usart ; in a,(crtstatus) ; get status cpl ; our hardware complements status register c = drive to select ;-rc: hl @ dph for drive else 0000 if bad drive ;- ld hl,0000 ; ready for error exit ld a,c ; a = drive code cp 2 ; ret nc ; exit if bad select code ld (cdrive),a ; save new current disk ld l,a ; hl = drive code rept 4 add hl,hl ; hl = hl * 16 endm ld de,dpbase ; de = base of table add hl,de ; perform the index operation ret ; and then exit ;* ;** ;* ;+ ?settrk: ;-op: Set-up Track pointer ;-pp: bc = track for next operation ;-rc: none ;- ld (@trk),bc ; save current track ret ; and exit ;* ;** ;* ;+ ?setsec: ;-op: Set-up Sector pointer ;-pp: bc = Sector for next operation ;-rc: none ;- ld (@sect),bc ; save current sector ret ; and then exit ;* ;** ;* ;+ ?setdma: ;-op: Set-UP DMA address pointer ;-pp: bc = address of dma area ;-rc: none ;- ld (@dma),bc ; save current dma address ret ; and then exit ;* ;** ;* ;+ ?read: ;-op: Read a sector ;-pp: Disk read parmaters set (i.e. track, sector and d ret nz ; return on error wt02: ld hl,wrtbuf ; hl @ sector buffer add hl,bc ; add in the offset ex de,hl ; de @ sector ld hl,(@dma) ; hl @ data ld bc,nbrec ; bc = # bytes/CP/M record ldir ; do the trnsfr ; ld a,true ; set write active to true ld (@wrtact),a ; ld a,(@wrtype) ; get back write type dec a ; check for directory ld a,0 ; for safty call z,?flush ; go flush data if so or a ; set flags ret ; and exit ;* ;** ;* page ;+ compute: ;-op: compute phys. block number ;-pp: track and sector are set ;-rc: hl = phys. block number ;- bc = index into block (0..bufsz) ;- ; ld hl,@trk ; hl @ track # ld e,0 ; clear low de ld d,m ; load low track inc hl ; point hi track ld a,(hl) ; a= hi track rra ; divide by two rr d ; rr e ; ex de,hl ; hl= track*128 ld a,(@sect) ; a = sector number srl a ; divide by 2 ld c,0 ; c= 0 or 80h rr c ; add a,l ; ld b,a ; and not mask ; ld l,a ; ld0 ; clear extra byte ld hl,cmdtbl ; hl @ cmd. block call ?docmd ; go do it pop de ; recover command ret z ; return if ok call SCSI$error ;go print disk error ld a,0ffh ;mark the error or a ; ret ;and exit ;* ;** ;* ;+ SCSI$error: ;-op: Handle SCSI Disk Errors ;- ld a,'D' ; code for data error call ?dskerr ; do the disk error ret ; and then exit ;* ;** ;* ; page ; ;* start of protocal handling routnes * ; ;+ ?docmd: ;-op: issue command to SCSI host adaptor ;-pp: hl @ command bytes to send ;- @actsec & @rpntr are valid ;-rc: no - zero : error in command (a = error bits) ;- zero : command was executed successfully ;- ld (lcmd@),hl ; save command @ ld a,retry ; get retry count ld (trycntr),a ; reset counter out (cparity),a ; reset parity error dcmd1: push bc ; save counter call ?putdma ; set dma address call ?select ; go select controler pop bc ; recover bc ; wait: ; ;* here we must wait for executiorive) ;-rc: a = 0 : no errors occured ;- = 0ffh : errors detected ;- ld hl,rdbuf ; point to read buffer ld (@rpntr),hl call compute ; get log. block # (hl =) ex de,hl ; is block loaded?? ld hl,(@wblk) ; is sector wrt. active?? or a ; sbc hl,de ; jr z,rd4 ; brif so ld hl,(@rblk) ; is block already loaded?? or a ; (in read buffer that is) sbc hl,de ; jr z,rd1 ; brif if loaded jr rd2 ; brif not ;* rd4: ld hl,wrtbuf ; index into wrt. buff. jp rd3 ; go do it rd1: ld hl,rdbuf ; index into rd. buff. rd3: add hl,bc ; bc = index, hl @ sector dat ld de,(@dma) ; de = address dma ld bc,nbrec ; bc = size of CP/M record ldir ; perform the transfer xor a ; exit with no errors ret ; and exit ;* rd2: ld (@actsct),de ; set-up for read ld (@rblk),de ; set pointer ld a,(@wrtact) ; see if warm boot active cp 'W' ; jr z,rd2.0 ; brif so res 0,l ; clear unit flag rd2.0: ld a,mgablks ; xxx blocks only call ?rdblk  a,b ; and mask ; ld b,a ; ld (@ofs),bc ; save offset ld a,(cdrive) ; for selection or a ; check for unit 0 ret z ; return if so set 0,l ; else set unit 1 flag ret ; and exit ;* ;** ;* ;+ ?flush: ;-op: flush write buffer if needed ;-pp: @wblk is set and valid ;- if @wrtact flag is set to true ;- ; ld hl,wrtbuf ; set dma to write buffer ld (@rpntr),hl ; ld a,(@wrtact) ; cp false ; buffer write active?? ret z ; return if not ld hl,(@wblk) ; ld (@actsct),hl ; actsec = wblkn ld a,mgablks ; write only xx block call wrtblk ; go write it ld a,false ; buffer not write active ld (@wrtact),a ; ld hl,(@rblk) ; is read/write to same l de,(@wblk or a ; sbc hl,de ; jr nz,flsh1 ; brif not ld hl,-1 ; force read ld (@rblk),hl ; flsh1: xor a ; record no error ret ; and exit ;* ;** ;* ; ; subttl SCSI Host Interface Adaptor Support Routines page ; ; *** >>> SACI Host Interface Adn * ; in a,(bstat) ; a <--- buss status and cd+req ; check for data jr nz,wait ; brif still data in a,(datai) ; a <-- completion status push af ; save ending status wait1: in a,(bstat) ; wait for req. and msg. and req+msg ; jr nz,wait1 ; in a,(datai) ; get byte of zero pop af ; recover status and 00011111b ; mask out errors jr nz,wait4 ; brif not ok in a,(bstat) ; check for parity and perr ; out (clrint),a ; clear interrupt ld a,0ffh ; jr nz,wait4 ; brif error xor a ; exit with zero ret ; and exit ;* ;* wait7: pop af ; clear out stack wait4: bit 2,a ; hardware busy?? jr z,wait6 ; brif not ld a,'R' ; code for ready error call ?dskerr ; jr wait5 ; and continue ;* wait6: ld hl,trycntr ; see if retry up dec (hl) ; jr z,wait2 ; brif retry is up wait5: ld hl,(lcmd@) ; recover last command jp dcmd1 ; and try again ;* wait2: out (clrint),a ; clear interrupt or a ; exit with non-zer ; go do it ret nz ; return on error jp rd1 ; go index into table ;* ;** ;* page ;+ ?write: ;-op: write a sector ;-pp: disk perameters are set (i.e. track, sector and drive) ;- reg c has write type 0,1,2 ;-rc: a = 0 : no errors detected ;- = 0ffh : errors detected ;- ld a,c ; a= write type ld (@wrtype),a ; save for later call compute ; go compute mga block wt03: ex de,hl ; de = block ld hl,(@wblk) ; see if the same as loaded or a ; clear carry sbc hl,de ; test jr z,wt02 ; brif so push de ; save goal blk# call ?flush ; flush out old block number pop hl ; hl= new block # ld (@actsct),hl ; up-date pointers ld (@wblk),hl ; ld hl,wrtbuf ; dma to write buffer ld (@rpntr),hl ; ; if bufsz-2048 ld a,mgablk ; read in a block call ?rdblk ; go read it in else ; block size = 2048 ld a,(@wrtype) ; see if write type is type 2 cp 2 ; ld a,mgablk ; ready for pre-read if necessary call nz,?rdblk ; brif so endif ; aptor Support Routines <<< *** ; ;+ ?rdblk: ;-op: read in x sectors ;-pp: a = number of blocks to read ;- @actsct is valid ;- ld e,rddata ; e = read data command jr precmd ; go prepare for it ;* ;** ;* ;+ wrtblk: ;-op: write out x blocks ;-pp: a = number of blocks to write ;- @actsct is valid ;- ld e,wrtdata ; e = write data cmd. ;+ precmd: ;-op: create command block ;-pp: a = number of block involved ;- e = first command byte ;- push de ; save command ld hl,cmdtbl ; hl @ command block ld (hl),e ; store command byte inc hl ; point next ld de,(@actsct) ; de = log. block number push af ; save block count ld a,(@wrtact) ; see if in warm boot cp 'W' ; jr z,pc10 ; brif so ld a,e ; mask out garbage and not mask ; ld e,a ; pc10: pop af ; recover block count ld (hl),d ; save it inc hl ; ld (hl),e ; inc hl ; ld (hl),0 ; always < 256 log. blocks inc hl ld (hl),a ; save # blocks to trnsfr inc hl ld (hl), o ret ; and exit ;* ;** ;* ;+ ?putdma: ;-op: send dma address to host adapter ;-pp: rpntr has dma address ;- ld a,(hidma) ; set hi-byte out (dmaport),a ; high byte always zero ld de,(@rpntr) ; de @ dma address ld a,d out (dmaport),a ; send byte 1 ld a,e out (dmaport),a ; send byte 2 ret ; and exit ;* ;** ;* ;+ ?select: ;-op: select controler ;- in a,(bstat) ; is controler busy?? and busy ; wait for not busy jr z,?select ; wait if so sel2: ld a,01h ; select controler #1 out (datao),a ; out (selport),a ; and select controler sel1: in a,(bstat) ; wait for req and req ; jr nz,sel1 ; ld d,a ; d=0, mark first command ; ;* now fall on thru to output command bytes * ; ;+ ?outcmd: ;-op: issue command bytes to host adaptor ;-pp: hl @ command bytes ;- in a,(bstat) ; grab buss status ld c,a ; save status and cd ; see if data ret nz ; exit if data ld a,c ; check for direc and direc ; ret z ; exit ; Current DMA addess @trk: defw 00 ; Current Track Number @sect: defw 00 ; Current Sector Number cmdtbl: defs 11 ; Iomega Command Table Storage @wrtype: defb 00h ; current write type @ofs: defw 00 ; Current disk cache index dirbf: defs 128 ; directory buffer chkA: defs (drm/4)+1 ; directory checksum for drive A: chkB: defs (drm/4)+1 ; directory checksum for drive B: allA: defw (dsma/8)+1 ; Allocation map for drive A: allB: defw (dsmb/8)+1 ; Allocation map for Drive B: rdbuf: defw bufsz ; address of read data buffer wrtbuf: defs bufsz ; address of write data buffer @extra: defb 00 ; extra byte ; end end 1wͲ IPLGEN00 -- Initial Program Booter and System Generator V1.1 For 60k Systems L)oad or M)ake System Track --->$MLmͲ ERROR: Please Type "M" or "L" $~#$_òͲ Please Enter Name of GEN'ed CP/M System --->$!6P !QR!6R!N#~.2#~.2#(#x>> Q†Ͳ ERROR: Cannot Open File $[!6$ Ͳ Loading File ...$!wQºßͲ OK $! "=";>2IͲ Operation Completed $Ͳ Enter 0 (Drive #0) or 1 (Drive #1) -->$061A> 2AͲ OK $Ͳ ERROR: Please Enter Either 0 or 1 $Ͳ Load System Function Selected $!"=!";>2IͲ Loading System ...$!I:Aw[=SC>2K2M!I9(=Ͳ ERROR: Disk I/O Error Detected, Operation Aborted $!K4!D4*C[;R"E> 2GTͩ͹QP PQ P QQ> W('Ͳ Please Wait, Drive is Spining Up$!G5(*ECQ:?S[CzS{SQ(>RPQ WQO@y >B > ~R#if input ld a,req+bdack ; bit 0,d ; see if first cmd. jr nz,?oc5 ; brif not ld a,req ; else just check for req. ?oc5: and c ; check for ready jr nz,?outcmd ; brif not (1.75/1.17) ?oc1: ld a,(hl) ; get command byte (1.75/1.17) out (datao),a ; send to controler (2.75/1.83) inc hl ; point next (1.5/1.0) ld d,1 ; mark not first command jr ?outcmd ; and do it again! ;* ;** ;* ; subttl MISC. Routines and Functions page ; ; *** Misc. Routines and Functions *** ; ; ;+ ?sectran: ;-op: perform sector translation ;-pp: de @ tran. table ;- bc = sector number ;- hl = tran. sector number ;- ld h,b ; simple 1 to 1 translation ld l,c ; ret ; add exit ;* ;** ;* ; ;+ ?prtmsg: ;-op: Print message string at hl ;-pp: hl @ message string terminated with a zero byte. ;-rc: none ;- ld a,(hl) ; check for EOS or a ; ret z ; exit if so ld c,a ; c = character inc hl ; point next character push hl ; and save call ?conTSU5D%HMQ .TXOUT`dRE81=NLINE$BѐРT35LMS030ST T3S5LBUFFERST T3 %:LASTSPSDDI%YDMASL dD#1 5TRYCNTRQPe^9hG3m4I(Rp` Dqi0r0D#ye9 & y9 n2'Cy@V P(o9Xy9 Ә4 & @o9 )NgC)@T9LfZ- Me\1[@ JE"yHt ( @T< 4D 7"`  t~FA|f@ ;d@K6A@a9DSqr&(fȤ9 !Ls:MhZ>pؠP4sHBip ??̪dS\ʦ@"6(|>av9f@ m4 "D@C0󠀞p2cI ;KxCH@K4 a܀m n3Ɠa@. jL(#Fha[E 6ADX4$f߀ e@)c,͸Ld )t4p6NS 4$a d MC)@0 #I "y@1 #I E"h|$f MAY`ly, 2Y "D@P6L'3(n:NB)h2 ABFf h(L7Lt2Dct4e1 @h(HͿ"PE )#,Ͷ@P(o0 &8y9 \.3n0 X[ݥ)eYdout ; and issue to terminal handler pop hl ; recover pointer jr ?prtmsg ; and continue ;* ;** ;* ;+ ?dskerr: ;-op: Disk Error Handler ;-pp: A = error code letter ;-rc: none ;- push af ; save error letter on stack ld hl,dem ; hl @ disk error message call ?prtmsg ; go print message header pop af ; c = error code lettre ld c,a ; call ?conout ; and print it ret ; and exit ;* dem: defb cr,lf,lf defb "Disk I/O Error :",0 ;* ;** ;* ; subttl BIOS Data Storage Area page ; ; *** >>> BIOS Data Storage Area <<< *** ; ; @rpntr: defw 00 ; Address of Internal Deblocking buffer @wblk: defw 00 ; Current Write block number @rblk: defw 00 ; Current Read block number @actsct: defw 00 ; Block number to Read/Write @wrtact: defb false ; True if block is write active lcmd@: defw 00 ; Address of last IOMEGA command trycntr: defb 00 ; Retry counter for IOMEGA i/o op.s hidma: defb 00h ; Page address of IOMEGA buffer area @dma: defw 00 C P=f h(E)!Ѐi9y<@E9!t2ΆS @O8NFnLFd0C4eio)-ݥ&d2 2j@ٶ (lm\Pxkl4#dYeq@las2 IX "'c(sqgN@C0.0LdL-L{i-(}-2L(]Q' ˘@d!|PgHFr r <PQS UJ;c =55:<PcQ=%>;SL#`y=%<<QUc  <RQPc@1MR<SQ#1%9 :Q 5-N::ST L#@55L:PST #55L:pST L#55L;>ST #@55L=TPMQIR<Pӕ#@Qa=URp <PQS UJ;c =55:<PcQ=  CP/M RMAC ASSEM 1.1 #001 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR TITLE 'CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR' ; NAME ('BIOS22') ; DATE 20-JUN-83 ; BY DAVID WAGSTAFF ; COPYRIGHT 1983 BY GRIFFIN TECH. ALL RIGHTS RESERVED ; ; MACLIB Z80 ; Z-80 CODING IS USED ASEG ; ABSOLUTE ADDRESSING IS NEEDED ; ; ; ; THIS MODULE CONTAINS THE BASIC INPUT/OUTPUT SYSTEM FOR ; VERSION 2.2 OF THE CP/M OPERATING SYSTEM. ; PORTIONS OF THE SERIAL PORT I/O HAVE NOT BEENED CODED FOR OVIOUS REASONS ; THEREFORE, THIS TASK IS LEFT TO THE CUSTOMER OF THIS PRODUCT. ; THE EQUATE 'SCSI$BASE' HAS BE EQUATED TO THE BASE ADDRESS FOR THE SCSI ; INTERFACE BOARD, THE CURRENT VALUE IS 050H. ; THE EQUATE 'MSIZE' SHOULD CALL ?PDEC LXI H,SPACE CALL ?PRTMSG ENDM LXI H,CRLF CALL ?PRTMSG POP D POP B POP H POP PSW JMP DR DM: DB MESG DB CR,LF,EOM SPACE: DB " ",EOM SKIP: DB "REGISTER DUMP AF, HL, DE, BC" CRLF: DB CR,LF,EOM DR: ENDM ; ; ; ; PAGE CP/M RMAC ASSEM 1.1 #003 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR ; ; *** ASCII CONSTANTS AND USER OPTIONS *** ; ASEG 0007 = BELL EQU 0007H ; SOUND CONSOLE BELL 000D = CR EQU 000DH ; CARIAGE RETURN 000A = LF EQU 000AH ; LINEFEED 000C = FFD EQU  ; 0001 = OFFSET EQU 0001 ; TRACK OFFSET FOR SYSTEM TRACK 0132 = NCYN EQU 306 ; # TRACK/DRIVE 0040 = NSCYN EQU 64 ; # SECTORS/TRACK 0002 = ?NBSCT EQU 2 ; # BLOCKS/SECTOR 0100 = NBBLK EQU 256 ; # BYTES/BLOCK CP/M RMAC ASSEM 1.1 #004 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR 0080 = NBREC EQU 128 ; CP/M RECORD SIZE 0800 = BLS EQU 2048 ; CP/M BLOCK SIZE 01FF = DRM EQU 512-1 ; # DIR. ENTRYS -1 0200 = BYSCT EQU NBBLK*?NBSCT ; # BYTES/SECTOR 8000 = NBCYN EQU NSCYN*BYSCT ; # BYTES/TRACK 0004 = NRSCT EQU BYSCT/NBREC ; # RECS/SECTOR 0100 = NRCYN EQU NSCYN*NRSCT ; # RECS/TRACK 0010 = NRECBLS EQU BLS/NBREC ; # RECS/BLS 0010 = NBLSCYN EQU NRCYN/NRECBLS ; # BLS/TRACK 0990 = DSMA EQU NBLSCYN*(NCYN/2); SIZE OF AN LOGCAL DRIVE A: 0980 = DSMB EQU NBLSCYN*((NCYN/2)-OFFSET) ; SIZE OF B: ; ;  BE SET TO THE SIZE OF THE OPERATING SYSTEM ; TO BE GEN'ED, TYPICALY THIS SHOULD BE ABOUT 60K. ; ; ; ; ** >> EDITING HISTORY << ** ; ; VER. DATE MODIFICATION ; ---- -------- ---------------------------------------- ; 00 06/20/83 1) CREATED. ; ; ; MDBE MACRO VALUE,SP ; MACRO TO PRINT VERSION OR DATE DB (VALUE SHR 12)+'0' DB ((VALUE SHR 8) AND 0FH)+'0' DB SP DB ((VALUE SHR 4) AND 0FH)+'0' DB (VALUE AND 0FH) +'0' ENDM ;*** DEBUG MACRO MESG,VALUES ; MACRO TO DEBUGGING BIOS LOCAL DM,DR,SPACE,SKIP ; 'MESG' IS A ASCII STRING LOCAL HLX,DEX,BCX,AFX,ARD ; TO BE PRINTD, 'VALUES' IS 000CH ; FORMFEED 0011 = XON EQU 0011H ; ^Q 0013 = XOFF EQU 0013H ; ^S 0000 = EOM EQU 0000H ; END OF MESSAGE MARKER 0000 = FALSE EQU 0000H ; FFFF = TRUE EQU NOT FALSE ; 000A = RETRY EQU 0010 ; RETRYS BEFORE HARD-ERROR 003C = MSIZE EQU 0060 ; 60K SYSTEM. ; ; ; *** PORT ASSIGNMENTS *** ; 0050 = SCSI$BASE EQU 0050H ; SCSI INTERFACE BOARD BASE 0010 = QUAD$EIA EQU 0010H ; BASE PORT FOR QUAD. EIA BOARD 0014 = CRTSTATUS EQU QUAD$EIA+4 ; STATUS PORT FOR CONSOLE 0015 = CRTDATA EQU QUAD$EIA+5 ; DATA PORT FOR CONSOLE ; 0001 = TXRDY EQU 0001H ; TX. READY BIT IN 8251 USART 0002 = RXRDY EQU 0002H ; RX. READY BIT IN 8251 USART ; ; *** SCSI PORT ASSIGNMENTS *** ; ; * BIT,BYTE AN * IOMEGA COMMAND SET * ; 0010 = FMTZTRK EQU 10000B ; FORMAT Z-TRACK 0012 = FLGSCT EQU 10010B ; FLAG SECTOR 0014 = FLGTRK EQU 10100B ; FLAG TRACK 0006 = C?SEEK EQU 00110B ; SEEK TRACK 0008 = C?HOME EQU 01000B ; ?HOME DRIVE 000A = REQST EQU 01010B ; REQEST STATUS 000C = REQES EQU 01100B ; REQEST EXTENDED STATUS 000E = CTEST EQU 01110B ; TEST CONTRL. STATUS 0001 = RDDATA EQU 00001B ; READ DATA 0015 = RDID EQU 10101B ; READ ID 0019 = RDDTOF EQU 11001B ; READ DATA WITH OFFSET 0011 = RDDIAG EQU 10001B ; READ DIAGNOSTIC 0003 = WRTDATA EQU 00011B ; WRITE DATA 0007 = WRTID EQU 00111B ; WRITE ID 0013 = WRTDIAG EQU 10011B ; WRITE DIAGNOSITC ; ; ; ; *** CP/M ENVIROMENT CONSTANTS *** ; 0100 = TPA EQU 0100H ; AD LOCAL CRLF ; A LIST OF MEMORY LOCATION JMP ARD ; TO DUMP TO THE TERMINAL. HLX: DW 00 ; A REGISTER DUMP WILL ALSO BCX: DW 00 ; BE PRINTED ON THE CONSOLE. DEX: DW 00 AFX: DW 00 ARD: STA AFX SHLD HLX SDED DEX SBCD BCX PUSH PSW PUSH H PUSH B CP/M RMAC ASSEM 1.1 #002 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR PUSH D IFNB IRP VAL, LHLD VAL CALL ?PDEC LXI H,SPACE CALL ?PRTMSG ENDM ENDIF LXI H,DM CALL ?PRTMSG LXI H,SKIP CALL ?PRTMSG IRP VAL, LHLD VAL D PORT ASSIGMENTS FOR * ; * SCSI HOST INTERFACE ADAPTOR * ; 0050 = DATAI EQU SCSI$BASE ; DATA IN REGISTER 0052 = DATAO EQU SCSI$BASE+2 ; DATA OUT REGISTER 0051 = BSTAT EQU SCSI$BASE+1 ; BUS STATUS 0050 = SELPORT EQU SCSI$BASE ; SELECT PORT ADR. 0051 = CLRINT EQU SCSI$BASE+1 ; CLR. INTRRUPT PORT 0053 = DMAPORT EQU SCSI$BASE+3 ; DMA ADDRESS PORT 0054 = CPARITY EQU SCSI$BASE+4 ; CLEAR PARITY PORT 0080 = BUSY EQU 80H ; CONTROLER BUSY BIT 0040 = CD EQU 40H ; COMMAND/DATA BIT 0020 = DIREC EQU 20H ; DIRECTON BIT 0010 = REQ EQU 10H ; REQUEST BIT 0008 = MSG EQU 08H ; END MESSAGE BIT 0004 = PERR EQU 04H ; PERR ERROR BIT 0002 = BDACK EQU 02H ; BOARD ACK. SIGNAL 0001 = LINT EQU 01H ; INTERUPTE BIT ; ; *** CARTRIAGE STORAGE INFORMATION FOR IOMEGA SYSTEM ***  DRESS OF START OF TPA A000 = BIAS EQU (MSIZE-20)*1024 ; D400 = CCP EQU 3400H+BIAS ; BASE OF CCP DC06 = BDOS EQU CCP+0806H ; BASE OF BDOS EA00 = BIOS EQU CCP+1600H ; BASE OF THIS BIOS 0003 = IOBYTE EQU 0003H ; ADDRESS OF IOBYTE 0004 = CDRIVE EQU 0004H ; CURRENT DISK INDICATOR 002C = NSECTS EQU (BIOS-CCP)/128 ; # OF SECTORS/ CCP ; ; ; *** IOMEGA BLOCKING SIZE EQUATES *** ; 0800 = BUFSZ EQU 2048 ; DATA BLOCKING SIZE 0008 = MGABLKS EQU BUFSZ/256 ; # OF IOMEGA BLOCKS 0010 = CPMBLKS EQU BUFSZ/NBREC ; # OF CP/M RECORDS 0007 = MASK EQU 07H ; SEE FOLLOWING TABLE ; ; ******************************************** ; * THE VALUE OF "MASK" DETERMINES THE BLOCK * ; * BUFFER SIZE OF THE DEBLOCKING ROUTINES. * ; RIVE A: TYPE 0035 040F DB 4,15 0037 00 DB 0 0038 9009 DW DSMA 003A FF01 DW DRM 003C 00FF DW 0FF00H 003E 8000 DW (DRM/4)+1 0040 0100 DW 1 ;**** DPBBLK: 0042 0001 DW NRCYN ; DRIVE B: TYPE 0044 040F DB 4,15 0046 00 DB 0 0047 8009 DW DSMB 0049 FF01 DW DRM 004B 00FF DW 0FF00H ; DEBUG = 0FFFFH 004D 8000 DW (DRM/4)+1 004F 9A00 DW 9AH ;**** ; ; ; *** >>> DISK PARAMETER HEADER TABLES <<< *** ; DPBASE: ; 0051 00000000 DW 0000,0000 ; DRIVE A: 0055 00000000 DW 0000,0000 ; 0059 79033300 DW DIRBF,DPABLK ; 005D F903F904 DW CHKA,ALLA ; ; 0061 00000000 DW 0000,0000 ; DRIVE B: 0065 00000000 DW 0000,0000 ; 0069 79034200 DW DIRBF,DPBBLK ; 006D 7904FB04 DW CHKB,ALLB ; ; 'W' ; MARK AS WARM BOOT 00D9 326003 STA @WRTACT ; 00DC 0E00 MVI C,0 ; SELECT DRIVE A: 00DE CD4801 CALL ?SELDSK ; 00E1 CD4701 CALL ?HOME ; RECALIBRATE DRIVE ; ;* AT THIS POINT WE MUST RELOAD IN EVERYTHING BUT THE BIOS * ; 00E4 3A0400 LDA CDRIVE ; A= CURRENT DISK NUMBER WBT1: 00E7 F5 PUSH PSW ; SAVE CURRENT DISK 00E8 210100 LXI H,0001 ; SET TO READY BLOCK 1 00EB 225E03 SHLD @ACTSCT ; 00EE 2100D4 LXI H,CCP ; HL @ BASE OF CCP WBT2: 00F1 225803 SHLD @RPNTR ; SAVE LOAD ADR. TO DMA POINTER 00F4 3E08 MVI A,8 ; GO READ IN 8 BLOCKS (8*256) BYTES 00F6 CD5B02 CALL ?RDBLK ; GO DO IT JRNZ WBTERR ; BRIF ERROR 00F9+201F DB 20H,WBTERR-$-1 00FB 2A5803 LHLD @RPNTR ; UP-DATE DMA POINTER 00FE 110008 LXI D,NBBLK*8 ; DE = TRANSFER SIZE 0101 19 DAD D ; 0102 3A5E03 LDA @ACTSCT ; POINT * THE VALUE OF "MASK" ARE: * ; * BUFSZ MASK * CP/M RMAC ASSEM 1.1 #005 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR ; * ----- ---- * ; * 2048 07H * ; * 4096 0FH * ; * 8192 1FH * ; * 16384 3FH * ; ******************************************** ; ; ; ; ORG BIOS ; START AT BIOS CSEG ; ; PAGE CP/M RMAC ASSEM 1.1 #006 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR ; 0000 C37100 JMP ?BOOT ; COLD START 0003 C3CB00 JMP ?WBOOT ; WARM BOOT 0006 C32301 JMP ?CONST ; CONSOLE STATUS 0009 C32C01 JMP ?CONIN ; CONSOLE INPUT 000C C33601 JMP ?CONO PAGE CP/M RMAC ASSEM 1.1 #008 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR ; ; ; *** >>> START OF BOOT AND WARM BOOT ROUTINES <<< *** ; ?BOOT: ;-OP: HANDLE MISC. INITILIZATION AND SIGNON MESSAGE PRINTING ;-PP: NONE ;-RC: NONE ;- 0071 AF XRA A ; CLEAR IOBYTE 0072 320300 STA IOBYTE ; 0075 320400 STA CDRIVE ; AND CURRENT DISK 0078 219900 LXI H,SIGNON ; GO PRINT SIGN-ON MESSAGE 007B CD2B03 CALL ?PRTMSG ; ?GOCPM: 007E 3EC3 MVI A,0C3H ; A = OP. CODE FOR 'JP' 0080 320000 STA 0000H ; VECTOR @ 0000H 0083 320500 STA 0005H ;& VECTOR @ 0005H 0086 2103EA LXI H,BIOS+3 ; LOCATION OF WBOOT ROUTINE 0089 220100 SHLD 0001H ; SAVE IT 008C 2106DC LXI H,BDOS ; LOCATION OF BDOS 008F 220600 SHLD 0006H ; SAVE TO SYSTEM VECTOR 0092  NEXT DATA BLOCK 0105 C608 ADI 08 ; 0107 325E03 STA @ACTSCT ; 010A FE11 CPI 11H ; SEE IF THE END HAS BEEN REACHED JRNZ WBT2 ; BRIF NOT DONE 010C+20E3 DB 20H,WBT2-$-1 010E 3E00 MVI A,FALSE ; MARK AS NOT WRITE ACTIVE 0110 326003 STA @WRTACT ; 0113 F1 POP PSW ; RECOVER CURRENT DISK NUMBER 0114 320400 STA CDRIVE ; 0117 C37E00 JMP ?GOCPM ; AN PASS CONTROL TO CCP ;* WBTERR: 011A 3E57 MVI A,'W' ; A = CODE FOR WARM BOOT ERROR 011C CD3703 CALL ?DSKERR ; GO PRINT THE MESSAGE 011F F1 POP PSW ; RECOVER ALL OLD NUMBER 0120 C3E700 JMP WBT1 ; AND TRY AGAIN ;* ;** ;* PAGE CP/M RMAC ASSEM 1.1 #010 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR ; ; *** >>> START OF CHARACTER I/O ROUTINES *** ;UT ; CONSOLE OUTPUT 000F C34001 JMP ?LIST ; PRINTER OUTPUT 0012 C34001 JMP ?PUNCH ; AUX: OUTPUT ROUTINE 0015 C34401 JMP ?READER ; AUX: INPUT ROUTINE 0018 C34701 JMP ?HOME ; RECALIBRATE DRIVE 001B C34801 JMP ?SELDSK ; SELECT DRIVE 001E C35C01 JMP ?SETTRK ; SET TRACK NUMBER 0021 C36101 JMP ?SETSEC ; SET SECTOR NUMBER 0024 C36601 JMP ?SETDMA ; SET DMA ADDRESS 0027 C36B01 JMP ?READ ; READ A SECTOR 002A C3B601 JMP ?WRITE ; WRITE A SECTOR 002D C34101 JMP ?LISTST ; RETURN PRINTER STATUS 0030 C32803 JMP ?SECTRAN ; SECTOR TRANSLATOR ROUTINE ; PAGE CP/M RMAC ASSEM 1.1 #007 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR ; ; *** >>> COMMON DATA STORAGE DEFINITION AREA <<< *** ; ; *** DISK PARAMETER BLOCK DEFINITIONS *** ; DPABLK: 0033 0001 DW NRCYN ; D3A0400 LDA CDRIVE ; GET THE CURRENT DISK 0095 4F MOV C,A ; TO REGISTER C 0096 C300D4 JMP CCP ; AND PASS CONTROL TO THE CCP ;* ;** ;* SIGNON: 0099 0D0A0A0A DB CR,LF,LF,LF 009D 42494F5332 DB 'BIOS220 --- CP/M VER. 2.2 BIOS 20-JUN-83',CR,LF 00C8 0D0A00 CRLF: DB CR,LF,EOM ;* ;** ;* PAGE CP/M RMAC ASSEM 1.1 #009 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR ;+ ?WBOOT: ;-OP: WARM BOOT CP/M SYSTEM. ;-PP: SYSTEM TRACKS OF DRIVE A: HAS A VALID SYSTEM ON IT. ;-RC: CCP IS RELOADED INTO CORE FROM SYSTEM TRACKS ;- 00CB 318000 LXI SP,0080H ; SET-UP THE STACK TO FREE AREA 00CE CD2B02 CALL ?FLUSH ; FLUSH DISK CACHE 00D1 21FFFF LXI H,-1 ; FORCE NEW READS 00D4 225C03 SHLD @RBLK ; 00D7 3E57 MVI A,  ?CONST: ;-OP: SEE IF CONSOLE HAS CHARACTER READY ;-PP: NONE ;-RC: A = 00 : NO CHARACTER READY ;- FF : CHARACTER READY ;- ; >>> SUPPLY CODE HERE FOR YOUR HARDWARE CONFIGURATION <<< ; SAMPLE CODE IS PROVIDED FOR A 8251 TYPE USART ; 0123 DB14 IN CRTSTATUS ; GET STATUS 0125 2F CMA ; OUR HARDWARE COMPLEMENTS STATUS REGISTER 0126 E602 ANI RXRDY ; 0128 C8 RZ ; EXIT IF NOT READY 0129 F6FF ORI 0FFH ; ELSE WITH WITH TRUE 012B C9 RET ;* ;** ;* ;+ ?CONIN: ;-OP: GET CHARACTER FROM THE CONSOLE ;-PP: NONE ;-RC: A = CHARACTER (PARITY BIT STRIPED, I.E. ONLY 7-BITS PRESENT) ;- 012C CD2301 CALL ?CONST ; WAIT FOR CHARACTER READY 012F B7 ORA AUR HARDWARE CONFIGURATION <<< ; 0141 3EFF MVI A,TRUE ; THIS IS JUST A DEFAULT 0143 C9 RET ; AND THEN EXIT ;* ;** ;* ;+ ?READER: ;-OP: HANDLE INPUT FROM A SECONDARY INPUT DEVICE ;-PP: NONE ;-RC: A = INPUTED CHARACTER. ;- ; >>> SUPPLY CODE HERE FOR YOUR HARDWARE CONFIGURATION <<< 0144 3E1A MVI A,'Z' AND 3FH ; THIS JUST RETURNS EOF 0146 C9 RET ; ;* ;** ;* ; ; PAGE CP/M RMAC ASSEM 1.1 #012 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR ; *** >>> DISK SUPPORT ROUTINES <<< *** ; ;+ ?HOME: ;-OP: THIS FUNCTION PERFORMS NO-OPERATION IN ;- THIS SYSTEM. DRESS POINTER ;-PP: BC = ADDRESS OF DMA AREA ;-RC: NONE ;- SBCD @DMA ; SAVE CURRENT DMA ADDRESS 0166+ED43 DB 0EDH,43H 0168+6503 DW @DMA 016A C9 RET ; AND THEN EXIT ;* ;** ;* ;+ ?READ: ;-OP: READ A SECTOR ;-PP: DISK READ PARMATERS SET (I.E. TRACK, SECTOR AND DRIVE) ;-RC: A = 0 : NO ERRORS OCCURED ;- = 0FFH : ERRORS DETECTED ;- 016B 21FD04 LXI H,RDBUF ; POINT TO READ BUFFER 016E 225803 SHLD @RPNTR 0171 CD0002 CALL COMPUTE ; GET LOG. BLOCK # (HL =) 0174 EB XCHG ; IS BLOCK LOADED?? 0175 2A5A03 LHLD @WBLK ; IS SECTOR WRT. ACTIVE?? 0178 B7 ORA A ; DSBC DE ; 0179+ED52 DB 0EDH,DE*8+42H JRZ RD4 ; BRIF SO 017B+280A DB 28H,RD4 ; JRZ ?CONIN ; 0130+28FA DB 28H,?CONIN-$-1 ; ; >>> SUPPLY CODE HERE FOR YOUR HARDWARE CONFIGURATION <<< ; >>> REGISTER A WILL RECEIVE CHARACTER, PORT HAS CHARACTER READY <<< ; SAMPLE CODE IS PROVIDED FOR A 8251 TYPE USART. ; 0132 DB15 IN CRTDATA ; GRAB THE DATA BYTE 0134 2F CMA ; OUR HARDWARE COMPLEMENTS THE DATA REGISTER 0135 C9 RET ; AND THEN EXIT ;* ;** ;* ;+ ?CONOUT: ;-OP: SEND CHARACTER TO CONSOLE ;-PP: C = CHARACTER ;-RC: NONE ;- ; >>> SUPPLY CODE HERE FOR YOUR HARDWARE CONFIGURATION <<< ; SAMPLE CODE IS PROVIDED FOR A 8251 TYPE USART 0136 DB14 IN CRTSTATUS ; WAIT FOR TX. READY 0138 E601 ANI TXRDY ; JRNZ ?CONOUT ; REMEMBER OUR HARDWARE  ;- 0147 C9 RET ; JUST EXIT ;* ;** ;* ;+ ?SELDSK: ;-OP: SELECT A DRIVE FOR FURTHER OPERATIONS ;-PP: C = DRIVE TO SELECT ;-RC: HL @ DPH FOR DRIVE ELSE 0000 IF BAD DRIVE ;- 0148 210000 LXI H,0000 ; READY FOR ERROR EXIT 014B 79 MOV A,C ; A = DRIVE CODE 014C FE02 CPI 2 ; 014E D0 RNC ; EXIT IF BAD SELECT CODE 014F 320400 STA CDRIVE ; SAVE NEW CURRENT DISK 0152 6F MOV L,A ; HL = DRIVE CODE REPT 4 DAD H ; HL = HL * 16 ENDM 0153+29 DAD H ; HL = HL * 16 0154+29 DAD H ; HL = HL * 16 0155+29 DAD H ; HL = HL * 16 0156+29 DAD H ; HL = HL * 16 0157 115100 LXI D,DPBASE ; DE = BASE OF TABLE 015A 19 DAD D ; PERFORM THE INDEX OPERATION 015B C9 RET ; AND TH-$-1 017D 2A5C03 LHLD @RBLK ; IS BLOCK ALREADY LOADED?? 0180 B7 ORA A ; (IN READ BUFFER THAT IS) DSBC DE ; 0181+ED52 DB 0EDH,DE*8+42H JRZ RD1 ; BRIF IF LOADED 0183+2808 DB 28H,RD1-$-1 JR RD2 ; BRIF NOT 0185+1815 DB 18H,RD2-$-1 ;* RD4: 0187 21FF04 LXI H,WRTBUF ; INDEX INTO WRT. BUFF. 018A C39001 JMP RD3 ; GO DO IT RD1: 018D 21FD04 LXI H,RDBUF ; INDEX INTO RD. BUFF. RD3: 0190 09 DAD B ; BC = INDEX, HL @ SECTOR DAT LDED @DMA ; DE = ADDRESS DMA CP/M RMAC ASSEM 1.1 #014 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR 0191+ED5B DB 0EDH,5BH 0193+6503 DW @DMA 0195 018000 LXI B,NBREC ; BC = SIZE OF CP/M RECORD LDIR ; PERFORM THE TRANSFER 0198+EDB0 DB 0EDH,0B0H 019A AF XRA A ; EXIT WITH NO ERRORS 019B C9 RET ; AND EXIT  013A+20FA DB 20H,?CONOUT-$-1 013C 79 MOV A,C ; A = CHARACTER TO SEND CP/M RMAC ASSEM 1.1 #011 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR 013D D315 OUT CRTDATA ; EJECT THE CHARACTER 013F C9 RET ; AND THEN EXIT ;* ;** ;* ;+ ?LIST: ?PUNCH: ;-OP: HANDLE OUTPUT TO LIST AND PUNCH DEVICES ;-PP: C = CHARACTER TO SEND ;-RC: NONE ;- ; >>> SUPPLY CODE HERE FOR YOUR HARDWARE CONFIGURATION <<< 0140 C9 RET ; THIS JUST ACTS AS A BIT-BUCKET ;* ;** ;* ;+ ?LISTST: ;-OP: RETURN STATUS OF PRINTER READY ;-PP: NONE ;-RC: A = 00 : PRINTER NOT READY ;- FF : PRINTER IS READY ;- ; >>> SUPPLY CODE HERE FOR YOEN EXIT ;* ;** ;* ;+ ?SETTRK: ;-OP: SET-UP TRACK POINTER ;-PP: BC = TRACK FOR NEXT OPERATION ;-RC: NONE ;- SBCD @TRK ; SAVE CURRENT TRACK 015C+ED43 DB 0EDH,43H 015E+6703 DW @TRK 0160 C9 RET ; AND EXIT ;* ;** ;* ;+ ?SETSEC: ;-OP: SET-UP SECTOR POINTER ;-PP: BC = SECTOR FOR NEXT OPERATION ;-RC: NONE CP/M RMAC ASSEM 1.1 #013 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR ;- SBCD @SECT ; SAVE CURRENT SECTOR 0161+ED43 DB 0EDH,43H 0163+6903 DW @SECT 0165 C9 RET ; AND THEN EXIT ;* ;** ;* ;+ ?SETDMA: ;-OP: SET-UP DMA ADŠPh0X`   @  X   @x @@h^@ WK Cf@ | (Bu "@@=jA@QO)CZ-he9 !p@B$b`-%M J/*3j@ 6U1"cC6⪰# " q* :>+iŇyaA{{?,F>aQ{%sDL*di 2 HR KY.idHu !*Ϳ.UZ[JBPݥ!@ 0F@KY@(`dJux Sc+L(ͫ`L<6Uh n) Vm+po >1*C.UeՀ2c= np0#?aXm: l8 Hgݤ::[!*:o UVUx |f!eXUp [@kwiH@*d!xְ3[oQ`Cۙ_xg1#; kfـ&!d$|Dfp6HC**1Y ~- }6VE>e> .`#L>jKŖW&m7 5 j( 4+vHnX=4gM()4 }e{< IB~ia`a`4OvAL80 BIOS2200/N,BIOS2200/P:EA00/X/E After the link, make sure that the end of the BIOS module dosn't wrap around back to zero (BIOS too big). Answer NO to the question about moving the module above loader memory. 5) Use DDT.COM to perform the system patching as follows. A) First load DDT and CPM60.COM with the following command: A>DDT CPM60.COM B) Next include the BIOS module with the correct offset to load it into the right place in the system, use the commands: -IBIOS2200.HEX -R3580 1] It should be noted at this point that no cold start booter is placed on the system tracks of the disk. The sector which would normally b ;* RD2: SDED @ACTSCT ; SET-UP FOR READ 019C+ED53 DB 0EDH,53H 019E+5E03 DW @ACTSCT SDED @RBLK ; SET POINTER 01A0+ED53 DB 0EDH,53H 01A2+5C03 DW @RBLK 01A4 3A6003 LDA @WRTACT ; SEE IF WARM BOOT ACTIVE 01A7 FE57 CPI 'W' ; JRZ RD20 ; BRIF SO 01A9+2802 DB 28H,RD20-$-1 RES 0,L ; CLEAR UNIT FLAG 01AB+CB85 DB 0CBH,0*8+L+80H RD20: 01AD 3E08 MVI A,MGABLKS ; XXX BLOCKS ONLY 01AF CD5B02 CALL ?RDBLK ; GO DO IT 01B2 C0 RNZ ; RETURN ON ERROR 01B3 C38D01 JMP RD1 ; GO INDEX INTO TABLE ;* ;** ;* PAGE CP/M RMAC ASSEM 1.1 #015 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR ;+ ?WRITE: ;-OP: WRITE A SECTOR ;-PP: DISK PERAMETERS ARE SET (I.E. TRACK, SECrאIo 1 ~- }6VE>e> .`#L>jKŖW&m7 5 j( 4+vHnX=4gM()e used for this purpose is free for use by the user for any purpose desired. The cold start booter is assumed to be in ROM. C) Make note the the NEXT field which is printed by DDT After loading the BIOS module. Take the two most significant digits of the next field and convert this value to decimal. Add one to this value and note this value for step 5E below. D) Type ^C (control C) to exit to the operating system. E) Save the newly created system with the SAVE command. Compute the number of pages to save from the NEXT field note i ste 5 above Nam th save fil CPM60.SYS. 6) Place a cartriage which will receive the system into the first IOMEGA drive. 7) Run the supplied program IPLGEN00. A) Type 'M' (for make system) to the first prompt. B) Type thTOR AND DRIVE) ;- REG C HAS WRITE TYPE 0,1,2 ;-RC: A = 0 : NO ERRORS DETECTED ;- = 0FFH : ERRORS DETECTED ;- 01B6 79 MOV A,C ; A= WRITE TYPE 01B7 327603 STA @WRTYPE ; SAVE FOR LATER 01BA CD0002 CALL COMPUTE ; GO COMPUTE MGA BLOCK WT03: 01BD EB XCHG ; DE = BLOCK 01BE 2A5A03 LHLD @WBLK ; SEE IF THE SAME AS LOADED 01C1 F607 ORI A ; CLEAR CARRY DSBC DE ; TEST 01C3+ED52 DB 0EDH,DE*8+42H JRZ WT02 ; BRIF SO 01C5+281C DB 28H,WT02-$-1 01C7 D5 PUSH D ; SAVE GOAL BLK# 01C8 CD2B02 CALL ?FLUSH ; FLUSH OUT OLD BLOCK NUMBER 01CB E1 POP H ; HL= NEW BLOCK # 01CC 225E03 SHLD @ACTSCT ; UP-DATE POINTERS 01CF 225A03 SHLD @WBLK ; 01D2 21FF04 LXI H,WRTBUF ; DMA TO WRITE BUFFER 01D5 225803 SHLD @RPNTR ; ; IF BUFSZ-2048  Instruction for Building BIOS2200 CP/M 2.2 System Date 22-Jun-83 1) Make any corrects/additions to the distribution copy of BIOS220 t suppor you computer seria I/ hardware 2) Use MOVCPM.COM (supplied with the distribution disk of your CP/M v2.2 system) to generate a 60k CP/M system. Use the following command: A>MOVCPM 60 * A>SAVE 34 CPM60.COM 3) Using M80.COM (or a compatible assemblier), assemble BIOS2200.MAC into BIOS2200.REL. Verify that no errors occurred during this process. Use the following command: A>M80 =BIOS2200 4) Now the BIOS2200.REL file must be converted into a Intel hex-ascii format (.HEX) file before it can be placed in th CPM60.CO file T d this L80.CO (Micro-Sof's linkee name of the file containing the gen'ed system to the next file, this is CPM60.SYS. C) Type the Correct Drive to the drive selection prompt. D) Following this you will have a IOMEGA cartrige with a system track on it. MVI A,MGABLKS ; READ IN A BLOCK CALL ?RDBLK ; GO READ IT IN ELSE ; BLOCK SIZE = 2048 01D8 3A7603 LDA @WRTYPE ; SEE IF WRITE TYPE IS TYPE 2 01DB FE02 CPI 2 ; 01DD 3E08 MVI A,MGABLKS ; READY FOR PRE-READ IF NECESSARY 01DF C45B02 CNZ ?RDBLK ; BRIF SO ENDIF ; 01E2 C0 RNZ ; RETURN ON ERROR WT02: 01E3 21FF04 LXI H,WRTBUF ; HL @ SECTOR BUFFER 01E6 09 DAD B ; ADD IN THE OFFSET 01E7 EB XCHG ; DE @ SECTOR 01E8 2A6503 LHLD @DMA ; HL @ DATA 01EB 018000 LXI B,NBREC ; BC = # BYTES/CP/M RECORD LDIR ; DO THE TRNSFR 01EE+EDB0 DB 0EDH,0B0H ; 01F0 3EFF MVI A,TRUE ; SET WRITE ACTIVE TO TRUE 01F2 326003 STA @WRTACT ; 01F5 3A7603 LDA @WRTYPE ; GET BACK WRITE TYPE 01F8 3D DCR A ; CHECK FOR DIRECTORY 01F9 3E00 MVI A,0 ; FOR SAFTY 01FB CC2B02 CZ ?FLK IS SET AND VALID ;- IF @WRTACT FLAG IS SET TO TRUE ;- ; 022B 21FF04 LXI H,WRTBUF ; SET DMA TO WRITE BUFFER 022E 225803 SHLD @RPNTR ; 0231 3A6003 LDA @WRTACT ; 0234 FE00 CPI FALSE ; BUFFER WRITE ACTIVE?? CP/M RMAC ASSEM 1.1 #018 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR 0236 C8 RZ ; RETURN IF NOT 0237 2A5A03 LHLD @WBLK ; 023A 225E03 SHLD @ACTSCT ; ACTSEC = WBLKN 023D 3E08 MVI A,MGABLKS ; WRITE ONLY XX BLOCK 023F CD5F02 CALL WRTBLK ; GO WRITE IT 0242 3E00 MVI A,FALSE ; BUFFER NOT WRITE ACTIVE 0244 326003 STA @WRTACT ; 0247 2A5C03 LHLD @RBLK ; IS READ/WRITE TO SAME LDED @WBLK ; 024A+ED5B DB 0EDH,5BH 024C+5A03 DW @WBLK 024E B7 ORA A ; DSBC DE ; 024F+ED52 DB 0EDH,DE*8+42H JRNZ FLSH1 ; BRIF NOT 0251+2006 DB 20H,FLSH1-$-1 0253 21FFFF LXI H,-1  MOV M,D ; SAVE IT 0279 23 INX H ; 027A 73 MOV M,E ; 027B 23 INX H ; 027C 3600 MVI M,0 ; ALWAYS < 256 LOG. BLOCKS 027E 23 INX H 027F 77 MOV M,A ; SAVE # BLOCKS TO TRNSFR 0280 23 INX H 0281 3600 MVI M,0 ; CLEAR EXTRA BYTE 0283 216B03 LXI H,CMDTBL ; HL @ CMD. BLOCK CP/M RMAC ASSEM 1.1 #020 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR 0286 CD9802 CALL ?DOCMD ; GO DO IT 0289 D1 POP D ; RECOVER COMMAND 028A C8 RZ ; RETURN IF OK 028B CD9202 CALL SCSI$ERROR ;GO PRINT DISK ERROR 028E 3EFF MVI A,0FFH ;MARK THE ERROR 0290 B7 ORA A ; 0291 C9 RET ;AND EXIT ;* ;** ;* ;+ SCSI$ERROR: ;-OP: HANDLE SCSI DISK ERRORS ;- 0292 3E44 MVI A,'D' ; CODE FOR DATA ERROR 0294 CD3703 CALL ?DSKERR ; DO THE DISK ERROR 0297 C9LUSH ; GO FLUSH DATA IF SO 01FE B7 ORA A ; SET FLAGS 01FF C9 RET ; AND EXIT CP/M RMAC ASSEM 1.1 #016 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR ;* ;** ;* PAGE CP/M RMAC ASSEM 1.1 #017 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR ;+ COMPUTE: ;-OP: COMPUTE PHYS. BLOCK NUMBER ;-PP: TRACK AND SECTOR ARE SET ;-RC: HL = PHYS. BLOCK NUMBER ;- BC = INDEX INTO BLOCK (0..BUFSZ) ;- ; 0200 216703 LXI H,@TRK ; HL @ TRACK # 0203 1E00 MVI E,0 ; CLEAR LOW DE 0205 56 MOV D,M ; LOAD LOW TRACK 0206 23 INX H ; POINT HI TRACK 0207 7E MOV A,M ; A= HI TRACK RRA ; DIVIDE BY TWO RARR D ; 0208+CB1A DB 0CBH, 18H + D RARR E ; 020A+CB1B DB 0CBH, 18H + E 020C EB ; FORCE READ 0256 225C03 SHLD @RBLK ; FLSH1: 0259 AF XRA A ; RECORD NO ERROR 025A C9 RET ; AND EXIT ;* ;** ;* ; ; PAGE CP/M RMAC ASSEM 1.1 #019 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR ; ; *** >>> SACI HOST INTERFACE ADAPTOR SUPPORT ROUTINES <<< *** ; ;+ ?RDBLK: ;-OP: READ IN X SECTORS ;-PP: A = NUMBER OF BLOCKS TO READ ;- @ACTSCT IS VALID ;- 025B 1E01 MVI E,RDDATA ; E = READ DATA COMMAND JR PRECMD ; GO PREPARE FOR IT 025D+1802 DB 18H,PRECMD-$-1 ;* ;** ;* ;+ WRTBLK: ;-OP: WRITE OUT X BLOCKS ;-PP: A = NUMBER OF BLOCKS TO RET ; AND THEN EXIT ;* ;** ;* ; PAGE CP/M RMAC ASSEM 1.1 #021 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR ; ;* START OF PROTOCAL HANDLING ROUTNES * ; ;+ ?DOCMD: ;-OP: ISSUE COMMAND TO SCSI HOST ADAPTOR ;-PP: HL @ COMMAND BYTES TO SEND ;- @ACTSEC & @RPNTR ARE VALID ;-RC: NO - ZERO : ERROR IN COMMAND (A = ERROR BITS) ;- ZERO : COMMAND WAS EXECUTED SUCCESSFULLY ;- 0298 226103 SHLD LCMD@ ; SAVE COMMAND @ 029B 3E0A MVI A,RETRY ; GET RETRY COUNT 029D 326303 STA TRYCNTR ; RESET COUNTER 02A0 D354 OUT CPARITY ; RESET PARITY ERROR DCMD1: 02A2 C5 PUSH B ; SAVE COUNTER 02A3 CDE802 CALL ?PUTDMA ; SET DMA ADDRESS 02A6 CDF802 CALL ?SELECT ; XCHG ; HL= TRACK*128 020D 3A6903 LDA @SECT ; A = SECTOR NUMBER SRLR A ; DIVIDE BY 2 0210+CB3F DB 0CBH, 38H + A 0212 0E00 MVI C,0 ; C= 0 OR 80H RARR C ; 0214+CB19 DB 0CBH, 18H + C 0216 85 ADD L ; 0217 47 MOV B,A ; 0218 E6F8 ANI NOT MASK ; 021A 6F MOV L,A ; 021B 78 MOV A,B ; 021C E607 ANI MASK ; 021E 47 MOV B,A ; SBCD @OFS ; SAVE OFFSET 021F+ED43 DB 0EDH,43H 0221+7703 DW @OFS 0223 3A0400 LDA CDRIVE ; FOR SELECTION 0226 B7 ORA A ; CHECK FOR UNIT 0 0227 C8 RZ ; RETURN IF SO SETB 0,L ; ELSE SET UNIT 1 FLAG 0228+CBC5 DB 0CBH,0*8+L+0C0H 022A C9 RET ; AND EXIT ;* ;** ;* ;+ ?FLUSH: ;-OP: FLUSH WRITE BUFFER IF NEEDED ;-PP: @WB WRITE ;- @ACTSCT IS VALID ;- 025F 1E03 MVI E,WRTDATA ; E = WRITE DATA CMD. ;+ PRECMD: ;-OP: CREATE COMMAND BLOCK ;-PP: A = NUMBER OF BLOCK INVOLVED ;- E = FIRST COMMAND BYTE ;- 0261 D5 PUSH D ; SAVE COMMAND 0262 216B03 LXI H,CMDTBL ; HL @ COMMAND BLOCK 0265 73 MOV M,E ; STORE COMMAND BYTE 0266 23 INX H ; POINT NEXT LDED @ACTSCT ; DE = LOG. BLOCK NUMBER 0267+ED5B DB 0EDH,5BH 0269+5E03 DW @ACTSCT 026B F5 PUSH PSW ; SAVE BLOCK COUNT 026C 3A6003 LDA @WRTACT ; SEE IF IN WARM BOOT 026F FE57 CPI 'W' ; JRZ PC10 ; BRIF SO 0271+2804 DB 28H,PC10-$-1 0273 7B MOV A,E ; MASK OUT GARBAGE 0274 E6F8 ANI NOT MASK ; 0276 5F MOV E,A ; PC10: 0277 F1 POP PSW ; RECOVER BLOCK COUNT 0278 72 GO SELECT CONTROLER 02A9 C1 POP B ; RECOVER BC ; WAIT: ; ;* HERE WE MUST WAIT FOR EXECUTION * ; 02AA DB51 IN BSTAT ; A <--- BUSS STATUS 02AC E650 ANI CD+REQ ; CHECK FOR DATA JRNZ WAIT ; BRIF STILL DATA 02AE+20FA DB 20H,WAIT-$-1 02B0 DB50 IN DATAI ; A <-- COMPLETION STATUS 02B2 F5 PUSH PSW ; SAVE ENDING STATUS WAIT1: 02B3 DB51 IN BSTAT ; WAIT FOR REQ. AND MSG. 02B5 E618 ANI REQ+MSG ; JRNZ WAIT1 ; 02B7+20FA DB 20H,WAIT1-$-1 02B9 DB50 IN DATAI ; GET BYTE OF ZERO 02BB F1 POP PSW ; RECOVER STATUS 02BC E61F ANI 00011111B ; MASK OUT ERRORS JRNZ WAIT4 ; BRIF NOT OK 02BE+200D DB 20H,WAIT4-$-1 02C0 DB51 IN BSTAT ; CHECK FOR PARITY 02C2 E604 ANI PERR ; 02C4 D351 OUT CLRINT ; CLEAR INTERRUPT 02C6 3EONTROLER BUSY?? 02FA E680 ANI BUSY ; WAIT FOR NOT BUSY JRZ ?SELECT ; WAIT IF SO 02FC+28FA DB 28H,?SELECT-$-1 SEL2: 02FE 3E01 MVI A,01H ; SELECT CONTROLER #1 0300 D352 OUT DATAO ; 0302 D350 OUT SELPORT ; AND SELECT CONTROLER SEL1: 0304 DB51 IN BSTAT ; WAIT FOR REQ CP/M RMAC ASSEM 1.1 #023 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR 0306 E610 ANI REQ ; JRNZ SEL1 ; 0308+20FA DB 20H,SEL1-$-1 030A 57 MOV D,A ; D=0, MARK FIRST COMMAND ; ;* NOW FALL ON THRU TO OUTPUT COMMAND BYTES * ; ;+ ?OUTCMD: ;-OP: ISSUE COMMAND BYTES TO HOST ADAPTOR ;-PP: HL @ COMMAND BYTES ;- 030B DB51 IN BSTAT ; GRAB BUSS STATUS 030D 4F MOV C,A ; SAVE STATUS 030E E640 ANI CD ; SEE IF DATA 0310 C0 RNZ ; CTER 0330 E5 PUSH H ; AND SAVE 0331 CD3601 CALL ?CONOUT ; AND ISSUE TO TERMINAL HANDLER 0334 E1 POP H ; RECOVER POINTER JR ?PRTMSG ; AND CONTINUE 0335+18F4 DB 18H,?PRTMSG-$-1 ;* ;** ;* ;+ ?DSKERR: ;-OP: DISK ERROR HANDLER ;-PP: A = ERROR CODE LETTER ;-RC: NONE ;- 0337 F5 PUSH PSW ; SAVE ERROR LETTER ON STACK 0338 214403 LXI H,DEM ; HL @ DISK ERROR MESSAGE 033B CD2B03 CALL ?PRTMSG ; GO PRINT MESSAGE HEADER 033E F1 POP PSW ; C = ERROR CODE LETTRE 033F 4F MOV C,A ; 0340 CD3601 CALL ?CONOUT ; AND PRINT IT 0343 C9 RET ; AND EXIT ;* DEM: 0344 0D0A0A DB CR,LF,LF 0347 4449534B20 DB 'DISK I/O ERROR :',0 ;* CP/M RMAC ASSEM 1.1 #025 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR FF MVI A,0FFH ; JRNZ WAIT4 ; BRIF ERROR 02C8+2003 DB 20H,WAIT4-$-1 02CA AF XRA A ; EXIT WITH ZERO 02CB C9 RET ; AND EXIT ;* ;* WAIT7: 02CC F1 POP PSW ; CLEAR OUT STACK WAIT4: BIT 2,A ; HARDWARE BUSY?? CP/M RMAC ASSEM 1.1 #022 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR 02CD+CB57 DB 0CBH,2*8+A+40H JRZ WAIT6 ; BRIF NOT 02CF+2807 DB 28H,WAIT6-$-1 02D1 3E52 MVI A,'R' ; CODE FOR READY ERROR 02D3 CD3703 CALL ?DSKERR ; JR WAIT5 ; AND CONTINUE 02D6+1806 DB 18H,WAIT5-$-1 ;* WAIT6: 02D8 216303 LXI H,TRYCNTR ; SEE IF RETRY UP 02DB 35 DCR M ; JRZ WAIT2 ; BRIF RETRY IS UP 02DC+2806 DB 28H,WAIT2-$-1 WAIT5: 02DE 2A6103 LHLD LCMD@ ; RECOVER LAST COMMAND 02E1 C3A202 JMP DCEXIT IF DATA 0311 79 MOV A,C ; CHECK FOR DIREC 0312 E620 ANI DIREC ; 0314 C8 RZ ; EXIT IF INPUT 0315 3E12 MVI A,REQ+BDACK ; BIT 0,D ; SEE IF FIRST CMD. 0317+CB42 DB 0CBH,0*8+D+40H JRNZ ?OC5 ; BRIF NOT 0319+2002 DB 20H,?OC5-$-1 031B 3E10 MVI A,REQ ; ELSE JUST CHECK FOR REQ. ?OC5: 031D A1 ANA C ; CHECK FOR READY JRNZ ?OUTCMD ; BRIF NOT (1.75/1.17) 031E+20EB DB 20H,?OUTCMD-$-1 ?OC1: 0320 7E MOV A,M ; GET COMMAND BYTE (1.75/1.17) 0321 D352 OUT DATAO ; SEND TO CONTROLER (2.75/1.83) 0323 23 INX H ; POINT NEXT (1.5/1.0) 0324 1601 MVI D,1 ; MARK NOT FIRST COMMAND JR ?OUTCMD ; AND DO IT AGAIN! 0326+18E3 DB 18H,?OUTCMD-$-1 ;* ;** ;* ; PAGE CP/M RMAC ASSEM 1.1 #024 CP/M VER 2.2 ;** ;* ; PAGE CP/M RMAC ASSEM 1.1 #026 CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR ; ; *** >>> BIOS DATA STORAGE AREA <<< *** ; ; 0358 0000 @RPNTR: DW 00 ; ADDRESS OF INTERNAL DEBLOCKING BUFFER 035A 0000 @WBLK: DW 00 ; CURRENT WRITE BLOCK NUMBER 035C 0000 @RBLK: DW 00 ; CURRENT READ BLOCK NUMBER 035E 0000 @ACTSCT: DW 00 ; BLOCK NUMBER TO READ/WRITE 0360 00 @WRTACT: DB FALSE ; TRUE IF BLOCK IS WRITE ACTIVE 0361 0000 LCMD@: DW 00 ; ADDRESS OF LAST IOMEGA COMMAND 0363 00 TRYCNTR: DB 00 ; RETRY COUNTER FOR IOMEGA I/O OP.S 0364 00 HIDMA: DB 00H ; PAGE ADDRESS OF IOMEGA BUFFER AREA 0365 0000 @DMA: DW 00 ; CURRENT DMA ADDESS 0367 0000 @TRK: DW 00 ; CURRENT TRACK NUMBER 0369 0000 @SECT: DW 00 ; CURRENT SECTOR NUMBER 036B CMDTBL: DS 11 ; IOMEGA COMMD1 ; AND TRY AGAIN ;* WAIT2: 02E4 D351 OUT CLRINT ; CLEAR INTERRUPT 02E6 B7 ORA A ; EXIT WITH NON-ZERO 02E7 C9 RET ; AND EXIT ;* ;** ;* ;+ ?PUTDMA: ;-OP: SEND DMA ADDRESS TO HOST ADAPTER ;-PP: RPNTR HAS DMA ADDRESS ;- 02E8 3A6403 LDA HIDMA ; SET HI-BYTE 02EB D353 OUT DMAPORT ; HIGH BYTE ALWAYS ZERO LDED @RPNTR ; DE @ DMA ADDRESS 02ED+ED5B DB 0EDH,5BH 02EF+5803 DW @RPNTR 02F1 7A MOV A,D 02F2 D353 OUT DMAPORT ; SEND BYTE 1 02F4 7B MOV A,E 02F5 D353 OUT DMAPORT ; SEND BYTE 2 02F7 C9 RET ; AND EXIT ;* ;** ;* ;+ ?SELECT: ;-OP: SELECT CONTROLER ;- 02F8 DB51 IN BSTAT ; IS C BIOS FOR SCSI HOST ADAPTOR ; ; *** MISC. ROUTINES AND FUNCTIONS *** ; ; ;+ ?SECTRAN: ;-OP: PERFORM SECTOR TRANSLATION ;-PP: DE @ TRAN. TABLE ;- BC = SECTOR NUMBER ;- HL = TRAN. SECTOR NUMBER ;- 0328 60 MOV H,B ; SIMPLE 1 TO 1 TRANSLATION 0329 69 MOV L,C ; 032A C9 RET ; ADD EXIT ;* ;** ;* ; ;+ ?PRTMSG: ;-OP: PRINT MESSAGE STRING AT HL ;-PP: HL @ MESSAGE STRING TERMINATED WITH A ZERO BYTE. ;-RC: NONE ;- 032B 7E MOV A,M ; CHECK FOR EOS 032C B7 ORA A ; 032D C8 RZ ; EXIT IF SO 032E 4F MOV C,A ; C = CHARACTER 032F 23 INX H ; POINT NEXT CHARAMAND TABLE STORAGE 0376 00 @WRTYPE: DB 00H ; CURRENT WRITE TYPE 0377 0000 @OFS: DW 00 ; CURRENT DISK CACHE INDEX 0379 DIRBF: DS 128 ; DIRECTORY BUFFER 03F9 CHKA: DS (DRM/4)+1 ; DIRECTORY CHECKSUM FOR DRIVE A: 0479 CHKB: DS (DRM/4)+1 ; DIRECTORY CHECKSUM FOR DRIVE B: 04F9 3301 ALLA: DW (DSMA/8)+1 ; ALLOCATION MAP FOR DRIVE A: 04FB 3101 ALLB: DW (DSMB/8)+1 ; ALLOCATION MAP FOR DRIVE B: 04FD 0008 RDBUF: DW BUFSZ ; ADDRESS OF READ DATA BUFFER 04FF WRTBUF: DS BUFSZ ; ADDRESS OF WRITE DATA BUFFER 0CFF 00 @EXTRA: DB 00 ; EXTRA BYTE ; 0D00 END A: DB 00H ; PAGE ADDRESS OF IOMEGA BUFFER AREA 0365 0000 @DMA: DW 00 ; CURRENT DMA ADDESS 0367 0000 @TRK: DW 00 ; CURRENT TRACK NUMBER 0369 0000 @SECT: DW 00 ; CURRENT SECTOR NUMBER 036B CMDTBL: DS 11 ; IOMEGA COMD04225864 :1001700003CD0002EB2A5A03B7ED52280A2A5C038A :10018000B7ED522808181521FF04C3900121FD0482 :1001900009ED5B6503018000EDB0AFC9ED535E036F :1001A000ED535C033A6003FE572802CB853E08CD31 :1001B0005B02C0C38D0179327603CD0002EB2A5A6F :1001C00003F607ED52281CD5CD2B02E1225E032257 :1001D0005A0321FF042258033A7603FE023E08C464 :1001E0005B02C021FF0409EB2A6503018000EDB02A :1001F0003EFF3260033A76033D3E00CC2B02B7C986 :100200002167031E0056237ECB1ACB1BEB3A6903F2 :10021000CB3F0E00CB198547E6F86F78E60747ED30 :100220004377033A0400B7C8CBC5C921FF0422585D :10023000033A6003FE00C82A5A03225E033E08CD3B :100240005F023E003260032A5C03ED5B5A03B7EDA8 :1002500052200621FFFF225C03AFC91E0118021EB7 :1002600003D5216B037323ED5B5E03F53A6003FE58 :100270005728047BE6F85FF1722373233600237757 :10028000233600216B03CD9802D1C8CD92023EFFE8 :10029000B7C93E44CD3703C92261033E0A32630326 :1002A000D354C5CDE802CDF802C1DB51E65020FAA7 :1002B000DB50F5DB51E61820FADB50F1E61F200D8C :1002C000DB51E604D3513EFF2003AFC9F1CB5728E1 :1002D000073E52CD370318֎ %P`Zî ;ä`,:Xæ,:è,:è,:ë,:ì,:ö,:å`H_ < W:f~@ y@+@0ِm+0@ B BnOaP(B$c!@-D2 +JB\2$@2 IERpp3fҰ! "cʰ ڐͨ# !Ux Bjͫ`B@*cʰF@@napP^2K6T^m Y#$|dD h xR)je!p6KZ@.edo hUVҐ*kwiHP D7dD7-P0 X+.ҝ^v- >3jc@O#*͠NUZ{ݥ!@qͥ`N^U1 U1v%[`o %*`ڰ?U u]ǣ2-"gXiuH,~2(R;o<9wi!do U1^||V1U\vR/!`D5 #vuXq@|'!F61CZٶ` f !n " cPʱʌVmf߀& l(MնQsA(eqIMa cªô@M2ݒ:m2VM2Sd.d>M2lEvD 0.a |e!AB ue!Xq ,ݐOYz=D5 J$m6dA@!$KER'062163033528062A61ED :1002E00003C3A202D351B7C93A6403D353ED5B5899 :1002F000037AD3537BD353C9DB51E68028FA3E01FE :10030000D352D350DB51E61020FA57DB514FE64071 :10031000C079E620C83E12CB4220023E10A120EB5D :100320007ED35223160118E36069C97EB7C84F23F4 :10033000E5CD3601E118F4F5214403CD2B03F14F4F :10034000CD3601C90D0A0A4449534B20492F4F208D :100350004552524F52203A000000000000000000B9 :0B036000000000000000000000000092 :0303760000000084 :0604F9003301310100088F :010CFF0000F4 :0000000000 0004377033A0400B7C8CBC5C921FF0422585D :10023000033A6003FE00C82A5A03225E033E08CD3B :100240005F023E003260032A5C03ED5B5A03B7EDA8 :1002500052200621FFFF225C03AFC91E0118021EB7 :1002600003D5216B037323ED5B5E03F53A6003FE58 :100270005728047BE6F85FF1722373233600237757 :10028000233600216B03CD9802D1C8CD92023EFFE8 :10029000B7C93E44CD3703C92261033E0A32630326 :1002A000D354C5CDE802CDF802C1DB51E65020FAA7 :1002B000DB50F5DB51E61820FADB50F1E61F200D8C :1002C000DB51E604D3513EFF2003AFC9F1CB5728E1 :1002D000073E52CD370318 o[3@ D08:10000000C37100C3CB00C32301C32C01C33601C39A :100010004001C34001C34401C34701C34801C35C5D :1000200001C36101C36601C36B01C3B601C34101D2 :10003000C328030001040F009009FF0100FF8000A6 :1000400001000001040F008009FF0100FF80009AF9 :1000500000000000000000000079033300F903F9FC :10006000040000000000000000790342007904FB56 :1000700004AF320300320400219900CD2B033EC3AC :100080003200003205002103EA2201002106DC22B1 :1000900006003A04004FC300D40D0A0A0A42494F31 :1000A00053323230202D2D2D2043502F4D205645D8 :1000B000522E20322E322042494F53202032302DF2 :1000C0004A554E2D38330D0A0D0A00318000CD2BD4 :1000D0000221FFFF225C033E573260030E00CD4831 :1000E00001CD47013A0400F5210100225E03210001 :1000F000D42258033E08CD5B02201F2A580311006A :1001000008193A5E03C608325E03FE1120E33E0082 :10011000326003F1320400C37E003E57CD3703F155 :10012000C3E700DB142FE602C8F6FFC9CD2301B7F1 :1001300028FADB152FC9DB14E60120FA79D315C99B :10014000C93EFFC93E1AC9C921000079FE02D0325A :1001500004006F2929292911510019C9ED436703AA :10016000C9ED436903C9ED436503C921F04F9 ALLA 04FB ALLB 0000 BC 0002 BDACK DC06 BDOS 0007 BELL A000 BIAS EA00 BIOS 0800 BLS 0051 BSTAT 0800 BUFSZ 0080 BUSY 0200 BYSCT 0008 C?HOME 0006 C?SEEK D400 CCP 0040 CD 0004 CDRIVE 03F9 CHKA 0479 CHKB 0051 CLRINT 036B CMDTBL 0200 COMPUTE 0054 CPARITY 0010 CPMBLKS 000D CR 00C8 CRLF 0015 CRTDATA 0014 CRTSTATUS 000E CTEST 0050 DATAI 0052 DATAO 02A2 DCMD1 0002 DE 0344 DEM 0379 DIRBF 0020 DIREC 0053 DMAPORT 0033 DPABLK 0051 DPBASE 0042 DPBBLK 01FF DRM 0990 DSMA 0980 DSMB 0000 EOM 0000 FALSE 000C FFD 0012 FLGSCT 0014 FLGTRK 0259 FLSH1 0010 FMTZTRK 0364 HIDMA 0004 HL 0003 IOBYTE 0004 IX 0004 IY 0361 LCMD@ 000A LF 0001 LINT 0007 MASK 0008 MGABLKS 0008 MSG 003C MSIZE 0100 NBBLK 8000 NBCYN 0010 NBLSCYN 0080 NBREC 0132 NCYN 0100 NRCYN 0010 NRECBLS 0004 NRSCT 0040 NSCYN 002C NSECTS 0001 OFFSET 0277 PC10 0004 PERR 0261 PRECMD 0010 QUADEIA 018D RD1 019C RD2 01AD RD20 0190 RD3 0187 RD4 04FD RDBUF 0001 RDDATA 0011 RDDIAG 0019 RDDTOF 0015 RDID 0010 REQ 000C REQES 000A REQST 000A RETRY 0208 RRA 0002 12)+'0' DB ((VALUE SHR 8) AND 0FH)+'0' DB SP DB ((VALUE SHR 4) AND 0FH)+'0' DB (VALUE AND 0FH) +'0' ENDM ;*** DEBUG MACRO MESG,VALUES ; MACRO TO DEBUGGING BIOS LOCAL DM,DR,SPACE,SKIP ; 'MESG' IS A ASCII STRING LOCAL HLX,DEX,BCX,AFX,ARD ; TO BE PRINTD, 'VALUES' IS LOCAL CRLF ; A LIST OF MEMORY LOCATION JMP ARD ; TO DUMP TO THE TERMINAL. HLX: DW 00 ; A REGISTER DUMP WILL ALSO BCX: DW 00 ; BE PRINTED ON THE CONSOLE. DEX: DW 00 AFX: DW 00 ARD: STA AFX SHLD HLX SDED DEX SBCD BCX PUSH PSW PUSH H PUSH B PUSH D IFNB IRP VAL, LHLD VAL CALL ?PDEC LXI H,SPACE CALL ?PRTMSG ENDM ENDIF LXI H,DM CALL ?PRTMSG LXI H,SKIP CALL ?PRTMSG IRP VAL, LHLD VAL CALL ?PDEC LXI H,SPACE CALL ?PRTMSG ENDM LXI H,CRLF CALL ?PRTMSG POP D POP B POP H POP PSW JMP DR DM: DB MESG DB CR,LF,EOM SPACE: DB " ",EOM SKIP: DB "REGISTER DUMP AF, HL, DE, BC" CRLF: DB CR,LF,EOM DR: ENDM ; BLS/NBREC ; # RECS/BLS NBLSCYN EQU NRCYN/NRECBLS ; # BLS/TRACK DSMA EQU NBLSCYN*(NCYN/2); SIZE OF AN LOGCAL DRIVE A: DSMB EQU NBLSCYN*((NCYN/2)-OFFSET) ; SIZE OF B: ; ; * IOMEGA COMMAND SET * ; FMTZTRK EQU 10000B ; FORMAT Z-TRACK FLGSCT EQU 10010B ; FLAG SECTOR FLGTRK EQU 10100B ; FLAG TRACK C?SEEK EQU 00110B ; SEEK TRACK C?HOME EQU 01000B ; ?HOME DRIVE REQST EQU 01010B ; REQEST STATUS REQES EQU 01100B ; REQEST EXTENDED STATUS CTEST EQU 01110B ; TEST CONTRL. STATUS RDDATA EQU 00001B ; READ DATA RDID EQU 10101B ; READ ID RDDTOF EQU 11001B ; READ DATA WITH OFFSET RDDIAG EQU 10001B ; READ DIAGNOSTIC WRTDATA EQU 00011B ; WRITE DATA WRTID EQU 00111B ; WRITE ID WRTDIAG EQU 10011B ; WRITE DIAGNOSITC ; ; ; ; *** CP/M ENVIROMENT CONSTANTS *** ; TPA EQU 0100H ; ADDRESS OF START OF TPA BIAS EQU (MSIZE-20)*1024 ; CCP EQU 3400H+BIAS ; BASE OF CCP BDOS EQU CCP+0806H ; BASE OF BDOS BIOS EQU CCP+1600H ; BASE OF THIS BIOS RXRDY 0050 SCSIBASE 0292 SCSIERROR 0304 SEL1 02FE SEL2 0050 SELPORT 0099 SIGNON 0100 TPA FFFF TRUE 0363 TRYCNTR 0001 TXRDY 02AA WAIT 02B3 WAIT1 02E4 WAIT2 02CD WAIT4 02DE WAIT5 02D8 WAIT6 02CC WAIT7 00E7 WBT1 00F1 WBT2 011A WBTERR 025F WRTBLK 04FF WRTBUF 0003 WRTDATA 0013 WRTDIAG 0007 WRTID 01E3 WT02 01BD WT03 0013 XOFF 0011 XON 0071 ?BOOT 012C ?CONIN 0136 ?CONOUT 0123 ?CONST 0298 ?DOCMD 0337 ?DSKERR 022B ?FLUSH 007E ?GOCPM 0147 ?HOME 0140 ?LIST 0141 ?LISTST 0002 ?NBSCT 0320 ?OC1 031D ?OC5 030B ?OUTCMD 032B ?PRTMSG 0140 ?PUNCH 02E8 ?PUTDMA 025B ?RDBLK 016B ?READ 0144 ?READER 0328 ?SECTRAN 0148 ?SELDSK 02F8 ?SELECT 0166 ?SETDMA 0161 ?SETSEC 015C ?SETTRK 00CB ?WBOOT 01B6 ?WRITE 035E @ACTSCT 0365 @DMA 0CFF @EXTRA 0377 @OFS 035C @RBLK 0358 @RPNTR 0369 @SECT 0367 @TRK 035A @WBLK 0360 @WRTACT 0376 @WRTYPE  ; ; ; PAGE ; ; *** ASCII CONSTANTS AND USER OPTIONS *** ; ASEG BELL EQU 0007H ; SOUND CONSOLE BELL CR EQU 000DH ; CARIAGE RETURN LF EQU 000AH ; LINEFEED FFD EQU 000CH ; FORMFEED XON EQU 0011H ; ^Q XOFF EQU 0013H ; ^S EOM EQU 0000H ; END OF MESSAGE MARKER FALSE EQU 0000H ; TRUE EQU NOT FALSE ; RETRY EQU 0010 ; RETRYS BEFORE HARD-ERROR MSIZE EQU 0060 ; 60K SYSTEM. ; ; ; *** PORT ASSIGNMENTS *** ; SCSI$BASE EQU 0050H ; SCSI INTERFACE BOARD BASE QUAD$EIA EQU 0010H ; BASE PORT FOR QUAD. EIA BOARD CRTSTATUS EQU QUAD$EIA+4 ; STATUS PORT FOR CONSOLE CRTDATA EQU QUAD$EIA+5 ; DATA PORT FOR CONSOLE ; TXRDY EQU 0001H ; TX. READY BIT IN 8251 USART RXRDY EQU 0002H ; RX. READY BIT IN 8251 USART ; ; *** SCSI PORT ASSIGNMENTS *** ; ; * BIT,BYTE AND PORT ASSIGMENTS FOR * ; * SCSI HOST INTERFACE ADAPTOR * ; DATAI EQU SCSI$BASE ; DATA IN REGISTER DATAO EQU SCSI$BASE+2 ; DATA OUT REG IOBYTE EQU 0003H ; ADDRESS OF IOBYTE CDRIVE EQU 0004H ; CURRENT DISK INDICATOR NSECTS EQU (BIOS-CCP)/128 ; # OF SECTORS/ CCP ; ; ; *** IOMEGA BLOCKING SIZE EQUATES *** ; BUFSZ EQU 2048 ; DATA BLOCKING SIZE MGABLKS EQU BUFSZ/256 ; # OF IOMEGA BLOCKS CPMBLKS EQU BUFSZ/NBREC ; # OF CP/M RECORDS MASK EQU 07H ; SEE FOLLOWING TABLE ; ; ******************************************** ; * THE VALUE OF "MASK" DETERMINES THE BLOCK * ; * BUFFER SIZE OF THE DEBLOCKING ROUTINES. * ; * THE VALUE OF "MASK" ARE: * ; * BUFSZ MASK * ; * ----- ---- * ; * 2048 07H * ; * 4096 0FH * ; * 8192 1FH * ; * 16384 3FH * ; ******************************************** ; ; ; ; ORG BIOS ; START AT BIOS CSEG ; ; PAGE ; JMP ?BOOT ; COLD START JMP ?WBOOT ; WARM BOOT JMP ?CONST ; CONSOLE STATUS JMP  TITLE 'CP/M VER 2.2 BIOS FOR SCSI HOST ADAPTOR' ; NAME ('BIOS22') ; DATE 20-JUN-83 ; BY DAVID WAGSTAFF ; COPYRIGHT 1983 BY GRIFFIN TECH. ALL RIGHTS RESERVED ; ; MACLIB Z80 ; Z-80 CODING IS USED ASEG ; ABSOLUTE ADDRESSING IS NEEDED ; ; ; ; THIS MODULE CONTAINS THE BASIC INPUT/OUTPUT SYSTEM FOR ; VERSION 2.2 OF THE CP/M OPERATING SYSTEM. ; PORTIONS OF THE SERIAL PORT I/O HAVE NOT BEENED CODED FOR OVIOUS REASONS ; THEREFORE, THIS TASK IS LEFT TO THE CUSTOMER OF THIS PRODUCT. ; THE EQUATE 'SCSI$BASE' HAS BE EQUATED TO THE BASE ADDRESS FOR THE SCSI ; INTERFACE BOARD, THE CURRENT VALUE IS 050H. ; THE EQUATE 'MSIZE' SHOULD BE SET TO THE SIZE OF THE OPERATING SYSTEM ; TO BE GEN'ED, TYPICALY THIS SHOULD BE ABOUT 60K. ; ; ; ; ** >> EDITING HISTORY << ** ; ; VER. DATE MODIFICATION ; ---- -------- ---------------------------------------- ; 00 06/20/83 1) CREATED. ; ; ; MDBE MACRO VALUE,SP ; MACRO TO PRINT VERSION OR DATE DB (VALUE SHRISTER BSTAT EQU SCSI$BASE+1 ; BUS STATUS SELPORT EQU SCSI$BASE ; SELECT PORT ADR. CLRINT EQU SCSI$BASE+1 ; CLR. INTRRUPT PORT DMAPORT EQU SCSI$BASE+3 ; DMA ADDRESS PORT CPARITY EQU SCSI$BASE+4 ; CLEAR PARITY PORT BUSY EQU 80H ; CONTROLER BUSY BIT CD EQU 40H ; COMMAND/DATA BIT DIREC EQU 20H ; DIRECTON BIT REQ EQU 10H ; REQUEST BIT MSG EQU 08H ; END MESSAGE BIT PERR EQU 04H ; PERR ERROR BIT BDACK EQU 02H ; BOARD ACK. SIGNAL LINT EQU 01H ; INTERUPTE BIT ; ; *** CARTRIAGE STORAGE INFORMATION FOR IOMEGA SYSTEM *** ; OFFSET EQU 0001 ; TRACK OFFSET FOR SYSTEM TRACK NCYN EQU 306 ; # TRACK/DRIVE NSCYN EQU 64 ; # SECTORS/TRACK ?NBSCT EQU 2 ; # BLOCKS/SECTOR NBBLK EQU 256 ; # BYTES/BLOCK NBREC EQU 128 ; CP/M RECORD SIZE BLS EQU 2048 ; CP/M BLOCK SIZE DRM EQU 512-1 ; # DIR. ENTRYS -1 BYSCT EQU NBBLK*?NBSCT ; # BYTES/SECTOR NBCYN EQU NSCYN*BYSCT ; # BYTES/TRACK NRSCT EQU BYSCT/NBREC ; # RECS/SECTOR NRCYN EQU NSCYN*NRSCT ; # RECS/TRACK NRECBLS EQU?CONIN ; CONSOLE INPUT JMP ?CONOUT ; CONSOLE OUTPUT JMP ?LIST ; PRINTER OUTPUT JMP ?PUNCH ; AUX: OUTPUT ROUTINE JMP ?READER ; AUX: INPUT ROUTINE JMP ?HOME ; RECALIBRATE DRIVE JMP ?SELDSK ; SELECT DRIVE JMP ?SETTRK ; SET TRACK NUMBER JMP ?SETSEC ; SET SECTOR NUMBER JMP ?SETDMA ; SET DMA ADDRESS JMP ?READ ; READ A SECTOR JMP ?WRITE ; WRITE A SECTOR JMP ?LISTST ; RETURN PRINTER STATUS JMP ?SECTRAN ; SECTOR TRANSLATOR ROUTINE ; PAGE ; ; *** >>> COMMON DATA STORAGE DEFINITION AREA <<< *** ; ; *** DISK PARAMETER BLOCK DEFINITIONS *** ; DPABLK: DW NRCYN ; DRIVE A: TYPE DB 4,15 DB 0 DW DSMA DW DRM DW 0FF00H DW (DRM/4)+1 DW 1 ;**** DPBBLK: DW NRCYN ; DRIVE B: TYPE DB 4,15 DB 0 DW DSMB DW DRM DW 0FF00H ; DEBUG = 0FFFFH DW (DRM/4)+1 DW 9AH ;**** ; ; ; *** >>> DISK PARAMETER HEADER TABLES <<< *** ; DPBASE: ; DW 0000,0000 ; DRIVE A: DW 0000,0000 ; DW DIRBF,DPABLK ; DW CHKA,ALLA RENT DISK NUMBER STA CDRIVE ; JMP ?GOCPM ; AN PASS CONTROL TO CCP ;* WBTERR: MVI A,'W' ; A = CODE FOR WARM BOOT ERROR CALL ?DSKERR ; GO PRINT THE MESSAGE POP PSW ; RECOVER ALL OLD NUMBER JMP WBT1 ; AND TRY AGAIN ;* ;** ;* PAGE ; ; *** >>> START OF CHARACTER I/O ROUTINES *** ; ?CONST: ;-OP: SEE IF CONSOLE HAS CHARACTER READY ;-PP: NONE ;-RC: A = 00 : NO CHARACTER READY ;- FF : CHARACTER READY ;- ; >>> SUPPLY CODE HERE FOR YOUR HARDWARE CONFIGURATION <<< ; SAMPLE CODE IS PROVIDED FOR A 8251 TYPE USART ; IN CRTSTATUS ; GET STATUS CMA ; OUR HARDWARE COMPLEMENTS STATUS REGISTER ANI RXRDY ; RZ ; EXIT IF NOT READY ORI 0FFH ; ELSE WITH WITH TRUE RET ;* ;** ;* ;+ ?CONIN: ;-OP: GET CHARACTER FROM THE CONSOLE ;-PP: NONE ;-RC: A = CHARACTER (PARITY BIT STRIPED, I.E. ONLY 7-BITS PRESENT) ;- CALL ?CONST ; WAIT FOR CHARACTER READY ORA A ; JRZ ?CONIN ; ; ; >>> SUPPLY CODE HERE FOR YOUR HARDWARE CONFIGURATION <<< ; >>> R?SETTRK: ;-OP: SET-UP TRACK POINTER ;-PP: BC = TRACK FOR NEXT OPERATION ;-RC: NONE ;- SBCD @TRK ; SAVE CURRENT TRACK RET ; AND EXIT ;* ;** ;* ;+ ?SETSEC: ;-OP: SET-UP SECTOR POINTER ;-PP: BC = SECTOR FOR NEXT OPERATION ;-RC: NONE ;- SBCD @SECT ; SAVE CURRENT SECTOR RET ; AND THEN EXIT ;* ;** ;* ;+ ?SETDMA: ;-OP: SET-UP DMA ADDRESS POINTER ;-PP: BC = ADDRESS OF DMA AREA ;-RC: NONE ;- SBCD @DMA ; SAVE CURRENT DMA ADDRESS RET ; AND THEN EXIT ;* ;** ;* ;+ ?READ: ;-OP: READ A SECTOR ;-PP: DISK READ PARMATERS SET (I.E. TRACK, SECTOR AND DRIVE) ;-RC: A = 0 : NO ERRORS OCCURED ;- = 0FFH : ERRORS DETECTED ;- LXI H,RDBUF ; POINT TO READ BUFFER SHLD @RPNTR CALL COMPUTE ; GET LOG. BLOCK # (HL =) XCHG ; IS BLOCK LOADED?? LHLD @WBLK ; IS SECTOR WRT. ACTIVE?? ORA A ; DSBC DE ; JRZ RD4 ; BRIF SO LHLD @RBLK ; IS BLOCK ALREADY LOADED?? ORA A ; (IN READ BUFFER THAT IS) DSBC DE ; JRZ RD1 ; BRIF IF LOADED JR RD2 ; B; ; DW 0000,0000 ; DRIVE B: DW 0000,0000 ; DW DIRBF,DPBBLK ; DW CHKB,ALLB ; ; PAGE ; ; ; *** >>> START OF BOOT AND WARM BOOT ROUTINES <<< *** ; ?BOOT: ;-OP: HANDLE MISC. INITILIZATION AND SIGNON MESSAGE PRINTING ;-PP: NONE ;-RC: NONE ;- XRA A ; CLEAR IOBYTE STA IOBYTE ; STA CDRIVE ; AND CURRENT DISK LXI H,SIGNON ; GO PRINT SIGN-ON MESSAGE CALL ?PRTMSG ; ?GOCPM: MVI A,0C3H ; A = OP. CODE FOR 'JP' STA 0000H ; VECTOR @ 0000H STA 0005H ;& VECTOR @ 0005H LXI H,BIOS+3 ; LOCATION OF WBOOT ROUTINE SHLD 0001H ; SAVE IT LXI H,BDOS ; LOCATION OF BDOS SHLD 0006H ; SAVE TO SYSTEM VECTOR LDA CDRIVE ; GET THE CURRENT DISK MOV C,A ; TO REGISTER C JMP CCP ; AND PASS CONTROL TO THE CCP ;* ;** ;* SIGNON: DB CR,LF,LF,LF DB 'BIOS220 --- CP/M VER. 2.2 BIOS 20-JUN-83',CR,LF CRLF: DB CR,LF,EOM ;* ;** ;* PAGE ;+ ?WBOOT: ;-OP: WARM BOOT CP/M SYSTEM. ;-PP: SYSTEM TRACKS OF DRIVE A: HAS A VALID SYSTEM ON IT. ;-RC: CCP IS RELEGISTER A WILL RECEIVE CHARACTER, PORT HAS CHARACTER READY <<< ; SAMPLE CODE IS PROVIDED FOR A 8251 TYPE USART. ; IN CRTDATA ; GRAB THE DATA BYTE CMA ; OUR HARDWARE COMPLEMENTS THE DATA REGISTER RET ; AND THEN EXIT ;* ;** ;* ;+ ?CONOUT: ;-OP: SEND CHARACTER TO CONSOLE ;-PP: C = CHARACTER ;-RC: NONE ;- ; >>> SUPPLY CODE HERE FOR YOUR HARDWARE CONFIGURATION <<< ; SAMPLE CODE IS PROVIDED FOR A 8251 TYPE USART IN CRTSTATUS ; WAIT FOR TX. READY ANI TXRDY ; JRNZ ?CONOUT ; REMEMBER OUR HARDWARE MOV A,C ; A = CHARACTER TO SEND OUT CRTDATA ; EJECT THE CHARACTER RET ; AND THEN EXIT ;* ;** ;* ;+ ?LIST: ?PUNCH: ;-OP: HANDLE OUTPUT TO LIST AND PUNCH DEVICES ;-PP: C = CHARACTER TO SEND ;-RC: NONE ;- ; >>> SUPPLY CODE HERE FOR YOUR HARDWARE CONFIGURATION <<< RET ; THIS JUST ACTS AS A BIT-BUCKET ;* ;** ;* ;+ ?LISTST: ;-OP: RETURN STATUS OF PRINTER READY ;-PP: NONE ;-RC: A = 00 : PRINTER NOT READY ;- FF : PRINTER IS READY ;- ; >>> SUPPLY CODE HERIF NOT ;* RD4: LXI H,WRTBUF ; INDEX INTO WRT. BUFF. JMP RD3 ; GO DO IT RD1: LXI H,RDBUF ; INDEX INTO RD. BUFF. RD3: DAD B ; BC = INDEX, HL @ SECTOR DAT LDED @DMA ; DE = ADDRESS DMA LXI B,NBREC ; BC = SIZE OF CP/M RECORD LDIR ; PERFORM THE TRANSFER XRA A ; EXIT WITH NO ERRORS RET ; AND EXIT ;* RD2: SDED @ACTSCT ; SET-UP FOR READ SDED @RBLK ; SET POINTER LDA @WRTACT ; SEE IF WARM BOOT ACTIVE CPI 'W' ; JRZ RD20 ; BRIF SO RES 0,L ; CLEAR UNIT FLAG RD20: MVI A,MGABLKS ; XXX BLOCKS ONLY CALL ?RDBLK ; GO DO IT RNZ ; RETURN ON ERROR JMP RD1 ; GO INDEX INTO TABLE ;* ;** ;* PAGE ;+ ?WRITE: ;-OP: WRITE A SECTOR ;-PP: DISK PERAMETERS ARE SET (I.E. TRACK, SECTOR AND DRIVE) ;- REG C HAS WRITE TYPE 0,1,2 ;-RC: A = 0 : NO ERRORS DETECTED ;- = 0FFH : ERRORS DETECTED ;- MOV A,C ; A= WRITE TYPE STA @WRTYPE ; SAVE FOR LATER CALL COMPUTE ; GO COMPUTE MGA BLOCK WT03: XCHG ; DE = BLOCK LHLD @WBLK ; SEE IF OADED INTO CORE FROM SYSTEM TRACKS ;- LXI SP,0080H ; SET-UP THE STACK TO FREE AREA CALL ?FLUSH ; FLUSH DISK CACHE LXI H,-1 ; FORCE NEW READS SHLD @RBLK ; MVI A,'W' ; MARK AS WARM BOOT STA @WRTACT ; MVI C,0 ; SELECT DRIVE A: CALL ?SELDSK ; CALL ?HOME ; RECALIBRATE DRIVE ; ;* AT THIS POINT WE MUST RELOAD IN EVERYTHING BUT THE BIOS * ; LDA CDRIVE ; A= CURRENT DISK NUMBER WBT1: PUSH PSW ; SAVE CURRENT DISK LXI H,0001 ; SET TO READY BLOCK 1 SHLD @ACTSCT ; LXI H,CCP ; HL @ BASE OF CCP WBT2: SHLD @RPNTR ; SAVE LOAD ADR. TO DMA POINTER MVI A,8 ; GO READ IN 8 BLOCKS (8*256) BYTES CALL ?RDBLK ; GO DO IT JRNZ WBTERR ; BRIF ERROR LHLD @RPNTR ; UP-DATE DMA POINTER LXI D,NBBLK*8 ; DE = TRANSFER SIZE DAD D ; LDA @ACTSCT ; POINT NEXT DATA BLOCK ADI 08 ; STA @ACTSCT ; CPI 11H ; SEE IF THE END HAS BEEN REACHED JRNZ WBT2 ; BRIF NOT DONE MVI A,FALSE ; MARK AS NOT WRITE ACTIVE STA @WRTACT ; POP PSW ; RECOVER CURRE FOR YOUR HARDWARE CONFIGURATION <<< ; MVI A,TRUE ; THIS IS JUST A DEFAULT RET ; AND THEN EXIT ;* ;** ;* ;+ ?READER: ;-OP: HANDLE INPUT FROM A SECONDARY INPUT DEVICE ;-PP: NONE ;-RC: A = INPUTED CHARACTER. ;- ; >>> SUPPLY CODE HERE FOR YOUR HARDWARE CONFIGURATION <<< MVI A,'Z' AND 3FH ; THIS JUST RETURNS EOF RET ; ;* ;** ;* ; ; PAGE ; *** >>> DISK SUPPORT ROUTINES <<< *** ; ;+ ?HOME: ;-OP: THIS FUNCTION PERFORMS NO-OPERATION IN ;- THIS SYSTEM. ;- RET ; JUST EXIT ;* ;** ;* ;+ ?SELDSK: ;-OP: SELECT A DRIVE FOR FURTHER OPERATIONS ;-PP: C = DRIVE TO SELECT ;-RC: HL @ DPH FOR DRIVE ELSE 0000 IF BAD DRIVE ;- LXI H,0000 ; READY FOR ERROR EXIT MOV A,C ; A = DRIVE CODE CPI 2 ; RNC ; EXIT IF BAD SELECT CODE STA CDRIVE ; SAVE NEW CURRENT DISK MOV L,A ; HL = DRIVE CODE REPT 4 DAD H ; HL = HL * 16 ENDM LXI D,DPBASE ; DE = BASE OF TABLE DAD D ; PERFORM THE INDEX OPERATION RET ; AND THEN EXIT ;* ;** ;* ;+ THE SAME AS LOADED ORI A ; CLEAR CARRY DSBC DE ; TEST JRZ WT02 ; BRIF SO PUSH D ; SAVE GOAL BLK# CALL ?FLUSH ; FLUSH OUT OLD BLOCK NUMBER POP H ; HL= NEW BLOCK # SHLD @ACTSCT ; UP-DATE POINTERS SHLD @WBLK ; LXI H,WRTBUF ; DMA TO WRITE BUFFER SHLD @RPNTR ; ; IF BUFSZ-2048 MVI A,MGABLKS ; READ IN A BLOCK CALL ?RDBLK ; GO READ IT IN ELSE ; BLOCK SIZE = 2048 LDA @WRTYPE ; SEE IF WRITE TYPE IS TYPE 2 CPI 2 ; MVI A,MGABLKS ; READY FOR PRE-READ IF NECESSARY CNZ ?RDBLK ; BRIF SO ENDIF ; RNZ ; RETURN ON ERROR WT02: LXI H,WRTBUF ; HL @ SECTOR BUFFER DAD B ; ADD IN THE OFFSET XCHG ; DE @ SECTOR LHLD @DMA ; HL @ DATA LXI B,NBREC ; BC = # BYTES/CP/M RECORD LDIR ; DO THE TRNSFR ; MVI A,TRUE ; SET WRITE ACTIVE TO TRUE STA @WRTACT ; LDA @WRTYPE ; GET BACK WRITE TYPE DCR A ; CHECK FOR DIRECTORY MVI A,0 ; FOR SAFTY CZ ?FLUSH ; GO FLUSH DATA IF SO ORA A ; SET FLAGS RET ; AND EXIT ;* ;** TORE COMMAND BYTE INX H ; POINT NEXT LDED @ACTSCT ; DE = LOG. BLOCK NUMBER PUSH PSW ; SAVE BLOCK COUNT LDA @WRTACT ; SEE IF IN WARM BOOT CPI 'W' ; JRZ PC10 ; BRIF SO MOV A,E ; MASK OUT GARBAGE ANI NOT MASK ; MOV E,A ; PC10: POP PSW ; RECOVER BLOCK COUNT MOV M,D ; SAVE IT INX H ; MOV M,E ; INX H ; MVI M,0 ; ALWAYS < 256 LOG. BLOCKS INX H MOV M,A ; SAVE # BLOCKS TO TRNSFR INX H MVI M,0 ; CLEAR EXTRA BYTE LXI H,CMDTBL ; HL @ CMD. BLOCK CALL ?DOCMD ; GO DO IT POP D ; RECOVER COMMAND RZ ; RETURN IF OK CALL SCSI$ERROR ;GO PRINT DISK ERROR MVI A,0FFH ;MARK THE ERROR ORA A ; RET ;AND EXIT ;* ;** ;* ;+ SCSI$ERROR: ;-OP: HANDLE SCSI DISK ERRORS ;- MVI A,'D' ; CODE FOR DATA ERROR CALL ?DSKERR ; DO THE DISK ERROR RET ; AND THEN EXIT ;* ;** ;* ; PAGE ; ;* START OF PROTOCAL HANDLING ROUTNES * ; ;+ ?DOCMD: ;-OP: ISSUE COMMAND TO SCSI HOST ADAPTOR ;-PP: HL @ COMMAND BYTES TO SEND TAT ; WAIT FOR REQ ANI REQ ; JRNZ SEL1 ; MOV D,A ; D=0, MARK FIRST COMMAND ; ;* NOW FALL ON THRU TO OUTPUT COMMAND BYTES * ; ;+ ?OUTCMD: ;-OP: ISSUE COMMAND BYTES TO HOST ADAPTOR ;-PP: HL @ COMMAND BYTES ;- IN BSTAT ; GRAB BUSS STATUS MOV C,A ; SAVE STATUS ANI CD ; SEE IF DATA RNZ ; EXIT IF DATA MOV A,C ; CHECK FOR DIREC ANI DIREC ; RZ ; EXIT IF INPUT MVI A,REQ+BDACK ; BIT 0,D ; SEE IF FIRST CMD. JRNZ ?OC5 ; BRIF NOT MVI A,REQ ; ELSE JUST CHECK FOR REQ. ?OC5: ANA C ; CHECK FOR READY JRNZ ?OUTCMD ; BRIF NOT (1.75/1.17) ?OC1: MOV A,M ; GET COMMAND BYTE (1.75/1.17) OUT DATAO ; SEND TO CONTROLER (2.75/1.83) INX H ; POINT NEXT (1.5/1.0) MVI D,1 ; MARK NOT FIRST COMMAND JR ?OUTCMD ; AND DO IT AGAIN! ;* ;** ;* ; PAGE ; ; *** MISC. ROUTINES AND FUNCTIONS *** ; ; ;+ ?SECTRAN: ;-OP: PERFORM SECTOR TRANSLATION ;-PP: DE @ TRAN. TABLE ;- BC = SECTOR NUMBER ;- HL = TRAN. SECTOR NUMBER ;-  ;* PAGE ;+ COMPUTE: ;-OP: COMPUTE PHYS. BLOCK NUMBER ;-PP: TRACK AND SECTOR ARE SET ;-RC: HL = PHYS. BLOCK NUMBER ;- BC = INDEX INTO BLOCK (0..BUFSZ) ;- ; LXI H,@TRK ; HL @ TRACK # MVI E,0 ; CLEAR LOW DE MOV D,M ; LOAD LOW TRACK INX H ; POINT HI TRACK MOV A,M ; A= HI TRACK RRA ; DIVIDE BY TWO RARR D ; RARR E ; XCHG ; HL= TRACK*128 LDA @SECT ; A = SECTOR NUMBER SRLR A ; DIVIDE BY 2 MVI C,0 ; C= 0 OR 80H RARR C ; ADD L ; MOV B,A ; ANI NOT MASK ; MOV L,A ; MOV A,B ; ANI MASK ; MOV B,A ; SBCD @OFS ; SAVE OFFSET LDA CDRIVE ; FOR SELECTION ORA A ; CHECK FOR UNIT 0 RZ ; RETURN IF SO SETB 0,L ; ELSE SET UNIT 1 FLAG RET ; AND EXIT ;* ;** ;* ;+ ?FLUSH: ;-OP: FLUSH WRITE BUFFER IF NEEDED ;-PP: @WBLK IS SET AND VALID ;- IF @WRTACT FLAG IS SET TO TRUE ;- ; LXI H,WRTBUF ; SET DMA TO WRITE BUFFER SHLD @RPNTR ; LDA @WRTACT ; CPI FALSE ; BUFFER WRITE ACTIVE?? RZ ; RETURN I;- @ACTSEC & @RPNTR ARE VALID ;-RC: NO - ZERO : ERROR IN COMMAND (A = ERROR BITS) ;- ZERO : COMMAND WAS EXECUTED SUCCESSFULLY ;- SHLD LCMD@ ; SAVE COMMAND @ MVI A,RETRY ; GET RETRY COUNT STA TRYCNTR ; RESET COUNTER OUT CPARITY ; RESET PARITY ERROR DCMD1: PUSH B ; SAVE COUNTER CALL ?PUTDMA ; SET DMA ADDRESS CALL ?SELECT ; GO SELECT CONTROLER POP B ; RECOVER BC ; WAIT: ; ;* HERE WE MUST WAIT FOR EXECUTION * ; IN BSTAT ; A <--- BUSS STATUS ANI CD+REQ ; CHECK FOR DATA JRNZ WAIT ; BRIF STILL DATA IN DATAI ; A <-- COMPLETION STATUS PUSH PSW ; SAVE ENDING STATUS WAIT1: IN BSTAT ; WAIT FOR REQ. AND MSG. ANI REQ+MSG ; JRNZ WAIT1 ; IN DATAI ; GET BYTE OF ZERO POP PSW ; RECOVER STATUS ANI 00011111B ; MASK OUT ERRORS JRNZ WAIT4 ; BRIF NOT OK IN BSTAT ; CHECK FOR PARITY ANI PERR ; OUT CLRINT ; CLEAR INTERRUPT MVI A,0FFH ; JRNZ WAIT4 ; BRIF ERROR XRA A ; EXIT WITH ZERO RET ; AND EXIT ;* ;* WAMOV H,B ; SIMPLE 1 TO 1 TRANSLATION MOV L,C ; RET ; ADD EXIT ;* ;** ;* ; ;+ ?PRTMSG: ;-OP: PRINT MESSAGE STRING AT HL ;-PP: HL @ MESSAGE STRING TERMINATED WITH A ZERO BYTE. ;-RC: NONE ;- MOV A,M ; CHECK FOR EOS ORA A ; RZ ; EXIT IF SO MOV C,A ; C = CHARACTER INX H ; POINT NEXT CHARACTER PUSH H ; AND SAVE CALL ?CONOUT ; AND ISSUE TO TERMINAL HANDLER POP H ; RECOVER POINTER JR ?PRTMSG ; AND CONTINUE ;* ;** ;* ;+ ?DSKERR: ;-OP: DISK ERROR HANDLER ;-PP: A = ERROR CODE LETTER ;-RC: NONE ;- PUSH PSW ; SAVE ERROR LETTER ON STACK LXI H,DEM ; HL @ DISK ERROR MESSAGE CALL ?PRTMSG ; GO PRINT MESSAGE HEADER POP PSW ; C = ERROR CODE LETTRE MOV C,A ; CALL ?CONOUT ; AND PRINT IT RET ; AND EXIT ;* DEM: DB CR,LF,LF DB 'DISK I/O ERROR :',0 ;* ;** ;* ; PAGE ; ; *** >>> BIOS DATA STORAGE AREA <<< *** ; ; @RPNTR: DW 00 ; ADDRESS OF INTERNAL DEBLOCKING BUFFER @WBLK: DW 00 ; CURRENT WRITE BLOCK NUMBER @RBLK: DW F NOT LHLD @WBLK ; SHLD @ACTSCT ; ACTSEC = WBLKN MVI A,MGABLKS ; WRITE ONLY XX BLOCK CALL WRTBLK ; GO WRITE IT MVI A,FALSE ; BUFFER NOT WRITE ACTIVE STA @WRTACT ; LHLD @RBLK ; IS READ/WRITE TO SAME LDED @WBLK ORA A ; DSBC DE ; JRNZ FLSH1 ; BRIF NOT LXI H,-1 ; FORCE READ SHLD @RBLK ; FLSH1: XRA A ; RECORD NO ERROR RET ; AND EXIT ;* ;** ;* ; ; PAGE ; ; *** >>> SACI HOST INTERFACE ADAPTOR SUPPORT ROUTINES <<< *** ; ;+ ?RDBLK: ;-OP: READ IN X SECTORS ;-PP: A = NUMBER OF BLOCKS TO READ ;- @ACTSCT IS VALID ;- MVI E,RDDATA ; E = READ DATA COMMAND JR PRECMD ; GO PREPARE FOR IT ;* ;** ;* ;+ WRTBLK: ;-OP: WRITE OUT X BLOCKS ;-PP: A = NUMBER OF BLOCKS TO WRITE ;- @ACTSCT IS VALID ;- MVI E,WRTDATA ; E = WRITE DATA CMD. ;+ PRECMD: ;-OP: CREATE COMMAND BLOCK ;-PP: A = NUMBER OF BLOCK INVOLVED ;- E = FIRST COMMAND BYTE ;- PUSH D ; SAVE COMMAND LXI H,CMDTBL ; HL @ COMMAND BLOCK MOV M,E ; SIT7: POP PSW ; CLEAR OUT STACK WAIT4: BIT 2,A ; HARDWARE BUSY?? JRZ WAIT6 ; BRIF NOT MVI A,'R' ; CODE FOR READY ERROR CALL ?DSKERR ; JR WAIT5 ; AND CONTINUE ;* WAIT6: LXI H,TRYCNTR ; SEE IF RETRY UP DCR M ; JRZ WAIT2 ; BRIF RETRY IS UP WAIT5: LHLD LCMD@ ; RECOVER LAST COMMAND JMP DCMD1 ; AND TRY AGAIN ;* WAIT2: OUT CLRINT ; CLEAR INTERRUPT ORA A ; EXIT WITH NON-ZERO RET ; AND EXIT ;* ;** ;* ;+ ?PUTDMA: ;-OP: SEND DMA ADDRESS TO HOST ADAPTER ;-PP: RPNTR HAS DMA ADDRESS ;- LDA HIDMA ; SET HI-BYTE OUT DMAPORT ; HIGH BYTE ALWAYS ZERO LDED @RPNTR ; DE @ DMA ADDRESS MOV A,D OUT DMAPORT ; SEND BYTE 1 MOV A,E OUT DMAPORT ; SEND BYTE 2 RET ; AND EXIT ;* ;** ;* ;+ ?SELECT: ;-OP: SELECT CONTROLER ;- IN BSTAT ; IS CONTROLER BUSY?? ANI BUSY ; WAIT FOR NOT BUSY JRZ ?SELECT ; WAIT IF SO SEL2: MVI A,01H ; SELECT CONTROLER #1 OUT DATAO ; OUT SELPORT ; AND SELECT CONTROLER SEL1: IN BS00 ; CURRENT READ BLOCK NUMBER @ACTSCT: DW 00 ; BLOCK NUMBER TO READ/WRITE @WRTACT: DB FALSE ; TRUE IF BLOCK IS WRITE ACTIVE LCMD@: DW 00 ; ADDRESS OF LAST IOMEGA COMMAND TRYCNTR: DB 00 ; RETRY COUNTER FOR IOMEGA I/O OP.S HIDMA: DB 00H ; PAGE ADDRESS OF IOMEGA BUFFER AREA @DMA: DW 00 ; CURRENT DMA ADDESS @TRK: DW 00 ; CURRENT TRACK NUMBER @SECT: DW 00 ; CURRENT SECTOR NUMBER CMDTBL: DS 11 ; IOMEGA COMMAND TABLE STORAGE @WRTYPE: DB 00H ; CURRENT WRITE TYPE @OFS: DW 00 ; CURRENT DISK CACHE INDEX DIRBF: DS 128 ; DIRECTORY BUFFER CHKA: DS (DRM/4)+1 ; DIRECTORY CHECKSUM FOR DRIVE A: CHKB: DS (DRM/4)+1 ; DIRECTORY CHECKSUM FOR DRIVE B: ALLA: DW (DSMA/8)+1 ; ALLOCATION MAP FOR DRIVE A: ALLB: DW (DSMB/8)+1 ; ALLOCATION MAP FOR DRIVE B: RDBUF: DW BUFSZ ; ADDRESS OF READ DATA BUFFER WRTBUF: DS BUFSZ ; ADDRESS OF WRITE DATA BUFFER @EXTRA: DB 00 ; EXTRA BYTE ; END END dma address port cparity equ SCSI$base+4 ; clear parity port busy equ 80h ; controler busy bit cd equ 40h ; command/data bit direc equ 20h ; directon bit req equ 10h ; request bit msg equ 08h ; end message bit perr equ 04h ; perr error bit bdack equ 02h ; board ack. signal lint equ 01h ; interupte bit ; ; cseg ; start:: ld sp,stack ; set up the stack pointer call txout .xlist defb cr,lf defb 'IPLGEN00 -- Initial Program Booter and' defb ' System Generator V1.1' defb cr,lf,lf defb 'For 60k Systems',cr,lf,lf,lf defb 'L)oad or M)ake System Track --->',eom call ci ; get answer cp 'M' ; see if make system jp z,make$system ; brif so cp 'L' ; see if load system jp z,load$system ; brif so call txout defb cr,lf,lf defb 'ERROR: Please Type "M" or "L"' defb cr,lf,lf,eom jp start ;* ;** ;* ;+ txout:: ;- ex (sp),hl ; hl @ data ld a,(hl) ; a = data inc hl ; put back pointer ex (sp),hl ; cp eom ; end of message??? rbrif done pop hl ; increment dma ld de,128 ; add hl,de ; jp ms070 ; ;* ms080:: call txout ; defb cr,lf,'OK',cr,lf,eom call get$drive ; go get the proper drive code ld hl,buffer+0880h ; start = buffer ld (begin),hl ; pop hl ; end = last dma ld (last),hl ; ld a,03 ; command is write ld (command),a ; call doio ; and do the i/o call txout defb cr,lf,lf defb 'Operation Completed',cr,lf,eom jp 0000 ;* ;** ;* ;+ get$drive: ;- call txout defb cr,lf defb 'Enter 0 (Drive #0) or 1 (Drive #1) -->',eom call ci cp '0' jp z,gd99 cp '1' jp nz,gd010 ld a,20h ld (drive),a gd99: call txout defb cr,lf defb 'OK',cr,lf,eom ret ;* gd010: call txout defb cr,lf defb 'ERROR: Please Enter Either 0 or 1',cr,lf,eom jp get$drive ;* ;** ;* ;+ load$system:: ;- call txout defb cr,lf,lf defb 'Load System Function Selected',cr,lf,eom call get$drive ld hl,0d400h ld (begin),hl ld hl,0f700h ld (last),hl ld a,1 ld (command),et z ; return if so ld e,a ; else e = character ld c,2 ; console output code call 0005h ; do the bdos stuff jp txout ; and repeat ;* ;** ;* ;+ ci:: ;- ld c,1 call 0005h ret ;* ;** ;* ;+ make$system:: ;- call txout .xlist defb cr,lf,lf defb 'Please Enter Name of GEN''ed CP/M System --->',eom .list ld hl,line$buffer ; hl @ line buffer ld (hl),80 ; max. line size = 80 characters ex de,hl ; de @ line buffer ld c,10 ; read console buffer call 0005h ; ld hl,fcb ; clear out fcb ld de,fcb+1 ; ld bc,33 ; ld (hl),00 ; prime the routine ldir ; perform the operation ld de,fcb+1 ; de @ filename ld hl,line$buffer+1 ; hl @ filename line ld c,(hl) ; c = size of line inc hl ; point to data part of line ld b,8 ; b = size of filename ms010:: ld a,(hl) ; a = data from line cp '.' ; is it a dot?? jp z,ms020 ; brif so ld (de),a ; else stuff to fcb inc hl ; inc de ; increment pointers djnz ms010 ;a call txout defb cr,lf,lf defb 'Loading System ...',eom call doio jp 0ea00h ;* ;** ;* ;+ doio:: ;- ld hl,command ld a,(drive) or (hl) ld (hl),a ld de,(begin) ld (dma),de ld a,1 ld (command+2),a ld (command+4),a doio10:: ld hl,command call docmd jr z,doio20 call txout defb cr,lf,lf defb 'ERROR: Disk I/O Error Detected, Operation Aborted' defb cr,lf,eom jp 0000 ;* doio20:: ld hl,command+2 inc (hl) ld hl,dma+1 inc (hl) ld hl,(dma) ld de,(last) or a sbc hl,de jp c,doio10 ret ;* ;** ;* ; ;* start of protocal handling routnes * ; ;+ docmd: ;-op: issue command to SCSI host adaptor ;-pp: hl @ command bytes to send ;- @actsec & @rpntr are valid ;-rc: no - zero : error in command (a = error bits) ;- zero : command was executed successfully ;- ld (lcmd@),hl ; save command @ ld a,retry ; get retry count ld (trycntr),a ; reset counter out (cparity),a ; reset parity error dcmd1: push bc ; save counter cal title 'Initial Program Loader and Generator V1.1" name ('iplgen') ; date 21-Jun-83 ; ; .z80 ; Z-80 coding is used ; ; aseg ; ; *** ASCII Constants *** ; cr equ 0dh lf equ 0ah bell equ 07h eom equ '$' retry equ 10 ; ; ; ; ; *** Port Assignments *** ; SCSI$base equ 0050h ; SCSI Interface board base QUAD$eia equ 0010h ; Base port for QUAD. eia board crtstatus equ QUAD$eia+4 ; Status port for console crtdata equ QUAD$eia+5 ; Data port for console ; txrdy equ 0001h ; Tx. Ready bit in 8251 usart rxrdy equ 0002h ; Rx. Ready bit in 8251 usart ; ; *** SCSI Port assignments *** ; ; * bit,byte and port assigments for * ; * SCSI host interface adaptor * ; datai equ SCSI$base ; data in register datao equ SCSI$base+2 ; data out register bstat equ SCSI$base+1 ; bus status selport equ SCSI$base ; select port adr. clrint equ SCSI$base+1 ; clr. intrrupt port dmaport equ SCSI$base+3 ;  ms030:: ld a,(hl) ; skip past '.' cp '.' ; jp z,ms020 ; brif found inc hl ; jp ms030 ; and countine ;* ms020:: inc hl ; point past '.' ld a,b ; see if all filename is filed or a ; jp z,ms040 ; brif so ms050:: ld a,' ' ; pad with spaces ld (de),a ; inc de ; djnz ms050 ; ms040:: ld bc,3 ; ldir ; trnsfr rest of file name ld de,fcb ; try to open ld c,15 ; call 0005h ; cp 0ffh ; check for error jp nz,ms060 ; brif ok call txout ; defb cr,lf,lf defb 'ERROR: Cannot Open File ',eom ld de,(line$buffer+1) ld hl,line$buffer+2 ld d,0 add hl,de ld (hl),'$' ld de,line$buffer+2 ld c,9 call 0005h jp make$system ;* ms060:: call txout defb cr,lf defb 'Loading File ...',eom ld hl,buffer ms070:: ex de,hl ; de @ dma buffer push de ; save ld c,26 ; set dma call 0005h ; ld de,fcb ; de @ fcb ld c,20 ; go read a record call 0005h ; perform the read or a ; check for errors jp nz,ms080 ; l ?putdma ; set dma address call ?select ; go select controler pop bc ; recover bc ; wait: ; ;* here we must wait for execution * ; in a,(bstat) ; a <--- buss status and cd+req ; check for data jr nz,wait ; brif still data in a,(datai) ; a <-- completion status push af ; save ending status wait1: in a,(bstat) ; wait for req. and msg. and req+msg ; jr nz,wait1 ; in a,(datai) ; get byte of zero pop af ; recover status and 00011111b ; mask out errors jr nz,wait4 ; brif not ok in a,(bstat) ; check for parity and perr ; out (clrint),a ; clear interrupt ld a,0ffh ; jr nz,wait4 ; brif error xor a ; exit with zero ret ; and exit ;* ;* wait7: pop af ; clear out stack wait4: bit 2,a ; hardware busy?? jr z,wait6 ; brif not call txout defb cr defb 'Please Wait, Drive is Spining Up',eom jr wait5 ; and continue ;* wait6: ld hl,trycntr ; see if retry up dec (hl) ; jr z,wait2 ; brif retry is up CTON BIT 0010 = REQ EQU 10H ; REQUEST BIT 0008 = MSG EQU 08H ; END MESSAGE BIT 0004 = PERR EQU 04H ; PERR ERROR BIT 0002 = BDACK EQU 02H ; BOARD ACK. SIGNAL 0001 = LINT EQU 01H ; INTERUPTE BIT ; ; CSEG ; START: CP/M RMAC ASSEM 1.1 #002 INITIAL PROGRAM LOADER AND GENERATOR V1.1 0000 318E00 LXI SP,STACK ; SET UP THE STACK POINTER 0003 CDB200 CALL TXOUT 0006 0D0A DB CR,LF 0008 49504C4745 DB 'IPLGEN00 -- INITIAL PROGRAM BOOTER AND' 002E 2053595354 DB ' SYSTEM GENERATOR V1.1' 0044 0D0A0A DB CR,LF,LF 0047 464F522036 DB 'FOR 60K SYSTEMS',CR,LF,LF,LF 005A 4C294F4144 DB 'L)OAD OR M)AKE SYSTEM TRACK --->',EOM 007B CDC200 CALL CI ; GET ANSWER 007E FE4D CPI 'M' ; SEE IF MAKE SYSTEM 0080 CAC800 JZ MAKE$SYSTEM ; BRIF SO 0083 FE4C CPI 'L' ; SEE IF LOAD SYSTEM 0085 CA6D02 JZ LOAD$SYSTEM ; BRIF SO 008 wait5: ld hl,(lcmd@) ; recover last command jp dcmd1 ; and try again ;* wait2: out (clrint),a ; clear interrupt or a ; exit with non-zero ret ; and exit ;* ;** ;* ;+ ?putdma: ;-op: send dma address to host adapter ;-pp: rpntr has dma address ;- ld a,(hidma) ; set hi-byte out (dmaport),a ; high byte always zero ld de,(dma) ; de @ dma address ld a,d out (dmaport),a ; send byte 1 ld a,e out (dmaport),a ; send byte 2 ret ; and exit ;* ;** ;* ;+ ?select: ;-op: select controler ;- in a,(bstat) ; is controler busy?? and busy ; wait for not busy jr z,?select ; wait if so sel2: ld a,01h ; select controler #1 out (datao),a ; out (selport),a ; and select controler sel1: in a,(bstat) ; wait for req and req ; jr nz,sel1 ; ld d,a ; d=0, mark first command ; ;* now fall on thru to output command bytes * ; ;+ ?outcmd: ;-op: issue command bytes to host adaptor ;-pp: hl @ command bytes ;- in a,(bstat) ; grab  CP/M RMAC ASSEM 1.1 #001 INITIAL PROGRAM LOADER AND GENERATOR V1.1 TITLE 'INITIAL PROGRAM LOADER AND GENERATOR V1.1' ; NAME ('IPLGEN') ; DATE 21-JUN-83 ; CONVERTED TO MAC/RMAC CODE 18 JULY 83 RHP ; MACLIB Z80 ; Z-80 CODING IS USED ; ; ASEG ; ; *** ASCII CONSTANTS *** ; 000D = CR EQU 0DH 000A = LF EQU 0AH 0007 = BELL EQU 07H 0024 = EOM EQU '$' 000A = RETRY EQU 10 0005 = BDOS EQU 0005H ; ; ; ; *** PORT ASSIGNMENTS *** ; 0050 = SCSI$BASE EQU 0050H ; SCSI INTERFACE BOARD BASE 0010 = QUAD$EIA EQU 0010H ; BASE PORT FOR QUAD. EIA BOARD 0014 = CRTSTATUS EQU QUAD$EIA+4 ; STATUS PORT FOR CONSOLE 008 CDB200 CALL TXOUT 008B 0D0A0A DB CR,LF,LF 008E 4552524F52 DB 'ERROR: PLEASE TYPE "M" OR "L"' 00AB 0D0A0A24 DB CR,LF,LF,EOM 00AF C30000 JMP START ;* ;** ;* ;+ TXOUT: ;- 00B2 E3 XTHL ; HL @ DATA 00B3 7E MOV A,M ; A = DATA 00B4 23 INX H ; PUT BACK POINTER 00B5 E3 XTHL ; 00B6 FE24 CPI EOM ; END OF MESSAGE??? 00B8 C8 RZ ; RETURN IF SO 00B9 5F MOV E,A ; ELSE E = CHARACTER 00BA 0E02 MVI C,2 ; CONSOLE OUTPUT CODE 00BC CD0500 CALL BDOS ; DO THE BDOS STUFF 00BF C3B200 JMP TXOUT ; AND REPEAT ;* ;** ;* ;+ CI: ;- 00C2 0E01 MVI C,1 00C4 CD0500 CALL BDOS 00C7 C9 RET ;* ;** ;* ;+ buss status ld c,a ; save status and cd ; see if data ret nz ; exit if data ld a,c ; check for direc and direc ; ret z ; exit if input ld a,req+bdack ; bit 0,d ; see if first cmd. jr nz,?oc5 ; brif not ld a,req ; else just check for req. ?oc5: and c ; check for ready jr nz,?outcmd ; brif not (1.75/1.17) ?oc1: ld a,(hl) ; get command byte (1.75/1.17) out (datao),a ; send to controler (2.75/1.83) inc hl ; point next (1.5/1.0) ld d,1 ; mark not first command jr ?outcmd ; and do it again! ;* ;** ;* ; ; dseg line$buffer:: defs 80+2 last:: defw 00 begin:: defw 00 hidma:: defw 00 drive:: defw 00 dma:: defw 00 lcmd@:: defw 00 trycntr:: defw 00 command:: defw 00,00,00,00 fcb:: defs 36 defw 100 stack:: buffer:: end mmand bytes * ; ;+ ?outcmd: ;-op: issue command bytes to host adaptor ;-pp: hl @ command bytes ;- in a,(bstat) ; grab 15 = CRTDATA EQU QUAD$EIA+5 ; DATA PORT FOR CONSOLE ; 0001 = TXRDY EQU 0001H ; TX. READY BIT IN 8251 USART 0002 = RXRDY EQU 0002H ; RX. READY BIT IN 8251 USART ; ; *** SCSI PORT ASSIGNMENTS *** ; ; * BIT,BYTE AND PORT ASSIGMENTS FOR * ; * SCSI HOST INTERFACE ADAPTOR * ; 0050 = DATAI EQU SCSI$BASE ; DATA IN REGISTER 0052 = DATAO EQU SCSI$BASE+2 ; DATA OUT REGISTER 0051 = BSTAT EQU SCSI$BASE+1 ; BUS STATUS 0050 = SELPORT EQU SCSI$BASE ; SELECT PORT ADR. 0051 = CLRINT EQU SCSI$BASE+1 ; CLR. INTRRUPT PORT 0053 = DMAPORT EQU SCSI$BASE+3 ; DMA ADDRESS PORT 0054 = CPARITY EQU SCSI$BASE+4 ; CLEAR PARITY PORT 0080 = BUSY EQU 80H ; CONTROLER BUSY BIT 0040 = CD EQU 40H ; COMMAND/DATA BIT 0020 = DIREC EQU 20H ; DIRE MAKE$SYSTEM: ;- 00C8 CDB200 CALL TXOUT 00CB 0D0A0A DB CR,LF,LF 00CE 504C454153 DB 'PLEASE ENTER NAME OF GEN''ED CP/M SYSTEM --->',EOM 00FB 210000 LXI H,LINE$BUFFER ; HL @ LINE BUFFER 00FE 3650 MVI M,80 ; MAX. LINE SIZE = 80 CHARACTERS 0100 EB XCHG ; DE @ LINE BUFFER 0101 0E0A MVI C,10 ; READ CONSOLE BUFFER CP/M RMAC ASSEM 1.1 #003 INITIAL PROGRAM LOADER AND GENERATOR V1.1 0103 CD0500 CALL BDOS ; 0106 216800 LXI H,FCB ; CLEAR OUT FCB 0109 116900 LXI D,FCB+1 ; 010C 012100 LXI B,33 ; 010F 3600 MVI M,00 ; PRIME THE ROUTINE LDIR ; PERFORM THE OPERATION 0111+EDB0 DB 0EDH,0B0H 0113 116900 LXI D,FCB+1 ; DE @ FILENAME 0116 210100 LXI H,LINE$BUFFER+1 ; HL @ FILENAME LINE 0119 4E MOV C,M ; C = SIZE OF LINE 011A 23 INX H ; POINT TO DATA PART OF LINE 011B 0608 MVI B,8 ; B = SIZE OF FILENAME MS010: 011D 7E 01A0 D5 PUSH D ; SAVE 01A1 0E1A MVI C,26 ; SET DMA 01A3 CD0500 CALL BDOS ; 01A6 116800 LXI D,FCB ; DE @ FCB 01A9 0E14 MVI C,20 ; GO READ A RECORD 01AB CD0500 CALL BDOS ; PERFORM THE READ 01AE B7 ORA A ; CHECK FOR ERRORS 01AF C2BA01 JNZ MS080 ; BRIF DONE 01B2 E1 POP H ; INCREMENT DMA 01B3 118000 LXI D,128 ; 01B6 19 DAD D ; 01B7 C39F01 JMP MS070 ; ;* MS080: 01BA CDB200 CALL TXOUT ; 01BD 0D0A4F4B0D DB CR,LF,'OK',CR,LF,EOM 01C4 CDF801 CALL GET$DRIVE ; GO GET THE PROPER DRIVE CODE 01C7 210E09 LXI H,BUFFER+0880H ; START = BUFFER 01CA 225400 SHLD BEGIN ; 01CD E1 POP H ; END = LAST DMA 01CE 225200 SHLD LAST ; 01D1 3E03 MVI A,03 ; COMMAND IS WRITE 01D3 326000 STA COMMAND ; 01D6 CDC602 CALL DOIO ; AND DO THE I/O 01D9 CDB200 CALL TXOUT 01DC 0D0A0A DB CR,LF,LF 01DF 4F50455241 DB 'OPERATION COMPLETED' 02DE 216000 LXI H,COMMAND 02E1 CD3903 CALL DOCMD CP/M RMAC ASSEM 1.1 #006 INITIAL PROGRAM LOADER AND GENERATOR V1.1 JRZ DOIO20 02E4+283D DB 28H,DOIO20-$-1 02E6 CDB200 CALL TXOUT 02E9 0D0A0A DB CR,LF,LF 02EC 4552524F52 DB 'ERROR: DISK I/O ERROR DETECTED, OPERATION ABORTED' 031D 0D0A24 DB CR,LF,EOM 0320 C30000 JMP 0000 ;* DOIO20: 0323 216200 LXI H,COMMAND+2 0326 34 INR M 0327 215B00 LXI H,DMA+1 032A 34 INR M 032B 2A5A00 LHLD DMA LDED LAST 032E+ED5B DB 0EDH,5BH 0330+5200 DW LAST 0332 B7 ORA A DSBC DE 0333+ED52 DB 0EDH,DE*8+42H 0335 DADE02 JC DOIO10 0338 C9 RET ;* ;** ;* ; ;* START OF PROTOCAL HANDLING ROUTNES * ; ;+ DOCMD: ;-OP: ISSUE MOV A,M ; A = DATA FROM LINE 011E FE2E CPI '.' ; IS IT A DOT?? 0120 CA3201 JZ MS020 ; BRIF SO 0123 12 STAX D ; ELSE STUFF TO FCB 0124 23 INX H ; 0125 13 INX D ; INCREMENT POINTERS DJNZ MS010 ; 0126+10F5 DB 10H,MS010-$-1 MS030: 0128 7E MOV A,M ; SKIP PAST '.' 0129 FE2E CPI '.' ; 012B CA3201 JZ MS020 ; BRIF FOUND 012E 23 INX H ; 012F C32801 JMP MS030 ; AND COUNTINE ;* MS020: 0132 23 INX H ; POINT PAST '.' 0133 78 MOV A,B ; SEE IF ALL FILENAME IS FILED 0134 B7 ORA A ; 0135 CA3E01 JZ MS040 ; BRIF SO MS050: 0138 3E20 MVI A,' ' ; PAD WITH SPACES 013A 12 STAX D ; 013B 13 INX D ; DJNZ MS050 ; 013C+10FA DB 10H,MS050-$-1 MS040: 013E 010300 LXI B,3 ; LDIR ; T,CR,LF,EOM 01F5 C30000 JMP 0000 ;* ;** ;* ;+ GET$DRIVE: ;- 01F8 CDB200 CALL TXOUT 01FB 0D0A DB CR,LF 01FD 454E544552 DB 'ENTER 0 (DRIVE #0) OR 1 (DRIVE #1) -->',EOM 0224 CDC200 CALL CI 0227 FE30 CPI '0' 0229 CA3602 JZ GD99 022C FE31 CPI '1' 022E C24102 JNZ GD010 CP/M RMAC ASSEM 1.1 #005 INITIAL PROGRAM LOADER AND GENERATOR V1.1 0231 3E20 MVI A,20H 0233 325800 STA DRIVE GD99: 0236 CDB200 CALL TXOUT 0239 0D0A DB CR,LF 023B 4F4B0D0A24 DB 'OK',CR,LF,EOM 0240 C9 RET ;* GD010: 0241 CDB200 CALL TXOUT 0244 0D0A DB CR,LF 0246 4552524F52 DB 'ERROR: PLEASE ENTER EITHER 0 OR 1',CR,LF,EOM 026A C3F801 JMP GET$DRIVE ;* ;** ;* ;+ LOAD$SYSTEM: ;- COMMAND TO SCSI HOST ADAPTOR ;-PP: HL @ COMMAND BYTES TO SEND ;- @ACTSEC & @RPNTR ARE VALID ;-RC: NO - ZERO : ERROR IN COMMAND (A = ERROR BITS) ;- ZERO : COMMAND WAS EXECUTED SUCCESSFULLY ;- 0339 225C00 SHLD LCMD@ ; SAVE COMMAND @ 033C 3E0A MVI A,RETRY ; GET RETRY COUNT 033E 325E00 STA TRYCNTR ; RESET COUNTER 0341 D354 OUT CPARITY ; RESET PARITY ERROR DCMD1: 0343 C5 PUSH B ; SAVE COUNTER 0344 CDA903 CALL ?PUTDMA ; SET DMA ADDRESS 0347 CDB903 CALL ?SELECT ; GO SELECT CONTROLER 034A C1 POP B ; RECOVER BC ; WAIT: ; ;* HERE WE MUST WAIT FOR EXECUTION * ; 034B DB51 IN BSTAT ; A <--- BUSS STATUS 034D E650 ANI CD+REQ ; CHECK FOR DATA JRNZ WAIT ; BRIF STILL DATA 034F+20FA DB 20H,WAIT-$-1 0351 DB50 RNSFR REST OF FILE NAME 0141+EDB0 DB 0EDH,0B0H 0143 116800 LXI D,FCB ; TRY TO OPEN 0146 0E0F MVI C,15 ; 0148 CD0500 CALL BDOS ; 014B FEFF CPI 0FFH ; CHECK FOR ERROR 014D C28601 JNZ MS060 ; BRIF OK 0150 CDB200 CALL TXOUT ; 0153 0D0A0A DB CR,LF,LF 0156 4552524F52 DB 'ERROR: CANNOT OPEN FILE ',EOM LDED LINE$BUFFER+1 016F+ED5B DB 0EDH,5BH 0171+0100 DW LINE$BUFFER+1 0173 210200 LXI H,LINE$BUFFER+2 0176 1600 MVI D,0 CP/M RMAC ASSEM 1.1 #004 INITIAL PROGRAM LOADER AND GENERATOR V1.1 0178 19 DAD D 0179 3624 MVI M,'$' 017B 110200 LXI D,LINE$BUFFER+2 017E 0E09 MVI C,9 0180 CD0500 CALL BDOS 0183 C3C800 JMP MAKE$SYSTEM ;* MS060: 0186 CDB200 CALL TXOUT 0189 0D0A DB CR,LF 018B 4C4F414449 DB 'LOADING FILE ...',EOM 019C 218E00 LXI H,BUFFER MS070: 019F EB XCHG ; DE @ DMA BUFFER  026D CDB200 CALL TXOUT 0270 0D0A0A DB CR,LF,LF 0273 4C4F414420 DB 'LOAD SYSTEM FUNCTION SELECTED',CR,LF,EOM 0293 CDF801 CALL GET$DRIVE 0296 2100D4 LXI H,0D400H 0299 225400 SHLD BEGIN 029C 2100F7 LXI H,0F700H 029F 225200 SHLD LAST 02A2 3E01 MVI A,1 02A4 326000 STA COMMAND 02A7 CDB200 CALL TXOUT 02AA 0D0A0A DB CR,LF,LF 02AD 4C4F414449 DB 'LOADING SYSTEM ...',EOM 02C0 CDC602 CALL DOIO 02C3 C300EA JMP 0EA00H ;* ;** ;* ;+ DOIO: ;- 02C6 216000 LXI H,COMMAND 02C9 3A5800 LDA DRIVE 02CC B6 ORA M 02CD 77 MOV M,A LDED BEGIN 02CE+ED5B DB 0EDH,5BH 02D0+5400 DW BEGIN SDED DMA 02D2+ED53 DB 0EDH,53H 02D4+5A00 DW DMA 02D6 3E01 MVI A,1 02D8 326200 STA COMMAND+2 02DB 326400 STA COMMAND+4 DOIO10:  IN DATAI ; A <-- COMPLETION STATUS 0353 F5 PUSH PSW ; SAVE ENDING STATUS CP/M RMAC ASSEM 1.1 #007 INITIAL PROGRAM LOADER AND GENERATOR V1.1 WAIT1: 0354 DB51 IN BSTAT ; WAIT FOR REQ. AND MSG. 0356 E618 ANI REQ+MSG ; JRNZ WAIT1 ; 0358+20FA DB 20H,WAIT1-$-1 035A DB50 IN DATAI ; GET BYTE OF ZERO 035C F1 POP PSW ; RECOVER STATUS 035D E61F ANI 00011111B ; MASK OUT ERRORS JRNZ WAIT4 ; BRIF NOT OK 035F+200D DB 20H,WAIT4-$-1 0361 DB51 IN BSTAT ; CHECK FOR PARITY 0363 E604 ANI PERR ; 0365 D351 OUT CLRINT ; CLEAR INTERRUPT 0367 3EFF MVI A,0FFH ; JRNZ WAIT4 ; BRIF ERROR 0369+2003 DB 20H,WAIT4-$-1 036B AF XRA A ; EXIT WITH ZERO 036C C9 RET ; AND EXIT ;* ;* WAIT7: 036D F1 POP PSW ; CLEAR OUT STACK WAIT4: ORT ; AND SELECT CONTROLER SEL1: 03C5 DB51 IN BSTAT ; WAIT FOR REQ 03C7 E610 ANI REQ ; JRNZ SEL1 ; 03C9+20FA DB 20H,SEL1-$-1 03CB 57 MOV D,A ; D=0, MARK FIRST COMMAND ; ;* NOW FALL ON THRU TO OUTPUT COMMAND BYTES * ; ;+ ?OUTCMD: ;-OP: ISSUE COMMAND BYTES TO HOST ADAPTOR ;-PP: HL @ COMMAND BYTES ;- 03CC DB51 IN BSTAT ; GRAB BUSS STATUS 03CE 4F MOV C,A ; SAVE STATUS 03CF E640 ANI CD ; SEE IF DATA 03D1 C0 RNZ ; EXIT IF DATA 03D2 79 MOV A,C ; CHECK FOR DIREC 03D3 E620 ANI DIREC ; 03D5 C8 RZ ; EXIT IF INPUT 03D6 3E12 MVI A,REQ+BDACK ; BIT 0,D ; SEE IF FIRST CMD. 03D8+CB42 DB 0CBH,0*8+D+40H JRNZ ?OC5 ; BRIF NOT 03DA+2002 DB 20H,?OC5-$-1 03DC 3E10 MV TITLE 'INITIAL PROGRAM LOADER AND GENERATOR V1.1' ; NAME ('IPLGEN') ; DATE 21-JUN-83 ; CONVERTED TO MAC/RMAC CODE 18 JULY 83 RHP ; MACLIB Z80 ; Z-80 CODING IS USED ; ; ASEG ; ; *** ASCII CONSTANTS *** ; CR EQU 0DH LF EQU 0AH BELL EQU 07H EOM EQU '$' RETRY EQU 10 BDOS EQU 0005H ; ; ; ; *** PORT ASSIGNMENTS *** ; SCSI$BASE EQU 0050H ; SCSI INTERFACE BOARD BASE QUAD$EIA EQU 0010H ; BASE PORT FOR QUAD. EIA BOARD CRTSTATUS EQU QUAD$EIA+4 ; STATUS PORT FOR CONSOLE CRTDATA EQU QUAD$EIA+5 ; DATA PORT FOR CONSOLE ; TXRDY EQU 0001H ; TX. READY BIT IN 8251 USART RXRDY EQU 0002H ; RX. READY BIT IN 8251 USART ; ; *** SCSI PORT ASSIGNMENTS *** ; ; * BIT,BYTE AND PORT ASSIGMENTS FOR * ; * SCSI HOST INTERFACE ADAPTOR * ; DATAI EQU SCSI$BASE ; DATA IN REGISTER DATAO EQU SCSI$BASE+2 ; DATA OUT REGISTER BSTAT EQU SCSI$BASE+1 ; BUS STATUS SELPORT EQU SCSI$BASE ; SELECT PORT ADR. CLRINT EQU BIT 2,A ; HARDWARE BUSY?? 036E+CB57 DB 0CBH,2*8+A+40H JRZ WAIT6 ; BRIF NOT 0370+2827 DB 28H,WAIT6-$-1 0372 CDB200 CALL TXOUT 0375 0D DB CR 0376 504C454153 DB 'PLEASE WAIT, DRIVE IS SPINING UP',EOM JR WAIT5 ; AND CONTINUE 0397+1806 DB 18H,WAIT5-$-1 ;* WAIT6: 0399 215E00 LXI H,TRYCNTR ; SEE IF RETRY UP 039C 35 DCR M ; JRZ WAIT2 ; BRIF RETRY IS UP 039D+2806 DB 28H,WAIT2-$-1 WAIT5: 039F 2A5C00 LHLD LCMD@ ; RECOVER LAST COMMAND 03A2 C34303 JMP DCMD1 ; AND TRY AGAIN ;* WAIT2: 03A5 D351 OUT CLRINT ; CLEAR INTERRUPT 03A7 B7 ORA A ; EXIT WITH NON-ZERO 03A8 C9 RET ; AND EXIT ;* ;** ;* ;+ ?PUTDMA: ;-OP: SEND DMA ADDRESS TO HOST ADAPTEI A,REQ ; ELSE JUST CHECK FOR REQ. ?OC5: 03DE A1 ANA C ; CHECK FOR READY JRNZ ?OUTCMD ; BRIF NOT (1.75/1.17) 03DF+20EB DB 20H,?OUTCMD-$-1 ?OC1: CP/M RMAC ASSEM 1.1 #009 INITIAL PROGRAM LOADER AND GENERATOR V1.1 03E1 7E MOV A,M ; GET COMMAND BYTE (1.75/1.17) 03E2 D352 OUT DATAO ; SEND TO CONTROLER (2.75/1.83) 03E4 23 INX H ; POINT NEXT (1.5/1.0) 03E5 1601 MVI D,1 ; MARK NOT FIRST COMMAND JR ?OUTCMD ; AND DO IT AGAIN! 03E7+18E3 DB 18H,?OUTCMD-$-1 ;* ;** ;* ; ; DSEG 0000 LINE$BUFFER: DS 80+2 0052 0000 LAST: DW 00 0054 0000 BEGIN: DW 00 0056 0000 HIDMA: DW 00 0058 0000 DRIVE: DW 00 005A 0000 DMA: DW 00 005C 0000 LCMD@: DW 00 005E 0000 TRYCNTR: DW 00 0060 0000000000CO SCSI$BASE+1 ; CLR. INTRRUPT PORT DMAPORT EQU SCSI$BASE+3 ; DMA ADDRESS PORT CPARITY EQU SCSI$BASE+4 ; CLEAR PARITY PORT BUSY EQU 80H ; CONTROLER BUSY BIT CD EQU 40H ; COMMAND/DATA BIT DIREC EQU 20H ; DIRECTON BIT REQ EQU 10H ; REQUEST BIT MSG EQU 08H ; END MESSAGE BIT PERR EQU 04H ; PERR ERROR BIT BDACK EQU 02H ; BOARD ACK. SIGNAL LINT EQU 01H ; INTERUPTE BIT ; ; CSEG ; START: LXI SP,STACK ; SET UP THE STACK POINTER CALL TXOUT DB CR,LF DB 'IPLGEN00 -- INITIAL PROGRAM BOOTER AND' DB ' SYSTEM GENERATOR V1.1' DB CR,LF,LF DB 'FOR 60K SYSTEMS',CR,LF,LF,LF DB 'L)OAD OR M)AKE SYSTEM TRACK --->',EOM CALL CI ; GET ANSWER CPI 'M' ; SEE IF MAKE SYSTEM JZ MAKE$SYSTEM ; BRIF SO CPI 'L' ; SEE IF LOAD SYSTEM JZ LOAD$SYSTEM ; BRIF SO CALL TXOUT DB CR,LF,LF DB 'ERROR: PLEASE TYPE "M" OR "L"' DB CR,LF,LF,EOM JMP START ;* ;** ;* ;+ TXOUT: ;- XTHL ; HL @ DATA MOV A,M ; A = DATA INX H ; PUT BACK POINTER XTHL ; CPI EOM R ;-PP: RPNTR HAS DMA ADDRESS ;- 03A9 3A5600 LDA HIDMA ; SET HI-BYTE 03AC D353 OUT DMAPORT ; HIGH BYTE ALWAYS ZERO CP/M RMAC ASSEM 1.1 #008 INITIAL PROGRAM LOADER AND GENERATOR V1.1 LDED DMA ; DE @ DMA ADDRESS 03AE+ED5B DB 0EDH,5BH 03B0+5A00 DW DMA 03B2 7A MOV A,D 03B3 D353 OUT DMAPORT ; SEND BYTE 1 03B5 7B MOV A,E 03B6 D353 OUT DMAPORT ; SEND BYTE 2 03B8 C9 RET ; AND EXIT ;* ;** ;* ;+ ?SELECT: ;-OP: SELECT CONTROLER ;- 03B9 DB51 IN BSTAT ; IS CONTROLER BUSY?? 03BB E680 ANI BUSY ; WAIT FOR NOT BUSY JRZ ?SELECT ; WAIT IF SO 03BD+28FA DB 28H,?SELECT-$-1 SEL2: 03BF 3E01 MVI A,01H ; SELECT CONTROLER #1 03C1 D352 OUT DATAO ; 03C3 D350 OUT SELPMMAND: DW 00,00,00,00 0068 FCB: DS 36 008C 6400 DW 100 STACK: BUFFER: 008E END ; END OF MESSAGE??? RZ ; RETURN IF SO MOV E,A ; ELSE E = CHARACTER MVI C,2 ; CONSOLE OUTPUT CODE CALL BDOS ; DO THE BDOS STUFF JMP TXOUT ; AND REPEAT ;* ;** ;* ;+ CI: ;- MVI C,1 CALL BDOS RET ;* ;** ;* ;+ MAKE$SYSTEM: ;- CALL TXOUT DB CR,LF,LF DB 'PLEASE ENTER NAME OF GEN''ED CP/M SYSTEM --->',EOM LXI H,LINE$BUFFER ; HL @ LINE BUFFER MVI M,80 ; MAX. LINE SIZE = 80 CHARACTERS XCHG ; DE @ LINE BUFFER MVI C,10 ; READ CONSOLE BUFFER CALL BDOS ; LXI H,FCB ; CLEAR OUT FCB LXI D,FCB+1 ; LXI B,33 ; MVI M,00 ; PRIME THE ROUTINE LDIR ; PERFORM THE OPERATION LXI D,FCB+1 ; DE @ FILENAME LXI H,LINE$BUFFER+1 ; HL @ FILENAME LINE MOV C,M ; C = SIZE OF LINE INX H ; POINT TO DATA PART OF LINE MVI B,8 ; B = SIZE OF FILENAME MS010: MOV A,M ; A = DATA FROM LINE CPI '.' ; IS IT A DOT?? JZ MS020 ; BRIF SO STAX D ; ELSE STUFF TO FCB INX H ; INX D ; INCREMENT POINTERS DJNZ MS010 ; MS030:  JMP 0EA00H ;* ;** ;* ;+ DOIO: ;- LXI H,COMMAND LDA DRIVE ORA M MOV M,A LDED BEGIN SDED DMA MVI A,1 STA COMMAND+2 STA COMMAND+4 DOIO10: LXI H,COMMAND CALL DOCMD JRZ DOIO20 CALL TXOUT DB CR,LF,LF DB 'ERROR: DISK I/O ERROR DETECTED, OPERATION ABORTED' DB CR,LF,EOM JMP 0000 ;* DOIO20: LXI H,COMMAND+2 INR M LXI H,DMA+1 INR M LHLD DMA LDED LAST ORA A DSBC DE JC DOIO10 RET ;* ;** ;* ; ;* START OF PROTOCAL HANDLING ROUTNES * ; ;+ DOCMD: ;-OP: ISSUE COMMAND TO SCSI HOST ADAPTOR ;-PP: HL @ COMMAND BYTES TO SEND ;- @ACTSEC & @RPNTR ARE VALID ;-RC: NO - ZERO : ERROR IN COMMAND (A = ERROR BITS) ;- ZERO : COMMAND WAS EXECUTED SUCCESSFULLY ;- SHLD LCMD@ ; SAVE COMMAND @ MVI A,RETRY ; GET RETRY COUNT STA TRYCNTR ; RESET COUNTER OUT CPARITY ; RESET PARITY ERROR DCMD1: PUSH B ; SAVE COUNTER CALL ?PUTDMA ; SET DMA ADDRESS CALL ?SELECT ; GO SELECT CONTROLER POP B ; RECOVER BC ; WAIT: ; ;* HVI A,REQ+BDACK ; BIT 0,D ; SEE IF FIRST CMD. JRNZ ?OC5 ; BRIF NOT MVI A,REQ ; ELSE JUST CHECK FOR REQ. ?OC5: ANA C ; CHECK FOR READY JRNZ ?OUTCMD ; BRIF NOT (1.75/1.17) ?OC1: MOV A,M ; GET COMMAND BYTE (1.75/1.17) OUT DATAO ; SEND TO CONTROLER (2.75/1.83) INX H ; POINT NEXT (1.5/1.0) MVI D,1 ; MARK NOT FIRST COMMAND JR ?OUTCMD ; AND DO IT AGAIN! ;* ;** ;* ; ; DSEG LINE$BUFFER: DS 80+2 LAST: DW 00 BEGIN: DW 00 HIDMA: DW 00 DRIVE: DW 00 DMA: DW 00 LCMD@: DW 00 TRYCNTR: DW 00 COMMAND: DW 00,00,00,00 FCB: DS 36 DW 100 STACK: BUFFER: END Q ; JRNZ SEL1 ; MOV D,A ; D=0, MARK FIRST COMMAND ; ;* NOW FALL ON THRU TO OUTPUT COMMAND BYTES * ; ;+ ?OUTCMD: ;-OP: ISSUE COMMAND BYTES TO HOST ADAPTOR ;-PP: HL @ COMMAND BYTES ;- IN BSTAT ; GRAB BUSS STATUS MOV C,A ; SAVE STATUS ANI CD ; SEE IF DATA RNZ ; EXIT IF DATA MOV A,C ; CHECK FOR DIREC ANI DIREC ; RZ ; EXIT IF INPUT MMOV A,M ; SKIP PAST '.' CPI '.' ; JZ MS020 ; BRIF FOUND INX H ; JMP MS030 ; AND COUNTINE ;* MS020: INX H ; POINT PAST '.' MOV A,B ; SEE IF ALL FILENAME IS FILED ORA A ; JZ MS040 ; BRIF SO MS050: MVI A,' ' ; PAD WITH SPACES STAX D ; INX D ; DJNZ MS050 ; MS040: LXI B,3 ; LDIR ; TRNSFR REST OF FILE NAME LXI D,FCB ; TRY TO OPEN MVI C,15 ; CALL BDOS ; CPI 0FFH ; CHECK FOR ERROR JNZ MS060 ; BRIF OK CALL TXOUT ; DB CR,LF,LF DB 'ERROR: CANNOT OPEN FILE ',EOM LDED LINE$BUFFER+1 LXI H,LINE$BUFFER+2 MVI D,0 DAD D MVI M,'$' LXI D,LINE$BUFFER+2 MVI C,9 CALL BDOS JMP MAKE$SYSTEM ;* MS060: CALL TXOUT DB CR,LF DB 'LOADING FILE ...',EOM LXI H,BUFFER MS070: XCHG ; DE @ DMA BUFFER PUSH D ; SAVE MVI C,26 ; SET DMA CALL BDOS ; LXI D,FCB ; DE @ FCB MVI C,20 ; GO READ A RECORD CALL BDOS ; PERFORM THE READ ORA A ; CHECK FOR ERRORS JNZ MS080 ; BRIF DONE POP H ; INCREMENT DMA ERE WE MUST WAIT FOR EXECUTION * ; IN BSTAT ; A <--- BUSS STATUS ANI CD+REQ ; CHECK FOR DATA JRNZ WAIT ; BRIF STILL DATA IN DATAI ; A <-- COMPLETION STATUS PUSH PSW ; SAVE ENDING STATUS WAIT1: IN BSTAT ; WAIT FOR REQ. AND MSG. ANI REQ+MSG ; JRNZ WAIT1 ; IN DATAI ; GET BYTE OF ZERO POP PSW ; RECOVER STATUS ANI 00011111B ; MASK OUT ERRORS JRNZ WAIT4 ; BRIF NOT OK IN BSTAT ; CHECK FOR PARITY ANI PERR ; OUT CLRINT ; CLEAR INTERRUPT MVI A,0FFH ; JRNZ WAIT4 ; BRIF ERROR XRA A ; EXIT WITH ZERO RET ; AND EXIT ;* ;* WAIT7: POP PSW ; CLEAR OUT STACK WAIT4: BIT 2,A ; HARDWARE BUSY?? JRZ WAIT6 ; BRIF NOT CALL TXOUT DB CR DB 'PLEASE WAIT, DRIVE IS SPINING UP',EOM JR WAIT5 ; AND CONTINUE ;* WAIT6: LXI H,TRYCNTR ; SEE IF RETRY UP DCR M ; JRZ WAIT2 ; BRIF RETRY IS UP WAIT5: LHLD LCMD@ ; RECOVER LAST COMMAND JMP DCMD1 ; AND TRY AGAIN ;* WAIT2: OUT CLRINT ; CLEAR INTERRUPT ORA A ; ELXI D,128 ; DAD D ; JMP MS070 ; ;* MS080: CALL TXOUT ; DB CR,LF,'OK',CR,LF,EOM CALL GET$DRIVE ; GO GET THE PROPER DRIVE CODE LXI H,BUFFER+0880H ; START = BUFFER SHLD BEGIN ; POP H ; END = LAST DMA SHLD LAST ; MVI A,03 ; COMMAND IS WRITE STA COMMAND ; CALL DOIO ; AND DO THE I/O CALL TXOUT DB CR,LF,LF DB 'OPERATION COMPLETED',CR,LF,EOM JMP 0000 ;* ;** ;* ;+ GET$DRIVE: ;- CALL TXOUT DB CR,LF DB 'ENTER 0 (DRIVE #0) OR 1 (DRIVE #1) -->',EOM CALL CI CPI '0' JZ GD99 CPI '1' JNZ GD010 MVI A,20H STA DRIVE GD99: CALL TXOUT DB CR,LF DB 'OK',CR,LF,EOM RET ;* GD010: CALL TXOUT DB CR,LF DB 'ERROR: PLEASE ENTER EITHER 0 OR 1',CR,LF,EOM JMP GET$DRIVE ;* ;** ;* ;+ LOAD$SYSTEM: ;- CALL TXOUT DB CR,LF,LF DB 'LOAD SYSTEM FUNCTION SELECTED',CR,LF,EOM CALL GET$DRIVE LXI H,0D400H SHLD BEGIN LXI H,0F700H SHLD LAST MVI A,1 STA COMMAND CALL TXOUT DB CR,LF,LF DB 'LOADING SYSTEM ...',EOM CALL DOIO XIT WITH NON-ZERO RET ; AND EXIT ;* ;** ;* ;+ ?PUTDMA: ;-OP: SEND DMA ADDRESS TO HOST ADAPTER ;-PP: RPNTR HAS DMA ADDRESS ;- LDA HIDMA ; SET HI-BYTE OUT DMAPORT ; HIGH BYTE ALWAYS ZERO LDED DMA ; DE @ DMA ADDRESS MOV A,D OUT DMAPORT ; SEND BYTE 1 MOV A,E OUT DMAPORT ; SEND BYTE 2 RET ; AND EXIT ;* ;** ;* ;+ ?SELECT: ;-OP: SELECT CONTROLER ;- IN BSTAT ; IS CONTROLER BUSY?? ANI BUSY ; WAIT FOR NOT BUSY JRZ ?SELECT ; WAIT IF SO SEL2: MVI A,01H ; SELECT CONTROLER #1 OUT DATAO ; OUT SELPORT ; AND SELECT CONTROLER SEL1: IN BSTAT ; WAIT FOR REQ ANI REQ ; JRNZ SEL1 ; MOV D,A ; D=0, MARK FIRST COMMAND ; ;* NOW FALL ON THRU TO OUTPUT COMMAND BYTES * ; ;+ ?OUTCMD: ;-OP: ISSUE COMMAND BYTES TO HOST ADAPTOR ;-PP: HL @ COMMAND BYTES ;- IN BSTAT ; GRAB BUSS STATUS MOV C,A ; SAVE STATUS ANI CD ; SEE IF DATA RNZ ; EXIT IF DATA MOV A,C ; CHECK FOR DIREC ANI DIREC ; RZ ; EXIT IF INPUT M֎ %^9`c $ r)8`0 EI8T$IHG)IA0;V@aY JE"yHt !IyP@O(I1$E !@`dl$ p%0@6ADyI'bI0  AuAh4 [ "Xv|ly, 3oE1`f`&mDA*I M(B) 0m B$E< B$E"Z>3n`ʦO ,Ͷ@Q<  ,d JE"yHt (@E'!T$JBR A#m4 &$ALS*I1TC*ILL"ʄR 4$f߀"ʀE`f h(L'Hq@S,ʄRh\.  us,-Tv2@,! r(m4 "D@D$bH "D򐀈E*HeB)X '" PO'$"yHE"ABF!@A[ ғj2DYp| eQ͵ lrm\Pz.`(<\5Qse@W^,NͶ@ҁm space: defb " ",eom skip: defb "Register Dump af, hl, de, bc" crlf: defb cr,lf,eom dr: endm ; .list ; ; ; subttl Equates and Constants page ; ; *** ASCII constants and User Options *** ; aseg bell equ 0007h ; sound console bell cr equ 000dh ; cariage return lf equ 000ah ; linefeed ffd equ 000ch ; formfeed xon equ 0011h ; ^q xoff equ 0013h ; ^s eom equ 0000h ; end of message marker false equ 0000h ; true equ not false ; retry equ 0010 ; Retrys before Hard-Error msize equ 0060 ; 60k system. ; ; ; *** Port Assignments *** ; SCSI$base equ 0050h ; SCSI Interface board base QUAD$eia equ 0010h ; Base port for QUAD. eia board crtstatus equ QUAD$eia+4 ; Status port for console crtdata equ QUAD$eia+5 ; Data port for console ; txrdy equ 0001h ; Tx. Ready bit in 8251 usart rxrdy equ 0002h ; Rx. Ready bit in 8251 usart ; ; *** SCSI Port assignments *** ; ; * bit,byte and port assigment0A)Dr $, D@I) eI8N#  ` !Q@Uu Q[GYXSvS=lÈ>IPm\( dL>(DL# C9pH t`8 title CP/M Ver 2.2 BIOS for SCSI Host Adaptor name ('bios22') ; date 20-Jun-83 ; by David Wagstaff ; copyright 1983 by Griffin Tech. All rights reserved ; ; .z80 ; z-80 coding is used aseg ; Absolute addressing is needed ; subttl Introduction, Externals, Internals and Macros ; ; ; This module contains the Basic Input/Output System for ; version 2.2 of the CP/M operating system. ; Portions of the Serial port I/O have not beened coded for ovious reasons ; therefore, this task is left to the customer of this product. ; The equate 'SCSI$BASE' has be equated to the base address for the SCSI ; interface board, the current value is 050h. ; The equate 'MSIZE' should be set to the size of the operating system ; to be gen'ed, typicaly this should be about 60k. ; ; ; ; ** >> Editing History << ** ; ; Ver. Date Modification ; ---- -------- ---------------------------------------- ; 00 06/20/83 1) Created. ; ; ; .xlist mdbe macro vals for * ; * SCSI host interface adaptor * ; datai equ SCSI$base ; data in register datao equ SCSI$base+2 ; data out register bstat equ SCSI$base+1 ; bus status selport equ SCSI$base ; select port adr. clrint equ SCSI$base+1 ; clr. intrrupt port dmaport equ SCSI$base+3 ; dma address port cparity equ SCSI$base+4 ; clear parity port busy equ 80h ; controler busy bit cd equ 40h ; command/data bit direc equ 20h ; directon bit req equ 10h ; request bit msg equ 08h ; end message bit perr equ 04h ; perr error bit bdack equ 02h ; board ack. signal lint equ 01h ; interupte bit ; ; *** Cartriage storage information for IOMEGA system *** ; ncyn equ 306 ; # track/drive nscyn equ 64 ; # sectors/track ?nbsct equ 2 ; # blocks/sector nbblk equ 256 ; # bytes/block nbrec equ 128 ; cp/m record size bls equ 2048 ; cp/m block size drm equ 512-1 ; # dir. entrys -1 bysct equ nbblk*?nbsct ; # bytes/sector nbcyn equ nscyn*bysct ; # bytes/track 0000 BC 0002 BDACK 0005 BDOS 0054 BEGIN 0007 BELL 0051 BSTAT 008E BUFFER 0080 BUSY 0040 CD 00C2 CI 0051 CLRINT 0060 COMMAND 0054 CPARITY 000D CR 0015 CRTDATA 0014 CRTSTATUS 0050 DATAI 0052 DATAO 0343 DCMD1 0002 DE 0020 DIREC 005A DMA 0053 DMAPORT 0339 DOCMD 02C6 DOIO 02DE DOIO10 0323 DOIO20 0058 DRIVE 0024 EOM 0068 FCB 0241 GD010 0236 GD99 01F8 GETDRIVE 0056 HIDMA 0004 HL 0004 IX 0004 IY 0052 LAST 005C LCMD@ 000A LF 0000 LINEBUFFER 0001 LINT 026D LOADSYSTEM 00C8 MAKESYSTEM 011D MS010 0132 MS020 0128 MS030 013E MS040 0138 MS050 0186 MS060 019F MS070 01BA MS080 0008 MSG 0004 PERR 0010 QUADEIA 0010 REQ 000A RETRY 0002 RXRDY 0050 SCSIBASE 03C5 SEL1 03BF SEL2 0050 SELPORT 008E STACK 0000 START 005E TRYCNTR 00B2 TXOUT 0001 TXRDY 034B WAIT 0354 WAIT1 03A5 WAIT2 036E WAIT4 039F WAIT5 0399 WAIT6 036D WAIT7 03E1 ?OC1 03DE ?OC5 03CC ?OUTCMD 03A9 ?PUTDMA 03B9 ?SELECT ue,sp ; macro to print version or date defb (value shr 12)+'0' defb ((value shr 8) and 0fh)+'0' defb sp defb ((value shr 4) and 0fh)+'0' defb (value and 0fh) +'0' endm ;*** debug macro mesg,values ; macro to debugging bios local dm,dr,space,skip ; 'mesg' is a ASCII string local hlx,dex,bcx,afx,ard ; to be printd, 'values' is local crlf ; a list of memory location jp ard ; to dump to the terminal. hlx: defw 00 ; A register dump will also bcx: defw 00 ; be printed on the console. dex: defw 00 afx: defw 00 ard: ld (afx),a ld (hlx),hl ld (dex),de ld (bcx),bc push af push hl push bc push de ifnb irp val, ld hl,(val) call ?pdec ld hl,space call ?prtmsg endm endif ld hl,dm call ?prtmsg ld hl,skip call ?prtmsg irp val, ld hl,(val) call ?pdec ld hl,space call ?prtmsg endm ld hl,crlf call ?prtmsg pop de pop bc pop hl pop af jp dr dm: defb mesg defb cr,lf,eonrsct equ bysct/nbrec ; # recs/sector nrcyn equ nscyn*nrsct ; # recs/track nrecbls equ bls/nbrec ; # recs/bls nblscyn equ nrcyn/nrecbls ; # bls/track dsma equ nblscyn*(ncyn/2); size of an logcal drive A: dsmb equ nblscyn*((ncyn/2)-offset) ; size of B: offset equ 0001 ; track offset for System Track ; ; * IOMEGA command set * ; fmtztrk equ 10000b ; format z-track flgsct equ 10010b ; flag sector flgtrk equ 10100b ; flag track c?seek equ 00110b ; seek track c?home equ 01000b ; ?home drive reqst equ 01010b ; reqest status reqes equ 01100b ; reqest extended status ctest equ 01110b ; test contrl. status rddata equ 00001b ; read data rdid equ 10101b ; read id rddtof equ 11001b ; read data with offset rddiag equ 10001b ; read diagnostic wrtdata equ 00011b ; write data wrtid equ 00111b ; write id wrtdiag equ 10011b ; write diagnositc ; ; ; ; *** CP/M Enviroment Constants *** ; tpa equ 0100h ; Address of start of tpefw dsmb defw drm defw 0ff00h ; debug = 0ffffh defw (drm/4)+1 defw 9ah ;**** ; ; ; *** >>> Disk Parameter header tables <<< *** ; dpbase: ; defw 0000,0000 ; Drive A: defw 0000,0000 ; defw dirbf,dpAblk ; defw chkA,allA ; ; defw 0000,0000 ; Drive B: defw 0000,0000 ; defw dirbf,dpBblk ; defw chkB,allB ; ; subttl Boot and Warm Boot Routines page ; ; ; *** >>> Start of BOOT and WARM BOOT Routines <<< *** ; ?boot: ;-op: Handle misc. initilization and signon message printing ;-pp: none ;-rc: none ;- xor a ; clear IOBYTE ld (iobyte),a ; ld (cdrive),a ; and current disk ld hl,signon ; go print sign-on message call ?prtmsg ; ?gocpm: ld a,0c3h ; a = op. code for 'jp' ld (0000h),a ; vector @ 0000h ld (0005h),a ;& vector @ 0005h ld hl,bios+3 ; location of wboot routine ld (00001h),hl ; save it ld hl,bdos ; location of BDOS ld (0006h),hl ; save to system vector ld a,(cdrive) ; get the current disk ld c,a ; to res register and rxrdy ; ret z ; exit if not ready or 0ffh ; else with with true ret ;* ;** ;* ;+ ?conin: ;-op: get character from the console ;-pp: none ;-rc: a = character (parity bit striped, i.e. only 7-bits present) ;- call ?const ; Wait for character ready or a ; jr z,?conin ; ; ; >>> Supply Code here for your hardware configuration <<< ; >>> register a will receive character, port has character ready <<< ; Sample code is provided for a 8251 type usart. ; in a,(crtdata) ; grab the data byte cpl ; our hardware complements the data register ret ; and then exit ;* ;** ;* ;+ ?conout: ;-op: send character to console ;-pp: c = character ;-rc: none ;- ; >>> Supply code here for your hardware configuration <<< ; Sample code is provided for a 8251 type usart in a,(crtstatus) ; wait for tx. ready and txrdy ; jr nz,?conout ; remember our hardware ld a,c ; a = character to send out (crtdata),a ; eject the character ret ; and then exit ;* a bias equ (msize-20)*1024 ; ccp equ 3400h+bias ; Base of CCP bdos equ ccp+0806h ; Base of BDOS bios equ ccp+1600h ; Base of this bios iobyte equ 0003h ; Address of IOBYTE cdrive equ 0004h ; Current disk indicator nsects equ (bios-ccp)/128 ; # of sectors/ ccp ; ; ; *** IOmega blocking size equates *** ; bufsz equ 2048 ; Data blocking size mgablks equ bufsz/256 ; # of iomega blocks cpmblks equ bufsz/nbrec ; # of cp/m records mask equ 07h ; see following table ; ; ******************************************** ; * the value of "mask" determines the block * ; * buffer size of the deblocking routines. * ; * the value of "mask" are: * ; * bufsz mask * ; * ----- ---- * ; * 2048 07h * ; * 4096 0fh * ; * 8192 1fh * ; * 16384 3fh * ; ******************************************** ; ; ; ; gister c jp ccp ; and pass control to the CCP ;* ;** ;* .xlist signon: defb cr,lf,lf,lf defb "BIOS220 --- CP/M Ver. 2.2 BIOS 20-Jun-83",cr,lf crlf: defb cr,lf,eom .list ;* ;** ;* page ;+ ?wboot: ;-op: Warm Boot CP/M system. ;-pp: System Tracks of Drive A: has a valid system on it. ;-rc: CCP is reloaded into core from system tracks ;- ld sp,0080h ; set-up the stack to free area call ?flush ; flush disk cache ld hl,-1 ; force new reads ld (@rblk),hl ; ld a,'W' ; mark as warm boot ld (@wrtact),a ; ld c,0 ; select drive A: call ?seldsk ; call ?home ; recalibrate drive ; ;* At this point we must reload in everything but the BIOS * ; ld a,(cdrive) ; a= current disk number wbt1: push af ; save current disk ld hl,0001 ; set to ready block 1 ld (@actsct),hl ; ld hl,ccp ; hl @ base of CCP wbt2: ld (@rpntr),hl ; save load adr. to dma pointer ld a,8 ; go read in 8 blocks (8*256) bytes call ?rdblk ; go do it jr nz,wbter ;** ;* ;+ ?list: ?punch: ;-op: handle output to list and punch devices ;-pp: c = character to send ;-rc: none ;- ; >>> Supply code here for your hardware configuration <<< ret ; This just acts as a bit-bucket ;* ;** ;* ;+ ?listst: ;-op: Return Status of Printer Ready ;-pp: none ;-rc: a = 00 : printer not ready ;- ff : printer is ready ;- ; >>> Supply Code Here for your hardware configuration <<< ; ld a,true ; this is just a default ret ; and then exit ;* ;** ;* ;+ ?reader: ;-op: handle input from a secondary input device ;-pp: none ;-rc: a = inputed character. ;- ; >>> Supply code here for your hardware configuration <<< ld a,'Z' and 3fh ; this just returns EOF ret ; ;* ;** ;* ; ; subttl Disk Support Routines page ; *** >>> Disk Support Routines <<< *** ; ;+ ?home: ;-op: This function performs no-operation in ;- this system. ;- ret ; just exit ;* ;** ;* ;+ ?seldsk: ;-op: Select a drive for further operatioorg bios ; start at bios cseg ; ; subttl Jump Vector Table for BIOS Functions page ; jp ?boot ; Cold Start jp ?wboot ; Warm boot jp ?const ; Console Status jp ?conin ; Console Input jp ?conout ; Console Output jp ?list ; Printer Output jp ?punch ; AUX: output routine jp ?reader ; AUX: input routine jp ?home ; Recalibrate Drive jp ?seldsk ; Select Drive jp ?settrk ; Set Track Number jp ?setsec ; Set Sector Number jp ?setdma ; Set DMA address jp ?read ; Read a Sector jp ?write ; Write a Sector jp ?listst ; Return Printer Status jp ?sectran ; Sector Translator routine ; subttl Comman Data Storage Definations page ; ; *** >>> Comman Data Storage Defination Area <<< *** ; ; *** Disk parameter block definations *** ; dpAblk: defw nrcyn ; DRIVE A: Type defb 4,15 defb 0 defw dsma defw drm defw 0ff00h defw (drm/4)+1 defw 1 ;**** dpBblk: defw nrcyn ; DRIVE B: Type defb 4,15 defb 0 dr ; brif error ld hl,(@rpntr) ; up-date dma pointer ld de,nbblk*8 ; de = transfer size add hl,de ; ld a,(@actsct) ; point next data block add a,08 ; ld (@actsct),a ; cp 11h ; see if the end has been reached jr nz,wbt2 ; brif not done ld a,false ; mark as not write active ld (@wrtact),a ; pop af ; recover current disk number ld (cdrive),a ; jp ?gocpm ; an pass control to CCP ;* wbterr: ld a,'W' ; a = code for warm boot error call ?dskerr ; go print the message pop af ; recover all old number jp wbt1 ; and try again ;* ;** ;* subttl Character I/O routines page ; ; *** >>> Start of Character I/O routines *** ; ?const: ;-op: See if console has character ready ;-pp: none ;-rc: a = 00 : no character ready ;- ff : character ready ;- ; >>> supply code here for your hardware configuration <<< ; Sample code is provided for a 8251 type usart ; in a,(crtstatus) ; get status cpl ; our hardware complements statuns ;-pp: c = drive to select ;-rc: hl @ dph for drive else 0000 if bad drive ;- ld hl,0000 ; ready for error exit ld a,c ; a = drive code cp 2 ; ret nc ; exit if bad select code ld (cdrive),a ; save new current disk ld l,a ; hl = drive code rept 4 add hl,hl ; hl = hl * 16 endm ld de,dpbase ; de = base of table add hl,de ; perform the index operation ret ; and then exit ;* ;** ;* ;+ ?settrk: ;-op: Set-up Track pointer ;-pp: bc = track for next operation ;-rc: none ;- ld (@trk),bc ; save current track ret ; and exit ;* ;** ;* ;+ ?setsec: ;-op: Set-up Sector pointer ;-pp: bc = Sector for next operation ;-rc: none ;- ld (@sect),bc ; save current sector ret ; and then exit ;* ;** ;* ;+ ?setdma: ;-op: Set-UP DMA address pointer ;-pp: bc = address of dma area ;-rc: none ;- ld (@dma),bc ; save current dma address ret ; and then exit ;* ;** ;* ;+ ?read: ;-op: Read a sector ;-pp: Disk read parmaters set (i.e. track, sendif ; ret nz ; return on error wt02: ld hl,wrtbuf ; hl @ sector buffer add hl,bc ; add in the offset ex de,hl ; de @ sector ld hl,(@dma) ; hl @ data ld bc,nbrec ; bc = # bytes/CP/M record ldir ; do the trnsfr ; ld a,true ; set write active to true ld (@wrtact),a ; ld a,(@wrtype) ; get back write type dec a ; check for directory ld a,0 ; for safty call z,?flush ; go flush data if so or a ; set flags ret ; and exit ;* ;** ;* page ;+ compute: ;-op: compute phys. block number ;-pp: track and sector are set ;-rc: hl = phys. block number ;- bc = index into block (0..bufsz) ;- ; ld hl,@trk ; hl @ track # ld e,0 ; clear low de ld d,m ; load low track inc hl ; point hi track ld a,(hl) ; a= hi track rra ; divide by two rr d ; rr e ; ex de,hl ; hl= track*128 ld a,(@sect) ; a = sector number srl a ; divide by 2 ld c,0 ; c= 0 or 80h rr c ; add a,l ; ld b,a ; and not mask ; ld l, ld (hl),0 ; clear extra byte ld hl,cmdtbl ; hl @ cmd. block call ?docmd ; go do it pop de ; recover command ret z ; return if ok call SCSI$error ;go print disk error ld a,0ffh ;mark the error or a ; ret ;and exit ;* ;** ;* ;+ SCSI$error: ;-op: Handle SCSI Disk Errors ;- ld a,'D' ; code for data error call ?dskerr ; do the disk error ret ; and then exit ;* ;** ;* ; page ; ;* start of protocal handling routnes * ; ;+ ?docmd: ;-op: issue command to SCSI host adaptor ;-pp: hl @ command bytes to send ;- @actsec & @rpntr are valid ;-rc: no - zero : error in command (a = error bits) ;- zero : command was executed successfully ;- ld (lcmd@),hl ; save command @ ld a,retry ; get retry count ld (trycntr),a ; reset counter out (cparity),a ; reset parity error dcmd1: push bc ; save counter call ?putdma ; set dma address call ?select ; go select controler pop bc ; recover bc ; wait: ; ;* here we must wait foctor and drive) ;-rc: a = 0 : no errors occured ;- = 0ffh : errors detected ;- ld hl,rdbuf ; point to read buffer ld (@rpntr),hl call compute ; get log. block # (hl =) ex de,hl ; is block loaded?? ld hl,(@wblk) ; is sector wrt. active?? or a ; sbc hl,de ; jr z,rd4 ; brif so ld hl,(@rblk) ; is block already loaded?? or a ; (in read buffer that is) sbc hl,de ; jr z,rd1 ; brif if loaded jr rd2 ; brif not ;* rd4: ld hl,wrtbuf ; index into wrt. buff. jp rd3 ; go do it rd1: ld hl,rdbuf ; index into rd. buff. rd3: add hl,bc ; bc = index, hl @ sector dat ld de,(@dma) ; de = address dma ld bc,nbrec ; bc = size of CP/M record ldir ; perform the transfer xor a ; exit with no errors ret ; and exit ;* rd2: ld (@actsct),de ; set-up for read ld (@rblk),de ; set pointer ld a,(@wrtact) ; see if warm boot active cp 'W' ; jr z,rd2.0 ; brif so res 0,l ; clear unit flag rd2.0: ld a,mgablks ; xxx blocks only caa ; ld a,b ; and mask ; ld b,a ; ld (@ofs),bc ; save offset ld a,(cdrive) ; for selection or a ; check for unit 0 ret z ; return if so set 0,l ; else set unit 1 flag ret ; and exit ;* ;** ;* ;+ ?flush: ;-op: flush write buffer if needed ;-pp: @wblk is set and valid ;- if @wrtact flag is set to true ;- ; ld hl,wrtbuf ; set dma to write buffer ld (@rpntr),hl ; ld a,(@wrtact) ; cp false ; buffer write active?? ret z ; return if not ld hl,(@wblk) ; ld (@actsct),hl ; actsec = wblkn ld a,mgablks ; write only xx block call wrtblk ; go write it ld a,false ; buffer not write active ld (@wrtact),a ; ld hl,(@rblk) ; is read/write to same l de,(@wblk or a ; sbc hl,de ; jr nz,flsh1 ; brif not ld hl,-1 ; force read ld (@rblk),hl ; flsh1: xor a ; record no error ret ; and exit ;* ;** ;* ; ; subttl SCSI Host Interface Adaptor Support Routines page ; ; *** >>> SACI Host Inr execution * ; in a,(bstat) ; a <--- buss status and cd+req ; check for data jr nz,wait ; brif still data in a,(datai) ; a <-- completion status push af ; save ending status wait1: in a,(bstat) ; wait for req. and msg. and req+msg ; jr nz,wait1 ; in a,(datai) ; get byte of zero pop af ; recover status and 00011111b ; mask out errors jr nz,wait4 ; brif not ok in a,(bstat) ; check for parity and perr ; out (clrint),a ; clear interrupt ld a,0ffh ; jr nz,wait4 ; brif error xor a ; exit with zero ret ; and exit ;* ;* wait7: pop af ; clear out stack wait4: bit 2,a ; hardware busy?? jr z,wait6 ; brif not ld a,'R' ; code for ready error call ?dskerr ; jr wait5 ; and continue ;* wait6: ld hl,trycntr ; see if retry up dec (hl) ; jr z,wait2 ; brif retry is up wait5: ld hl,(lcmd@) ; recover last command jp dcmd1 ; and try again ;* wait2: out (clrint),a ; clear interrupt or a ; exit will ?rdblk ; go do it ret nz ; return on error jp rd1 ; go index into table ;* ;** ;* page ;+ ?write: ;-op: write a sector ;-pp: disk perameters are set (i.e. track, sector and drive) ;- reg c has write type 0,1,2 ;-rc: a = 0 : no errors detected ;- = 0ffh : errors detected ;- ld a,c ; a= write type ld (@wrtype),a ; save for later call compute ; go compute mga block wt03: ex de,hl ; de = block ld hl,(@wblk) ; see if the same as loaded or a ; clear carry sbc hl,de ; test jr z,wt02 ; brif so push de ; save goal blk# call ?flush ; flush out old block number pop hl ; hl= new block # ld (@actsct),hl ; up-date pointers ld (@wblk),hl ; ld hl,wrtbuf ; dma to write buffer ld (@rpntr),hl ; ; if bufsz-2048 ld a,mgablk ; read in a block call ?rdblk ; go read it in else ; block size = 2048 ld a,(@wrtype) ; see if write type is type 2 cp 2 ; ld a,mgablk ; ready for pre-read if necessary call nz,?rdblk ; brif so eterface Adaptor Support Routines <<< *** ; ;+ ?rdblk: ;-op: read in x sectors ;-pp: a = number of blocks to read ;- @actsct is valid ;- ld e,rddata ; e = read data command jr precmd ; go prepare for it ;* ;** ;* ;+ wrtblk: ;-op: write out x blocks ;-pp: a = number of blocks to write ;- @actsct is valid ;- ld e,wrtdata ; e = write data cmd. ;+ precmd: ;-op: create command block ;-pp: a = number of block involved ;- e = first command byte ;- push de ; save command ld hl,cmdtbl ; hl @ command block ld (hl),e ; store command byte inc hl ; point next ld de,(@actsct) ; de = log. block number push af ; save block count ld a,(@wrtact) ; see if in warm boot cp 'W' ; jr z,pc10 ; brif so ld a,e ; mask out garbage and not mask ; ld e,a ; pc10: pop af ; recover block count ld (hl),d ; save it inc hl ; ld (hl),e ; inc hl ; ld (hl),0 ; always < 256 log. blocks inc hl ld (hl),a ; save # blocks to trnsfr inc hl th non-zero ret ; and exit ;* ;** ;* ;+ ?putdma: ;-op: send dma address to host adapter ;-pp: rpntr has dma address ;- ld a,(hidma) ; set hi-byte out (dmaport),a ; high byte always zero ld de,(@rpntr) ; de @ dma address ld a,d out (dmaport),a ; send byte 1 ld a,e out (dmaport),a ; send byte 2 ret ; and exit ;* ;** ;* ;+ ?select: ;-op: select controler ;- in a,(bstat) ; is controler busy?? and busy ; wait for not busy jr z,?select ; wait if so sel2: ld a,01h ; select controler #1 out (datao),a ; out (selport),a ; and select controler sel1: in a,(bstat) ; wait for req and req ; jr nz,sel1 ; ld d,a ; d=0, mark first command ; ;* now fall on thru to output command bytes * ; ;+ ?outcmd: ;-op: issue command bytes to host adaptor ;-pp: hl @ command bytes ;- in a,(bstat) ; grab buss status ld c,a ; save status and cd ; see if data ret nz ; exit if data ld a,c ; check for direc and direc ; ret zdefw 00 ; Current DMA addess @trk: defw 00 ; Current Track Number @sect: defw 00 ; Current Sector Number cmdtbl: defs 11 ; Iomega Command Table Storage @wrtype: defb 00h ; current write type @ofs: defw 00 ; Current disk cache index dirbf: defs 128 ; directory buffer chkA: defs (drm/4)+1 ; directory checksum for drive A: chkB: defs (drm/4)+1 ; directory checksum for drive B: allA: defw (dsma/8)+1 ; Allocation map for drive A: allB: defw (dsmb/8)+1 ; Allocation map for Drive B: rdbuf: defw bufsz ; address of read data buffer wrtbuf: defs bufsz ; address of write data buffer @extra: defb 00 ; extra byte ; end end e 4K bytes dw dks&dn ; Total blocks db dir&dn ; Directory blocks db 2 ; Sector size 512 bytes dw 16*heads&dn ; Sectors per track dw cyls&dn ; Total tracks on disk dw hoff ; Reserved tracks .xall dstlen defl $-dst&dn endm ; ; ; scsi controller opcodes OPRDY EQU 0 OPZERO EQU 1 OPSENS EQU 3 OPFORM EQU 4 OPREAD EQU 8 OPWRIT EQU 10 OPSEK EQU 11 ;***************************************************** ; DTC-10 PORT ADDRESSES ;***************************************************** ; controller addresses CBASE EQU 050H BSTAT EQU CBASE+2 BCON EQU CBASE+1 DATAIN EQU CBASE+0 DATAOUT EQU CBASE+0 ;***************************************************** ; DTC -10 STATUS EQUATES ;***************************************************** ; controller status codes BUSY EQU 08H REQ EQU 80H SLCT EQU 40H DODATA EQU 02H ; ; ; ; ;*** Status and error bits ; secs equ 16 ;Physical sectors per track per head ; ; DSEG ;DATA STUFF ; DM ; exit if input ld a,req+bdack ; bit 0,d ; see if first cmd. jr nz,?oc5 ; brif not ld a,req ; else just check for req. ?oc5: and c ; check for ready jr nz,?outcmd ; brif not (1.75/1.17) ?oc1: ld a,(hl) ; get command byte (1.75/1.17) out (datao),a ; send to controler (2.75/1.83) inc hl ; point next (1.5/1.0) ld d,1 ; mark not first command jr ?outcmd ; and do it again! ;* ;** ;* ; subttl MISC. Routines and Functions page ; ; *** Misc. Routines and Functions *** ; ; ;+ ?sectran: ;-op: perform sector translation ;-pp: de @ tran. table ;- bc = sector number ;- hl = tran. sector number ;- ld h,b ; simple 1 to 1 translation ld l,c ; ret ; add exit ;* ;** ;* ; ;+ ?prtmsg: ;-op: Print message string at hl ;-pp: hl @ message string terminated with a zero byte. ;-rc: none ;- ld a,(hl) ; check for EOS or a ; ret z ; exit if so ld c,a ; c = character inc hl ; point next character push hl ; and save  TITLE TURBODOS OPERATING SYSTEM - IOMEGA DTC-10 DISK DRIVER .Z80 ; NAME ('IOMEGADR') ;MODULE ID ;***************************************************** ; Comment: ; this driver package is constructed in a way that should make ; it easy to add other SCSI drives to this interface. ; ; It is however at this time restricted to IOMEGA. ; It will handle up to 4 subsystems by changing the ; equates in two places. Hd0,1,2,3 and hddsks. ; ; author: Peter H. Mack (805) 527-0737 ; date: July 15,1983 ; rev: ------------ ;***************************************************** ; INCLUDE DREQUATE.LIB ;O/S SYMBOLIC EQUATES ; FALSE EQU 0 ;DEFINE LOGICAL VALUES TRUE EQU NOT FALSE ; ; ;*** Hard Disk selection choices *** ; IOMEGA EQU 1 ; Iomega 8 inch cartridge ; ;*** IOMEGA Disk equates *** ; HOFF EQU 1 ; Number of reserved tracks for loader ; ;*** IOMEGA Physical drives *** ; hd0 equ IOMEGA ; Set to type of drive or false if not used hd1 equ IOMEGA ;XSPH: ;MUTUAL EXCLUSION SEMAPHORE DW 1 ;SEMAPHORE COUNT ..DMXH: DW ..DMXH ;SEMAPHORE P/D HEAD DW ..DMXH ; HDCSPH: ;HDC SEMAPHORE DW 0 ;SEMAPHORE COUNT ..HDCH: DW ..HDCH ;SEMAPHORE P/D HEAD DW ..HDCH ; dmaptr: ds 2 ;temporary dma pointer storage sector: ds 1 ;temporary sector storage seccnt: ds 1 ;temporary sector count storage drive: ds 1 ;temporary drive number storage ; ; cdb - command data block CDB: DS 1 ;(1) group/opcode DS 1 ;(2) lun/block msb (always 0) DS 1 ;(3) block addr msb DS 1 ;(4) block addr lsb DS 1 ;(5) number of data blocks DS 1 ;(6) special option (always 0) ; ;***************************************************** ; Main dispatcher routine ;***************************************************** ; CSEG ;CODE STUFF ; ; IOMEGA INITIALIZATION ; DSKIN@:: CALL DINIT ; RET ; DINIT: RET ; ; DISK CONTROLLER DRIVER BEGINS HERE ; DSKDR@:: LD HL,DMXSPH ;GET MUTUAL EXCLUSION SEMAPHORE CALL WAIT## ;DISPATC call ?conout ; and issue to terminal handler pop hl ; recover pointer jr ?prtmsg ; and continue ;* ;** ;* ;+ ?dskerr: ;-op: Disk Error Handler ;-pp: A = error code letter ;-rc: none ;- push af ; save error letter on stack ld hl,dem ; hl @ disk error message call ?prtmsg ; go print message header pop af ; c = error code lettre ld c,a ; call ?conout ; and print it ret ; and exit ;* dem: defb cr,lf,lf defb "Disk I/O Error :",0 ;* ;** ;* ; subttl BIOS Data Storage Area page ; ; *** >>> BIOS Data Storage Area <<< *** ; ; @rpntr: defw 00 ; Address of Internal Deblocking buffer @wblk: defw 00 ; Current Write block number @rblk: defw 00 ; Current Read block number @actsct: defw 00 ; Block number to Read/Write @wrtact: defb false ; True if block is write active lcmd@: defw 00 ; Address of last IOMEGA command trycntr: defb 00 ; Retry counter for IOMEGA i/o op.s hidma: defb 00h ; Page address of IOMEGA buffer area @dma:  all drives must have same interface type hd2 equ IOMEGA ; i.e. all SA1000 type or all ST506 type hd3 equ IOMEGA ; TST MACRO DN ;physical hard disk defined IF HD&DN x defl 1 else x defl 0 endif endm hddsks defl 0 ;number of physical hard disk drives hdtst macro rept 4 tst %hddsks ;test all four physical drives iff x exitm endif .lall hddsks defl hddsks+1 .xall endm ;end rept endm ;end hdtst hdtst ;calculate number of physical hard disks ; ; dsktyp macro dn,typ .sfcond if typ eq IOMEGA strate&dn defl 10 ; 10 MS cyls&dn defl 306 heads&dn defl 4 fixed&dn defl false ;cartridge drive endif dks&dn defl heads&dn*(cyls&dn-hoff)*2 ;hard disk size in blocks ;dir&dn defl ((dks&dn / 128) + 1) ; DIR entries = blocks / 128 dir&dn defl 8 endm x defl 0 rept hddsks dsktyp %x,hd%x x defl x+1 endm dstdef macro dn ; Disk specifcation table defination macro .lall dst&dn: db 5 or (80h and fixed&dn) ; Block sizH IF NECESSARY CALL ..DD ;CALL DISK DRIVER PUSH AF ;SAVE RETURN CODE LD HL,DMXSPH ;GET MUTUAL EXCLUSION SEMAPHORE CALL SIGNAL## ;SIGNAL PROCESS AS READY POP AF ;RESTORE RETURN CODE RET ;DONE ; ..DD: LD A,(IX+PDRFCN) ;GET PD REQ FUNCTION NUMBER OR A ;PD REQ FUNCTION NUMBER=0? JP Z,RDDISK ;IF SO, CONTINUE DEC A ;PD REQ FUNCTION NUMBER=1? JP Z,WRDISK ;IF SO, CONTINUE DEC A ;PD REQ FUNCTION NUMBER=2? JP Z,RETDST ;IF SO, CONTINUE DEC A ;PD REQ FUNCTION NUMBER=3? JP Z,RETRDY ;IF SO, CONTINUE DEC A ;PD REQ FUNCTION NUMBER=4? JP Z,FORMAT ;IF SO, CONTINUE RET ;ELSE, DONE ; ;***************************************************** ; Return ready - opcode 3 ; returns ACC = 0ffh = ok ; 0 = error ;***************************************************** ; retrdy: ld a,oprdy ;iomega opcode ld (cdb),a call setcdb ret z call docom call cmpstat cpl ret ; and leave ;***************************************************** ; Return disnt of 128 blocks per track ; If other drives are to be used, then this will have to be ; rewritten. ;***************************************************** selblk: ld L,(ix+pdrtrk) ld H,(ix+pdrtrk+1) call shftlh ;*2 call shftlh ;*4 call shftlh ;*8 call shftlh ;*16 call shftlh ;*32 call shftlh ;*64 ld E,(ix+pdrsec) ld D,(ix+pdrsec+1) add HL,DE ;add sectors call shftlh ;blocks = secs*2 ld A,H ld (cdb+2),A ld A,L ld (cdb+3),A ld A,(ix+pdrsc) ;sector count rlca ;mult * 2 ld (cdb+4),a ret ; ;***************************************************** ; set up cdb ; returns ACC = 0ffh = ok ; 0 = error ;***************************************************** ; setcdb: call seldrv ret z call selblk ld L,(ix+pdrdma) ld H,(ix+pdrdma+1) ld (dmaptr),HL or 0FFH ret ; ;***************************************************** ; select drive ; returns ACC = 0ffh = ok ; 0 = error ;****************************************************controller jr dareq ;go back for another byte CMPSTAT: in a,(datain) ;input completion status ld C,A ;place in c for further use. LREQ: in A,(bstat) ;looking for last req ld B,A ;save for checking and req ;check for req jr z,lreq ;loop until found in A,(datain) ;input last byte o A ;se i las byt no zero jr nz,seterr ;if last byte non zero ld A,C ;now check completion status and 09FH ;to see if it is zero jr nz,seterr ;if not zero xor a ret SETERR: ld a,0FFH ;set error flag ret ;***************************************************** ; read data from disk ;***************************************************** READDAT: ld HL,(dmaptr) ;load data pointer RDREQ: in A,(bstat) ;input bus status ld C,A ;store for further checking and req ;look for req jr z,rdreq ;else loop ld A,C and 10H ;check for com jr nz,cmpstat ;if com present must be complete in A,(datain) ;input data from controller ld (HL),A inc HL jr rdrek specification table - opcode 2 ; returns ACC = 0ffh = ok ; 0 = error ;***************************************************** ; retdst: call retrdy ;is drive ready or A jr nz,dstrdy ;if so skip ld (IX+pdrdst),A ; otherwise zero dst pointer ld (IX+pdrdst+1),A ret ; and return dstrdy: ld A,(IX+pdrdrv) ;get requested drive ld B,A ;and save for mult add A,A ;*2 add A,A ;*4 add A,B ;*5 add A,A ;*10 add A,B ;*11 ld HL,dstbase ;get base address of dst tables ld E,A ;make offset 16 bits ld D,0 add HL,DE ; and put together ld (IX+pdrdst),L ;save for return ld (IX+pdrdst+1),H or 0ffh ;set valid return flag ret ; and leave ; ;***************************************************** ; read disk - opcode 0 ; returns acc = 0 ok ; 0ffh error ;***************************************************** ; rddisk: ld a,opread ;set up command ld (cdb),a call setcdb jr z,rds02 ;exit error ld B,10 ;retrys rds01: push BC ld HL,c* ; seldrv: ld A,(IX+pdrdrv) ;get requested drive cp hddsks ;make sure valid drive number jp nc,selnrdy ;exit if not rlca ;put drive into proper place for command rlca rlca rlca rlca ld (cdb+1),a or 0FFH ;set worked flag ret selnrdy: xor 0 ;return not ready ret ;***************************************************** ; get controller ;***************************************************** GETCON: in a,(bstat) ;input from status port and busy ;mask select bit (busy) jr nz,getcon ;if busy, keep looping ld a,slct ;assert select out (bcon),a ;to get controller CBUSY: in a,(bstat) ;input bus status and busy ;look at busy jr z,cbusy ;loop until we aquire controller ld a,dodata ;data enable out (bcon),a ret ;***************************************************** ; do a command ;***************************************************** DOCOM: call getcon ;get controller call outcom ;output command ret ;*************************q ;***************************************************** ; SHFTLH -- SHIFT LEFT HL 1 BIT POSITION ; CARRY CONTAINS MSB ;***************************************************** .8080 SHFTLH:: PUSH PSW ANA A ; CLEAR CARRY SHFL: MOV A,L ; SHIFT LOW RAL ; ROTATE 9-BIT ACC LEFT MOV L,A MOV A,H ; SHIFT HIGH RAL MOV H,A POP PSW RET .Z80 ;***************************************************** ; disk specification tables ;***************************************************** x defl 0 dstbase: rept hddsks ;define disk specification tables ; for all hard drives on controller dstdef %x x defl x+1 endm end db call docom call readdat pop BC and A ret z ;exit ok dec B jr nz,rds01 rds02: ld A,0FFH ret ;error exit ;***************************************************** ; write disk - opcode 1 ; returns acc = 0 ok ; 0ffh error ;***************************************************** ; wrdisk: ld A,opwrit ;set up command ld (cdb),A call setcdb jr z,wrts02 ;error ld B,10 wrts01: push BC ld HL,cdb call docom call writedat pop BC and A ret z ;exit ok dec B jr nz,wrts01 wrts02: ld A,0FFH ret ;error exit ;***************************************************** ; format routine Opcode - 4 ; (not applicable for iomega drive) ;***************************************************** ; format: xor A ; Otherwise set good return ret ; And leave ;***************************************************** ; load block cdb with block number and #blocks ; comment: the iomega drive system is addressed by block ; numbers this routine assumes a consta**************************** ; output commands ;***************************************************** OUTCOM: ld HL,cdb ;load cdb pointer COMREQ: in A,(bstat) ;input from bus status ld C,A ;store in reg(c) or A ;set status flags jp p,comreq ;wait for req and 10H ;check for com/data ret z ;return if data req. ld A,C ;also see if controller and 40H ;switched direction ret z ;if it wants to send data,return ld a,(HL) out (dataout),a ;write commands to controller inc HL jr comreq ;loop as long as commands are requested. ;***************************************************** ; write data to disk ;***************************************************** WRITEDAT: ld HL,(dmaptr) ;load pointer to data DAREQ: in A,(bstat) ;input bus status ld C,A and req ;set flags jr z,dareq ;loop for req ld A,C and 10H jr nz,cmpstat ;on receipt of command complete status ld A,M ;get data out (dataout),a ;output to controller inc HL ;increment SQQ`dE4M-ISHFTLH Mk@e@ px@\". K% ` pA,f .hdO*YVzʨU/ $|amd3h 6,^ۧpct dO:C6[Pct {?#@3n$1D8DEYdD> 6 @`SC@XMX*v@@?*Ktnlͮ,ͮ,ͮ-VY2`іnqdoX!iSt `?_Fp8 =p)9(N`@>4,mfH6Dʐ ˘?40ðUe"{(|\(@)CP[2|@WGH6D2P<lwU9.o>H  2@T@$ @ DGA@2"Z"t") G]rB2bDdL) FB@" J8 =p)9IPLGEN01MACGQRSTUIPLGEN01PRNVWXYZ[\]IPLGEN01PRN ^IPLGEN01ASME_`abcIPLGEN01REL dIPLGEN01SYMeBIOS2201MACfghijklmBIOS2201MAC>nopqIOMEGA MAC^rstuvwIOMEGA $$$> "*}3!!K*}3!*Zͼ!*Vͻ!*\ͻ!:y*Tͻ!!*Xͼ!:¦*i#*V{ozgͻ!>" :_:_*wbV*m|:GW7_%:_: :_*gaDM~_)# x%*g#}o|g"X:dO) M"X~# Vɴ|g}o a0O0ڄ:҄0AOx2!2Ú!;6N#F*e}& /oa*Z"Z2>2>DM<!6 `i"!~"#> "͟ͻ>K_1>Q{_ F Fno. of our drvs cnt defl 0 ;; cnt of how many entrys made drvmap: irp drvtyp, if drvtyp lt 16 xdmap %drvtyp ;; enter previous drv into dmap cnt defl cnt+1 else if drvtyp eq nodrive xxdmap ;; enter no drv entry into dmap cnt defl cnt+1 else if (drvtyp eq f8) or (drvtyp eq f548) or (drvtyp eq f596) dmap %dno,drvtyp,%fpdno fpdno defl fpdno+1 dno defl dno+1 cnt defl cnt+1 else rep (drvty sh 8 ; ente logica drv int dmap dmap %dno,drvtyp,%hpdno dno defl dno+1 cnt defl cnt+1 endm hpdno defl hpdno+1 endif endif endif endm rept (010h-cnt) ;; fill in rest of drive map xxdmap endm dno defl 0 hpdno defl 0 fpdno defl 0 irp drvtyp, ;;-------------------------------- ;; 5.25" 48-TPI FLOPPY DISK DRIVE ;;-------------------------------- if drvtyp eq f548 dph %dno,drvtyp if frst548 eq 0ffffh fdpb548: ;;----------------------------------------------------- ;; XEROX 820, KAYPRO II SINGLE DENSITY FORMA .xlist ;-------------------------------- ; AUTHOR Marcus G. Calescibetta ; DATE May 2, 1984 ; VERSION 2.3 ;-------------------------------- false equ 0 true equ not false ;;--------------- ;; DRIVE EQUATES ;;--------------- ;; ;; high byte = no. of logical drives on physical drive ;; low byte = physical drive type number (a unique no. identifing drive type) ;; nodrive equ 000fh ;; use to skip logigical drives f548 equ 01f0h ;; 5.25" - 48 tpi floppy drive f596 equ 01f1h ;; 5.25" - 96 tpi floppy drive f8 equ 01f2h ;; 8" floppy drive st503 equ 0100h ;; Seagate 503 st506 equ 0101h ;; Seagate 506 tm601s equ 0102h ;; Tandon 601s tm602s equ 0103h ;; Tandon 602s tm603s equ 0104h ;; Tandon 603s tm603se equ 0205h ;; Tandon 603se tm501 equ 0106h ;; Tandon 501 tm502 equ 0207h ;; Tandon 502 tm503 equ 0208h ;; Tandon 503 sa602 equ 0109h ;; Shugart 602 sa604 equ 010ah ;; Shugart 604 sa606 equ 010bh ;; Shugart 606 sa1002 equ 010ch ;T ;;----------------------------------------------------- ;; ;; dpb 10,18,3,7,0,82,31,8,3,1024 ;; ;;----------------------------------------------------- ;; OSBORNE SINGLE DENSITY FORMAT ;;----------------------------------------------------- ;; ;; dpb 10,20,4,15,1,45,63,16,3,2048 ;; ;;----------------------------------------------------- dpb 10,20,4,15,1,45,63,16,3,2048 dpb 11,32,4,15,0,77,63,32,1,2048 dpb 12,64,4,15,0,155,127,32,1,2048 fddb548: ;;----------------------------------------------------- ;; XEROX 820, KAYPRO II SINGLE DENSITY FORMAT ;;----------------------------------------------------- ;; ;; ddb 10,%fpdno,0,0,1024,128,64,1 ;; ;;----------------------------------------------------- ;; OSBORNE SINGLE DENSITY FORMAT ;;----------------------------------------------------- ;; ;; ddb 10,%fpdno,0,0,2048,256,64,1 ;; ;;----------------------------------------------------- ddb 10,%fpdno,0,0,2048,256,64,1 ddb 11,%fpdno,0,0,2048,1024,4,1 ddb 12,%fpdno,0,0,207COPYRIGHT (C) 1982 BY MICRO-GUIDANCE WAIPAHU, HI VERS 3.65 Sorry, I require CP/M VERSION 2.x to work correctly. Directory Drive - A [User 00] Used: Used: | + User Files Total Files Directory Entries K Bytes Free: PRESS ANY KEY TO CONTINUE (CTRL-C TO QUIT)!9"w1 |X X!æ 22mʄ ʄP̑+̗:mh :_!:'G0w#x0w22A2!\~2_A2!]~ >? +w#2h2j:\?2!6":h!">2\!ƀ_*V#"VO: >J! ~ ! ~Gb# QsPYʩ! M*T#"T*\#"\*!"#+wyŽxŽbk6V  V###F#~#_ »:d)=NyxyOxyx! :f/*T#"T*\"{|^!"}*{:2GH}o|gW*{"{"y!v:yl!_p#}p#=„p|<^>2DMo&)))) ~!ʳ!:¼##>."*y+"y|:=’Ì*{}<:2; Shugart 1002 sa1004 equ 010dh ;; Shugart 1004 q2010 equ 010eh ;; Quantum 2010 q2020 equ 020fh ;; Quantum 2020 q2030 equ 0310h ;; Quantum 2030 q2040 equ 0411h ;; Quantum 2040 m4010 equ 0112h ;; Mini Scribe 4010 m4020 equ 0213h ;; Mini Scribe 4020 dma5 equ 0114h ;; DMA 5 removable dma55c equ 0215h ;; DMA 5/5 cartriage boot dma55f equ 0216h ;; DMA 5/5 fixed boot maxhst defl 0 ;; maximum host sector size maxusg defl 0 ;; maximum no. phy sec per block frst8 defl 0ffffh ;; first 8" floppy drive flag frst548 defl 0ffffh ;; first 5.25" 48 tpi floppy drive flag frst596 defl 0ffffh ;; first 5.25" 96 tpi floppy drive flag ;;------------------------------------ ;; MACRO - DISK PARAMETER DEFINITIONS ;;------------------------------------ dskdef macro drvstr .lall ;------------------ ; SYSTEM DRIVE MAP ;------------------ .xall hpdno defl 0 ;; hard disk physical drive no. fpdno defl 0 ;; floppy disk physical drive no. dno defl 0 ;; logical drv  48,1024,4,2 tran548: ;;----------------------------------------------------- ;; XEROX 820, KAYPRO II SINGLE DENSITY FORMAT ;;----------------------------------------------------- ;; ;; db 1,6,11,16,3,8,13,18,5 ;; db 10,15,2,7,12,17,4,9,14 ;; ds 8,0ffh ;; ;;----------------------------------------------------- ;; OSBORNE SINGLE DENSITY FORMAT ;;----------------------------------------------------- ;; ;; db 2,3,6,7,10,11,14,15,18,19 ;; db 4,5,8,9,12,13,16,17,20,21 ;; ds 6,0ffh ;; ;;----------------------------------------------------- db 2,3,6,7,10,11,14,15,18,19 db 4,5,8,9,12,13,16,17,20,21 ds 6,0ffh frst548 defl 0 endif alvcsv %dno,155,32 dno defl dno+1 endif ;;-------------------------------- ;; 5.25" 96-TPI FLOPPY DISK DRIVE ;;-------------------------------- if drvtyp eq f596 dph %dno,drvtyp if frst596 eq 0ffffh fdpb596: dpb 20,18,3,7,0,82,63,16,3,1024 dpb 21,32,4,15,0,150,63,32,1,2048 dpb 22,64,4,15,0,300,127,32,1,2048 fddb596: ddb,511,0,1,4096 ddb %dno+0,%hpdno,0,0,4096,512,16,2 alvcsv %dno+0,607,0 dno defl dno+1 endif ;;------------------ ;; ST 506 HARD DISK ;;------------------ if drvtyp eq st506 dph %dno dpb %dno+0,256,5,31,1,1215,511,0,1,4096 ddb %dno+0,%hpdno,0,0,4096,512,16,4 alvcsv %dno+0,1215,0 dno defl dno+1 endif ;;------------------- ;; TM 601S HARD DISK ;;------------------- if drvtyp eq tm601S dph %dno dpb %dno+0,128,5,31,1,607,511,0,1,4096 ddb %dno+0,%hpdno,0,0,4096,512,16,2 alvcsv %dno+0,607,0 dno defl dno+1 endif ;;------------------- ;; TM 602S HARD DISK ;;------------------- if drvtyp eq tm602S dph %dno dpb %dno+0,256,5,31,1,1215,511,0,1,4096 ddb %dno+0,%hpdno,0,0,4096,512,16,4 alvcsv %dno+0,1215,0 dno defl dno+1 endif ;;------------------- ;; TM 603S HARD DISK ;;------------------- if drvtyp eq tm603S dph %dno dpb %dno+0,384,5,31,1,1823,1023,0,1,4096 ddb %dno+0,%hpdno,0,0,4096,512,16,6 alvcsv %dno+0,1823,0 dno defl dno+1 endif1002 dph %dno dpb %dno+0,128,5,31,1,1019,511,0,1,4096 ddb %dno+0,%hpdno,0,0,4096,512,16,2 alvcsv %dno+0,1019,0 dno defl dno+1 endif ;;------------------- ;; SA 1004 HARD DISK ;;------------------- if drvtyp eq sa1004 dph %dno dpb %dno+0,256,5,31,1,2039,1023,0,1,4096 ddb %dno+0,%hpdno,0,0,4096,512,16,4 alvcsv %dno+0,2039,0 dno defl dno+1 endif ;;------------------------ ;; QUANTUM 2010 HARD DISK ;;------------------------ if drvtyp eq q2010 dph %dno dpb %dno+0,128,5,31,1,2043,1023,0,1,4096 ddb %dno+0,%hpdno,0,0,4096,512,16,2 alvcsv %dno+0,2043,0 dno defl dno+1 endif ;;------------------------ ;; QUANTUM 2020 HARD DISK ;;------------------------ if drvtyp eq q2020 dph %dno dph %dno+1 ;; ;; Partion drive by track offset (use Q2020 loader) ;; ;; dpb %dno+0,256,5,31,1,2047,1023,0,1,4096 ;; dpb %dno+1,256,5,31,1,2039,1023,0,257,4096 ;; ddb %dno+0,%hpdno,0,0,4096,512,16,4 ;; ddb %dno+1,%hpdno,0,0,4096,512,16,4 ;; alvcsv %dno+0,2047,0 ;; alvc 20,%fpdno,0,0,1024,128,32,1 ddb 21,%fpdno,0,0,2048,1024,4,1 ddb 22,%fpdno,0,0,2048,1024,4,2 tran596: db 1,7,13,19,25,5,11,17,23,3,9,15,21 db 2,8,14,20,26,6,12,18,24,4,10,16,22 frst596 defl 0 endif alvcsv %dno,300,32 dno defl dno+1 endif ;;---------------------- ;; 8" FLOPPY DISK DRIVE ;;---------------------- if drvtyp eq f8 dph %dno,drvtyp if frst8 eq 0ffffh fdpb8: dpb 30,26,3,7,0,242,63,16,2,1024 dpb 31,64,4,15,0,303,127,32,1,2048 dpb 32,128,4,15,0,607,255,32,1,2048 fddb8: ddb 30,%fpdno,0,0,1024,128,32,1 ddb 31,%fpdno,0,0,2048,1024,8,1 ddb 32,%fpdno,0,0,2048,1024,8,2 tran8: db 1,7,13,19,25,5,11,17,23,3,9,15,21 db 2,8,14,20,26,6,12,18,24,4,10,16,22 frst8 defl 0 endif alvcsv %dno,607,32 dno defl dno+1 endif ;;------------------------------------------- ;; DMA MICRO MAGNUM 5/5 HARD DISK FIXED BOOT ;;------------------------------------------- if drvtyp eq dma55f dph %dno dph %dno+1 dpb %dno+0,128,5,31,1,1219,511,0,1, ;;-------------------- ;; TM 603SE HARD DISK ;;-------------------- if drvtyp eq tm603SE dph %dno dph %dno+1 dpb %dno+0,384,5,31,1,2047,1023,0,1,4096 dpb %dno+1,384,5,31,1,699,511,0,172,4096 ddb %dno+0,%hpdno,0,0,4096,512,16,6 ddb %dno+1,%hpdno,0,0,4096,512,16,6 alvcsv %dno+0,2047,0 alvcsv %dno+1,699,0 dno defl dno+2 endif ;;------------------ ;; TM 501 HARD DISK ;;------------------ if drvtyp eq tm501 dph %dno dpb %dno+0,128,5,31,1,1219,511,0,1,4096 ddb %dno+0,%hpdno,0,3,4096,512,16,2 alvcsv %dno+0,1219,0 dno defl dno+1 endif ;;------------------ ;; TM 502 HARD DISK ;;------------------ if drvtyp eq tm502 dph %dno dph %dno+1 dpb %dno+0,256,5,31,1,2047,1023,0,1,4096 dpb %dno+1,256,5,31,1,391,511,0,257,4096 ddb %dno+0,%hpdno,0,3,4096,512,16,4 ddb %dno+1,%hpdno,0,3,4096,512,16,4 alvcsv %dno+0,2047,0 alvcsv %dno+1,391,0 dno defl dno+2 endif ;;------------------ ;; TM 503 HARD DISK ;;------------------ if drvtyp eq tm503 dph sv %dno+1,2039,0 ;; ;; Partion drive by head offset (use Q2010 loader) ;; ;; dpb %dno+0,128,5,31,1,2043,1023,0,1,4096 ;; dpb %dno+1,128,5,31,1,2043,1023,0,1,4096 ;; ddb %dno+0,%hpdno,0,0,4096,512,16,2 ;; ddb %dno+1,%hpdno,2,0,4096,512,16,2 ;; alvcsv %dno+0,2043,0 ;; alvcsv %dno+1,2043,0 ;; dpb %dno+0,256,5,31,1,2047,1023,0,1,4096 dpb %dno+1,256,5,31,1,2039,1023,0,257,4096 ddb %dno+0,%hpdno,0,0,4096,512,16,4 ddb %dno+1,%hpdno,0,0,4096,512,16,4 alvcsv %dno+0,2047,0 alvcsv %dno+1,2039,0 dno defl dno+2 endif ;;------------------------ ;; QUANTUM 2030 HARD DISK ;;------------------------ if drvtyp eq q2030 dph %dno dph %dno+1 dph %dno+2 dpb %dno+0,384,5,31,1,2047,1023,0,1,4096 dpb %dno+1,384,5,31,1,2047,1023,0,172,4096 dpb %dno+2,384,5,31,1,2031,1023,0,343,4096 ddb %dno+0,%hpdno,0,0,4096,512,16,6 ddb %dno+1,%hpdno,0,0,4096,512,16,6 ddb %dno+2,%hpdno,0,0,4096,512,16,6 alvcsv %dno+0,2047,0 alvcsv %dno+1,2047,0 alvcsv %dno+2,2031,0 dno defl dno+3 endif 4096 dpb %dno+1,128,5,31,1,1219,511,0,1,4096 ddb %dno+0,%hpdno,2,15,4096,256,32,2 ddb %dno+1,%hpdno,0,15,4096,256,32,2 alvcsv %dno+0,1219,0 alvcsv %dno+1,1219,0 dno defl dno+2 endif ;;----------------------------------------------- ;; DMA MICRO MAGNUM 5/5 HARD DISK CARTRIAGE BOOT ;;----------------------------------------------- if drvtyp eq dma55c dph %dno dph %dno+1 dpb %dno+0,128,5,31,1,1219,511,0,1,4096 dpb %dno+1,128,5,31,1,1219,511,0,1,4096 ddb %dno+0,%hpdno,0,15,4096,256,32,2 ddb %dno+1,%hpdno,2,15,4096,256,32,2 alvcsv %dno+0,1219,0 alvcsv %dno+1,1219,0 dno defl dno+2 endif ;;------------------------------ ;; DMA MICRO MAGNUM 5 HARD DISK ;;------------------------------ if drvtyp eq dma5 dph %dno dpb %dno+0,128,5,31,1,1219,511,0,1,4096 ddb %dno+0,%hpdno,0,15,4096,256,32,2 alvcsv %dno+0,1219,0 dno defl dno+1 endif ;;------------------ ;; ST 503 HARD DISK ;;------------------ if drvtyp eq st503 dph %dno dpb %dno+0,128,5,31,1,607%dno dph %dno+1 dpb %dno+0,384,5,31,1,2047,1023,0,1,4096 dpb %dno+1,384,5,31,1,1611,1023,0,172,4096 ddb %dno+0,%hpdno,0,0,4096,512,16,6 ddb %dno+1,%hpdno,0,0,4096,512,16,6 alvcsv %dno+0,2047,0 alvcsv %dno+1,1611,0 dno defl dno+2 endif ;;------------------ ;; SA 602 HARD DISK ;;------------------ if drvtyp eq sa602 dph %dno dpb %dno+0,128,5,31,1,635,511,0,1,4096 ddb %dno+0,%hpdno,0,3,4096,512,16,2 alvcsv %dno+0,635,0 dno defl dno+1 endif ;;------------------ ;; SA 604 HARD DISK ;;------------------ if drvtyp eq sa604 dph %dno dpb %dno+0,256,5,31,1,1271,511,0,1,4096 ddb %dno+0,%hpdno,0,3,4096,512,16,4 alvcsv %dno+0,1271,0 dno defl dno+1 endif ;;------------------ ;; SA 606 HARD DISK ;;------------------ if drvtyp eq sa606 dph %dno dpb %dno+0,384,5,31,1,1907,1023,0,1,4096 ddb %dno+0,%hpdno,0,3,4096,512,16,6 alvcsv %dno+0,1907,0 dno defl dno+1 endif ;;------------------- ;; SA 1002 HARD DISK ;;------------------- if drvtyp eq sa! ;;------------------------ ;; QUANTUM 2040 HARD DISK ;;------------------------ if drvtyp eq q2040 dph %dno dph %dno+1 dph %dno+2 dph %dno+3 dpb %dno+0,512,5,31,1,2047,1023,0,1,4096 dpb %dno+1,512,5,31,1,2047,1023,0,129,4096 dpb %dno+2,512,5,31,1,2047,1023,0,257,4096 dpb %dno+3,512,5,31,1,2031,1023,0,385,4096 ddb %dno+0,%hpdno,0,0,4096,512,16,8 ddb %dno+1,%hpdno,0,0,4096,512,16,8 ddb %dno+2,%hpdno,0,0,4096,512,16,8 ddb %dno+3,%hpdno,0,0,4096,512,16,8 alvcsv %dno+0,2047,0 alvcsv %dno+1,2047,0 alvcsv %dno+2,2047,0 alvcsv %dno+3,2031,0 dno defl dno+4 endif ;;--------------------------- ;; MINISCRIBE 4010 HARD DISK ;;--------------------------- if drvtyp eq m4010 dph %dno dpb %dno+0,128,5,31,1,1915,1023,0,1,4096 ddb %dno+0,%hpdno,0,0,4096,512,16,2 alvcsv %dno+0,1915,0 dno defl dno+1 endif ;;--------------------------- ;; MINISCRIBE 4020 HARD DISK ;;--------------------------- if drvtyp eq m4020 dph %dno dph %dno+1 dpb %dno+0,256,5,31,1 dpb addr for fpy filled in dynamicly endif dw csv&dn ; directory check vector dw alv&dn ; disk allocation vector endm ;;------------------------------ ;; MACRO - DISK PARAMETER BLOCK ;;------------------------------ dpb macro dn,spt,bsh,blm,exm,dsm,drm,cks,off,bsiz .lall ;---------------------- ; DISK PARAMETER BLOCK ;---------------------- .xall dpb&dn: dw spt ; cpm sectors per track db bsh ; block shift factor db blm ; block mask db exm ; extent mask dw dsm ; no. blocks on drive dw drm ; no. directory entrys rsvdir dn,drm,bsiz ;;reserved directory blocks dw cks ; no. directory entries to check dw off ; track offset endm ;;------------------------------- ;; MACRO - DISK DEBLOCKING BLOCK ;;------------------------------- ddb macro dn,pd,hdoff,srate,bsiz,hsiz,hsspt,hhd .lall ;----------------------- ; DISK DEBLOCKING BLOCK ;----------------------- .xall ddb&dn: dw hsiz ; host sec size ssiz hsiz ;;sdh regi 512 bps else if secsiz eq 256 db 000h ; sdh reg sec siz 000 = 256 bps else db 000h endif endif endif endm ;;------------------------------ ;; MACRO - COMPUTE SHIFT FACTOR ;;------------------------------ shff macro num @y defl num @x defl 0 rept 8 if @y eq 1 db @x ; log2 (num) exitm endif @y defl @y shr 1 @x defl @x + 1 endm endm .list lock allocation 1 done defl 0ffh exitm endif al1&dn defl al1&dn or y y defl y shr 1 x defl x-1 endm endif if done eq 0 db al0&dn ; directory block allocation 0 db al1&dn ; directory block allocation 1 endif endm ;;----------------------------------- ;; MACRO - COMPUTE DRIVE SECTOR SIZE ;;----------------------------------- ssiz macro secsiz if secsiz eq 128 db 060h ; sdh reg sec siz 060 = 128 bps else if secsiz eq 512 db 020h ; sdh reg sec siz 020 =,2047,1023,0,1,4096 dpb %dno+1,256,5,31,1,1783,1023,0,257,4096 ddb %dno+0,%hpdno,0,0,4096,512,16,4 ddb %dno+1,%hpdno,0,0,4096,512,16,4 alvcsv %dno+0,2047,0 alvcsv %dno+1,1783,0 dno defl dno+2 endif if (drvtyp eq f8) or (drvtyp eq f548) or (drvtyp eq f596) fpdno defl fpdno+1 else if drvtyp gt 15 hpdno defl hpdno+1 endif endif endm if frst8 eq 0ffffh fdpb8: ; no 8" floppy used but need label fddb8: ; no 8" floppy used but need label tran8: ; no 8" floppy used but need label endif if frst548 eq 0ffffh fdpb548: ; no 5"-48 tpi drv used but need label fddb548: ; no 5"-48 tpi drv used but need label tran548: ; no 5"-48 tpi drv used but need label endif if frst596 eq 0ffffh fdpb596: ; no 5"-96 tpi drv used but need label fddb596: ; no 5"-96 tpi drv used but need label tran596: ; no 5"=96 tpi drv used but need label endif usgblk: ds maxusg ; maximum # host sectors / block dirbuf: ds 128d ; cp/m directory buffer storage hstster sector size db pd ; physical drive no. db hdoff ; head offset (for partioning by hds) db srate ; cmd register step rate db hsspt-1 ; host sec per trk - 1 (hst sec msk) db (bsiz/hsiz)-1 ; host sec per blk - 1 (blk sec msk) shff ((hsiz/128)*hsspt) ;;calc log2 cpm spt shff (bsiz/128) ;;calc log2 cpm spb db hhd-1 ; heads - 1 shff (hsiz/128) ;;calc log2 cpm sps db (hsiz/128)-1 ; cpm sps - 1 if hsiz gt maxhst maxhst defl hsiz endif if (bsiz/hsiz) gt maxusg maxusg defl (bsiz/hsiz) endif endm ;;-------------------------------------- ;; MACRO - COMPUTE ALV AND CSV BUF SIZE ;;-------------------------------------- alvcsv macro dn,dsm,cks .lall ;--------------------------------------- ; DRIVE ALLOCATION AND CHECK SUM VECTOR ;--------------------------------------- .xall alv&dn: ds (dsm/8)+1 ; drive block allocation vector csv&dn: ds cks ; drive directory check vector endm ;;-------------------------------------- ;; MACRO - COMPUbuf: ; host buffer follows endm ;;------------------- ;; MACRO - DRIVE MAP ;;------------------- dmap macro dn,drvtyp,pdno if drvtyp eq f548 db 1,pdno ; 5" - 48 tpi floppy dw dph&dn,ddb&10 else if drvtyp eq f596 db 2,pdno ; 5" - 96 tpi floppy dw dph&dn,ddb&20 else if drvtyp eq f8 db 3,pdno ; 8" floppy dw dph&dn,ddb&30 else db 0,pdno ; hard disk dw dph&dn,ddb&dn endif endif endif endm xdmap macro dn db 010h,dn ; other bio's drive dw 0,0 endm xxdmap macro db 0ffh,0ffh ; no drive selected dw 0ffffh,0ffffh endm ;;--------------------------- ;; MACRO - DISK HEADER BLOCK ;;--------------------------- dph macro dn,dtyp .lall ;------------------- ; DISK HEADER BLOCK ;------------------- .xall dph&dn: dw 0000 ; translation vector dw 0000 ; scratch pad 1 dw 0000 ; scratch pad 2 dw 0000 ; scratch pad 3 dw dirbuf ; dirbuf addr ifb dw dpb&dn ; dpb addr for hrd dsk else dw 0 ;TE NO. DIRECTORY BLOCKS ;;-------------------------------------- rsvdir macro dn,drm,bsiz x defl ((drm+1)/(bsiz/32)) y defl 080h done defl 0 al0&dn defl 0 al1&dn defl 0 rept 8 if x eq 0 db al0&dn ; directory block allocation 0 db al1&dn ; directory block allocation 1 done defl 0ffh exitm endif al0&dn defl al0&dn or y y defl y shr 1 x defl x-1 endm y defl 080h if done eq 0 rept 8 if x eq 0 db al0&dn ; directory block allocation 0 db al1&dn ; directory block allocation 1 done defl 0ffh exitm endif al1&dn defl al1&dn or y y defl y shr 1 x defl x-1 endm endif if done eq 0 db al0&dn ; directory block allocation 0 db al1&dn ; directory block allocation 1 endif endm ;;----------------------------------- ;; MACRO - COMPUTE DRIVE SECTOR SIZE ;;----------------------------------- ssiz macro secsiz if secsiz eq 128 db 060h ; sdh reg sec siz 060 = 128 bps else if secsiz eq 512 db 020h ; sdh reg sec siz 020 ="; CP/M 2.0 disk re-definition library ; ; Copyright (c) 1979 ; Digital Research ; Box 579 ; Pacific Grove, CA ; 93950 ; ; CP/M logical disk drives are defined using the ; macros given below, where the sequence of calls ; is: ; ; disks n ; diskdef parameter-list-0 ; diskdef parameter-list-1 ; ... ; diskdef parameter-list-n ; endef ; ; where n is the number of logical disk drives attached ; to the CP/M system, and parameter-list-i defines the ; characteristics of the ith drive (i=0,1,...,n-1) ; ; each parameter-list-i takes the form ; dn,fsc,lsc,[skf],bls,dks,dir,cks,ofs,[0] ; where ; dn is the disk number 0,1,...,n-1 ; fsc is the first sector number (usually 0 or 1) ; lsc is the last sector number on a track ; skf is optional "skew factor" for sector translate ; bls is the data block size (1024,2048,...,16384) ; dks is the disk size in bls increments (word) ; dir is the number of directory elements (word) ; cks is the number of dir elements to checksum ; ofs is the number of u als&fsc ;same allocation vector size css&dn equ css&fsc ;same checksum vector size xlt&dn equ xlt&fsc ;same translate table else secmax set lsc-(fsc) ;;sectors 0...secmax sectors set secmax+1;;number of sectors als&dn set (dks)/8 ;;size of allocation vector if ((dks) mod 8) ne 0 als&dn set als&dn+1 endif css&dn set (cks)/4 ;;number of checksum elements ;; generate the block shift value blkval set bls/128 ;;number of sectors/block blkshf set 0 ;;counts right 0's in blkval blkmsk set 0 ;;fills with 1's from right rept 16 ;;once for each bit position if blkval=1 exitm endif ;; otherwise, high order 1 not found yet blkshf set blkshf+1 blkmsk set (blkmsk shl 1) or 1 blkval set blkval/2 endm ;; generate the extent mask byte blkval set bls/1024 ;;number of kilobytes/block extmsk set 0 ;;fill from right with 1's rept 16 if blkval=1 exitm endif ;; otherwise more to shift extmsk set (extmsk shl 1) or 1 blkval set blkval/2 endm ;; may be double byte allocation if (dks)nddat equ $ datsiz equ $-begdat ;; db 0 at this point forces hex record endm ; = gcd(sectors,skew) neltst set sectors/gcdn ;; neltst is number of elements to generate ;; before we overlap previous elements nelts set neltst ;;counter xlt&dn equ $ ;translate table rept sectors ;;once for each sector if sectors < 256 ddb %nxtsec+(fsc) else ddw %nxtsec+(fsc) endif nxtsec set nxtsec+(skf) if nxtsec >= sectors nxtsec set nxtsec-sectors endif nelts set nelts-1 if nelts = 0 nxtbas set nxtbas+1 nxtsec set nxtbas nelts set neltst endif endm endif ;;end of nul fac test endif ;;end of nul bls test endm ; defds macro lab,space lab: ds space endm ; lds macro lb,dn,val defds lb&dn,%val&dn endm ; endef macro ;; generate the necessary ram data areas begdat equ $ dirbuf: ds 128 ;directory access buffer dsknxt set 0 rept ndisks ;;once for each disk lds alv,%dsknxt,als lds csv,%dsknxt,css dsknxt set dsknxt+1 endm etracks to skip (word) ; [0] is an optional 0 which forces 16K/directory entry ; ; for convenience, the form ; dn,dm ; defines disk dn as having the same characteristics as ; a previously defined disk dm. ; ; a standard four drive CP/M system is defined by ; disks 4 ; diskdef 0,1,26,6,1024,243,64,64,2 ; dsk set 0 ; rept 3 ; dsk set dsk+1 ; diskdef %dsk,0 ; endm ; endef ; ; the value of "begdat" at the end of assembly defines the ; beginning of the uninitialize ram area above the bios, ; while the value of "enddat" defines the next location ; following the end of the data area. the size of this ; area is given by the value of "datsiz" at the end of the ; assembly. note that the allocation vector will be quite ; large if a large disk size is defined with a small block ; size. ; dskhdr macro dn ;; define a single disk header list dpe&dn: dw xlt&dn,0000h ;translate table dw 0000h,0000h ;scratch area dw dirbuf,dpb&dn ;dir buff,parm block dw csv&dn,alv&dn ;check, alloc vec > 256 extmsk set (extmsk shr 1) endif ;; may be optional [0] in last position if not nul k16 extmsk set k16 endif ;; now generate directory reservation bit vector dirrem set dir ;;# remaining to process dirbks set bls/32 ;;number of entries per block dirblk set 0 ;;fill with 1's on each loop rept 16 if dirrem=0 exitm endif ;; not complete, iterate once again ;; shift right and add 1 high order bit dirblk set (dirblk shr 1) or 8000h if dirrem > dirbks dirrem set dirrem-dirbks else dirrem set 0 endif endm dpbhdr dn ;;generate equ $ ddw %sectors,<;sec per track> ddb %blkshf,<;block shift> ddb %blkmsk,<;block mask> ddb %extmsk,<;extnt mask> ddw %(dks)-1,<;disk size-1> ddw %(dir)-1,<;directory max> ddb %dirblk shr 8,<;alloc0> ddb %dirblk and 0ffh,<;alloc1> ddw %(cks)/4,<;check size> ddw %ofs,<;offset> ;; generate the translate table, if requested if nul skf xlt&dn equ 0 ;no xlate table else if skf = 0 xlt&dn equ 0 ;no xlate table else ;; generators endm ; disks macro nd ;; define nd disks ndisks set nd ;;for later reference dpbase equ $ ;base of disk parameter blocks ;; generate the nd elements dsknxt set 0 rept nd dskhdr %dsknxt dsknxt set dsknxt+1 endm endm ; dpbhdr macro dn dpb&dn equ $ ;disk parm block endm ; ddb macro data,comment ;; define a db statement db data comment endm ; ddw macro data,comment ;; define a dw statement dw data comment endm ; gcd macro m,n ;; greatest common divisor of m,n ;; produces value gcdn as result ;; (used in sector translate table generation) gcdm set m ;;variable for m gcdn set n ;;variable for n gcdr set 0 ;;variable for r rept 65535 gcdx set gcdm/gcdn gcdr set gcdm - gcdx*gcdn if gcdr = 0 exitm endif gcdm set gcdn gcdn set gcdr endm endm ; diskdef macro dn,fsc,lsc,skf,bls,dks,dir,cks,ofs,k16 ;; generate the set statements for later tables if nul lsc ;; current disk dn same as previous fsc dpb&dn equ dpb&fsc ;equivalent parameters als&dn eqte the translate table nxtsec set 0 ;;next sector to fill nxtbas set 0 ;;moves by one on overflow gcd %sectors,skf ;; gcdn = gcd(sectors,skew) neltst set sectors/gcdn ;; neltst is number of elements to generate ;; before we overlap previous elements nelts set neltst ;;counter xlt&dn equ $ ;translate table rept sectors ;;once for each sector if sectors < 256 ddb %nxtsec+(fsc) else ddw %nxtsec+(fsc) endif nxtsec set nxtsec+(skf) if nxtsec >= sectors nxtsec set nxtsec-sectors endif nelts set nelts-1 if nelts = 0 nxtbas set nxtbas+1 nxtsec set nxtbas nelts set neltst endif endm endif ;;end of nul fac test endif ;;end of nul bls test endm ; defds macro lab,space lab: ds space endm ; lds macro lb,dn,val defds lb&dn,%val&dn endm ; endef macro ;; generate the necessary ram data areas begdat equ $ dirbuf: ds 128 ;directory access buffer dsknxt set 0 rept ndisks ;;once for each disk lds alv,%dsknxt,als lds csv,%dsknxt,css dsknxt set dsknxt+1 endm e#; ; Z-80 MACRO LIBRARY ; ; THE FOLLOWING MACROS ENABLE ASSEMBLING Z-80 INSTRUCTIONS ; WITH THE DIGITAL RESEARCH MACRO ASSEMBLER. ; ; INVOKE WITH "MACLIB Z80" ; ; ; ; MACRO FORMATS ; ----- ------- ; ; ; MACRO ZILOG TDL ; ----- ----- --- ; ; LDX R,D LD R,(IX+D) MOV R,D(IX) ; LDY R,D LD R,(IY+D) MOV R,D(IY) ; STX R,D LD (IX+D),R MOV D(IX),R ; STY R,D LD (IY+D),R MOV D(IY),R ; MVIX NN,D LD (IX+D),NN MVI D(IX) ; MVIY NN,D LD (IY+D),NN MVI D(IY) ; LDAI LD A,I LDAI ; LDAR LD A,R LDAR ; STAI LD I,A STAI ; STAR LD R,A STAR ; LXIX NNNN LD IX,NNNN LXI IX,NNNN ; LXIY NNNN LD IY,NNNN LXI IY,NNNN ; LBCD NNNN LD BC,(NNNN) LBCD NNNN ; LDED NNNN LD DE,(NNNN) LDED NNNN ; LSPD NNNN LD SP,(NNNN) LSPD NNNN ; LIXD NNNN LD IX,(NNNN) LIXD NNNN ; LIYD NNNN LD IY,(NNNN) LIYD NNNN ; SBCD NNNN LD (NNNN),BC SBCD NNNN ; SDED NNNN LD (NNNN),DE SDED NNNN ; SSPD NNNN LD (NNNN),SP SSPD NNNN ; SIXD NNNN LD (NNNN),IX SIXD NNNN ; SIYD NNNN LD (NNNN),IY SIYD  (C),R OUTP R ; INI INI INI ; INIR INIR INIR ; OUTI OTI OUTI ; OUTIR OTIR OUTIR ; IND IND IND ; INDR INDR INDR ; OUTD OTD OUTD ; OUTDR OTDR OUTDR ; RLCR R RLC R RLCR R ; RLCX D RLC (IX+D) RLCR D(IX) ; RLCY D RLC (IY+D) RLCR D(IY) ; RALR R RL R RALR R ; RALX D RL (IX+D) RALR D(IX) ; RALY D RL (IY+D) RALR D(IY) ; RRCR R RRC R RRCR R ; RRCX D RRC (IX+D) RRCR D(IX) ; RRCY D RRC (IY+D) RRCR D(IY) ; RARR R RR R RARR R ; RARX D RR (IX+D) RARR D(IX) ; RARY D RR (IY+D) RARR D(IY) ; SLAR R SLA R SLAR R ; SLAX D SLA (IX+D) SLAR D(IX) ; SLAY D SLA (IY+D) SLAR D(IY) ; SRAR R SRA R SRAR R ; SRAX D SRA (IX+D) SRAR D(IX) ; SRAY D SRA (IY+D) SRAR D(IY) ; SRLR R SRL R SRLR R ; SRLX D SRL (IX+D) SRLR D(IX) ; SRLY D SRL (IY+D) SRLR D(IY) ; RLD RLD RLD ; RRD RRD RRD ; ; ; ; @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 0FFMACRO ?D @CHK ?D DB 0FDH,96H,?D ENDM SBCX MACRO ?D @CHK ?D DB 0DDH,9EH,?D ENDM SBCY MACRO ?D @CHK ?D DB 0FDH,9EH,?D ENDM ANDX MACRO ?D @CHK ?D DB 0DDH,0A6H,?D ENDM ANDY MACRO ?D @CHK ?D DB 0FDH,0A6H,?D ENDM XORX MACRO ?D @CHK ?D DB 0DDH,0AEH,?D ENDM XORY MACRO ?D @CHK ?D DB 0FDH,0AEH,?D ENDM ORX MACRO ?D @CHK ?D DB 0DDH,0B6H,?D ENDM ORY MACRO ?D @CHK ?D DB 0FDH,0B6H,?D ENDM CMPX MACRO ?D @CHK ?D DB 0DDH,0BEH,?D ENDM CMPY MACRO ?D @CHK ?D DB 0FDH,0BEH,?D ENDM INRX MACRO ?D @CHK ?D DB 0DDH,34H,?D ENDM INRY MACRO ?D @CHK ?D DB 0FDH,34H,?D ENDM DCRX MACRO ?D @CHK ?D DB 0DDH,035H,?D ENDM DCRY MACRO ?D @CHK ?D DB 0FDH,35H,?D ENDM NEG MACRO DB 0EDH,44H ENDM IM0 MACRO DB 0EDH,46H ENDM IM1 MACRO DB 0EDH,56H ENDM IM2 MACRO DB 0EDH,5EH ENDM BC EQU 0 DE EQU 2 HL EQU 4 IX EQU 4 IY EQU 4 DADC MACRO ?R DB 0EDH,?R*8+4AH ENDM DSBC MACRO ?R DB 0EDH,?R*8+42H NNNN ; SPIX LD SP,IX SPIX ; SPIY LD SP,IY SPIY ; PUSHIX PUSH IX PUSH IX ; PUSHIY PUSH IY PUSH IY ; POPIX POP IX POP IX ; POPIY POP IY POP IY ; EXAF EX AF,AF' EXAF ; EXX EXX EXX ; XTIX EX (SP),IX XTIX ; XTIY EX (SP),IY XTIY ; LDI LDI LDI ; LDIR LDIR LDIR ; LDD LDD LDD ; LDDR LDDR LDDR ; CCI CPI CCI ; CCIR CPIR CCIR ; CCD CPD CCD ; CCDR CPDR CCDR ; ADDX D ADD (IX+D) ADD D(IX) ; ADDY D ADD (IY+D) ADD D(IY) ; ADCX D ADC (IX+D) ADC D(IX) ; ADCY D ADC (IY+D) ADC D(IY) ; SUBX D SUB (IX+D) SUB D(IX) ; SUBY D SUB (IY+D) SUB D(IY) ; SBCX D SBC (IX+D) SBB D(IX) ; SBCY D SBC (IY+D) SBB D(IY) ; ANDX D AND (IX+D) ANA D(IX) ; ANDY D AND (IY+D) ANA D(IY) ; XORX D XOR (IX+D) XRA D(IX) ; XORY D XOR (IY+D) XRA D(IY) ; ORX D OR (IX+D) ORA D(IX) ; ORY D OR (IY+D) ORA D(IY) ; CMPX D CP (IX+D) CMP D(IX) ; CMPY D CP (IY+D) CMP D(IY) ; INRX D INC (IX+D) INR D(IX) ; INRY D INC (IY+D) INR D(IY) ; DCRX 80H) 'DISPLACEMENT RANGE ERROR - Z80 LIB' ENDIF ENDM LDX MACRO ?R,?D @CHK ?D DB 0DDH,?R*8+46H,?D ENDM LDY MACRO ?R,?D @CHK ?D DB 0FDH,?R*8+46H,?D ENDM STX MACRO ?R,?D @CHK ?D DB 0DDH,70H+?R,?D ENDM STY MACRO ?R,?D @CHK ?D DB 0FDH,70H+?R,?D ENDM MVIX MACRO ?N,?D @CHK ?D DB 0DDH,36H,?D,?N ENDM MVIY MACRO ?N,?D @CHK ?D DB 0FDH,36H,?D,?N ENDM LDAI MACRO DB 0EDH,57H ENDM LDAR MACRO DB 0EDH,5FH ENDM STAI MACRO DB 0EDH,47H ENDM STAR MACRO DB 0EDH,4FH ENDM LXIX MACRO ?NNNN DB 0DDH,21H DW ?NNNN ENDM LXIY MACRO ?NNNN DB 0FDH,21H DW ?NNNN ENDM LDED MACRO ?NNNN DB 0EDH,5BH DW ?NNNN ENDM LBCD MACRO ?NNNN DB 0EDH,4BH DW ?NNNN ENDM LSPD MACRO ?NNNN DB 0EDH,07BH DW ?NNNN ENDM LIXD MACRO ?NNNN DB 0DDH,2AH DW ?NNNN ENDM LIYD MACRO ?NNNN DB 0FDH,2AH DW ?NNNN ENDM SBCD MACRO ?NNNN DB 0EDH,43H DW ?NNNN ENDM SDED MACRO ?NNNN DB 0EDH,53H DW ?NNNN ENDM SSPD MACRO ?NNNN DB 0EDENDM DADX MACRO ?R DB 0DDH,?R*8+09H ENDM DADY MACRO ?R DB 0FDH,?R*8+09H ENDM INXIX MACRO DB 0DDH,23H ENDM INXIY MACRO DB 0FDH,23H ENDM DCXIX MACRO DB 0DDH,2BH ENDM DCXIY MACRO DB 0FDH,2BH ENDM BIT MACRO ?N,?R DB 0CBH,?N*8+?R+40H ENDM SETB MACRO ?N,?R DB 0CBH,?N*8+?R+0C0H ENDM RES MACRO ?N,?R DB 0CBH,?N*8+?R+80H ENDM BITX MACRO ?N,?D @CHK ?D DB 0DDH,0CBH,?D,?N*8+46H ENDM BITY MACRO ?N,?D @CHK ?D DB 0FDH,0CBH,?D,?N*8+46H ENDM SETX MACRO ?N,?D @CHK ?D DB 0DDH,0CBH,?D,?N*8+0C6H ENDM SETY MACRO ?N,?D @CHK ?D DB 0FDH,0CBH,?D,?N*8+0C6H ENDM RESX MACRO ?N,?D @CHK ?D DB 0DDH,0CBH,?D,?N*8+86H ENDM RESY MACRO ?N,?D @CHK ?D DB 0FDH,0CBH,?D,?N*8+86H ENDM JR MACRO ?N DB 18H,?N-$-1 ENDM JRC MACRO ?N DB 38H,?N-$-1 ENDM JRNC MACRO ?N DB 30H,?N-$-1 ENDM JRZ MACRO ?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 PD INC (IX+D) INR D(IX) ; DCRY D DEC (IY+D) DCR D(IY) ; NEG NEG NEG ; IM0 IM0 IM0 ; IM1 IM1 IM1 ; IM2 IM2 IM2 ; DADC RR ADC HL,RR DADC RR ; DSBC RR SBC HL,RR DSBC RR ; DADX RR ADD IX,RR DADX RR ; DADY RR ADD IY,RR DADY RR ; INXIX INC IX INX IX ; INXIY INC IY INX IY ; DCXIX DEC IX DCX IX ; DCXIY DEC IY DCX IY ; BIT B,R BIT B,R BIT B,R ; SETB B,R SET B,R SET B,R ; RES B,R RES B,R RES B,R ; BITX B,D BIT B,(IX+D) BIT B,D(IX) ; BITY B,D BIT B,(IY+D) BIT B,D(IY) ; SETX B,D SET B,(IX+D) SET B,D(IX) ; SETY B,D SET B,(IY+D) SET B,D(IY) ; RESX B,D RES B,(IX+D) RES B,D(IX) ; RESY B,D RES B,(IY+D) RES B,D(IY) ; JR ADDR JR ADDR-$ JMPR ADDR ; JRC ADDR JR C,ADDR-$ JRC ADDR ; JRNC ADDR JR NC,ADDR-$ JRNC ADDR ; JRZ ADDR JR Z,ADDR-$ JRC ADDR ; JRNZ ADDR JR NZ,ADDR-$ JRNZ ADDR ; DJNZ ADDR DJNZ ADDR-$ DJNZ ADDR ; PCIX JMP (IX) PCIX ; PCIY JMP (IY) PCIY ; RETI RETI RETI ; RETN RETN RETN ; INP R IN R,(C) INP R ; OUTP R OUTH,73H DW ?NNNN ENDM SIXD MACRO ?NNNN DB 0DDH,22H DW ?NNNN ENDM SIYD MACRO ?NNNN DB 0FDH,22H DW ?NNNN ENDM SPIX MACRO DB 0DDH,0F9H ENDM SPIY MACRO DB 0FDH,0F9H ENDM PUSHIX MACRO DB 0DDH,0E5H ENDM PUSHIY MACRO DB 0FDH,0E5H ENDM POPIX MACRO DB 0DDH,0E1H ENDM POPIY MACRO DB 0FDH,0E1H ENDM EXAF MACRO DB 08H ENDM EXX MACRO DB 0D9H ENDM XTIX MACRO DB 0DDH,0E3H ENDM XTIY MACRO DB 0FDH,0E3H ENDM LDI MACRO DB 0EDH,0A0H ENDM LDIR MACRO DB 0EDH,0B0H ENDM LDD MACRO DB 0EDH,0A8H ENDM LDDR MACRO DB 0EDH,0B8H ENDM CCI MACRO DB 0EDH,0A1H ENDM CCIR MACRO DB 0EDH,0B1H ENDM CCD MACRO DB 0EDH,0A9H ENDM CCDR MACRO DB 0EDH,0B9H ENDM ADDX MACRO ?D @CHK ?D DB 0DDH,86H,?D ENDM ADDY MACRO ?D @CHK ?D DB 0FDH,86H,?D ENDM ADCX MACRO ?D @CHK ?D DB 0DDH,8EH,?D ENDM ADCY MACRO ?D @CHK ?D DB 0FDH,8EH,?D ENDM SUBX MACRO ?D @CHK ?D DB 0DDH,96H,?D ENDM SUBY $CIY MACRO DB 0FDH,0E9H ENDM RETI MACRO DB 0EDH,4DH ENDM RETN MACRO DB 0EDH,45H ENDM INP MACRO ?R DB 0EDH,?R*8+40H ENDM OUTP MACRO ?R DB 0EDH,?R*8+41H ENDM INI MACRO DB 0EDH,0A2H ENDM INIR MACRO DB 0EDH,0B2H ENDM IND MACRO DB 0EDH,0AAH ENDM INDR MACRO DB 0EDH,0BAH ENDM OUTI MACRO DB 0EDH,0A3H ENDM OUTIR MACRO DB 0EDH,0B3H ENDM OUTD MACRO DB 0EDH,0ABH ENDM OUTDR MACRO DB 0EDH,0BBH ENDM RLCR MACRO ?R DB 0CBH, 00H + ?R ENDM RLCX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 06H ENDM RLCY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 06H ENDM RALR MACRO ?R DB 0CBH, 10H+?R ENDM RALX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 16H ENDM RALY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 16H ENDM RRCR MACRO ?R DB 0CBH, 08H + ?R ENDM RRCX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 0EH ENDM RRCY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 0EH ENDM RARR MACRO ?R DB 0CBH, 18H + ?R ENDM RARX MACRO ?D @CHK ; ; DISK COMMAND PACKET OFFSETS ; PDRDP EQU 0 ;PD REQUEST DESCRIPTOR PACKET PDRFCN EQU 0 ;PD REQUEST FUNCTION NUMBER PDRDRV EQU 1 ;PD REQUEST DRIVE NUMBER PDRTRK EQU 2 ;PD REQUEST TRACK NUMBER PDRSEC EQU 4 ;PD REQUEST SECTOR NUMBER PDRSC EQU 6 ;PD REQUEST SECTOR COUNT PDRTC EQU 8 ;PD REQUEST TRANSFER COUNT PDRDMA EQU 10 ;PD REQUEST DMA ADDRESS PDRDST EQU 12 ;PD REQUEST DRIVE SPEC TABLE ADDR PDRLEN EQU 14 ;PD REQUEST DESCRIPTOR PACKET LENGTH ; DSKNFO EQU 14 ;DISK TYPE INFORMATION BLKSIZ EQU 14 ;BLOCK SIZE NMBLKS EQU 15 ;NUMBER OF BLOCKS NMBDIR EQU 17 ;NUMBER OF DIRECTORY BLOCKS SECSIZ EQU 18 ;PHYSICAL SECTOR SIZE (2^N*128) SECTRK EQU 19 ;PHYSICAL SECTORS PER TRACK TRKDSK EQU 21 ;PHYSICAL TRACKS PER DISK RESTRK EQU 23 ;NUMBER OF RESERVED TRACKS DNFOL EQU 11 ;DISK INFO LENGTH ; ; .CREF .LIST ZUB#UBTTL*UI$ITLECHGR@ORRA*RITHL680807Z80%COMMENT&CREF'DEPHASE(LALL;LFCOND)LIST*PASS2+PHASE,PRINTX-RADIX5REQUEST.SALL(('()-((5*5,,))))))))h6f6(5C,~&+*A4**i7+9M+ +[9;7+U+\+!++))*+++,))d+h+m+'-@  F"  (85vCd} *F=~#"F= oA 0 : 7}ɷ[ a { } 6 *F=+"F=*F=#"F= aS 6 != q#a !=6#ͱ  2<a w# yʟ ͱ x җ x Gy2=xͱ җ × $.@?_// // &:? ͱ & 6 ͱ 7 G!r?:=' " 2=~!?  "p?^#V!g? w#: !=~K 6!=N zʾ ^#V#^#V#~=y =G‹ #n #~=¸ #"?=#~+?j?!g?w#Ÿ w#s#rP P +>Ð <*A=~*@####~7#_"@:=$.?_ ;O$ ?D DB 0DDH, 0CBH, ?D, 1EH ENDM RARY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 1EH ENDM SLAR MACRO ?R DB 0CBH, 20H + ?R ENDM SLAX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 26H ENDM SLAY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 26H ENDM SRAR MACRO ?R DB 0CBH, 28H+?R ENDM SRAX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 2EH ENDM SRAY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 2EH ENDM SRLR MACRO ?R DB 0CBH, 38H + ?R ENDM SRLX MACRO ?D @CHK ?D DB 0DDH, 0CBH, ?D, 3EH ENDM SRLY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 3EH ENDM RLD MACRO DB 0EDH, 6FH ENDM RRD MACRO DB 0EDH, 67H ENDM !  GMAC"'@!+@=~vO#~ Q w#6 #wD̈́K>2<2@2>2-=2<2<2=2<2?2=!= w#—<2(=2.=2/=2=> 2<:@2<:@2*=>;23=<22=!"4=+"@+"6=*'@!!62[?21=2+=29=2?<2)=?!H="F= ~# R*4=#"4=!"6=:2==23=!9=>2@2@͖ CCl CC0Cw#C!H= ʎ ~w# Žw:9==28=͖q:,=ʨNЯ2,=4OMگ!F> 2H=J> J7ò- !"C=20==2?*="=:H=*>$2H=$2E=U :ʋ:E=$:==$U !=~4#>$Nwy#*F=+~# ʿ+U ~#~"RR *F=+"F=:(=k+s -"x-ʯ7D-"F=+ÿ:(=ʹ1 -"C=j # :µ@ U 6 :(= ʒ8 :(=l`k#~! _^#V#N1! ; !H="F=*C=|U :(=lÍ'!==Nwy#3!>">!> q#K6 U l;l:<—:>VʋMʋDʋX2[?~+ACDEMNOPQRUVX!>~ p:>2>"?=͓ *n?z :m?O s#rw# & =7 >wG#w"?=#w#w#w###w#I "A=####p*@͍ ;*?=|>!x F?Symbol table full |}:<:@:-=*?=~@ڹ >>vL!=F#~vL *p?  G~8#~ +~w#~w#s#r#*=s#r~@w:<# ~a~a#^#V#͍ R*=xD{a#za:> *?=# :0=a*?=~*?=#~wxGõ>LyL@ Z6LZ@LZRLZRLyZOLyym-LZRO*ZRv̝LZR*ZOLyZ@*m-L6 ,ɷÝKN͝Ým-zf<ĝ{Y! ^#N! ^#VZԝBxL{?LZ8ĝBLNܝc:<Ü̓ :>H:<0:<Ü>L:< L>2<:<<=<2<ů2< 6 (-2LKҫ:<ԝ Om-ͷyHLyL:>G¯BxGj*=*=͍ j##T9zC<xx .XLIST .XCREF ; ; ASCII EQUIVALENCES ; ANUL EQU 00H ;NULL ASOH EQU 01H ;SOH ASTX EQU 02H ;STX AETX EQU 03H ;ETX AEOT EQU 04H ;EOT AENQ EQU 05H ;ENQ AACK EQU 06H ;ACK ABEL EQU 07H ;BELL ABS EQU 08H ;BS AHT EQU 09H ;HT ALF EQU 0AH ;LF AVT EQU 0BH ;VT AFF EQU 0CH ;FF ACR EQU 0DH ;CR ASO EQU 0EH ;SO ASI EQU 0FH ;SI ADLE EQU 10H ;DLE ADC1 EQU 11H ;DC1 ADC2 EQU 12H ;DC2 ADC3 EQU 13H ;DC3 ADC4 EQU 14H ;DC4 ANAK EQU 15H ;NAK ASYN EQU 16H ;SYN AETB EQU 17H ;ETB ACAN EQU 18H ;CAN AEM EQU 19H ;EM ASUB EQU 1AH ;SUB AESC EQU 1BH ;ESC AFS EQU 1CH ;FS AGS EQU 1DH ;GS ARS EQU 1EH ;RS AUS EQU 1FH ;US ASP EQU 20H ;SPACE ARUB EQU 7FH ;RUBOUT (DEL) ; WBOOT EQU 0000H ;WARM START ENTRYPOINT IOBYTE EQU 0003H ;I/O CONFIGURATION BYTE CURDRV EQU 0004H ;CURRENT DEFAULT DRIVE OPSYS EQU 0005H ;OPERATING SYSTEM ENTRYPOINT TFCB EQU 005CH ;DEFAULT FILE CONTROL BLOCK TBUF EQU 0080H ;DEFAULT DISK BUFFER ADDRESS TPA EQU 0100H ;TRANSIENT PROGRAM AREA BASE %No END statement:=.ʊ$ʒ[YTE3ALLSALL1Cj?CF1M/MA?MCMP2NC2NZOMMONOND1PQ PrPDsPDR2PE*PIrPIsPIRj/PL2POSEG1Z'AAj'AA ADBC"CR CXR ECEFB"EFLEFMEFSEFWIiISJNZSSEGWIiILSE ND NDC NDIF NDM NTRY QUQXjXXXITMXTXTERNALXTRN LOBALkvALTvLTF2FB9FDIFFEFF:FIDN3FNBFTaM)NQNRNC8NCLUDErNDsNDRrNIsNIR"NRNXF1F2FDEFFNDEFRPRPC1C1M2MP2NC2NZ1PQP2PE2POQR1ZQD2:DA DAXrDDsDDRrDIsDIR3*HLDOCALJXI8ACLIBACRO:@OVBVIAMErDEGOPjOPQRRARG*RIsTDRsTIR*UTR UTsUTDsUTIAGECHLOPR"OP UBLICUSHS$USHALARC!EPTZ&ESETR(ETsMETIsEETN IMY*LjLALCZ,LCkLCAroLDMNCNZPPEPOY.RjRARCZ0RCkRCArgRD"STR2STZBB*BIR4BCj7CFZ6ET"ET3"HLD0IMZ8LAPHLZ:RA%m-ë*ů2< 6 (2L{Nԝ:<ĝc:<=ĝNԝc>LcnAÜNԝcn [:<ĝ>Lĝ;{:<=ĝ>L@ÜNܝ*e R:<fĝ[NܝcH:<(:<ĝ>LcNܝe ĝ>LcNܝ:< ĝ:<ĝ>LZԝO*k7:<(>Lں{:<̝ :<Lcĝ>L[/k:<̝"(:< :<*cy  :<Ü:<Ü>%{ :L/:<L>FL;{N*c:<ʴ ĝ:<ĝ>LyBONĝe ̝c:<ĝ5N*c:<ʴ(:<ĝ â:<Nܝe ̝c:<̝Gxĝ> Ü:<ĝ :<[4:<:<ʙԝ c:<ĝÜ([:>:> c:<̝ ڱ:LyC͜(2>2>:<(>"LÒ:<ĝ>2LÒ:< :< ĝ:< `ƝL͜ĝc:<=x*F=+H 2=*F=++"F=H "F=GHg:<o|DHB} |BwDʕHʝOdQ•ͼOqQ þ!H Bq0Ի)z#zͥDnHn!H 0)T]))_è!H 0Ի)))_ÿ!H G0 ))))_Hû:<4!H 00 ܻO:<=ܻ<_Pc$ =ͥ=ͼ6 q6 :=2=ҿ=$ ʿ!  ʿo#g=b#t!S ~Œ2< ;ʹ ʹ° & × °6 þ*F= # #7 -#~G ĵxw+!"F=$ t:<ʮ:<7͓ $ !*@w!7 Gx22>">ĩ:<>C~@x##^#VOQb#^#V"=y y¾þ7͓ "?=~Bڨ~8:<2<##~2  þ:=X # '¿ 'n$¿j OþXOR AND NOT MOD SHL SHR OR EQ NE LT LE GT GE LOW HIGHNUL TYPE :< :<:2>2=2<2>2>2>2<2<9">*)@͍ 4\!]!~!! f!O2>̓!=y "" "?"y2W?͎!W!<7~?)<\)w!<4:(=2(=!b*T],l*zr* Y*#*F=z̝}O|G:> U Oĝ7 -#~@w ~ĵwy,ʉ*1>O*>; *F=+~# ****#"F= () 'O*6 ) )ĝ@ >2/=Y+2/=Y+2-=Y+U G+ G+ $ :+~@w,U ,+>2-=>2.=Y+2.=@ >2.=Y+}+>}+:@/o:22<(2 {=ʝҝ<2 +{22=+?pU :=+>!=w#"?=:<ĩ,+:,= *F=+qN1,4O=2,=*F=~#"F=!5, () 'U ') )@ :<:=x,>=!]?G~µw#„,p, /U ,/@ #~µ~$w2'+"=>2=!"=ñ&>2=:=U - -~w#~d -~wĝ>L2*L>LyK͜c:<} :<^:<;͜{:<  s:<񇇇@OÜ :<ĝ>LGÜ:<( c`ƝLp:<͜(@{ĝ>:L[ĝ:< Ü;c>6LKB(@{(YPy:<O:<ĝ>LyWÜ!>?AFwx# 3:<G:<7b*=#"='h'*>'>͍ +*>:@`))0) ‘0Ž:>:>6!6"6'6*#">ßG:>@2>:2>!>~ͯ~@ô~ʹ#~?Gxʚ#~72>>A;hS#^#V"=G̓2>#^#V">>C1#^#V+~z><2>= G>>B#~Š:>@>§>2>>A;''2>{2>!>"?=ͩ:<*=##"=:>G:>@x̓:>G̓*>#">C'B'x&x746!96**>##~#fo6"6'##">̓xP:>@xʈ:C+B+x*=++*>#:=G~w#s#r#*=s#rC'B'b:>2>:>x̓³z ĩ2>*>#~2>*>#>͍ +*>:@)0) 0 6 ,8!:>8!2>> ß!:W?O:>O!f! "x̓!G:W?O`!"f!ó _y{y!*=YGó !"_~xž!ůG|2>?"y2W?͎!!F%:W?Of!è!@ 2W?:W?G2>O! x怱!>w*F=+N{*>2>z |= yWx=z6"z6"ʳ 6"6"6" >G̓!Gó "Y?zR" ͪ""=">y2W?͎!"ʡ"2X?ʋ"ʋ"ʋ"ʋ"ʋ"ͪ":X?*Y?!#o>g~#fo:W?O*Y?ʶ"y}!"=y%"*="""*>"{%z%   P#Z#d#n###N$$%##Q%\%h%u%{%%%%#%&&&-&C&c&̈́$zW{_̈́$zW{_̈́$zW{_*>|/W}/_:W?O>%%*>|/W}/_:W?O>%%̈́$zʬ#)â#̈́$#+}zW{_ò#*>:W?y#:W?O2>:W? #*="=*>͔$>%%*>G$:W?%$%$y%$$$:W?%$ ?$=:W?9$y9$2>:W?O>%%{_zW*>i$:W?O> %%i$ DM!>=ʂ$))p$p$:W? *>:W?y*>ͳ$:W?O> %%zzB%|G|$|%$%|/G}/O!>$ $7>{_zW}o|,,͝-w͵,~Bدw#w#w#wU ~#~>-,"C=m-:>21=Ux¯x 20=*C="?= x4̓ :>"C=~w|21=m-x¯*C=-#~µ~@ w#s#r#*=s#r4͸K:?w/:<Ĩ/!<4~=Z.!]?~-!1>~-!@#]?~# . .. . -!V?p#"?=ͩ2'!5O"@ A."?=~w#~@k/~.#^#Vͩ.*= ͩ *={ĩn*F=ԃ +!"4="6=}2/=p!/!3=44!r?>͗;Z:3=8p!3=44!/!?>͗;Zʹ/*<|.:@<2[?2[?.!L//!O//*<|/>,vL:@<>,J:@<2[?2[?!_//ʹ//̓ͩ*>|,/F/ͩ+:@C/>vLKLNo Fatal error(s) Warning(s):=Gͩ./!//)ô/REPT/IRP/IRPC/MACROUnterminated /!//)> Z> Z:@<> J> J!/:@0"?%O;.0~<=r0:@<2@:@:@=2@<#~^0:@^0:@^07"?:?=2? &0*F=~ 0 0U 0"F=0>&2?>1&0:?0>&;:2?*@~ 1=1O+1 0x">DExx0:(:*=G:)=G:(=N:/=S:> ~:> o:@+2+>ÿ>+2+>:> ¿:.=:> :1=:,=>C2*>:[?:/=:> !3=4:2=p:[?:@>vL!> ~#d:+=Z:?=##:?#!9=~#06d(>C:8=H> d!H=~# Z dK> d> dO:[?yvLJ>23=:/=ʍ> vL!1>!*4=#|+:/=ʤ*6=#"6=:/=|ʾ>-vLZ!>ZZ>SvLä~#vLPX |>:d MACRO-80 3.44 09-Dec-81 PAGE :> Q)*<#"<*<#" !>">O!f ~*>w!>"> '"!*=:=*=:=:=x¦*=*=͍ "?="=ĩ:A> y> C+B+y*?=+~xGW> #######FyxG+#W>_xGxGFɯFxGF .7FxFx!>~w#4ZL>2>U C \ \'"(ʬ)ʯ+ʲ-ʵ*ʸ/ʻ;ʨ,ʨ >>>> > > >!G) # ) o2=) # x) eo) n=g=$|g}oɯO_yW*>z5%|5%|ͳ$%:W?O> %%>O!G͙%͍ o%͙%͍ ?o%͙%͍ W_ ͙%È%͙%͍ o%͙%{_zo%7o%?o%:W?L&*>*>\W:W?O>%*>]W:W?O>:>@2>!>4~?%o%$w5y%:>2>̈́$}R_̈́$}R_̈́$}@_̈́$}6_̈́$}Ro{R_̈́$}?_*=*=͍ :W?_ :> Ox&> 2>,̓ x 2=xGʱ&:=±&*=*=͍ :=G*="=:<ă"= :=&:<ĩ:\?2':\?ȯ2\?U 2'1>G2=<2\?2=*=õ&2'1>2\?G2=*=õ&2'1>2\?G2=*=õ&:\?,:==`'o& ^#V*=͍ s#r2=*=##K':<ʇ':=ʇ'*= ͩ2=1 6 "ʠ''(G) ) *F=++' ) '³' ʳ'6 ,';'' "F=(y(# G) ) 'L) ȸ'# ( ,ʍ'LÍ'Z:=y,ʍ'̓ x1 "N('ĝO) d( o(GŷLP(xx|(L,A(1(h'y,›(ZCä(:@ʹ(z*=#"=:<'ä(*=:=Gõ&2(:<:>U<2>1h'̓ y,(:<=)G2<:<=)2<&+~10:@*@~<1=11O+11 #1x+~111<*F=U 0w1G~# \1 d10P1x0G0&06 "F= ʐ1 ʐ16 Ö10}1ͱ k1å1ͱ k10ß1 ;1ù1:0 ʞ: ù1:: 1 1:"%@ʞ: ʞ:> ;:Þ::@1*@4I2* @~82G+#2~/_2~F2=G+~F23*2+<=C2+;2~>.33?*@O DEU Ă2=ʦ3%2,ʰ3 ʰ3 ʰ3;ʰ3!) 3w+ Ô2"{3q3(:> 63:<.33PX 2|2>:f3)0R3>)30R3=363D>3E>3 >0f3xG3x0:R3 f30O:f3>0f3y*{3w+"{36 *{32Ow+ ʏ3 3~3w+ ~3Ô2ʢ3w+22322{=*F=+~ 6 6 ʵ3õ3!=͍ 3#6 +>1&3:>1!  4>1!4r ?Stack overflow, try more P switches (:> O4"?/c4> \^4U :U H0ʄ4H=;: y4ɯ;:͞:!*#@*?!!44͍ 4:@¾4x4*?͔9͊02@*?r:5H=͈:3 4*@*@*?"?"QAQBQCQDQEQHQLQMbSPcPSWQIQR bBCbDEbHLbAFjIXDjIYdrNZqZrNCqPrPOrPEA@2,A*Jx I -AoIJIT?IJT7JY7ILYIJS7JT7>IR7JD7R7>I> ڀI6 #=xIy.2@*J5AxژIʥIJÙIy/yJL¾I2@JOæINI2@÷IOI2@÷IRI2@÷ICI2@2@÷IMI2@÷IIJ2@÷IXJ>2@÷IZJ2@÷IP7:@<2@÷IJ[HJ0HJADJ:HJ-JO!~6GzJ#~ cJUJHFx+#tJ~iJ2@ÚJ2@:@JK>*J GF> J:HF!IF"Fo>g6 #> w:@J!IF~ JaJJAw#þJ~# J J K#"F_*F+~ #KJ#"F+~7ȷ> J> JEB!"CB!@:@NKCA!"AA!@:@K~K͡K vL> vL>vL*CBEB@NLEB@K:@ʰH:@K>L*AACA@NLCA@K|}YLƀ)`iíL> vL> vL> vL:@ʰH:@¡M =­L!CA>!@íL:@ʰH:@J*AA|=L#"AABA@"@ bkë4:?2@+5ů2@@ :@ʊ5U :U O^5yf5y n5y@{5:@=2@:@<2@:@:<(:@#~>P)!ɷ/"@i2O:> ʰ5*@͊0y6+,ĝ5) <ĝw+:> G6G5͌2 D6>G65# <2@ 5 =6:@6G6 ;,76<36>76G67676 w+5:@G66+.0xĝ" @&i"?m6\4>Ô5^4*%@>2@3H0ʱ6 ʶ1;ʫ1'ʡ6"ʡ6>1Ç6G͕0 ʶ1ʛ6â6"%@;:͞:!*#@* @*?!!64>2@" @͍ 7:@6x 7* @##~#7+4r:47H=r:1:3 7* @4 bk6 ʝOJ) V7JG7> J> J:> @ ʝ2 @O ʄ7@ u77\4^4!H=: @O~ʥ7 #Ù7!ɷ #"?~(w/"@i2 ,7w+2@2@@=NM!=*M!>JM_!@ sM qM vL~zMËM7ȷ!MF@@²M> J!MFKDISK FULL!M:>ŒN@Nw#2@.ʷN!ڷNw#N2@.ʾN!ҥNþN6 #·N:@.Nw#NpMMN2M2M:M=OMM0O!M"M>2M*M~+O70O#"M0@* @!94" @"@2@r:I9H=r:1:3 +9*@* @4* @#2@4}_|W:=̓ :> 2=xx2=*=T9"=:=2=@ !!@Ns#Frͦ9ͯ9q#p*@^#V+*@##^#V+*!@}9ͯ9"!@9*@ "@*)@͍ I;*?%:?͍ I;*@T9ͦ9*%@{_{:s#r#>w#wͯ9%:s#r*:"#@*#@ͦ9s#r{_*%@{̺9*@w{W:a:"%@{_ͯ9zʺ9*@}‚:}o~r:{ʗ:a:{_ͯ9{ȯw#w*@s#r͔9*#@ͦ9q#p*%@{:*@"%@~{_ͦ9{_{:a:*@*?:?;*)@%T9o zo W{_*@*@T9BK*@"@xE;+w 8;"@O;9*A=*@T9o zo W{_*@T9BK*@*A="@ "@xʕ; w#È;2>2>O!^#V#ͷ; ;:>Zz^#V{;};++V+^{;w#w+++; F#"?=~@#~<~#^#VG5<<_<{…<{@Đ<{ʈ<{_!f~vLz<###~#vL;<>L<5m<:>wZ!3=4:2=p*?=~@w> |<> vL>*>M>C>UvL2<*?=#{G#^#V#^#V"=̓"?=#~ ĩ>IvL!>">*>6!>~G#^#VͩP?Command error?File not found?Can't enter file~J#F!FF!FF!FFXGCOMSCNF",AF2@!@͸H> 2-A25A2,Ay,2@G:@2@H>A:@G;AH-A:,A2@ 2@G:@@2@!@͸Hy=7H 7H,A#H 7!@͸H:@!@ܘH!@:@SH@;A> =IHܘH:@hH:@hH:@2@ _2̈́K%K;K*@##:@2@G,A ~²HHw# ¨H #èH w#»H:@!5A~ Hw#H*J:7>IxHJOx=y&I['*+"S" " " " go"Q"`2 2!2!2X2Z2]2^2c2_2\2W!*" " " " "=";!" " " " 2 2 !" ?No Start Address?Loading Error?Nothing Loaded?Out of memory?Illegal Polish Exp:!‡!!!2!!!2*S! ~ 4!>2 2Y:c2c ,/MEG@RSUXYE{ O :Ù&O†2WHO2WG:c2c:'>`͇Ax¹'"U _2:f Ğ2U!c~w:f ~w:f 2Yæ2Y*`|##yȷ#jC~@#I" #ͬ*`|#*U~ !:Y:c~ G@x k o Link-80 3.44 09-Dec-81 Copyright (c) 1981 Microsoft ?Command Error~P#~#  `{ +!~G #~ ex+#<~: /͔>*P d> P:e!fo>g6 7ʌʌ  y:+y#P2\2f g !  :\GO: " " " " * * " ";* * BK* * "=2 G<2 k [ M  ~++GOŸ& H+D ; & yE >  * [ S } 7~k ~~r <</_* Å |}! 6S#6Y#6M<$>* * ͅ ~O~@ +^+V > h%+~h% > h%= >~ <</O ß ͑&%|}G[h%> h%> h%:WG)0P) 60P3|L}U[P0:͔! ~#foN"N"N>>PÔRQUESTͬæ* : * ͅ ~_~@+++~#* BK" ö+++ö2!2 2 2 : go" " " 2X" <2 : * * * * *=͝QiEZͿE! ~#foBK#: =ʝ: ”* |ʊҔ}Ҕ͝p#: ”* |ʲҔ·}ҔÔ: =: Uw+p+q+p+q#Bi++s" ͇:7>[?@2g ԇx " h 5)> F6 #=>x2f y.̇p xanbʃ!p ~ ƒ6R#6E#6Ly[ҥ0ڥAҡ:ҥÊ[ʡ]ʡ@ʡ\ʡ^ʡ_ʡOb: : 2 BK|A~_q#Vp\AU: =" 7ɩ))'):B($: ̈́: r2 * * DM* " *= "=* BK" " " " * " Ͷ'* |‡}ʠ~_|!^#V* " (M\~#+>>><2Z=O! $! ^#V0y=Uy?\ͅ ?\|y! i! us#rx^#V͞! p#”* ! N#F#~#fo! ^#V  ! ~#foͅ H! {_{_~H! ^q#Vp! ~s#_~rW}&: $#qͅ {_! 6)`i{ڠ! #Yš* * 6* " * * " ͞* ͅ ҙ" ! yڬ! ^#V ڻ F#fh! ^#V ^#Vy! ^z6#z: O4ͅ {Ҏ!y yBKO!; s#r! s#r! s#rͅ ڬ! s#r!; s#ry ! ~#fo! ѵ! }_|W>2 * * <* * : <ͅ P* * W{_* #" " "=:WGO0ڗ xڗ)))ҖʌҖ)o>gdy +%Overlaying areaDataProgramÔ!! ~#fo!ͅ ͅ ͅ &}< = yy7yM7>,>#ͅ !M> _!h >?P~#P!yk!:!ʆ!; Not Found> P> P>2 g 28: _<2 !~g ! w#! wO |!y:!(͔*QDMÙ&[Begin execution]:Z:X* * ͅ ~`~¨@w+++o>GO ~+t>ʊ6 #=ƒ* ! ͮ 2X * ~O_+++y++:XK͔:c2c *Q>[P"N!C \* s#r!I >@w+r+s+@1: 2 r+sA: =* >jV/o/g ڮA~@w:]2^s+++~ s2^q+p:^O!;>2 }|!; s#rͅ y A!>/P͔A~W+++~P+%2nd COMMON Larger /*;" |2 * ͅ A> j~@wA7U: >8: =->G: =7>@w@w+w++1: 2 : : =r+sA!HIF5#wj~+ܾU6+6++r+sA*K:J2 fU: ;: =>@w+6++r+sA:!A>.2!2P* !J͞!g2!+}2_! w#!ڐ ‚! \" " : :Z!ګ!  w#! ¸+w2!͞A!!?/D illegal with common runtime?No code can be loaded before program withcommon runtime not found, please create header file?End of file on common runtime header!aǗzʣ̈́"Qb! ^#V! ͪ!;ͪyک: * * ͅ * " * '* * * BK#V^#V! s#r Gyx! @s#r#1xS|W}_x2 * 2 yoxg* " *="=*?PYͅ ڙ"?: ʹ=¯* !" * * ͅ үï͝*={OzG* * DM7xw#  +x~+ xw+ : 7={O>: 7J?Intersecting wO* ͅ <26: ?Oʣ: Jͅ Jͅ J!M>,P*6&0M^#Vy!HF#~#P>(P>)P: " Start = External Public = %*   \! ~# != = = \* ͅ = *ͅ = s#r"N2 * * ͅ ʐ ʅ 2 M\: z x/Gy/O~w#~wM M" z _z! ^#V   $ 2 = ] m `i ^+V! 4* M ! 4Ð ! 5 PY\  s #r lg   # |/g}/o   DM!>= ))K K z zi  BK}o|g҄ : ʫ ͅ ҫ | >]P͔: : $>2*Q"!o&'  d   >0G /}o|g x0   > xPH>G~#' j~@+^+V$MEMRY$$PROG$COMNM*QA!Hw#] j{ ~@{ +^+V"Q! 2A! ?Start symbol - - undefinedg  ~#³ ͞ REL7*`}2X:c` j: j͔ p @p ͔`p p p * } , >wk  :`? !K * !b  Undefined Global(s) Bytes Free 2bP  ~O~>-ʑ > >/P+^+V+~P ™ /PN~ ʼ !ÿ "~ N+^+V>>PN:b?2b̔>wt :bȯ2b* " ͅ " " ";" " ͅ 7* * * ͅ ]!* * * BK* * * * * " * * BK* * " " " "; ~w#~wPYb>̈́BKj~@: ~@w+~_q+U: =>Cw+p+q+r+sA! ͔A%Mult. Def. Global ~@*`+"`PYb>̈́BKůj~+nN+F@‡: ›:B(b: =›zAA;|A: ›r#sA: ›|A\zA#U: =ʯ>Bw+r+s+r+sA*`#"`!7~#46+wxG ɯ2 7Y!HYH!Hw74#6 _Gw#;!T"7O<2 XP̊wwO!9 N#F 2[: ʚ2[AC( r>-: " *=>2 * ͅ A*=>j+^+V\"?Ab: =#<2 =A: A*= APY7* K" !*="=* !" }2 <2 A:[* * |G}ʼ~O©H©A+++¨+—~ y/O oHOx_Ow#2 +w+w+w+ w+w+("!2Z!:Z?!͙!͙! y-!* * ͅ #* " ͅ |!*Sͅ "yb!*Sͅ "ͅ ڵ!*Sͅ ڮ!!!ù!!!!!!!2 YxbelowaboveOrigin loader memory, move anyway(Y or N)?ͅ 0"ͅ D" "!ͅ D"yS": W"*Sʀ"a"Oͅ €"y*S€"! ͅ ҇"!9;;;;;;ͅ "ͅ ڣ"z"&'7"ڿ"""ͅ #ͅ #"z"7* ";* "=* *;)##+#KP*;";!* BK*;* *=l#ʮ#l#O* * " * *=BK* *="=#PY* " * " Ø#* *=#BK* * " * * " " *=" *;" ! 8$~R#~E#~L4$:c)$7$w+)$COMHEX`$  <%2 : $}$* * ͅ $!c~ʌ$ ~$:\ʲ$: µ$*Q\" " &yO: &w&%*Q|$ͅ $%ͅ $ͅ $.%>%7Ԓ%R%:same interface type hd2 equ false ; i.e. all SA1000 type or all ST506 type hd3 equ false SUBTTL SYMBOLIC EQUATES ;page if intrin or introut ints equ true else ints equ false endif ; board hardware equates cmd equ 0ch ;fdc command register trk equ cmd+1 ;track register sec equ cmd+2 ;sector register data equ cmd+3 ;data register wait equ 14h ;INTRQ and DRQ synch port (see manual) pioad equ 4 ;PIO channel A data pioac equ 6 ; " " " control piobd equ 5 ; " " B data piobc equ 7 ; " " " control memry equ 16h ;memory control port ; ; sector deblocking equates ; hstcnt equ 8 ;number of sectors in buffer hstshft equ 3 ;shift factor for # of sectors in buffer if mini ddpspt equ 4 ;double density physical sectors per track if m48tpi tracks equ 39 ;minifloppies else tracks equ 76 ;96tpi drives endif else ddpspt equ 8 ;eight inch tracks equ 76 endif dpblen equ 15 ;length of a DPB ; ; floppy disk %yO%>%R%: Ă% <%>h%*Q}h%|h%سȯh%zG%%z~#h%\%!: _w{<%2  %%"%yO#"%!%\%.%fh%¹%! ~+ x :_*Q:_*Q\!%?Can't save object file{{ _zW;&> A&{ H&O>:h%y Y~# c&+&>:h%G*Q >>h%!*'͞'!0'͞'!3'͞'!9'͞'##²&##͞'##¿&#͞'!z'͞'!'͞'* "'* "'* "'* "'* "'* "'&'m&'͓','V'G'V'l'|'V'l'|'V'l'|'!' N#F#^#V#~#fo|} +x~+ q'xw# |'xw# Ó'~#fo&'q#p:B(* ͅ ~'M(:J2A(*;" 2 U6+:A(wAMz(2A(7(:B((*;" :A(2B(*;r#s+:A(i(*;͢(" 2A(2B(!* p# P(!HN#*~# ^(Ar#s *){ʅ({ƀ_҅(zʞ()Å(ͣ) *)!.*ʹ)!.*V#^(((!((ʹ)(z(!.*ʹ)(ͣ)z{7. TITLE ADVANCED DIGITAL SUPERBIOS FOR SUPER QUAD Dec 18 1982 14:30 ;***************************************************************** ;** ** ;** ADVANCED DIGITAL SUPER QUAD Z80 SBC ** ;** ** ;** SUPER BIOS ** ;** ** ;** This bios contains drivers for: ** ;** ** ;** Floppy disk ** ;** ** NO Hard disk ** ;** Two serial ports ** ;** Parallel port ** ;** ** ;** Console input and output can be polled or ** ;** interrupt driven. Seperatly sellected. ** ;** ** ;** Warm boot can be from disk or from prom. ** ;** ** MOD BY C ERICSSON 9-22-84 ** ** ;** ** ;** Written by: ** ;** ** ;** Scott Carter ** ;** Greg Lindberg ** ;** ** ;***************************************************************** SUBTTL Customization Equates ;page 60 .z80 true equ 0ffffh false equ 0 mini equ false ;true for minifloppy BIOS special equ true  hardware parameter offsets ; ****** these are offsets into table do not change ****** ; density equ 0 ;0=single, 1=single side double D, 2= 2S2D seekrt equ 1 ;THIS IS OFFSET INTO TABLE, VALUE IN TABLE CAN BE ;seek rate 0=3ms, 1=6ms, 2=10ms, 3=15ms ;these times double for minifloppies pspt equ 2 ;physical sectors per track (one side) drvtrk equ 3 ;track a floppy is at parmlen equ 4 ;length of the parameter block ; ; miscellaneous equates ; iobyte equ 3 ;used to select various consoles and printers cdisk equ 4 ;default disk user number bdos equ 5 retries equ 10 ;retry count for disk operations inbfsz equ 32 ;size of input buffer for interrupt input must be power of 2 outbfsz equ 64 ;size of output buffer for interrupt output must be power of 2 public savnum,biosiz,mxld64k,kld64k,syssiz,ldofst,allfpy,lastadd SUBTTL Hard disk equates ;page hddsks defl 0 ;number of physical hard disk drives hdldrvs defl 0 ;number of l*z w#)0:ww:*!;) )+ )!1)?Segment , file not foundcan't create fileread errorDisk is full)!@))!O))ͣ)!a))ͣ)!l).***‹)*—).** rept 16-nmbfpy-hdldrvs dw 0 endm ;rept endm ;dsktbl SUBTTL BIOS ENTRY AND PUBLIC TABLES page ; ; BIOS jump table start:: jp coldboot wboota:: jp wboot jp const jp conin jp conout jp list jp punch jp reader jp home jp seldsk jp settrk jp setsec jp setdma jp read jp write jp listst jp sectran ccpstart:: d HL,contbl jmp2: and 00000011b ;get console field jr dskcon reader:: ld d,3 ld hl,rdrtbl ld a,(iobyte) jr gordr punch:: ld d,6 ld hl,puntbl ld a,(iobyte) rra rra gordr:: rra rra jr jmp2 SUBTTL Configuration tables page ;----------------------------------------------------------------------- ; ; Hardware configuration table ; org 100h-2 iodma:: db 80h ;this is the low order byte ;of the 80h default dsktbl ;define disk assignment table contbl equ $+1 dw cpu dw cpu ;default=serial 0 db 1 ;alternate=serial 1 db 0,0,0 ;space for two more console drivers lsttbl equ $+1 dw cpu if parprnt dw cpu+2 ;default=parallel db 1 ;alternate=serial 1 else dw cpu+1 ;default=serial 1 db 2 ;alternate=parallel endif db 0,0,0 rdrtbl equ $+1 dw cpu dw cpu+1 ;default=serial 1 db 0 ;alternate=serial 0 db 0,0,0 ;space for two more readers drivers puntbl equ $+1 dw cpu dw cpu+1 ;default=serial 1 db 0-100H ;BEGINNING OF RELOCATION TABLE ; ; This routine clears the variable area of bdos for warmboot ; from prom ; CLEAR:: LD HL,START-VROFST ;FIND ADDRESS OF BDOS VARIABLES LD (HL),0E5H ;SET FIRST VARIABLE XOR A ;SET UP FOR NEXT VARIABLES ld (start-0af3h),A ;clear listing toggle INC HL ; LD (HL),A ;CLEAR NEXT INC HL ; LD (HL),A ;CLEAR NEXT INC HL ; LD (HL),A ;CLEAR NEXT INC HL ; LD (HL),A ;CLEAR NEXT INC HL ; LD (HL),80H ;INIT NEXT INC HL ; LD (HL),A ;CLEAR NEXT PUSH HL ;SAVE THIS ADDRESS (SOURCE FOR CLEAR) INC HL ; (DESTINATION) EX DE,HL ;PUT DESTINATION ADDRESS IN DE POP HL ;GET SOURCE ADDRESS BACK LD BC,CLRLEN ;SET LENGTH LDIR ;CLEAR REST OF VARIABLES ; LD DE,CCPMOVER ;DESTINATION FOR CCPMOVER LD HL,WRMLDR ;SOURCE FOR CCPMOVER LD BC,LDRLEN ;LENGTH TO MOVE LDIR ;MOVE CCPMOVER TO LOW MEMORY JP CCPMOVER ;GO DO IT ; WRMLDR:: .PHASE 80H ; ; This routine will relocate the ccp from the on board prom ; dw start-1600h ;CP/M boot address bdosjmp:: dw start-0dfah ;BDOS jump ; ; warm boot table ; filled in by CPMLDR ; ; contains entries of form dw track, dw first sector, dw last sector ; it is a map of where the image of the CCP and BDOS reside on disk bootbl:: dw 0,0,0 ;space for four entries dw 0,0,0 dw 0,0,0 dw 0,0,0 dw 0 ;extra to guarantee 0 track to exit properly page if ints ;interrupt driven i/o ds 16-(($-start) mod 16) ; ; serial channel interrupt vector table ; contains one entry for each interrupt that ; can be generated by sio/dart ; serinttbl:: dw intret ; channel B transmitter buffer empty dw intret ; channel B external interrupts dw intret ; channel B receiver ready dw intret ; channel B special receive interrupt if introut dw tran0int ; channel A transmitter buffer empty else dw intret ; channel A transmitter buffer empty endif dw intret ; channel A external interrupts if intrin dw recv0int ; channel A receiver ;alternate=serial 0 db 0,0,0,0 ;space for two more punch drivers SUBTTL Warm boot code page ; ; Wboot reads in the CCP and BDOS from the CPM.SYS file ; CPMLDR initializes the bootbl to be a list of items of ; ; track (dw), first sector(db), last sector(db) ; wboot:: if not prmboot ;use this code if warm boot from disk if ints di ;turn interrupts off endif ld SP,100 ;use default buffer ld C,0 ;drive A:: call seldsk ;select drive A:: ld A,H or L jp z,booterr ;bad select ld E,(HL) inc HL ld D,(HL) ;DE=sector translate from DPH ld (bootxlt),DE ld HL,(ccpstart) ;start of CCP-starting DMA ld IY,bootbl-6 ;point to boot table nxttrk: push HL ;current DMA ;read sectors of next track ld DE,6 ;update track pointer add IY,DE ld C,(IY) ld B,(IY+1) ;BC=track ld A,B or C jr z,bootdone ;last track done call settrk ld C,(IY+2) ;get next sector to read ld B,(IY+3) dec BC ;pre decrement it ld (nextsc),BC ;save *to memory regardless of system size. ; ; ccp should be located in upper 2k of onboard prom with ; relocation table in 256 bytes below it. ; CCPMOVER:: LD DE,(CCPSTART) ;GET ADDRESS TO LOAD CCP TO LD A,4FH ;TURN PROM ON OUT (MEMRY),A ; ; STRTMOV:: LD HL,RELCCP ;GET BEGINNING RELOCATABLE CCP LD B,D ;PUT RELOCATION OFFSET INTO B LD IY,RELTAB ;GET ADDRESS OF RELOCATION TABLE LD IX,CCPLEN ;GET ADDRESS OF CCP LENGTH STRTLOP:: LD C,8 ;SET UP RELOCATION BIT COUNTER LD A,(IY+0) ;GET RELOCATION BYTE MOVLOP:: RLCA ;NEED TO RELOCATE IT PUSH AF ;SAVE AF LD A,(HL) ;GET BYTE TO MOVE JR NC,STOR ;SKIP RELOCATION IF NOT NEEDED FOR THIS BYTE ADD A,B ; OTHERWISE RELOCATE BYTE STOR:: LD (DE),A ;STORE BYTE AT NEW LOCATION POP AF ;GET BACK INC DE ;UPDATE POINTERS INC HL ; DEC (IX+0) ;DONE MOVING YET JR NZ,NOTDNE ;IF LOW BYTE NOT ZERO SKIP REST OF CHECK DEC (IX+1) JR Z,DNEMOV ;IF SO LEAVE NOTDNE:: DEC C ;NEED TO UPDATE RELOCATION BYTE POINTERdress ld a,l ;update pointer inc a and inbfsz-1 ld (outptri),a ei ;ok to turn interrupts on now ld a,(hl) ;get char ret ;all done recv0int:: ld (svstk),SP ;save user stack pointer ld SP,locstk push HL ;save registers push DE push AF ld HL,(outptri) ;check if overflow inc H ld A,L and inbfsz-1 cp H j nz,rcv0 ;ski i roo fo more IN A,(0) ;clear input port xor A ;clear channel no. ld C,07 ;send bell call serout jr rcv02 ;exit rcv01: ld de,(inptri) ;get pointer to store address ld d,0 ld hl,inpbuf ;get address of base of buffer add hl,de ;find next address in buffer in a,(0) ;get input char and 7fh ;mask out parity ld (hl),a ;save char ld a,l ;update pointer inc a and inbfsz-1 ld (inptri),a rcv02: pop AF pop DE pop HL ;restore registers ld SP,(svstk) endif if ints ;enable for bad interrupts intret:: ei ;enable interrupts reti ;return from interrupt endif page serout:: l for printer-check busy line inc A ld C,A ld A,10h ;reset DART latch to get current value of BUSY out (C),A in A,(C) and 0ch cp 0ch ld A,0ffh ret z cpl ret page polplist:: ;parallel printer driver poll ld A,(frstpar) ;first time parallel called? or A jr z,noinit ;no, interface already initialized out (pioac),A ;set channel A to output ld A,0cfh out (piobc),A ;set channel B to bit mode ld A,00011111b ;bit 7-5 output, 4-0 input out (piobc),A xor A out (piobd),A ld (frstpar),A ;reset first noinit:: in A,(piobd) and 1 ;test busy bit ret z ;printer busy ld A,0ffh ret ;printer not busy plist:: ;parallel printer driver call polplist or A jr z,plist ld A,C out (pioad),A ;character on PIO A channel ld A,80h out (piobd),A ;strobe printer xor A out (piobd),A ;reset strobe ret frstpar:: db 0fh ;first initialization code for parallel ;printer-flag that PIO has not been initialized SUBTTL Floppy disk driver module pa JR NZ,MOVLOP ;IF NOT GO DO MORE INC IY ; OTHERWISE BUMP POINTER JR STRTLOP ; AND GO TO REINITIALIZE COUNTER ; DNEMOV:: LD A,6FH ;TURN PROM OFF OUT (MEMRY),A ; endif ;prom boot code ld HL,(ccpstart) ld A,(cdisk) ld C,A if ints ei ;turn interrupts on endif jp (HL) ;go to CP/M if prmboot ; ; CCPLEN:: DW 800H ;COUNTER FOR LENGTH OF CCP TO RELOCATE ; LDRLEN EQU $-CCPMOVER ;LENGTH OF CCPMOVER ; .DEPHASE WRMLDRN EQU $ else nextsc: ds 2 ;temp storage for next sector to read an wboot bootxlt:: dw 0 ;boot disk sector translate table endif booterr:: ld DE,badbootmsg call pmsg halt ;must reset system badbootmsg:: db 'Warm boot error-reset system' crlf:: db 0dh,0ah,'$' SUBTTL Console and List drivers page cpuio equ (($-start-1)/256)+1 ; ; Console/list drivers ; All have entry A=driver number, other parameters per CP/M ; A=0 serial port 0; A=1 serial port 1; A=2 parallel (list only) org cpuio*256 cpu::  ld B,C ;character to output add A,A if introut jr z,bufout ;for first serial port if interrupts endif inc A ld C,A serst:: in A,(C) and 4 jr z,serst dec C out (C),B ret if introut bufout:: di ;kill interrupts for a bit ld hl,(inptro) ;get buffer pointers ld a,l ;anything in buffer sub h jr z,chkout ;if not go check if anything in transmitter ei ;interrupts on again for a bit bfot1: ld hl,(inptro) ;get buffer pointers inc l ;any room in buffer ld a,l and outbfsz-1 sub h jr z,bfot1 ;wait if not di ;turn interrupts off some more dec l ;set up pointer into buffer ld h,0 ld de,outbuf add hl,de ld (hl),c ;put char into buffer ld a,l ;update input pointer inc a and outbfsz-1 ld (inptro),a ei ;interrupts on ret ;and return chkout:: in a,(1) ;get transmitter status and 4 ;is transmitter empty jr z,bfot1 ;if not go put char into buffer ld a,c ;otherwise send char out (0),a ei ;and nowge fpyio equ (($-start-1)/256)+1 ;make line up on page boundary ; ; Floppy disk drive driver module ; org fpyio*256 fpy:: ; floppy driver jump table jp fhome jp fseldsk jp fsettrk jp fsetsec jp fread jp fwrite jp fflush db 'FLOPPY ' ;module name for display purposes dskparm:: ;disk hardware parameter block ;one block for each drive rept nmbfpy if (mini and not special) db 1 ;single sided double density else db 0 ;density - 0=single D; 1=1 side, Double D; 2= 2S 2D endif db seekrate ;seek rate - 0=3ms, 1=6ms, 2=10ms, 3=15ms if (mini and not special) db ddpspt else db 26 ;physical sectors per track - 26 in SD, ddpspt in DD endif db 0 ;track drive currently set at endm page ; ; CP/M disk tables fDPHbase:: fdisks ; defind disk parameter headers for floppys page ; ; DPB's for the three formats of disk:: ; ; 8" Single sided, single density ; 5" Single sided, double density ; 5" Double sided, double density ; fdpbase:: sssddpb:: ;single  ;standard console/list routines for CPU serial ports jp pserin ; jp serin ;these three go direct to serial jp serout ; jp lstout jp pollst db 'SBCIO ' ;module name for display pserin:: ;poll serial in-return A=0ff if char ready, else 0 add A,A if intrin jr z,polbuf ;for first serial port endif inc A ;A=command port ld C,A in A,(C) and 1 ret z ;no character waiting ld A,0ffh ret if intrin polbuf:: ld hl,(outptri) ;get pointers input and output locs in buffer ld a,h sub l ;any thing in buffer ret z ;nothing there ld a,0ffh ;there is something ret endif serin:: ld B,A call pserin ld A,B jr z,serin ;loop until character received add A,A if intrin jr z,bufin ;for first serial port endif ld C,A in A,(C) and 7fh ;mask high order bit ret if intrin bufin:: di ;disable interrupts for saftey ld h,0 ;make into offset to retrieve from ld de,inpbuf ;get address of buffer add hl,de ;get ad return with interrupts on ret tran0int:: ld (svstk),SP ;save user stack pointer ld SP,locstk push HL ;save registers push DE push AF ld hl,(inptro) ;anything more to send ld a,l sub h jr z,trret ;if not leave ld l,h ;get address of next char to send ld h,0 ld de,outbuf add hl,de ld a,(hl) ;get char to send out (0),a ;send it inc l ;update pointer ld a,l and outbfsz-1 ld (outptro),a jr trint1 trret: ld a,28h ;reset tx interrupt out (1),a trint1: if intrin jp rcv02 ;if interrupt input use that return else pop AF ;restore registors pop DE pop HL ld SP,(svstk) ei ;interrupts back on reti ;and return endif ;intrin endif ;introut page ; these are the drivers modified for use with the printer lstout:: cp 2 ;parallel? jr z,plist ld B,A ;must be serial ld E,C lstot1:: call plserout or A ld A,B jr z,lstot1 dec C out (C),E ret pollst:: cp 2 jr z,polplist plserout:: add A,A ;serial out pol+ a bit ex (SP),HL ex (SP),HL ex (SP),HL in A,(cmd) ;drive ready? and 10000000b ret z ;yes ld HL,rdytry ;should we try once again dec (HL) jr nz,tstrdy ;yes ld DE,wpterr call pmsg call pdrv ld DE,ntrdyerr call pmsg ld DE,abortmsg call pmsg call conin cp 3 jr nz,tstrdy pop HL ;abort operation ld A,1 ret page ; ; Seek attempts to step the R/W head to the track in (iotrk) ; seek:: ld A,retries ld (retryc),A seek2:: ld A,(iotrk) ld C,A ;track stays in C in A,(trk) sub C jr nz,diftrk ;different track ld A,(curfpy) ld B,A ld A,(lstskdrv) ;last drive on which a seek took place sub B ret z ;already there ld D,14h ;seek and verify but unload head at beginning jr samtrk diftrk:: ld D,1ch ;seek with verify, load head at beginning samtrk:: ld A,C out (data),A ld A,(IX+seekrt) ;seek rate mask or D di out (cmd),A ld A,(curfpy) ;make current drive last drive ld (lstskdrv),A in A,(wait) ei rla jr c,seekerrld (psec),A ld A,0A3h ;second byte of OUTI instruction ld (iotran+1),A ld A,0ACh ;sector write ld (oper),A jp strtsel ;and do i/o wrtdbl:: call fflush ;flush buffer or A ret nz ;return bad sector if hard flush error cpl ld (blk2sec),A ;clear unalocated sector indicator call sidesec ;set up for new i/o call readprep ;do read to buffer or A ret nz ;physical error jr movwrt ;and move new sector from DMA page fflush:: ;flush deblocking buffer to disk ld A,(wrtpend) ;do we have a write pending? or A ld A,0ffh ld (bufvalid),A ;buffer data not valid cpl ret z push IX ;save pointer (drive may have changed) ld IX,(blkptr) ;for most recently selected drive ;which is the one to flush ld A,0A3h ;second byte of OUTI instruction ld (iotran+1),A ld A,0ACh ;FDC write sector command ld (oper),A ld HL,(iodrvtrk) push HL ld HL,(blkdrvtrk) ld (iodrvtrk),HL ;set drive to select and track ld A,(blksec) call sideflsh ;set u4,20,26,6,12,18,24,4,10,16,22 ;secotrs 14-16 fhome:: ld C,0 fsettrk:: ld A,C ld (iotrk),A ret fsetsec:: ld A,C ld (iosec),A ret setdma:: ld (iodma),BC ;shared among all drivers ret page ; ; Fseldsk selects the physical floppy in A (0-3) ; B=0 if last disk selected was a different floppy ; C=logical disk the floppy corresponds to fseldsk:: ld B,A call getden ;will set density byte if successful or A jr nz,fbadsel ;couldn't get density ;all physical operations OK here ld (hwptr),IX ;store for later use ld A,(IX+density) inc A ;make 1-3 ld B,A ld HL,fdpbase-dpblen ld DE,dpblen fgetdpb:: add HL,DE djnz fgetdpb ;HL=DPB address ld C,L ld B,H ld A,(curfpy) call seldph ld A,(IX+density) or A jr z,setran ;single density,set translate vector xor A ld (HL),A inc HL ld (HL),A jr putdpb setran:: ld DE,trans ;single density translate table ld (HL),E inc HL ld (HL),D putdpb:: ld DE,9 ;offset of DPB in DPH add ;no INTRQ from FDC in A,(cmd) and 10011001b ;seek error, CRC error, or incomplete jr nz,seekerr ;seek successful ld (IX+drvtrk),C ret seekerr:: ld E,1ch ;seek command call diskerror jr seek2 lstskdrv:: db 0 ;drive on which last disk operation took place page ; write writes the sector to the selected disk fwrite:: ld IX,(hwptr) ;restore IX to parameter block ld A,(IX+density) or A jr z,wrtsngl ld A,2 cp C jr z,unalloc dec A cp C jr z,directry ;directory sector jr wrtnorm unalloc:: ;unallocated sector write (no preread) call fflush or A ret nz ;flush error ld A,(iosec) and not(hstcnt-1) ;get first sector in buffer ld (blksec),A xor hstcnt*2 ld (blk2sec),A ;if this is an unallocated block ;then two physical sectors (2K) were ;unallocated ;here we have a sector to write that ;is currently in the host buffer movwrt:: call mkbufad ;get correct address in buffer ex DE,HL ldir ld A,0ffh ldp head bit and sector for flush call strtsel ;do physical flush pop HL ld (iodrvtrk),HL ;restore selected drive and track pop IX ld (wrtpend),A ;clear flag if no errors ret page ; ; Read reads the sector from the selected disk ; In double density, the sector may already be in the host buffer ; fread:: ld IX,(hwptr) ;restore parameter pointer ld A,(IX+density) ;density byte or A jr z,rdsngl ;singl density call inbuf jr c,rddbl ;sector not in buffer ; sector is in buffer movrd:: call mkbufad ;HL=start of sector in buffer ldir ret ;transfer done rddbl:: call fflush ;flush previous buffer or A ret nz ;physical error in flush call sidesec call readprep or A ret nz jr movrd rdsngl:: ld A,(iosec) ld (psec),A ;physical sector same as CP/M sector ;in single density readprep:: ld A,0A2h ;second byte of INI instruction ld (iotran+1),A ;patch rdwrite routine ld A,08ch ;sector read command ld (oper),A page strts HL,DE ld (HL),C inc HL ld (HL),B dec HL dec HL sbc HL,DE ;restore DPH (carry reset by or A) ret fbadsel:: ld A,(tempfpy) ld (curfpy),A ;restore changes made by getden ld HL,0 ret ;return error seldph:: add A,A add A,A add A,A add A,A ld L,A ld H,0 ld DE,fdphbase add HL,DE ret page ; ; Seldrv selects the drive from (curfpy), head from (head) ; (bit 0 set for head1), and density from (IX+density) ; it assembles the correct byte and outputs to wait ; and updates the track register with the most recent information seldrv:: ld A,(IX+density) or A jr z,setdens ld A,00001000b ;set double density bit ld B,A ld A,(head) rlca rlca ;move head bit to bit 2 or B setdens:: ld B,A ld A,(curfpy) or B out (wait),A ld A,(IX+drvtrk) ;get track from parameter table ;this may be first physical i/o out (trk),A ld A,2 ;set try flag ld (rdytry),A tstrdy:: ld A,0d0h ;reset status to controller out (cmd),A ex (SP),HL ;wait (wrtpend),A ;write pending cpl ;return with no errors ret directry:: ;write to a directory sector ;the disk may be removed after this ;so we will make this write immediate call wrtnorm ;do a normal write or A ret nz ;error in previous flush or read jr fflush ;and flush this sector wrtnorm:: ;a block that has been written before call inbuf ;returns C flag set if not in buffer jr nc,movwrt ;and A to relative sector if in buffer ;not in buffer but might be sector of other 1k of ;an unallocated 2K data block ld A,D ;iosec and not (hstcnt-1) ld D,A ;first sector of new 1k block ld A,(blk2sec) cp D ; = unalocated block jr nz,wrtdbl ;unless sector of other 1K in ;unallocated data block call inbuf2 ;checks iotrk=blktrk jr c,wrtdbl call fflush ;previously unallocated data or A ret nz cpl ld (blk2sec),A ;clear unallocated sector indicator jr movwrt ;and write this sector wrtsngl:: ld A,(iosec) ,rive ; corresponding to logical disk in C. The physical drive is in B. ; If the disk is already logged in since the last software reset, ; GETDEN just returns (in essence). If the disk has not been logged in, ; GETDEN will try to read track 0, sector 1 (in single density for 8", ; in double density for 5") to determine the disk format. ; If the attempt is successful, Getden will update the ; dens, pspt, and drvtrk fields of the paramter table getden:: if not prmboot ld A,C ;is it logical drive A: or A jr NZ,nlogdin ;if so can't change density ld D,B ;save physical drive ld A,(frstsel) ;first select or A jp z,logdin ;skip if not ld A,0 ; otherwise clear flag ld (frstsel),A ; and continue nlogdin: endif ld HL,(start-51h) ;get login vector, A: = least significant bit ld D,B bit 3,C ;high byte or low byte ld A,L jr z,frst8 ld A,H res 3,B frst8: ld B,C inc B ;B = (drive MOD 8) + 1 rol1: rra ;set carry from drive bit djnz rol1 jr c,logdiningl ;use the CP/M DMA buffer in single density ld HL,hstbuf ;use host buffer for double density operations ld D,hstcnt ;number of 128 byte units to transfer jr strtio dmasingl:: ld HL,(iodma) strtio:: ld A,(psec) out (sec),A ;set physical sector ld A,E out (cmd),A ;start read/write operation call rdwrite ;do the actual i/o in A,(cmd) ei ;now ok to interrupt-status is saved ld E,A ;save status or B ;B returned from rdwrite is lost bytes count ret z ;if status OK and no lost bytes ld A,E and 10111111b ;clear write protect bit ld A,(oper) jr nz,nowpt ;write protect was not the problem cp 0ach ;was it a write operation jr nz,nowpt ;only error was disk write protected ld DE,wpterr call pmsg call pdrv ld DE,wpter2 call pmsg ld DE,abortmsg call pmsg call conin cp 3 ;was it control-C? jr nz,iotry ld A,1 ret ;return to BDOS with error nowpt:: ld D,A call diskerror call seek2 or A jr z,iotry ;if nonzero then hopeless seek erpt hstshft rrca endm ;A=physical sector number, but it may ;be on the second side ld B,(IX+pspt) cp B ld C,0 jr c,side0 sub B inc C side0:: inc A ld (psec),A ;physical sector on one side ld A,C ld (head),A ;set head control byte ret page ; ; inbuf returns carry flag set if sector not in buffer ; also returns (iosec) in D ; if sector is in buffer, returns offset (0 - hstcnt-1) in A ; inbuf:: ld A,(iosec) ld D,A ld A,(bufvalid) ;0 if contains valid data, else 255 rra ret c inbuf2:: ld HL,(iodrvtrk) ;check for 2nd sector ;of unallocated block ld BC,(blkdrvtrk) sbc HL,BC ;same drive and track jr z,rttrk scf ret ;not a match rttrk:: ld A,(blksec) ld B,A ld A,D sub B ret C ;sector lower # than buffer cp hstcnt ;carry set if in buffer ccf ret ; stores drive, track, sector of contents of buffer for use by flush ; also saves hardware pointer and sets buffer valid flag ; returns HL=start of sector in buffer, DE ;disk already logged in ;go look at track 0 sector 1 logdrv:: push DE call fflush ;getden uses buffer pop DE or A ret nz ld A,0d0h ;reset FDC out (cmd),A ld A,(curfpy) ld (tempfpy),A ;save most recent floppy ld A,D ld (curfpy),A call getparm if mini if not special set 3,A ;set double density for minifloppy endif endif out (wait),A ;select new drive, head 0, single D call resto1 ;back to track zero xor A ld (iotrk),A ld (head),A ;force head 0 if not mini ld (IX+density),A ;track zero always single density endif inc A if mini ld (IX+density),A ;double density for minifloppies endif ld (iosec),A ;read sector 1 ld HL,(iodma) ;save old DMA address push HL ld HL,hstbuf ;buffer has already been flushed ld (iodma),HL call rdsngl pop HL ld (iodma),HL ;restore dma or A ret nz ;can't read sector ld A,(hstbuf+7fh) ;code byte for disk type OR A jr z,codeok ;some SD disks have old loaders here sub 0e5h ;cror ret ; ; rdwrite does the actual transfer to/from the FDC ; HL set to DMA address on entry, D=number of 128 byte units to transfer ; transfer direction has been set by poking INI or OUTI instruction rdwrite:: ld B,128 ;bytes in one CP/M sector loop:: in A,(wait) or A ret p ;no more DRQ iotran:: ini ;start with read ;the second byte of this instruction is patched to ;be either INI or OUTI depending on need jr nz,loop dec D jr nz,rdwrite jr loop ;sector done, wait for INTRQ from fdc page ; ; disk error will eventually have all kinds of nice messages ; diskerror:: ld A,(retryc) dec A ld (retryc),A jr nz,restore ;more retries to attempt ld A,E cp 1ch ;was it a seek error? jr z,pseekerr cp 0ach ;writing? jr z,pwriterr ld DE,rderr jr perrtyp pwriterr:: ld DE,wrterr jr perrtyp pseekerr:: ld DE,skerr perrtyp:: call pmsg ld DE,trkerr call pmsg ld A,(iotrk) call phex ld DE,secerr call pmsg ld A,(psec) call phex ld DE,si=DMA address, BC=128, A=0 mkbufad:: ld (blkptr),IX ld HL,(iodrvtrk) ld (blkdrvtrk),HL ld A,(iosec) ld B,A and not(hstcnt-1) ld (blksec),A ld A,B and hstcnt-1 ld B,A ;B=relative sector in buffer inc B ld HL,hstbuf-128 ld DE,128 shft2:: add HL,DE djnz shft2 ld BC,128 ;make ready for sector LDIR ld DE,(iodma) xor A ld (bufvalid),A ret page ; ; returns IX=start of DHPB (disk hardware parameter block) for ; the drive in A (0-3) ; uses B,DE also, returns D=0 getparm:: ld B,A inc B ld IX,dskparm-parmlen ;hardware parameter block ld DE,parmlen shft1:: add IX,DE djnz shft1 ret ; ; Sectran input:: Logical sector in BC, translate table in DE ; no translation if DE=0 ; ; Returns physical sector in HL ; Note:: only used in single density sectran:: ld A,D or E ld L,C ld H,B ret z ;no sector translation ex DE,HL add HL,BC ld L,(HL) ld H,0 ret page ; ; Getden sets variables to reflect the density of the disk in d-ode for a normal single density disk cp 3 jr c,codeok ld DE,badcode ;not our code byte call pmsg call pdrv ld A,255 ret codeok:: ld (IX+density),A or A jr z,snglspt ld A,ddpspt ;physical sectors on one side of DD jr putpspt snglspt:: ld A,26d ;single density physical sectors putpspt:: ld (IX+pspt),A xor A ret ;no errors logdin:: ld A,D ;drive already logged in ld (curfpy),A call getparm ld A,(IX+density) jr codeok ; drive can't change density bootlog:: db 1 ;0 = A: logged in, nonzero = not logged SUBTTL Hard disk drivers page .sfcond if hard .lfcond hdcio equ (($-start-1)/256)+1 ;make line up on page boundary ; ; Hard disk drive driver module ; org hdcio*256 hdc:: ; hard disk controller jump table jp hhome jp hseldsk jp hsettrk jp hsetsec jp hread jp hwrite jp hflush db 'HARDDISK' ;module name for display purposes page ; ; CP/M Hard disk tables ; hDPHbase:: hddisks hdldrvs ;set up disk parameter headers ;  ld A,L ;find first sector in group and not 31 ld L,A ld (hunalsec),HL ld A,B rrca ;find out which sector this is in group rrca and 7 ld B,A xor A ;set proper bit in unallocated vector scf hstunv: rla djnz hstunv ld (unalcv),a ;and save it for later ; ; ;here we have a sector to write that ;is currently in the host buffer hmvwrt:: call hmkbfad ;get correct address in buffer ex DE,HL ldir ld A,0ffh ld (hwrtpnd),A ;write pending cpl ;return with no errors ret hdirectry:: ;write to a directory sector ;the disk may be removed after this ;so we will make this write immediate call hwrtnorm ;do a normal write or A ret nz ;error in previous flush or read jr hflush ;and flush this sector hwrtnorm:: ;a block that has been written before call hinbuf ;returns C flag set if not in buffer jr nc,hmvwrt ;and A to relative sector if in buffer ;not in buffer but might be unallocated sector in ;an unallrrors pop HL ld (hiodrvtrk+1),HL ;restore selected drive and track push AF pop HL ex (SP),HL push HL pop AF ld (hiodrvtrk),a pop AF ret page ; ; Read reads the sector from the selected disk ; it handles any necessary buffering ; hread:: call hinbuf ;is it in the buffer jr c,hrd ;sector not in buffer ; sector is in buffer hmvrd:: call hmkbfad ;HL=start of sector in buffer ldir ret ;transfer done hrd:: call hflush ;flush previous buffer or A ret nz ;physical error in flush call hsidselc call hrdprep or A ret nz jr hmvrd ; ; read preperation ; hrdprep:: call hseldrv ;physically select drive and head call hseek ;step to correct track ; ; this actually reads the necessary sector ; it assumes that the head has already settled on the correct track ; (and that the proper head has been selected) ld HL,hstbuf ;point to buffer ld BC,hdcdata ;count and port di ;protect transfer ld A,cread ;send read command out (c; DPB's for HARD DISKS ; ; hdpbase equ $+4 hddpbs hddsks ;set up disk parameter blocks page hhome:: ld BC,0 ;force track 0 hsettrk:: ld (hdiotrk),BC ;save track number ret hsetsec:: ld (hdiosec),BC ;save sector number ret ; ; Hseldsk selects the hard disk in A ; B=0 if last disk selected was a different drive ; C=logical disk the drive corresponds to hseldsk:: res 7,a ;make sure high bit = 0 add A,A ;*2 add A,A ;*4 add A,A ;*8 add A,A ;*16 ld L,A ;make 16 bits ld H,0 ld DE,hdphbase ;add in base address add HL,DE push HL ;save address for return ld DE,10 ;find dpb address add HL,DE ld E,(HL) ;get it inc HL ld D,(HL) ld HL,15 ;make address of physical unit add HL,DE ld A,(HL) ;get physical unit ld (curhdsk),a ;set to new drive pop HL ;get returned address back ld IX,0 ;clear to indicate hard disk ret ; and go ; ; Seldrv selects the drive from (curhdsk), head from (hhead) ; it assembles the correct ocated 4K data block call hinbf2 ;checks hdiodrvtrk=hblkdrvtrk jr c,hwrt ;not same track or disk ld HL,(hdiosec) ;get sector ld DE,(hunalsec) ;get last unallocated block start ld B,L ;save L ld A,L ;find start of group and not 31 ld L,A sbc HL,DE jr nz,hwrt1 ;not in same group ld A,B rrca ;find out which sector this is in group rrca and 7 inc A ld B,A xor A ;set proper bit to test unallocated vector scf htstunv: rla djnz htstunv ld B,A ;save for test ld A,(unalcv) ld C,A ;save and B ;already written this sector ? jr nz,hwrt ;yes ld A,C ;mark new sector as writen or b ld (unalcv),a call hflush ;previously unallocated data or A ret nz jr hmvwrt ;and write this sector hwrt:: ld HL,0ffffh ;Clear unallocated sector 'cause on diff. track ld (hunalsec),HL hwrt1:: call hflush ;flush buffer or A ret nz ;return bad sector if hard flush error call hsidselc ;set up for new i/o call hrdprep ;do read tomnd),A hrdw:: in A,(status) ;done yet and A jp m,hrdw ;if not wait inir ;256 bytes twice inir ei in A,(status) and 1 ;any errors ret z ;return if not ; page ; ; hard disk error message processor ; ; This routine gives the user a detailed error report ; herrors:: push AF ;save error indication ld DE,herrst CALL pmsg ; First the error code IN A,(HDCERR) CALL phex ld DE,errst ; Status byte call pmsg in A,(status) call phex ld DE,errhd CALL pmsg ; then the head IN A,(SDH) push AF ;save drive no AND 7 CALL hex1 ; Print single digit ld DE,errcyl CALL pmsg ; the cylinder IN A,(CYLHI) ; Report CYLHI first CALL phex IN A,(CYLLO) ; then CYLLO CALL phex ld DE,errsec CALL pmsg ; and finally the sector IN A,(SECNO) CALL phex ld DE,errdr ;send drive mess call pmsg pop AF rra ;get drive rra rra and 3 call hex1 ld A,(hdesc0+8) ;restore drive rlca or crest out (comnd),A herrlp:: in A,(status)byte and outputs it ; and updates the track register with the most recent information hseldrv:: ld a,(curhdsk) ;get disk rlca ;move it over rlca rlca ld hl,hhead ;get head or (hl) or 20h ; or 80h ;set sector size to 512 bytes and ECC out (sdh),a ;send to controller ret page ; ; Seek sets head to the track in (hdiotrk) ; and sector to (hpsec), sector count to one ; hseek:: ld a,(hdiotrk) ;send low order byte of track out (cyllo),a ld a,(hdiotrk+1) ;send high byte out (cylhi),a ld A,(hpsec) ;send physical sector out (secno),A ld A,1 ;set sector count out (secnt),A ret page ; ; hwrite writes the sector to the selected disk ; and takes care of any necessary buffering ; hwrite:: ld A,2 ;unallocated write cp C jr z,hunalloc dec A cp C jr z,hdirectry ;directory sector jr hwrtnorm hunalloc:: ;unallocated sector write (no preread) call hflush or A ret nz ;flush error ld HL,(hdiosec) ;get sector ld B,L ;save it o buffer or A ret nz ;physical error jr hmvwrt ;and move new sector from DMA page ; ; hflush flushes buffer to disk if write from it is pending ; hflush:: ;flush deblocking buffer to disk ld A,(hwrtpnd) ;do we have a write pending? or A ld A,0ffh ld (bufvalid),A ;buffer data not valid cpl ret z ;nothing in buffer to flush ld A,(hiodrvtrk) push AF ld HL,(hiodrvtrk+1) push HL ld HL,(hblkdrvtrk+1) ld (hiodrvtrk+1),HL ;set drive to select and track ld HL,(hblksec) call hflsdsc ;set up head bit and sector for flush call hseldrv ;select drive call hseek ;make sure proper track and sector ;do physical flush ld HL,hstbuf ;point to buffer ld BC,hdcdata ;count and port di ;protect transfer ld A,cwrite ;send write command out (comnd),A otir ;256 bytes twice otir ei hwrtw:: in A,(status) ;done yet and A jp m,hwrtw ;if not wait and 1 ;any errors jp nz,herrors ;process if so ; ld (hwrtpnd),A ;clear flag if no e