IMD 1.17: 2/06/2011 15:26:44 superbios 26 sec 256 bytes  1><<2O!|2.}2"DM =*1!"DMͶ>OچO!"Æ ¹*1 !"DMͶ>O چ O!"Æ ¹*1!"DMͶ>OچO!"Æ ¹*1!"DMͶ>OچO!"Æ ¹*1 ͨ!w# ‘!"ͨ!"DM>O ڨ O!"è *1ͨ!w# ‘!"ͨ!"DM>OڨO!"è *$1!w# x>2F1-y2dc' O2d-c- f*3áÒE8×vðû*Ò:L!3w# CC*#~!wwwww>>26҃>2͝q>>26ͭ"’y/2/¡:/͡:G:O:/W:W:W:*DM>>y2! ! 7>`i"'2222!> }7ɯ7y?2yM?22ͭy2:>x V2H*>k~#~#~# ~#!|õ>kw#w#w# w#¢!!͇_:=2:=N>7::<'!:##wy2!}A:l>xWH:2$z7' !>2w,U!͇lJA:O! :G>x2> !" GÊy2!+| 0!N#^q#{~6#6B:w#w ~2#~> -22:O:/:O:=/wOj*+|c~ :w>7*))!w~҂~~z‡^#V:w6r{7~µ~ʺ~¿y/G!^#~##~w~22:2:!\X COPYRIGHT (C) 1979, DIGITAL RESEARCH _͌> ͒> Ò> Ò͘~#͌ì _2<ý2˽ýýý߽ý !Ķ2:2a{_:ķʖ:ķ>Ľ˽ʖ:=2–!B!6#5ڽʖ:Ľ!ͬ¾ʧݾÂݾ )!F#xʺ~0wëw!" !~6ͽ:ý(!#͘*~ ""͌#>?͌͘ݾ =_.:;<> Oo$>!Y2*O"ʉ@G:ʐ:wÖx2p0ʹ#*©6?ëw˜0ï#6 ¹.0#*ٿ6?ۿwȿ0߿#6 #6" #~?  xDIR ERA TYPESAVEREN USER" B!yO#< Ty#O 321y_͸2y2ͽ:1͘оA͌>>͌9ؾо2^ :ķ¥.!_~#fow]­Îå!v"!çREAD ERRORçNO FILE^:ķ ! ~ 3#0 Wx x G ~ # 3x~#B!Y~ɯ2:ķ=!ľý:ķ=!ľ:ý^T!~  6?#ˆ:`O> K{͘оA͒>:͒͢>:͒͢xK > K > ͒x   ͢¾ØÆ^ BRͧ9!5‚#~Y‚#"T<ÆALL (Y/N)?^ Tнʧ͘!6!~ڇ ¯w4!Y~ʆ͌¾†t=ʆf ^ T ¯2o&)|+!ؾڽ<ͧվÆNO SPACE^ :Ty!B*O=?_s#"^sG!~Yøpsp2mÆÆf ͧÆFILE EXISTS _: É: :ķʉ=2)ͽÉ T!@нk!ؾ}|q=qf^!~2>`~2į2\!!B!~> >#0~O#Cx2͘վ1)ͽÂf zͧÆBAD LOADCOMf^: !Ķ Â$$$ SUB" Břťūű"C{2!"E9"1Aȯ22!ty)K!G_^#V*Cǐ~уEќѥѫ ,&-AGMSț!!ô!ô!Bdos Err On : $Bad Sector$Select$File R/O$:BA2!~6 O͐  :ȷE B 2>: ȷb# : ȷy! 4 5~yy5 6yҐ^H@Oy H H: –ͬ  #H: ! Ⱦ Hù H H $O͐: 2 *CN# x: 2 p&x~+é7Ư2 H! >w_: ! Ⱦ5ͤNkͱ¦ͱxʊ#Nx: ȷ! Ȗ2 ͤ! 5™#wO~x½p Hy<< ӷʑ :!qMD#2E>! ^#V w#P:BO|^#V#"##"##"##"!O*!O*|!6ʝ6>ӯ*w#w*w#w'û*ӷ! J*""!N#F*^#V*~#foyx*{_zW+*yx#*DM*s#r*s#ryOxG*0MD!!N:ҷ EG>O: \ɷSɀ*C :ҷqn& ^#V>O^"*}:*)=":O:ҡo"*C *C!ͮ~2~2ͦ:Ҧ2ͮ:ɯO:ҁw:w |g}o*ү#  ):BO!yoxg*:BO}!N#F "*#*s#r^ ~!J! J*:҅o$*C~i6iw**{#zr+s{ozg**͕** ʾ,w͜͸Ͳ!!N#F$**O!~#:AȾ#~$=2Ek͌::/GyO>2!q*C"͡ʔ*JҔ^:Oyʃ?|x | s̖-|N-# S:2E!~Яw>T D^6k-äPYy 5*{zBK5ڋ>*Cw~#+w#w+ɯ2E22i^ *C :ҷ~w~͔͔# #  w ~>2!E5T*C!"C"C!w# F! w͌xʯ2͢*C ~<wʃG:Ҡ!Ҧʎì 4~ʶ¬:<ʶ$ʶïZͻɯx>2>2ͻ:!ҾZί2:Eȷẅ́͊Ͳ>2>2T*CGͻ:ẅ́n>2;O ^DM;}H>"*C :ҷ:ddslO s#r:Eȷ͊:==»y==»*Ww#*"͸*:G#š"͸:!Ҿw4!iw:Z!E~=26ɯ2*C!!~~#~O~G#n,-.‹! w! yG!x͢.:E<ʄ! q!pQ:E<. ʄ$.:E<ʄi6}2ExN! ~态O>G~G!~G} *C!r#r#r ^ͥ_y#x#{s+p+q-*C ͥ!!q#p#w*:BOYG}*MD "ã:!BȾw!>2*C~=2u:B2~2wE:A*Cȶw>"!""ү2B!"!rQQQâ~?ͦ~?rQ*"CQ-Q͜QüQrQ$Q*):B"*)*)Q;*"E:;:A2AQÓQÜQ*C}/_|/*ҤW}_*"}o|g":ҷʑ*C6:ҷʑw:2E**E}DQ>2àÁvlÐÒÅÊibÌ× 56K CP/M Vers. 2.2, Cbios rev 3.1 For Thinker Toys Disk Jockey 2D Controller @ 0E000H. ~#O Ó1!!6͓ӯ22!͊>22!"!"22:O!>2G7:ӧ:1>>22ʳӯ2O3-0>2?!"^>r><<V *^"^2?O!"^DMr> u*y2`i"y2A~ n& ~ʥ/oy2={$>22 =' !Z_A7*#~o&~9O s#rA ~2n~2!:o&))))y ~#fo+F{׸y2>2:O=ʃշz<2!ʟ#ʐ :=o&)))))))!>5֯5>2>=>2>!2" :O3:اO :O0O>7>!7!w#7!R!o!:_~#fo!R!:V!:rʁy!ÄlցFyy:=2>222!>= >>2      %&'()*+, -. /0  12!"34#$!"#$1234%&'(5678 )*+,9:;<  -./0 12345678 !"#$%&'(9:;<=>?@)*+,-./0?4 < 3@+ t4  h@x1@;W@|), lVޡ.O0O>7>!7!w#7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtroller @ 0E000H. ~#O Ó PIP COM:BIOS ASM` CBIOS ASME COPY COM>CPM SYS@CPMINSTADOC DEBLOCK ASMPDISKDEF LIB1 !"SBCBOOT ASMTSBCBOOT HEXUSUPRBIOSMACVWXYZ[\]SUPRBIOSMACi^_`abcdUPDATES DOC eUSER DOCfgZ80 LIBNhijklABORTED$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:Z$:Y $Nͮ!6 :Z!Cwͯ !6:Z^hd!Y6{:Y/>!Y/H{ͯ :Y<2TŠ :Z:Y=HҮͯ !X6:XҾ:q2r !6:Z:/HNͿ!Y6:Z> !Y/>!tp+q*s !uq*u& *qM *rM !wp+q*v!!yp+q*x"!{p+q*z$!|6|  !p+q*> >ڪ Þ !"p+q/ *!DM9: :2#:!# !}:# *#&~ N!#4 !}6:DUMP ASM!#$%DUMP COM&FORMAT ASMA'()*+FORMAT COM ,FORMAT DOC-INTRFACEDOC,./0LDRBDOS MACM12345LDRBIOS MACt6789:;<=(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:/OU! 6nPACE)$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} :}2VL> @M9 HHͯ :!w:Y<2U:Y0}:Y@E}:Y!S!6:T z!6:m!6:z!6h :Z:Y,:Y HHҰͯ :Y 2Xó:TE:T2:V2}v!q!*8!*6: >͔:_ :ͳ.!(s+p+q+p+q:(=2(N *$*& w*$#"$*&#"&' !"N*M^7 !)6:!)ھ *N*DM͆ 2*ʭ :*ʗ ͯ *N"P*6:2)÷ *N"N!)4d !"N/ !R0}=2- !"R*M^_ !+6:-!+1 *RLDRGEN COM>LOADER DOC?@MACRO LIBABCDEFGHMACRO LIB IMOVCPM COMLJKLMNNEWSIZE DOCORAMDISK MACPQREADFRSTDOCRS 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$2q21:q2r<! 6+6+6!W6#6!6#6:VG*o .!6:}^*M^!6!6!U6+6 :Z$:Z:E=2 :Zʤ]:ҷ\ʹPʹͮ:Z!]h :ZN͌! ͥW>W!\q:\_  !^p+q.*]   !`q*`&!bp+q*a2_!dp+q*c2_!fp+q*e2_2_!hp+q*g!jp+q*i!lp+q*k!np+q*m2_!pp+q*o x ".*.DM͆  ͯ *R"R!+4 : !"R͆ !+6:-!+ ? 20*#"!,6:,ր!0Ң *,& :,Rx 20!,4m *R"R:0ڹ ͯ !+4I 20!"R!1q:1 !4>! :! :22*TM:   *R}2: "8 *8x *: *:&"R!;q:Y:; Y:Wҩ:; ʩ:2<ʘ:<€!<6<:<2!<ژ!6 >!Ҥ; !W6::;:TH:; !6*;M :; !W6!=q:=a/>z!=*@M:@>!(:=2%> >>!F!5+N!~ ~2B!4<2BT>>!}*Mͭz:2!6:<2é>!ҥ*MͭҞ!6!6> :Bé:B(!Cq:!CwO!~ ~2D*C&~ :Bw>!B:D!4!6>:<2!}:Y[ ͱ!5!Z6:E%:<2E*F6 *F 6å!Kq!L6> !Ld*L&I :K]>!L4A>:[<2[O*F :Yw:Y?†!6!Mq!Y6?!M:[ҠgÐ!Nq*N&*F~!6:q2r2Y:Y :Y]Hں:YA2OO>:Y 2Yͯ .:`>>!bp+q:`-!`6*aDM9:_=!_6:`{ 2cX!_6E*M& :cw:M<2MOw*:c>>2j0O> ړ:j0:jAO>ҥ::jA ~~Hͭ!fwͼO`i*ͼ\2kO>3:k! !l6:M!0>+!s!x"@O-!"8**"xO4x " 4"":U!2n~: !ҏà:ڠ*YMEÏ:nҭ<<:2dͿ!o6#6>!p*p& ~:p!o6!p4og_{ozg^#V))) _{ozg^#V) *^#V|g}o 4O{ozgi`N#Fog H Z=Y& ^#VPiOpi"r*r}:r*r)=¢i:rO:ro"r*Ih *Ih!ͽi~2r~2r͵i:r2rͽi:rO:rw:rw |g}oiqu $-patch ;base of cpm console processor bdos equ 806h+cpmb ;basic dos (resident portion) cpml equ $-cpmb ;length (in bytes) of cpm system nsects equ cpml/128 ;number of sectors to load offset equ 2 ;number of disk tracks used by cp/m cdisk equ 0004h! ^#VRJ *Rx :1w*R#"R = = = = = ͯ  *1M !6q  !6q  !6q  *1& !6à  !6 à  !60à  *1& !6  !6  !6  *1& . 1 4 7 : = F P [ f q  /H:=_2=:=!>q:>A/>Z!>/H8:> 2>:>:U=O>m:!} Hmd>9>!A6:2?*UM!E ^#VNJڗO *N*~2@*N#"Nm2@m͖ 2@m!6m!6m!6 m2@m> *&~ N2Y !Gp+q!6!Z6+6 ![6:[ S:[ M!Y6g8:2*YM8p!Z6!E6!H6>!Hڕ*H& 6!H4z!6!6#6#6![6*YM8:[ھ:Y*͇g2Yê:Y:¿:E:[,͡A<2EO>÷:YS:YQHI:<2P2Y:Y H@"2YÍ2Y02PO> c!P6Í2Y02JO> ڍ*P&*J& !Psc*O& :Pw:O·>!Pұͯ :P2r2Y:Y_!Y6=!T6>'!TE!T4!Zp+q*Y !^!l:l=O! NE!l4 E E:k0.*M& 6$9k9.Yͯ *M^2U :2:2ͳ:_³ͯ !6!"R!"P7 *M^n/ :/:H!_6:_ͯ !6:o7B1O B%*P"R+*"R <:h*oM2PO!q6!s67 *M^͆ \͔!r6:_!q:rHҗ!r4ͧu/ :_´:s°9ͯ .:r<2q:__!  !6:/! :s<2s; MDS-800 I/O Drivers for CP/M 2.2 ; (four drive single density version) ; ; Version 2.2 February, 1980 ; vers equ 22 ;version 2.2 ; ; Copyright (c) 1980 ; Digital Research ; Box 579, Pacific Grove ; California, 93950 ; ; true equ 0ffffh ;valu ;address of last logged disk on warm start buff equ 0080h ;default buffer address retry equ 10 ;max retries on disk i/o before error ; ; perform following functions ; boot cold start ; wboot warm start (save i/o byte) ; (boot and wboot are the same :22!3q:3 " *3M n :4 *3M n :24!:4Q !:424: !4:w>!4n !45 Y :3 { !6!5q:5!wҙ  â :50O !6q:6O| :6O| !76:2: '2 :'2:'2*Mͣ *Mͣ * Mͣ :ͯ m!62m!62m!62m!A62@m'2:?2:Ғ:T2?!T6*@ME:?2T:A:Ҳ:X<2X2Aý:@ 2A:A} >ͯ ::@2@:*@M:  *YM8):Y[ͱ!5!Z6ñ:[5!R6#6>!Sڰ!Q6:Q<2QO>/:Q!RO!T *QM͡H~K:Q¡!Z6[–ͱ!5:S2Y:R2R!S4=:Y[¼ͱ4:[![6:Y.2YO8:[ :Y* ͇gr+s+p+q*]~$7*]>*[>H&>*[#"[*]#"]> 2Y:SNPJ/:Y!`6!M6>2f:ʚ!M6:f”H9>!M6.f!f6ͼ2e>2eʻ.ê:`>>"hͼ2g:e!`!e5ͼ2dͭ!f\2*"N>!"ͯ >!1ͯ !mq:mF:2K!6*R}b!4EK *M^́:_ƒͯ U:_::9OY#9.3ͳ.:2 ͳ 6C9ͮZ.!t6> !tM*t& ~2u F:t ?.*uM!t4>!Ea:E=2g:2:r]>!E҅:E=2Ë:2!q:rʗ!:¤]:Y ʳ]!wp+qNͥ*vDM! ͌ :Z:Y=H]:2_e of "true" false equ not true ;"false" test equ false ;true if test bios ; if test bias equ 03400h ;base of CCP in test system endif if not test bias equ 0000h ;generate relocatable cp/m system endif ; patch equ 1600h ; org patch cpmb e  for mds) ; const console status ; reg-a = 00 if no character ready ; reg-a = ff if character ready ; conin console character in (result in reg-a) ; conout console character out (char in reg-c) ; list list out (char in reg-c) ; punch punch out (chters) ; read read track/sector to preset dma address ; write write track/sector from preset dma address ; ; jump vector for indiviual routines jmp boot wboote: jmp wboot jmp const jmp conin jmp conout jmp list jmp punch jmp reader jmp  ; ; the following code assumes the mds monitor exists at 0f800h ; and uses the i/o subroutines within the monitor ; ; we also assume the mds system has four disk drives revrt equ 0fdh ;interrupt revert port intc equ 0fch ;interrupt mask port icon qu 78h ;base of disk command io ports dstat equ base ;disk status (input) rtype equ base+1 ;result type (input) rbyte equ base+3 ;result byte (input) ; ilow equ base+1 ;iopb low address (output) ihigh equ base+2 ;iopb high address (output) ; readf sp,buff+80h lxi h,signon call prmsg ;print message xra a ;clear accumulator sta cdisk ;set initially to disk a jmp gocpm ;go to cp/m ; ; wboot:; loader on track 0, sector 1, which will be skipped for warm ; read cp/m from disk - assuming thecount call read jnz booterr ;retry if errors occur lhld iod ;increment dma address lxi d,128 ;sector size dad d ;incremented dma address in hl mov b,h mov c,l ;ready for call to set dma call setdma lda ios ;sector number just read cpi 2 mvi a,inte ;rst0 and rst7 bits on out intc xra a out icon ;interrupt control ; ; set default buffer address to 80h lxi b,buff call setdma ; ; reset monitor entry points mvi a,jmp sta 0 lxi h,wboote shld 1 ;jmp wboot at location 00  lxi h,bootmsg call prmsg jmp rmon80 ;mds hardware monitor ; bootmsg: db '?boot',0 ; ; const: ;console status to reg-a ; (exactly the same as mds call) jmp csts ; conin: ;console character to reg-a call ci ani 7fh ;remove parity bit 0 if error mov a,c cpi ndisks ;too large? rnc ;leave HL = 0000 ; ani 10b ;00 00 for drive 0,1 and 10 10 for drive 2,3 sta dbank ;to select drive bank mov a,c ;00, 01, 10, 11 ani 1b ;mds has 0,1 at 78, 2,3 at 88 ora a ;result 00? jz setdar in reg-c) ; reader paper tape reader in (result to reg-a) ; home move to track 00 ; ; (the following calls set-up the io parameter block for the ; mds, which is used to perform subsequent reads and writes) ; seldsk select disk given by reg-c (0,1,home jmp seldsk jmp settrk jmp setsec jmp setdma jmp read jmp write jmp listst ;list status jmp sectran ; maclib diskdef ;load the disk definition library disks 4 ;four disks diskdef 0,1,26,6,1024,243,64,64,offset diskdef 1,0 disequ 0f3h ;interrupt control port inte equ 0111$1110b ;enable rst 0(warm boot), rst 7 (monitor) ; ; mds monitor equates mon80 equ 0f800h ;mds monitor rmon80 equ 0ff0fh ;restart mon80 (boot error) ci equ 0f803h ;console character to reg-a ri equ 0f806equ 4h ;read function writf equ 6h ;write function recal equ 3h ;recalibrate drive iordy equ 4h ;i/o finished mask cr equ 0dh ;carriage return lf equ 0ah ;line feed ; signon: ;signon message: xxk cp/m vers y.y db cr,lf,lf if test db '32' ;32k re is a 128 byte cold start ; start. ; lxi sp,buff ;using dma - thus 80 thru ff available for stack ; mvi c,retry ;max retries push b wboot0: ;enter here on error retries lxi b,cpmb ;set dma address to start of disk system call setdma mvi c6 ;read last sector? jc rd1 ; must be sector 26, zero and go to next track lda iot ;get track to register a inr a mov c,a ;ready for call call settrk xra a ;clear sector number rd1: inr a ;to next sector mov c,a ;ready for call call setse sta 5 lxi h,bdos shld 6 ;jmp bdos at location 5 if not test sta 7*8 ;jmp to mon80 (may have been changed by ddt) lxi h,mon80 shld 7*8+1 endif ; leave iobyte set ; previously selected disk was b, send parameter to cpm lda cdisk ;last logret ; conout: ;console character from c to console out jmp co ; list: ;list device out ; (exactly the same as mds call) jmp lo ; listst: ;return list status xra a ret ;always not ready ; punch: ;punch device out ; (exactly the same as rive mvi a,00110000b ;selects drive 1 in bank setdrive: mov b,a ;save the function lxi h,iof ;io function mov a,m ani 11001111b ;mask out disk number ora b ;mask in new disk number mov m,a ;save it in iopb mov l,c mvi h,0 ;HL=disk number2...) ; settrk set track address (0,...76) for subsequent read/write ; setsec set sector address (1,...,26) for subsequent read/write ; setdma set subsequent dma address (initially 80h) ; ; (read and write assume previous calls to set up the io paramekdef 2,0 diskdef 3,0 ; endef occurs at end of assembly ; ; end of controller - independent code, the remaining subroutines ; are tailored to the particular operating environment, and must ; be altered for any system which differs from the intel mds.h ;reader in to reg-a co equ 0f809h ;console char from c to console out po equ 0f80ch ;punch char from c to punch device lo equ 0f80fh ;list from c to list device csts equ 0f812h ;console status 00/ff to register a ; ; disk ports and commands base eexample bios endif if not test db '00' ;memory size filled by relocator endif db 'k CP/M vers ' db vers/10+'0','.',vers mod 10+'0' db cr,lf,0 ; boot: ;print signon message and go to ccp ; (note: mds boot initialized iobyte at 0003h) lxi ,0 ;boot from drive 0 call seldsk mvi c,0 call settrk ;start with track 0 mvi c,2 ;start reading sector 2 call setsec ; ; read sectors, count nsects to zero pop b ;10-error count mvi b,nsects rdsec: ;read next sector push b ;save sector c pop b ;recall sector count dcr b ;done? jnz rdsec ; ; done with the load, reset default buffer address gocpm: ;(enter here from cold start boot) ; enable rst0 and rst7 di mvi a,12h ;initialize command out revrt xra a out intc ;clearedged disk number mov c,a ;send to ccp to log it in ei jmp cpmb ; ; error condition occurred, print message and retry booterr: pop b ;recall counts dcr c jz booter0 ; try again push b jmp wboot0 ; booter0: ; otherwise too many retries mds call) jmp po ; reader: ;reader character in to reg-a ; (exactly the same as mds call) jmp ri ; home: ;move to home position ; treat as track 00 seek mvi c,0 jmp settrk ; seldsk: ;select disk given by register c lxi h,0000h ;return 000  dad h ;*2 dad h ;*4 dad h ;*8 dad h ;*16 lxi d,dpbase dad d ;HL=disk header table address ret ; ; settrk: ;set track address given by c lxi h,iot mov m,c ret ; setsec: ;set sector number given by c lxi h,ios mov m,c ret sec have error set in reg-a ; ; write: ;disk write function mvi c,writf call setfunc ;set to write function call waitio ret ;may have error set ; ; ; utility subroutines prmsg: ;print message at h,l to 0 mov a,m ora a ;zero? rz ; more tselect proper disk bank mov m,a ;set disk select bit on/off ret ; waitio: mvi c,retry ;max retries before perm error rewait: ; start the i/o function and wait for completion call intype ;in rtype call inbyte ;clears the controller ; lda dlete (00) unlinked ; 00 unlinked i/o complete, 01 linked i/o complete (not used) ; 10 disk status changed 11 (not used) cpi 10b ;ready status change? jz wready ; ; must be 00 in the accumulator ora a jnz werror ;some other condition,accepted as ok above) ; 1 - crc error ; 2 - seek error ; 3 - address error (hardware malfunction) ; 4 - data over/under flow (hardware malfunction) ; 5 - write protect (treated as not ready) ; 6 - write error (hardware malfunction) ; 7 - not ready da dbank ora a jnz intyp1 ;skip to bank 10 in rtype ret intyp1: in rtype+10h ;78 for 0,1 88 for 2,3 ret ; inbyte: lda dbank ora a jnz inbyt1 in rbyte ret inbyt1: in rbyte+10h ret ; instat: lda dbank ora a jnz insta1 in dsta; Skeletal CBIOS for first level of CP/M 2.0 alteration ; msize equ 20 ;cp/m version memory size in kilobytes ; ; "bias" is address offset from 3400H for memory systems ; than 16K (referred to as "b" throughout the text). ; bias equ (msize-20)*1024 punch ;punch character out jmp reader ;reader character out jmp home ;move head to home position jmp seldsk ;select disk jmp settrk ;set track number jmp setsec ;set sector number jmp setdma ;set dma address jmp read ;read disk jmp disk 03 dw trans,0000H dw 0000H,0000H dw dirbf,dpblk dw chk03,all03 ; ; sector translate vector trans: db 1,7,13,19 ;sectors 1,2,3,4 db 25,5,11,17 ;sectors 5,6,7,8 db 23,3,9,15 ;sectors 9,10,11,12 db 21,2,8,14 ;sectors 13,14,15,16 db 20,tran: ;translate sector bc using table at de mvi b,0 ;double precision sector number in BC xchg ;translate table address to HL dad b ;translate(sector) address mov a,m ;translated sector number to A sta ios mov l,a ;return sector number in o print push h mov c,a call conout pop h inx h jmp prmsg ; setfunc: ; set function for next i/o (command in reg-c) lxi h,iof ;io function address mov a,m ;get it to accumulator for masking ani 11111000b ;remove previous command ora cbank ;set bank flags ora a ;zero if drive 0,1 and nz if 2,3 mvi a,iopb and 0ffh ;low address for iopb mvi b,iopb shr 8 ;high address for iopb jnz iodr1 ;drive bank 1? out ilow ;low address to controller mov a,b out ihigh ;high address jm retry ; ; check i/o error bits call inbyte ral jc wready ;unit not ready rar ani 11111110b ;any other errors? (deleted data ok) jnz werror ; ; read or write is ok, accumulator contains zero ret ; wready: ;not ready, treat as error fo; (accumulator bits are numbered 7 6 5 4 3 2 1 0) ; ; it may be useful to filter out the various conditions, ; but we will get a permanent error message if it is not ; recoverable. in any case, the not ready condition is ; treated as a separate condit ret insta1: in dstat+10h ret ; ; ; ; data areas (must be in ram) dbank: db 0 ;disk bank 00 if drive 0,1 ; 10 if drive 2,3 iopb: ;io parameter block db 80h ;normal i/o operation iof: db readf ;io function, initial read ion: db 1 ;num ccp equ 3400H+bias ;base of ccp bdos equ ccp+806h ;base of bdos bios equ ccp+1600h ;base of bios cdisk equ 0004H ;current disk number 0=A,...,15=P iobyte equ 0003h ;intel i/o byte ; org bios ;origin of this program nsects equ ($-ccp)/128 ;warm stawrite ;write disk jmp listst ;return list status jmp sectran ;sector translate ; ; fixed data tables for four-drive standard ; IBM-compatible 8" disks ; disk parameter header for disk 00 dpbase: dw trans,0000H dw 0000H,0000H dw dirbf,dpblk 26,6,12 ;sectors 17,18,19,20 db 18,24,4,10 ;sectors 21,22,23,24 db 16,22 ;sectors 25,26 ; dpblk: ;disk parameter block, common to all disks dw 26 ;sectors per track db 3 ;block shift factor db 7 ;block mask db 0 ;null mask dw 242 ;disL ret ; setdma: ;set dma address given by regs b,c mov l,c mov h,b shld iod ret ; read: ;read next disk record (assuming disk/trk/sec/dma set) mvi c,readf ;set to read function call setfunc call waitio ;perform read function ret ;may ;set to new command mov m,a ;replaced in iopb ; the mds-800 controller requires disk bank bit in sector byte ; mask the bit from the current i/o function ani 00100000b ;mask the disk select bit lxi h,ios ;address the sector select byte ora m ;p wait0 ;to wait for complete ; iodr1: ;drive bank 1 out ilow+10h ;88 for drive bank 10 mov a,b out ihigh+10h ; wait0: call instat ;wait for completion ani iordy ;ready? jz wait0 ; ; check io completion ok call intype ;must be io compr now call inbyte ;clear result byte jmp trycount ; werror: ;return hardware malfunction (crc, track, seek, etc.) ; the mds controller has returned a bit in each position ; of the accumulator, corresponding to the conditions: ; 0 - deleted data (tion for later improvement trycount: ; register c contains retry count, decrement 'til zero dcr c jnz rewait ;for another try ; ; cannot recover from error mvi a,1 ;error code ret ; ; intype, inbyte, instat read drive bank 00 or 10 intype: lber of sectors to read iot: db offset ;track number ios: db 1 ;sector number iod: dw buff ;io address ; ; ; define ram areas for bdos operation endef end rt sector count ; ; jump vector for individual subroutines jmp boot ;cold start wboote: jmp wboot ;warm start jmp const ;console status jmp conin ;console character in jmp conout ;console character out jmp list ;list character out jmp  dw chk00,all00 ; disk parameter header for disk 01 dw trans,0000H dw 0000H,0000H dw dirbf,dpblk dw chk01,all01 ; disk parameter header for disk 02 dw trans,0000H dw 0000H,0000H dw dirbf,dpblk dw chk02,all02 ; disk parameter header for  k size-1 dw 63 ;directory max db 192 ;alloc 0 db 0 ;alloc 1 dw 16 ;check size dw 2 ;track offset ; ; end of fixed tables ; ; individual subroutines to perform each function boot: ;simplest case is to just perform parameter initializatiosector 1 ; contains the cold start loader, which is skipped in a warm start lxi h,ccp ;base of cp/m (initial load point) load1: ;load one more sector push b ;save sector count, current track push d ;save next sector to read push h ;save dma addrr address pop b ;recall number of sectors remaining, and current trk dcr b ;sectors=sectors-1 jz gocpm ;transfer to cp/m if all have been loaded ; ; more sectors remain to load, check for track change inr d mov a,d ;sector=27?, if so, change trt shld 1 ;set address field for jmp at 0 ; sta 5 ;for jmp to bdos lxi h,bdos ;bdos entry point shld 6 ;address field of jump at 5 to bdos ; lxi b,80h ;default dma address is 80h call setdma ; ei ;enable the interrupt system lda cdisk ;gcter output from register c mov a,c ;get to accumulator ds 10h ;space for output routine ret ; list: ;list character from register c mov a,c ;character to register a ret ;null subroutine ; listst: ;return list status (0 if not ready, 1 if re ; translate this call into a settrk call with parameter 00 mvi c,0 ;select track 0 call settrk ret ;we will move to 00 on first read/write ; seldsk: ;select disk given by register C lxi h,0000h ;error return code mov a,c sta diskno cpi 4 c mov a,c sta sector ds 10h ;space for sector select ret ; sectran: ;translate the sector given by BC using the ;translate table given by DE xchg ;HL=.trans dad b ;HL=.trans(sector) mov l,m ;L = trans(sector) mvi h,0 ;HL= trans(sectond ; waitio: ;enter here from read and write to perform the actual i/o ; operation. return a 00h in register a if the operation completes ; properly, and 01h if an error occurs during the read or write ; ; in this case, we have saved the disk numbebytes for expansion dmaad: ds 2 ;direct memory address diskno: ds 1 ;disk number 0-15 ; ; scratch ram area for BDOS use begdat equ $ ;beginning of data area dirbf: ds 128 ;scratch directory area all00: ds 31 ;allocation vector 0 all01: ds 31 ;allocn xra a ;zero in the accum sta iobyte ;clear the iobyte sta cdisk ;select disk zero jmp gocpm ;initialize and go to cp/m ; wboot: ;simplest case is to read the disk until all sectors loaded lxi sp,80h ;use space below buffer for stack mvess mov c,d ;get sector address to register c call setsec ;set sector address from register c pop b ;recall dma address to b,c push b ;replace on stack for later recall call setdma ;set dma address from b,c ; ; drive set to 0, track set, sectoracks cpi 27 jc load1 ;carry generated if sector<27 ; ; end of current track, go to next track mvi d,1 ;begin with first sector of next track inr c ;track=track+1 ; ; save register state, and change tracks push b push d push h call settret current disk number mov c,a ;send to the ccp jmp ccp ;go to cp/m for further processing ; ; ; simple i/o handlers (must be filled in by user) ; in each case, the entry point is provided, with space reserved ; to insert your own code ; const: ady) xra a ;0 is always ok to return ret ; punch: ;punch character from register c mov a,c ;character to register a ret ;null subroutine ; ; reader: ;read character into register a from reader device mvi a,1ah ;enter end of file for now (re;must be between 0 and 3 rnc ;no carry if 4,5,... ; disk number is in the proper range ds 10 ;space for disk select ; compute proper disk parameter header address lda diskno mov l,a ;L=disk number 0,1,2,3 mvi h,0 ;high order zero dad h ;*2 r) ret ;with value in HL ; setdma: ;set dma address given by registers b and c mov l,c ;low order address mov h,b ;high order address shld dmaad ;save the address ds 10h ;space for setting the dma address ret ; read: ;perform read operatior in 'diskno' (0,1) ; the track number in 'track' (0-76) ; the sector number in 'sector' (1-26) ; the dma address in 'dmaad' (0-65535) ds 256 ;space reserved for I/O drivers mvi a,1 ;error condition ret ;replaced when filled-in ; ; the reation vector 1 all02: ds 31 ;allocation vector 2 all03: ds 31 ;allocation vector 3 chk00: ds 16 ;check vector 0 chk01: ds 16 ;check vector 1 chk02: ds 16 ;check vector 2 chk03: ds 16 ;check vector 3 ; enddat equ $ ;end of data area datsiz equ $-bei c,0 ;select disk 0 call seldsk call home ;go to track 00 ; mvi b,nsects ;b counts # of sectors to load mvi c,0 ;c has the current track number mvi d,2 ;d has the next sector to read ; note that we begin by reading track 0, sector 2 since  set, dma address set call read cpi 00h ;any errors? jnz wboot ;retry the entire boot if an error occurs ; ; no error, move to next sector pop h ;recall dma address lxi d,128 ;dma=dma+128 dad d ;new dma address is in h,l pop d ;recall sectok ;track address set from register c pop h pop d pop b jmp load1 ;for another sector ; ; end of load operation, set parameters and go to cp/m gocpm: mvi a,0c3h ;c3 is a jmp instruction sta 0 ;for jmp to wboot lxi h,wboote ;wboot entry poin;console status, return 0ffh if character ready, 00h if not ds 10h ;space for status subroutine mvi a,00h ret ; conin: ;console character into register a ds 10h ;space for input routine ani 7fh ;strip parity bit ret ; conout: ;console charaplace later) ani 7fh ;remember to strip parity bit ret ; ; ; i/o drivers for the disk follow ; for now, we will simply store the parameters away for use ; in the read and write subroutines ; home: ;move to the track 00 position of current drive  dad h ;*4 dad h ;*8 dad h ;*16 (size of each header) lxi d,dpbase dad d ;HL=.dpbase(diskno*16) ret ; settrk: ;set track given by register c mov a,c sta track ds 10h ;space for track select ret ; setsec: ;set sector given by register n (usually this is similar to write ; so we will allow space to set up read command, then use ; common code in write) ds 10h ;set up read command jmp waitio ;to perform the actual i/o ; write: ;perform a write operation ds 10h ;set up write commamainder of the CBIOS is reserved uninitialized ; data area, and does not need to be a part of the ; system memory image (the space must be available, ; however, between "begdat" and "enddat"). ; track: ds 2 ;two bytes for expansion sector: ds 2 ;two  gdat;size of data area end ? +COMPARE ERROR ON TRACK $(HEX) SECTOR $PERMANENT $+PERMANENT SOURCE DISK ERROR EXIT $+PERMANENT DESTINATION DISK ERROR EXIT $ +SOURCE ON A +OBJECT ON B +TYPE $ $0:_:A2:A2O:2OX*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠    :O:O :O2:Oͨ:O:O:OJ#:<2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠    X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   OPY DATA S,D" OR "COPY ALL S,D" (DEFAULT SOURCE,DESTINATION IS A,B)$+FUNCTION COMPLETE (& = REPEAT, = CPM$!#O 6$:SʝDʬAʻ.&.&M.&M"   L `!)#X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠        ~ #~2A2#~,#~2A2#~$R]u  & `:OX*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:2!!?ͫ!?? i# YY :9 )>:<2  GMD!?"͠   R*"͠> !?"͠   X*"͠> :Oͨ:O:O:OJ#:*!9"!9"!9" !9" !!9"!$9"!'9"!$9"!'9"1>yYSTEM$ATA$LL$+COMMAND "COPY$" HAS SYNTAX ERROR $+THIS PROGRAM IS INITIATED WITH THE COMMAND +"COPY SYSTEM S,D", "C  1dG|^#VS*3*N#F#x(:ͤN #F#"DM͛x 8[͐MDͨͬ 3*5"!">22!7"!##*3:O7͕vWarm boot error-reset system $p++R:2 !ɇo&-~( >G:G: ~ > 2:O y~ 8 qͧ*~(H>(=(!&:22Z>2/͢990: B8:2>2>2G=:>2/*>2>2* *" z2 ͇~Can't recognize density of disk in$Read$Write$Seek$ error on track $ sector $ side $ drive $ Creatin bootabl SUPERBIO dis fo customer wh alread ow CP/M 1 Patc you cop o MOVCPM.CO a describe i th attache Digita Researc Note Thi i necessar becaus th SUPERBIO use sectM and DDT to create a system file. A>MOVCP 6 62 i th norma syste siz ) CONTSTRUCTING 62K CP/M V2.2 READY FOR "SYSGEN" OR "SAVE 34 CPM62.COM" A>SAVE 34 B:CPM62.COM A>B: B>A:DDԠ CPM62.CO Usn to customers who have purchased CP/M from Advanced Micro Digital. "0>OSBCIO Gx(OxAyx >/:(>>2>e(y>$OͫƐ'@'O:#G" 2*~(98Z=:2>2>28> 2> :G /_~(!*:{ ͘ _ͧ8(  := R{((CHN͕S͕:͢d͕:͢n͕:͢v͕: ͕͢>222u͕:??H͕:!1O͕:)8͕͕1O͕:g.:|Ñ Super Quad CP/M v X2.0 $K CP/M 2.2 installed Default console is serial port $ Default printer is $parallel printer driver$serial poo blocking/deblockin algorith (differen tha th Digita Researc algorithm tha use th director writ cod i t flus dis buffer afte fil closing. 2) Make a copy of your SUPERBIOS distribution disk to work on. Do PIP B:=*.*[ you DD t brin iCP/M ) NEXT PC 2300 0100 -M980,1F7F,100 ( Move the CCP and BDOS to 100H ) -ICPM.SYS -R1600 ( The CPM.SYS file has the BIOS image ) -M2D00,3700,1700 ( Move the 2àGäèÛìðÐ: __Gy_(+g(DͲ <`G.|y2!zi` n&C   :!_zV#_~  :!(:! :0:1g.ôöûgFLOPPY mmmlm?@/ _      y2y2Wx HY͕ 8"~ : 2z2 ͇2w<2*!"7":(8  ͕>w(>>wrt $ $ 00O>0Gvo] then use SYSGEN to transfer the loader. 3 Pu th cop o o th SUPERBIO distributio dis i you secon flopp driv (B:) an you curren CP/ syste dis (wit th patche MOVCPM.COM i th firs flopp driv (A:). 4) Run MOVCPnew BIOS to 1700H ) -l1700,1702 ( Make sure move went OK ) 1700 JMP FA00 -G0 ( Exit and save ) B>ERA CPM.SYS B>SAVE 32 CPM.SYS 5 Yo no hav bootabl syste dis equivalen t thos se  ;***************************************************** ;* * ;* Sector Deblocking Algorithms for CP/M 2.0 * ;* * ;******************************* * ;* * ;***************************************************** blksiz equ 2048 ;CP/M allocation size hstsiz equ 512 ;host disk sector size hstspt equ 20 ;host disk sectors/trk hstblk equ hstsiz/1to directory wrual equ 2 ;write to unallocated ; ;***************************************************** ;* * ;* The BDOS entry points given below show the * ;* code which is relevant to debloc flag homed: ret ; seldsk: ;select disk mov a,c ;selected disk number sta sekdsk ;seek disk number mov l,a ;disk number to HL mvi h,0 rept 4 ;multiply by 16 dad h endm lxi d,dpbase ;base of parm block dad d ;hl=.dpb(curdsk)  * ;* the previous BIOS defintion for READ. * ;* * ;***************************************************** read: ;read the selected CP/M sector xra a sta unacnt mvi a,1 sta readop ;rccumulator sta readop ;not a read operation mov a,c ;write type in c sta wrtype cpi wrual ;write unallocated? jnz chkuna ;check for unalloc ; ; write to unallocated, set parameters mvi a,blksiz/128 ;next unalloc recs sta unacnt lda sejnz alloc ;skip if not ; ; tracks are the same lda seksec ;same sector? lxi h,unasec cmp m ;seksec = unasec? jnz alloc ;skip if not ; ; match, move to next sector for future ref inr m ;unasec = unasec+1 mov a,m ;end of track? cpi cp******* ;* * ;* Common code for READ and WRITE follows * ;* * ;***************************************************** rwoper: ;enter here to pertrack? lxi h,hsttrk call sektrkcmp ;sektrk = hsttrk? jnz nomatch ; ; same disk, same track, same buffer? lda sekhst lxi h,hstsec ;sekhst = hstsec? cmp m jz match ;skip if match ; nomatch: ;proper disk, but not correct sector lda hstw********************** ; ; utility macro to compute sector mask smask macro hblk ;; compute log2(hblk), return @x as result ;; (2 ** @x = hblk on return) @y set hblk @x set 0 ;; count right shifts of @y until = 1 rept 8 if @y = 1 exitm endi28 ;CP/M sects/host buff cpmspt equ hstblk * hstspt ;CP/M sectors/track secmsk equ hstblk-1 ;sector mask smask hstblk ;compute sector mask secshf equ @x ;log2(hstblk) ; ;***************************************************** ;* king only. * ;* * ;***************************************************** ; ; DISKDEF macro, or hand coded tables go here dpbase equ $ ;disk param block base ; boot: wboot: ;enter here on systemret ; settrk: ;set track given by registers BC mov h,b mov l,c shld sektrk ;track to seek ret ; setsec: ;set sector given by register c mov a,c sta seksec ;sector to seek ret ; setdma: ;set dma address given by BC mov h,b mead operation sta rsflag ;must read data mvi a,wrual sta wrtype ;treat as unalloc jmp rwoper ;to perform the read ; ;***************************************************** ;* * ;* The WRITE enkdsk ;disk to seek sta unadsk ;unadsk = sekdsk lhld sektrk shld unatrk ;unatrk = sectrk lda seksec sta unasec ;unasec = seksec ; chkuna: ;check for write to unallocated sector lda unacnt ;any unalloc remain? ora a jz alloc ;skip imspt ;count CP/M sectors jc noovf ;skip if no overflow ; ; overflow to next track mvi m,0 ;unasec = 0 lhld unatrk inx h shld unatrk ;unatrk = unatrk+1 ; noovf: ;match found, mark as unnecessary read xra a ;0 to accumulator sta rsflform the read/write xra a ;zero to accum sta erflag ;no errors (yet) lda seksec ;compute host sector rept secshf ora a ;carry = 0 rar ;shift right endm sta sekhst ;host sector to seek ; ; active host sector? lxi h,hstact ;host acrt ;host written? ora a cnz writehst ;clear host buff ; filhst: ;may have to fill the host buffer lda sekdsk sta hstdsk lhld sektrk shld hsttrk lda sekhst sta hstsec lda rsflag ;need to read? ora a cnz readhst ;yes, if 1 xra f ;; @y is not 1, shift right one position @y set @y shr 1 @x set @x + 1 endm endm ; ;***************************************************** ;* * ;* CP/M to host disk constants  * ;* BDOS constants on entry to write * ;* * ;***************************************************** wrall equ 0 ;write to allocated wrdir equ 1 ;write  boot to initialize xra a ;0 to accumulator sta hstact ;host buffer inactive sta unacnt ;clear unalloc count ret ; home: ;home the selected disk home: lda hstwrt ;check for pending write ora a jnz homed sta hstact ;clear host activeov l,c shld dmaadr ret ; sectran: ;translate sector number BC mov h,b mov l,c ret ; ;***************************************************** ;* * ;* The READ entry point takes the place of try point takes the place of * ;* the previous BIOS defintion for WRITE. * ;* * ;***************************************************** write: ;write the selected CP/M sector xra a ;0 to af not ; ; more unallocated records remain dcr a ;unacnt = unacnt-1 sta unacnt lda sekdsk ;same disk? lxi h,unadsk cmp m ;sekdsk = unadsk? jnz alloc ;skip if not ; ; disks are the same lxi h,unatrk call sektrkcmp ;sektrk = unatrk? ag ;rsflag = 0 jmp rwoper ;to perform the write ; alloc: ;not an unallocated record, requires pre-read xra a ;0 to accum sta unacnt ;unacnt = 0 inr a ;1 to accum sta rsflag ;rsflag = 1 ; ;**********************************************tive flag mov a,m mvi m,1 ;always becomes 1 ora a ;was it already? jz filhst ;fill host if not ; ; host buffer active, same as seek buffer? lda sekdsk lxi h,hstdsk ;same disk? cmp m ;sekdsk = hstdsk? jnz nomatch ; ; same disk, same   a ;0 to accum sta hstwrt ;no pending write ; match: ;copy data to or from buffer lda seksec ;mask buffer number ani secmsk ;least signif bits mov l,a ;ready to shift mvi h,0 ;double count rept 7 ;shift left 7 dad h endm ; hl hased to/from host buffer lda wrtype ;write type cpi wrdir ;to directory? lda erflag ;in case of errors rnz ;no further processing ; ; clear host buffer for directory write ora a ;errors? rnz ;skip if so xra a ;0 to accum sta hstwrt inx d inx h ldax d cmp m ;sets flags ret ; ;***************************************************** ;* * ;* WRITEHST performs the physical write to * ;* the host disk, READHST reads the p********************************************** ;* * ;* Unitialized RAM data areas * ;* * ;***************************************************** ; flag readop: ds 1 ;1 if read operation wrtype: ds 1 ;write operation type dmaadr: ds 2 ;last dma address hstbuf: ds hstsiz ;host buffer ; ;***************************************************** ;* def 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,...,tracks 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 de 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 vecproduces 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  relative host buffer address lxi d,hstbuf dad d ;hl = host address xchg ;now in DE lhld dmaadr ;get/put CP/M data mvi c,128 ;length of move lda readop ;which way? ora a jnz rwmove ;skip if read ; ; write operation, mark and switch ;buffer written call writehst lda erflag ret ; ;***************************************************** ;* * ;* Utility subroutine for 16-bit compare * ;* hysical * ;* disk. * ;* * ;***************************************************** writehst: ;hstdsk = host disk #, hsttrk = host track #, ;hstsec = host sect #. write "hstsiz" bytes ;fr sekdsk: ds 1 ;seek disk number sektrk: ds 2 ;seek track number seksec: ds 1 ;seek sector number ; hstdsk: ds 1 ;host disk number hsttrk: ds 2 ;host track number hstsec: ds 1 ;host sector number ; sekhst: ds 1 ;seek shr secshf hstact: ds 1 * ;* The ENDEF macro invocation goes here * ;* * ;***************************************************** end 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 "skfined 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 biotors 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 dgcdm 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 eq direction mvi a,1 sta hstwrt ;hstwrt = 1 xchg ;source/dest swap ; rwmove: ;C initially 128, DE is source, HL is dest ldax d ;source character inx d mov m,a ;to dest inx h dcr c ;loop 128 times jnz rwmove ; ; data has been mov * ;***************************************************** sektrkcmp: ;HL = .unatrk or .hsttrk, compare with sektrk xchg lxi h,sektrk ldax d ;low byte compare cmp m ;same? rnz ;return if not ; low bytes equal, test high 1som hstbuf and return error flag in erflag. ;return erflag non-zero if error ret ; readhst: ;hstdsk = host disk #, hsttrk = host track #, ;hstsec = host sect #. read "hstsiz" bytes ;into hstbuf and return error flag in erflag. ret ; ;******* ;host active flag hstwrt: ds 1 ;host written flag ; unacnt: ds 1 ;unalloc rec cnt unadsk: ds 1 ;last unalloc disk unatrk: ds 2 ;last unalloc track unasec: ds 1 ;last unalloc sector ; erflag: ds 1 ;error reporting rsflag: ds 1 ;read sector; 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 ; diskew 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 s, ; 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 largen 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 ;;   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 allocatl 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)se 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 shs 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 endifnddat equ $ datsiz equ $-begdat ;; db 0 at this point forces hex record endm ; TYPE FUNCTION PRINTF EQU 9 ;BUFFER PRINT ENTRY BRKF EQU 11 ;BREAK KEY FUNCTION (TRUE IF CHAR READY) OPENF EQU 15 ;FILE OPEN READF EQU 20 ;READ FUNCTION ; FCB EQU 5CH ;FILE CONTROL BLOCK ADDRESS BUFF EQU 80H ;INPUT DISK BUFFER ADDRESS ; ; NON GRAPHEA (RESTORED AT FINIS) LXI SP,STKTOP ; READ AND PRINT SUCCESSIVE BUFFERS CALL SETUP ;SET UP INPUT FILE CPI 255 ;255 IF FILE NOT PRESENT JNZ OPENOK ;SKIP IF OPEN IS OK ; ; FILE NOT THERE, GIVE ERROR MESSAGE AND RETURN LXI D,OPNMSG CALL ERR ion 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 ;;fi > 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 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 ;; genera 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 lIC CHARACTERS CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED ; ; FILE CONTROL BLOCK DEFINITIONS FCBDN EQU FCB+0 ;DISK NAME FCBFN EQU FCB+1 ;FILE NAME FCBFT EQU FCB+9 ;DISK FILE TYPE (3 CHARACTERS) FCBRL EQU FCB+12 ;FILE'S CURRENT REEL NUMBER FCJMP FINIS ;TO RETURN ; OPENOK: ;OPEN OPERATION OK, SET BUFFER INDEX TO END MVI A,80H STA IBP ;SET BUFFER POINTER TO 80H ; HL CONTAINS NEXT ADDRESS TO PRINT LXI H,0 ;START WITH 0000 ; GLOOP: PUSH H ;SAVE LINE POSITION CALL GNB POP H ;RECALLlls 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 blkvar 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 elte 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 elementb&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; FILE DUMP PROGRAM, READS AN INPUT FILE AND PRINTS IN HEX ; ; COPYRIGHT (C) 1975, 1976, 1977, 1978 ; DIGITAL RESEARCH ; BOX 579, PACIFIC GROVE ; CALIFORNIA, 93950 ; ORG 100H BDOS EQU 0005H ;DOS ENTRY POINT CONS EQU 1 ;READ CONSOLE TYPEF EQU 2 ;BRC EQU FCB+15 ;FILE'S RECORD COUNT (0 TO 128) FCBCR EQU FCB+32 ;CURRENT (NEXT) RECORD NUMBER (0 TO 127) FCBLN EQU FCB+33 ;FCB LENGTH ; ; SET UP STACK LXI H,0 DAD SP ; ENTRY STACK POINTER IN HL FROM THE CCP SHLD OLDSP ; SET SP TO LOCAL STACK AR   LINE POSITION JC FINIS ;CARRY SET BY GNB IF END FILE MOV B,A ; PRINT HEX VALUES ; CHECK FOR LINE FOLD MOV A,L ANI 0FH ;CHECK LOW 4 BITS JNZ NONUM ; PRINT LINE NUMBER CALL CRLF ; ; CHECK FOR BREAK KEY CALL BREAK ; ACCUM LSB = 1 IF CHARARKF CALL BDOS POP B! POP D! POP H; ENVIRONMENT RESTORED RET ; PCHAR: ;PRINT A CHARACTER PUSH H! PUSH D! PUSH B; SAVED MVI C,TYPEF MOV E,A CALL BDOS POP B! POP D! POP H; RESTORED RET ; CRLF: MVI A,CR CALL PCHAR MVI A,LF CALL PC ; READ ANOTHER BUFFER ; ; CALL DISKR ORA A ;ZERO VALUE IF READ OK JZ G0 ;FOR ANOTHER BYTE ; END OF DATA, RETURN WITH CARRY SET FOR EOF STC RET ; G0: ;READ THE BYTE AT BUFF+REG A MOV E,A ;LS BYTE OF BUFFER INDEX MVI D,0 ;DOUBLE PRECISIONVI C,READF CALL BDOS POP B! POP D! POP H RET ; ; FIXED MESSAGE AREA SIGNON: DB 'FILE DUMP VERSION 1.4$' OPNMSG: DB CR,LF,'NO INPUT FILE PRESENT ON DISK$' ; VARIABLE AREA IBP: DS 2 ;INPUT BUFFER POINTER OLDSP: DS 2 ;ENTRY SP VALUE FROM CCP ;!9"1W͜Q>2!͢QG}DrYQ|͏}͏#> ex͏#r* _> e> e ҉0Ë7e}} :³ʳ7_<2!~ɯ2|\\FILE DUMP VERSION 1.4$ NO INPUT FICTER READY RRC ;INTO CARRY JC FINIS ;DON'T PRINT ANY MORE ; MOV A,H CALL PHEX MOV A,L CALL PHEX NONUM: INX H ;TO NEXT LINE NUMBER MVI A,' ' CALL PCHAR MOV A,B CALL PHEX JMP GLOOP ; FINIS: ; END OF DUMP, RETURN TO CCP ; (NOTE HAR RET ; ; PNIB: ;PRINT NIBBLE IN REG A ANI 0FH ;LOW 4 BITS CPI 10 JNC P10 ; LESS THAN OR EQUAL TO 9 ADI '0' JMP PRN ; ; GREATER OR EQUAL TO 10 P10: ADI 'A' - 10 PRN: CALL PCHAR RET ; PHEX: ;PRINT HEX CHAR IN REG A PUSH PSW RRC INDEX TO DE INR A ;INDEX=INDEX+1 STA IBP ;BACK TO MEMORY ; POINTER IS INCREMENTED ; SAVE THE CURRENT FILE ADDRESS LXI H,BUFF DAD D ; ABSOLUTE CHARACTER ADDRESS IS IN HL MOV A,M ; BYTE IS IN THE ACCUMULATOR ORA A ;RESET CARRY BIT RET ;  ; STACK AREA DS 64 ;RESERVE 32 LEVEL STACK STKTOP: ; END LE PRESENT ON DISK$!Y , <    *$A!6 # T!w $r# *`: 0 *A*! ~ ʰxkb))))_y‘BK{ͅ*!66!"80*{#z+++ #THAT A JMP TO 0000H REBOOTS) CALL CRLF LHLD OLDSP SPHL ; STACK POINTER CONTAINS CCP'S STACK LOCATION RET ;TO THE CCP ; ; ; SUBROUTINES ; BREAK: ;CHECK BREAK KEY (ACTUALLY ANY KEY WILL DO) PUSH H! PUSH D! PUSH B; ENVIRONMENT SAVED MVI C,B RRC RRC RRC CALL PNIB ;PRINT NIBBLE POP PSW CALL PNIB RET ; ERR: ;PRINT ERROR MESSAGE ; D,E ADDRESSES MESSAGE ENDING WITH "$" MVI C,PRINTF ;PRINT BUFFER FUNCTION CALL BDOS RET ; ; GNB: ;GET NEXT BYTE LDA IBP CPI 80H JNZ G0 SETUP: ;SET UP FILE ; OPEN THE FILE FOR INPUT XRA A ;ZERO TO ACCUM STA FCBCR ;CLEAR CURRENT RECORD ; LXI D,FCB MVI C,OPENF CALL BDOS ; 255 IN ACCUM IF OPEN ERROR RET ; DISKR: ;READ DISK FILE RECORD PUSH H! PUSH D! PUSH B LXI D,FCB M ; ; ; ; MACLIB MACRO ; ;FORMAT PROGRAM FOR THE WD1791 FDISK CONTROLLER ; INTERLEAVED SECTOR VERSION ; ; ************** DD DISK CONTROLLER **************** ; TRUE EQU 0FFFFH FALSE EQU NOT TRUE ; ; ;*****************************************DSEL EQU 014H TRACK EQU CMD+1 SECT EQU CMD+2 ; IF NOT MINI SECNT EQU 8 SSECT EQU 26 MTK EQU 76 ;77 TRACKS (0-76) GAP1 EQU 80 GAP3 EQU 80 PRE0 EQU 12 SGAP4F EQU 40 SGAP2F EQU 26 SGAP20 EQU 6 SGAP1F EQU 27 ENDIF ; ; IF MINI S IF MINI MVI A,CODE1 STA CODE2 ; set allways double density XRA A ELSE ; 8 inch drives MVI A,0E5H ;INIZ CODE2 TO ISNT CODEQ STA CODE2 PRINT CALL IMPC ;GET CHAR CPI 'D' CR,LF,'Format System Tracks only ? (Y,N) :'> CALL IMPC CPI 'N' JZ DOIT CPI 'Y' JNZ SYSTK XRA A STA FLAG DOIT: XRA A STA DBLFL LDA DENS ORA A JNZ DOIT1 MVI A,CODE1 ; assume single sided STA CODE2 PRINT CALL IMPC CPI 'S' JZ DOIT1 CPI 'D' JNZ DOIT MVI A,CODEQ STA CODE2 MVI A,1 STA DBLFL DOIT1: PRINT LDA DISKNO ADI 41H CHAROUT PRINT <': and press the Re,0F6H CALL PUT ENDIF SLOOP: XRA A MVI B,SGAP20 CALL PUT MVI M,0FEH INX H MOV M,D ;TRACK INX H LDA SIDE MOV M,A ;SET SIDE INX H MOV M,E INX H MVI M,0 INX H MVI M,0F7H INX H MVI A,0FFH MVI B,11 CALL PUT MVI B,6  PUT DCR C JNZ SLOOP3 PUSH D LXI H,BUFF XCHG ;PUT IN D,E LXI H,WLOOP MVI A,WTRACK di OUT CMD ; CALL WLOOP ei POP D IN CMD ;GET STATUS ORA A ;TEST JNZ ERROR LDA DENS ORA A JZ START2 INR D MOV A,D OUT DAL ;A A MVI D,0 JZ WAS12 MVI A,1 STA SIDE LOOP2: LDA SIDE ADD A ADD A MOV B,A LDA DISKNO ORA B ORI 8 OUT WAIT ; SELECT DRIVE, DENSITY & HEAD MVI E,0 ;RESET SECTOR COUNTER LXI H,TABLE ;RESET POINTER SHLD PTR ;RESET TABLE POT FLAGS NEXTSE: JZ NEXTTK CALL PUTZERO MVI A,0F5H MVI B,3 CALL PUT MVI M,0FEH INX H MOV M,D ;TRACK INX H LDA SIDE MOV M,A ;SET SIDE INX H MOV M,E INX H MVI M,3 INX H MVI M,0F7H INX H MVI A,4EH MVI B,22 CALL PUT LOOP3 PUSH D LXI H,BUFF XCHG ;PUT IN D,E LXI H,WLOOP MVI A,WTRACK di OUT CMD ; CALL WLOOP POP D IN CMD ;GET STATUS ei ORA A ;TEST JNZ ERROR LDA DBLFL ;SEE IF DOUBLE SIDED ORA A JZ ONES2 ;DO ONLY ONLY ONE SIDE LDA SIDE  0 ;SECTOR 1 FOR DOUBLE DENSITY DISKS ; CODE1 EQU 0e6H ;single sided CODEQ EQU 0e7H ;double sided ;********************************************* ; BDOS EQU 5 WBOOT EQU 0 CMD EQU 00CH DAL EQU CMD+3 WAIT EQU 014H WTRACK EQU 0F4H SEEK EQU 19H TO EQU 1 ;6MS STEP ORG 100H ; START: LXI SP,START PRINT PRINT IF MINI PRINT ENDIF COMPLT: T MVI A,0FFH ;INIZ SYSTEM FLAG TO NOT STA FLAG ;SYSTEM CALL IMPC ;GET ANSWER SUI 'A' JC QUIT CPI 4 JNC QUIT ; START1: MOV C,A STA DISKNO ;SAVE DRIVE NUMBER SYSTK: PRINT <turn key '> CHARIN CPI 0DH JNZ 0 ; exit if not return PRINT LDA DISKNO OUT WAIT ;SELECT DISK & SET SINGLE DENSITY MVI A,RESTO di OUT CMD IN WAIT ;WAIT FOR DONE ei ; XRA A MOV D,A ;START WITH TRACK 0 STA SIDE ;SET SID XRA A CALL PUT MVI M,0FBH INX H MVI A,0E5H MVI B,128 CALL PUT ;DATA 128 BYTES MOV A,E DCR A ;SEE IF SECTOR 1 ORA D ;MAKE SURE TRACK 0 JNZ NO1 LDA DENS ORA A JNZ NOTDD DCX H LDA CODE2 ;DENSITY CODE MOV M,A INX H NOTDTELL 1791 LDA DENS CMP D ;DENS IS 77+1 OR 0 JZ COMPLT ;IF D=78 AND DENS = 78 THEN DONE MVI A,SEEK di OUT CMD IN WAIT ;WAIT FOR END OF SEEK ei ; ;SEE IF LAST TRACK ; LDA FLAG MOV B,A MOV A,D ;GET TRACK SUI 2 ORA B ;IF D=2INTER LXI H,BUFF ;DMA BUFFER MVI B,GAP1 ;GAP 1 MVI A,4EH CALL PUT LOOP: LDA DBLFL ORA A JZ INTER1 MOV A,D CPI 0 JNZ INTERL JMP INTER2 INTER1: MOV A,D ;SEE IF TRACK 1 CPI 0 JNZ INTERL ;IF NOT TK 0 THEN DO INTERLEAVE ; ; ;  MVI B,12 XRA A CALL PUT MVI A,0F5H MVI B,3 CALL PUT MVI M,0FBH INX H MVI A,0E5H MVI B,0 CALL PUT ;DATA 1024 BYTES CALL PUT CALL PUT CALL PUT IF MINI MOV A,E ; GET SECTOR DCR A ORA D JNZ MN0S1 push H push D l ;GET SIDE NUMBER DCR A ;TEST SIDE JZ WAS12 MVI A,1 ;DO SIDE 1 STA SIDE ;DO OTHER SIDE JMP LOOP2 WAS12: ;DO NEXT TRACK XRA A STA SIDE ;SET SIDE 0 ONES2: INR D MOV A,D CPI MTK+1 ;LAST TRACK? JZ COMPLT OUT DAL MVI A,SEEK dwrite protected'> JMP COMPLT QUIT: LDA 4 ;SELECT DRIVE 0 HEAD 0 ANI 03H OUT WAIT ;DO IT JMP WBOOT ;GO BACK TO CPM IMPC: ;INPUT A CHAR. FROM THE CONSOLE XRA A STA IBUFF+2 INPUT IBUFF,80 LDA IBUFF+2 RET ; ; WLOOP: IN WAIT ORA,4 ENDIF DB 00 BUFF: IBUFF: END START AڹҹO2< Format System Tracks only ? (Y,N) :$ NUY22:²>2Ó Format Single or Double Sided (S,D) :$h SʲDU>2>2 Insert diskette into drive $ :A_: and press the Return  < Disk Formatting Error Disk drive Status : $  `RƐ'@'_IʋÀ Drive not ready$n l@lî Disk is write protected$ l:2 >P:e wher th doubl densit cod i suppose t be Th SUPERBIO interpret eithe 0 o E t b singl density anythin els (othe tha th SUPERBIOӠ doubl densit codes causin a error I yo ar unabl t rea supposedli OUT CMD IN WAIT ei LDA FLAG ;TEST ALL DISK? ORA A JZ COMPLT JMP LOOP2 PUT: MOV M,A INX H DCR B JNZ PUT RET PUTZERO: MVI B,PRE0 XRA A CALL PUT RET ERROR: PUSH PSW PRINT  W2!>(6#>6#r#:w#s#6#6#> 6#>{=•:•+:w#6#>{S> ¨!!>  :z:l> :Gzl72: SUPERBIOS disk formats Th SUPERBIO singl densit eigh inc forma i completel IB͠ standar 3740 Th disk shoul b readabl b an CP/ standar singl densit system Not tha th Advance Micr Dig standar singl densit disk tr runnin th SUPERBIOӠ forma progra wit th FORMAԠ SYSTE͠ TRACKӠ ONL option Thi wil fil th oute tw track wit E an no hur any of the data. Th SUPERBIO doubl densit forma forive Status : '> POP PSW PUSH PSW HEXOUT ;PRINT ERROR STATUS POP PSW PUSH PSW ANI 80H JZ ERROR1 POP PSW PRINT JMP COMPLT ERROR1: POP PSW ANI 40H ;SEE IF WRITE PROTECT JZ COMPLT PRINT 2à Enter Density, Single or Double (S,D) :$t D´ûS¹>N2 Enter Disk Drive to be Formatted (A,B,C,D) :$ >2>2:G:!"!P>N:5zB;zB{ N*^{#"ʡ>6#r#:w#s#6#6#>N >6#>6#>NP%>N £!!>  ::=>22zMl> :lw#ita forma progra fill al sector wit E5' i accordanc with standard practice. Som eigh inc singl densit disk fro othe system ma no b readabl a firs wit th SUPERBIOS Thi i becaus the hav od byte locat  eigh inc disk ha th firs trac o eac dis b singl density i accordanc wit IB͠ practice Al track o minifloppie ar doubl density Byt 7 o trac zero secto i cod byt (thi i th standar location) Ou chose t optimiz sequentia secto operation suc a progra loads sinc thes operation ar th mos sensityiv to the skew factor. ntries fou lis entries on reader an on punch tabl entr consist o tw bytes Th firs byt i th hig orde byt o th addres o th devic handler Th handle module alway star o pag boundary s thi byt i suffici lis devices an dis handlers Eac handle module starts on a page boundary with a jump table. Character handlers: The jump table is : table+0 jp poll console character in table+3 jp console character input ta home table+3 jp select disk table+6 jp set track table+9 jp set sector table+0C jp read sector table+0F jp write sector table+12H jp flush buffers Eac routin excep flus receive th nolec routin returnin nonzer valu i HL) th bi wil b reset an bi 7 of A will be reset until the next warm boot. Selec als receive paramete i B i zer o entr t selec i th las dis succesfull selecte wa idisk select will be denied. DMA address handling: Unde certai conditions th BDO wil issu selec dis cal t ne disk an expec th previou DM addres t remai i force Therefore th Se DM addres BIO cal simpl sto enabl improve performanc i a interrupt- drive enviromen sinc contex switchin wil b堠 fast Therefore w recommen tha an modification yo mak t th cod d no us th alternat registers excep i you interrup hanca b rewritte t b polle i yo nee th CPՠ t sampl interrupt durin th see period realtim cloc usin 6 H interrup wi los tim durin dis access bu H clock should be OK. Example SUPERBIOS module: Th code ar E fo singl density E fo singl side doubl density an E fo doubl side doubl density Ther i n doubl side singl densit format a ther ar n standard availabl fo suc disks. Doubl densit disk  SUPRERBIOS internal interface specifications Th SUPERBIO i modular tabl drive progra designe for easy expansion and modification. Th firs tw memor page o th SUPERBIOӠ perfor mappin fro logicaen t specif th addres o al th routine i th handler Th secon byt i devic numbe withi th handler Fo example har dis formatte a tw logica drive woul b addresse b tw tabl entries bot wit th sam addreble+6 jp console character output table+9 jp list character output table+0C jp list status table+0F eight character ASCII name for module Th routine receiv exactl th sam paramter a describe i th Crma parameter passe accordin t th CP/ Alteratio guide Th writ routin wil receiv th deblockin informatio i describe i th appendi o secto blocking/deblocking (Se als th cod fo rea an writ i th flopp th sam modul a th ne dis bein selected Thi informatio ma b useful in determining buffer flushing strategies. Th flus entr poin i use b th logica dis selec handler Flus i calle o th currentl selecte dre th valu a fixe locatio (F an F relativ t th star o th BIOS) You rea an writ routine wil hav t ge th DM address from this location before each operation. .pa Interrupt handlers: A th moment th SUPERBIOdlers. Ver fe CP/ program us th alternat registe set I yo us on o thos tha does w sugges yo includ fla byt t indicat t you interrup handler tha they mus sav registers Thi wil b include i th fil RAMDISK.MA i include a a exampl o modula dis driver I show th us o th dis calls an ca b use as is. hav onl on reserve track Th sector ar 102 byte i length Eigh inc disk hav eigh sector pe track fiv inc disk hav four Th physica ske o th dis i thre fo eigh inch tw fo fiv inch Thes number wer unit t physica drivers Thi par o th program will not normally need to be changed. Th logica t physica devic assignmen tabl i a 100 relativ t th star o th BIOS I contain sixtee dis entries fou consol es bu with two device numbers (0 and 1, usually). Thi mappin syste make i possibl t reconfigur th system without having to reassemble the BIOS. Drive module com i tw flavors characte i/ handler (console anP/͠ Alteratio Guide I addition eac routin receive th devic numbe i A Th routine wil retur t their caller whatever the normal code for CP/M 2 would be. .pa Disk Handlers: The jump table is : table+0 jp  modul o th SUPERBIOS) Th device number is passed in A. Selec dis receive tw addtiona paramters O th firs cal t selec give dis afte war boot bi o wil b set I th selec i successfu (know b th seis wheneve dis i differen modul i selected Thi i sig tha an share buffer mus b flushed Flus shoul retur i i th flus wa successful nonzer i a erro occured I flush returns an error code, the new  doe no hav an interrupt- drive code However futur release wil us interrupt fo typeahead har dis controller an possibl othe use a well Th us o th Z8 alternat registe se i reserve fo syste us ONLY Thi wil nex releas o th SUPERBIOS. Th SUPERBIO disable interrupt whe th CP i waitin o a INTR o DR fro th FDC durin see an secto read/write Interrupt canno b enable durin th secto read/write bu th see   buffer equ 2000h monit equ 0f033h ;return to monitor for error memory equ 16h ;to enable monitor PROM ; loader bios access bios equ 500h conout equ bios+0ch seldsk equ bios+1bh settrk equ bios+1eh setsec equ bios+21h setdma equ bios+24h B,(HL) ld (dirbuf),BC push HL call setdma ;use the dirbuf for operations pop HL inc HL ;(HL)=DPB address ld E,(HL) inc HL ld D,(HL) page ex DE,HL ;HL=DPB address ld E,(HL) inc HL ld D,(HL) ;(HL)=sectors per track ld (SPT),DEk page ; Current status of program: ; The disk on which the system file resides has been selected ; and the head has been stepped to the first directory track ; Note that the directory will always start at sector 1 of ; the first non-system traceed to do sector translation? ld DE,(XLT) ;translate table call sectran push HL pop BC notran: call setsec call read or A ld DE,permerr jp nz,error ;physical error pop HL ;sector just read inc HL ld (cursec),HL ; ; The next secto,DE ld DE,nofile jp z,error jr nextsec page ; ; Match: match takes as a parameter HL pointing to a directory ; entry. Match returns the zero flag set if the file matches. ; match: ex DE,HL ;use DE to point to directory ld HL,Filefcb+1 ; ld DE,filefcb+15d ;DE=block allocation area in filefcb ld BC,17d ldir ;move to file fcb ld IY,filefcb+16 ;pointer to next block ld IX,boottbl ;pointer to current table entry call getblk ;returns block # in DE newtbl: push DE call mktr newtbl newtrk: ld (IX+3),A ;spt-1 last sector on track ld BC,4 add IX,BC ;pointer to next track ld B,A inc B ld A,L ;sector number relative to start of last track sub B ld (IX+3),A ;last sector of this block xor A ld (IX+2),A ;stae inc IY ld A,(IY) onebyte: ld D,A inc IY or E ;block # = 0? ret nz pop DE ;lose return in loop jr tbldone ; mktrk gets block # in DE, returns track in BC, 1st sector in HL mktrk: ex DE,HL ld A,(bsh) ld B,A shftblk: add HL,HL  read equ bios+27h sectran equ bios+30h page start: ld SP,100h ;use default buffer ld C,0 ld E,0 ;make seldsk know this is the first call call seldsk ld A,H or L ld DE,badsel jp z,error ;bad select-HL=0000 ;HL=DPH addres ;highest sector number before next track inc HL ld A,(HL) ;Block shift factor ld (BSH),A inc HL ld A,(HL) ld (BLM),A ;block mask inc A ld (blksec),A ;sectors per block inc HL inc HL inc HL ld A,(HL) ;A=msb of DSM or total block k, and will occupy consecutive ; sectors through the end of the directory. The total number ; of sectors occupied is (maxdir)/4, but they may be on more ; than one track. ; nextsec: ;read next directory sector into the DIRBUF ld HL,(SPT) ld r of the directory (4 entries) is now in the DIRBUF ; Now see if we can find the file ; ld HL,(dirbuf) ld DE,32d ld B,4 nextdir: push HL push DE push BC call match ;match directory entry with FCB pop BC pop DE pop HL jr z,found ;fifirst character in filename to search ld BC,0b0ch ;11 characters to match nextch: inc DE ld A,(DE) ;next character in directory entry and 7fh ;mask file attribute bits cpi ret nz ;no match, return djnz nextch ret page ; ; Now we haverk ;returns track in BC, 1st sector in HL ld (IX),C ld (IX+1),B ;store track ld (IX+2),L ;first sector ld DE,(blksec) add HL,DE dec HL ;HL=last sector of block ld A,(spt) dec A ;sectors numbered 0-(spt-1) cp L jr c,newtrk ;block overrt sector zero ld C,(IX-4) ld B,(IX-3) ;last track inc BC ld (IX),C ld (IX+1),B jr nxtblk page moreblks: push DE ;save new block # ld A,(blksec) ld B,(IX+3) ;last sector so far add A,B ld L,A ;new high sector ld A,(spt) dec A djnz shftblk ;HL=absolute sector number ld DE,(spt) scf ccf ld BC,(trkoff) dec BC mortrk: sbc HL,DE inc BC jr nc,mortrk add HL,DE ;restore sector relative in track ret page ; ; table now contains the track/sector map for all; Program to investigate CP/M directory structures on the disk ; ; Warning! assumes first sector number is 0!!!! ; Will only work for drives with capacity of 64K sectors or less ; (=8 megabytes) bdossecs equ 44 ;sectors to read on warm boot .z80 s ld C,(HL) ;XLT table, low order byte inc HL ld B,(HL) ld A,B or C ;A=0 iff no sector translation ld (trans),A ld (XLT),BC ld DE,7 add HL,DE ;(HL)=DIRBUF address - might as well use it ;for our workspace ld C,(HL) inc HL ldcount of drive ld (blkmsb),A inc HL ld E,(HL) inc HL ld D,(HL) ld (maxdir),DE ld DE,5 add HL,DE ;(HL)=track offset ld C,(HL) inc HL ld B,(HL) ld (trkoff),BC ld (curtrk),BC call settrk ;directory starts at first non-system tracBC,(cursec) sbc HL,BC jr nc,trksame ;haven't gone to next track yet ld BC,(curtrk) inc BC ld (curtrk),BC call settrk ;step disk ld BC,0 ;first sector, new track trksame: push BC ;logical sector ld A,(trans) or A jr z,notran ;do we nle found add HL,DE djnz nextdir ; ; we've search this sector-no match. Was it the last? ; ld HL,(absec) inc HL ld (absec),HL dec HL ;HL=sectors read so far add HL,HL add HL,HL ;sectors x 4 = directory entries ld DE,(maxdir) sbc HL the correct directory entry, with HL pointing to ; the the start of the FCB ; Next we expand the block allocation data into a table of items: ; ; dw track, db first sector, db last sector found: ld DE,15d add HL,DE ;(HL)=records in this extent flows to next track ld (IX+3),L nxtblk: call getblk ;get next block # pop HL ;last block scf ccf sbc HL,DE inc HL ;HL=0 if new block adjacent to last ld A,H or L jr z,moreblks ld BC,4 add IX,BC ;set pointer to next track item j cp L jr c,newtrk ;this block overflows track ld (IX+3),L ;set new last sector jr nxtblk ; getblk returns the block # (IY) in DE and moves IY to the next ; also, exits loop if block # = 0 getblk: ld E,(IY) ld A,(blkmsb) or A jr z,onebyt  the blocks in ; the directory. Now read the table into memory. ; tbldone: ld HL,buffer ;start of CCP-starting DMA nxttrk: push HL ;unitialized data-sector count push HL ;current DMA ;read sectors of next track ld HL,(bootptr) ;poinpop BC ;sector data ld A,B ;last sector to read inc C ;read next sector cp C jr c,nxttrk ;done with last sector ld DE,128 add HL,DE ;update DMA push BC push HL ld B,0 ;C=sector to read (<256) ld DE,(xlt) call sectran ld C;sectors in this track add HL,DE ld A,bdossecs ;number of sectors for wboot cp L jr z,movtbl ;this track ends exactly at the BIOS jr nc,nxtitem ;keep reading table ;this is the item we must cut down ;B=first sector, C=last sector, ow move image to execution ;area ld HL,buffer ld DE,(buffer+1633h) ;ccp start ld C,0 ld A,(filefcb+15) ;128 byte records allocated rrca rr C ;carry=> odd number of records and 7fh ld B,A ldir ;transfer jp buffer+1600h ;coldboot s/block) BLM: ds 1 ;block mask = records/block-1 blkmsb: ds 1 ;non-zero is >255 blocks on drive ;=msb of DSM in DPB blksec: ds 2 ;sectors per block (BLM+1) dirbuf: ds 2 ;address of DIRBUF trans: ds 1 ;0 if no sector translation XLT: ds 2 ;2 ;sector register data equ cmd+3 ;data register wait equ 14h ;INTRQ and DRQ synch port (see manual) memry equ 16h ;memory control port ; sector deblocking equates hstcnt equ 8 ;number of sectors in buffer hstshft equ 3 ;shift factor for # ofe equ 3 ;used to select various consoles and printers cdisk equ 4 ;default disk user number retries equ 10 ;retry count for disk operations page 60 seekrate equ 1 ;6ms for 8", 12ms for 5" ; ; BIOS jump table ;start: jp coldboot ;wboota: jp wbootion 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 ; ; Console/list drivers ;t to boottbl entry ld C,(HL) inc HL ld B,(HL) ;BC=track push HL ld A,B or C jr z,bootdone ;last track done call settrk pop HL ;boottbl pointer inc HL ld C,(HL) ;first sector dec C ;will be incremented before setsec inc HL,L ld B,H call setsec call read or A ld DE,permerr jr nz,error ;physical read error jr nxtsec bootptr: dw boottbl ;initial track value page ; ; the .SYS file is now in memory starting at (buffer) ; ; we must go through it and remoE=C-B+1 ;A=bdossecs, L=sectors through end of track ld D,A ld A,L sub D ;A=sectors to remove ld D,A ld A,C sub D ld (IX+3),A ;must contain at least one sector in track page ; ; table has now been modified for CP/M wboot use ; jump ;-------------------------------------------- ; ; TEmp! error: ex DE,HL ld B,(hl) inc HL call pstrng ld HL,errmsg call pstrng ld B,11d ld HL,filefcb+1 call pstr2 ld A,4fh out (memory),A jp monit pstrng: ld B,(HL) itranslate table address SPT: ds 2 ;sector per track count maxdir: ds 2 ;number of directory entries on disk trkoff: ds 2 ;track offset curtrk: ds 2 ;current track cursec: ds 2 absec: ds 2 ;absolute sector ;messages badsel: db 6,'Select' pe.z80 ;-------------------------------------------------------------------------- ; ; Floppy disk loader bios ; ;-------------------------------------------------------------------------- true equ 0ffffh false equ 0 mini equ false ;true for min sectors in buffer if mini ddpspt equ 4 ;double density physical sectors per track tracks equ 39 ;minifloppies else ddpspt equ 8 tracks equ 76 endif dpblen equ 15 ;length of a DPB ; disk hardware parameter offsets density equ 0 ;0=singlet ret dw 0 ret dw 0 jp const jp conin jp conout ; jp list ; jp punch ; jp reader ret dw 0 ret dw 0 ret dw 0 jp fhome jp fseldsk jp fsettrk jp fsetsec jp fsetdma jp fread ; jp fwrite ret nop nop ; jp listst 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) cpu: ;standard console/list routines for CPU serial ports jp pserin ; jp serin ;these three go direct to serial jp ser ld B,(HL) ;last sector inc HL ld (bootptr),HL ;save pointer pop HL ;DMA pop DE ;old sectors push BC ;new sectors push HL ;DMA nxtsec: pop HL ;DMA push HL ld B,H ld C,L ;move to BC call setdma pop HL ;last DMA ve all the BIOS sectors ; to make it a table of CCP and BDOS sectors only for wboot bootdone: ld IX,boottbl-4 ld HL,0 ;count of sectors in table so far nxtitem: ld DE,4 add IX,DE ld B,(IX+2) ld A,(IX+3) ld C,A sub B inc A ld E,A IX+3 is end of last table entry movtbl: push IX pop HL ld DE,boottbl-4 sbc HL,DE ;HL=length to move ld B,H ld C,L ld HL,boottbl ld DE,buffer+1637h ;boottbl in buffer-after jump table ldir ;move table ;boottbl filled in, nnc HL ;HL=first character, B=count pstr2: push HL ld C,(HL) push BC call conout pop BC pop HL djnz pstr2 ret ;storage filefcb: db 0 ;drive 'A:' db 'CPM ' db 'SYS' ds 20 BSH: ds 1 ;block shift factor = log2(recordrmerr: db 4,'Read' nofile: db 14,'File not found' errmsg: db 14,' error: file ' boottbl: ds 20 end ifloppy BIOS special equ false ;true for 8"-5" special board bootdrv equ 0 ;floppy to boot from bootcon equ 0 ;console for loader messages ; board hardware equates cmd equ 0ch ;fdc command register trk equ cmd+1 ;track register sec equ cmd+, 1=single side double D, 2= 2S2D seekrt equ 1 ;seek rate 0=3ms, 1=6ms, 2=10ms, 3=15ms 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 iobyt ret dw 0 jp sectran page ; console vectors for later use const: ld A,bootcon jp pserin conin: ld A,bootcon jp serin conout: ld A,bootcon jp serout ; ; Sectran input: Logical sector in BC, translate table in DE ; no transla out ; pserin: ;poll serial in-return A=0ff if char ready, else 0 add A,A inc A ;A=command port ld C,A in A,(C) and 1 ret z ;no character waiting ld A,0ffh ret serin: ld B,A call pserin ld A,B jr z,serin ;loop until c, 3=15ms if mini db ddpspt else db 26 ;physical sectors per track - 26 in SD, ddpspt in DD endif db 0 ;track drive currently set at endm ; ; CP/M disk tables fDPHbase: dw trans,0,0,0 dw dirbuf,fdpbase dw 0,0 ; ; DPB's for the thrck offset (system tracks) ssdddpb: ;single sided double density dw 8*ddpspt ;128 byte sectors per track db 4 db 0fh db 0 dw (tracks*ddpspt/2)-1 ;each of 76 tracks has ddpspt/2 2K blocks if mini dw 63 else dw 127 endif if mini fsettrk: ld A,C ld (iotrk),A ret fsetsec: ld A,C ld (iosec),A ret fsetdma: ld (iodma),BC ret page ; ; Fseldsk selects the physical floppy in A (0-3) fseldsk: ld D,bootdrv ld E,C ;save logical disk call getden ;will te table ld (HL),E inc HL ld (HL),D putdpb: ld DE,9 ;offset of DPB in DPH add 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 HL,0 ret ;return error page ; his may be first physical i/o out (trk),A 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 ret z ;already there  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 xor A ;no errors ret ;trans;step to correct track ; ; diskio actually reads or writes the necessary sector ; it assumes that the head has already settled on the correct track ; (and that the head has been selected on the correct side!) ; and that the bytes in rdwrite for R/W ettled. Bit 2 will give a 15 ms delay ld E,A ld A,(IX+density) or A ld D,1 ;one sector i/o transfer for single denisty jr z,dmasingl ;use the CP/M DMA buffer in single density ld HL,hstbuf ;use host buffer for double density operations ld Dharacter received add A,A ld C,A in A,(C) and 7fh ;mask high order bit ret serout: ld B,C ;character to output add A,A inc A ld C,A serst: in A,(C) and 4 jr z,serst dec C out (C),B ret page page ; ; Floppy disk drive driee formats of disk: ; ; 8" Single sided, single density ; 5" Single sided, double density ; 5" Double sided, double density ; fdpbase: sssddpb: ;single density (1K block) dw 26 ;sectors per track db 3 ;block shift (log2[block size/128]) db db 80h else db 0c0h endif db 0 dw 32 dw 1 dsdddpb: ;double sided double density dw 16*ddpspt ;one track consists of both sides db 4 db 0fh db 0 dw (tracks*ddpspt)-1 ;each of 76 tracks has ddpspt 2K blocks if mini dw 127 elsset 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; 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 ld A,C out (data),A ld A,(IX+seekrt) ;seek rate mask or 1ch ;seek with verify di out (cmd),A in A,(wait) ei rla jr c,seekerr ;no INTRQ from FDC in A,(cmd) and 10011001b ;seek error, CRC error, or incomplete jr nz,seeker fer done rddbl: call sidesec call readprep or A ret nz ld (bufvalid),A ;buffer contains valid data ld A,(iotrk) ld (blktrk),A ld A,(iosec) and hstcnt-1 jr movrd rdsngl: ld A,(iosec) ld (psec),A ;physical sector same as CP/M seand sector size have been filled diskio: ld A,retries ld (retryc),A iotry: ld A,0d0h ;force interrupt no conditions di out (cmd),A ld A,(oper) ld B,A ld C,data ;prepare for indirect I/O intruction ex (SP),HL ;waste some time ,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 ld E,A ver module ; dskparm: ;disk hardware parameter block ;one block for each drive rept 4 if mini 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 7 ;block mask ([block size/128]-1) db 0 ;extent mask dw 242 ;highest block on disk (numbered from 0) dw 63 ;directory entries-1 db 0c0h ;alloc0 -first two bits for two blocks for Dir db 0 ;alloc1 dw 16 ;checked directories dw 2 ;trae dw 255 endif if mini db 0c0h else db 0f0h endif db 0 dw 32 dw 1 trans: ;single density translate table db 1,7,13,19,25,5,11,17,23,3,9,15,21 ;sectors 1-13 db 2,8,14,20,26,6,12,18,24,4,10,16,22 ;secotrs 14-16 fhome: ld C,0  HL,DE djnz fgetdpb ;HL=DPB address ld C,L ld B,H ld HL,fdphbase 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 transla+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 ;t ;seek successful ld (IX+drvtrk),C ret seekerr: call diskerr jr seek2 page 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 parameterctor ;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 strtsel: call seldrv ;physically select drive and head call seek ex (SP),HL ex (SP),HL ex (SP),HL in A,(cmd) and 20h ;bit 5=head loaded rrca rrca rrca ;move bit 5 to bit 2 cpl and B ; the purpose of these manipulations has been ; to set bit 2 of the FDC command if the head ; isn't s  ;save status or B ;B returned from rdwrite is lost bytes count ret z ;if status OK and no lost bytes call diskerror call seek or A jr z,iotry ;if nonzero then hopeless seek error ret ; ; rdwrite does the actual transfer to/from theds of nice messages ; diskerror: ld A,(retryc) dec A jr nz,restore ;more retries to attempt ld A,1 ;return error code to CP/M pop DE ret ;return to BDOS ; ; ; Restore is called from a disk operation with A=retries left ; restore: uble density ; sidesec computes the correct physical sector and side ; sidesec: ld A,(iosec) and not(hstcnt-1) ;computer first CP/M sector in block ld (blksec),A sideflsh: ;called to set up for a flush rept hstshft rrca endm ;A=ph ld B,A ld A,(blktrk) cp B jr z,rttrk ;on right track, at least 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 ; mkbufad receiv djnz shft1 ret page ; ; Getden attempts to find the density of the disk in drive (D) ; by trying to read the current track address in both densities ; If the attempt is successful, Getden will update the ; dens, pspt, and drvtrk fields of the p if mini ld (IX+density),A ;double density for minifloppies endif ld (iosec),A ;read sector 1 ld HL,hstbuf ;buffer has already been flushed ld (iodma),HL call rdsngl or A ret nz ;can't read sector ld A,(hstbuf+7fh) ;code byte for D, physical for SD blksec: ds 1 ;first logical sector in current host blk2sec: ds 1 ;8th CP/M sector in an unallocated 2K block blktrk: ds 1 ;track the buffer is from psec: ds 1 ;current physical sector bufvalid: db 0ffh ;buffer contains valid dahould be shared by all disk modules as much as possible dirbuf: ;coldboot code lives in the directory buffer ; hstbuf equ dirbuf+128d ;host sector deblocking buffer ;no allocation vectors needed end  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: ld (retryc),A in A,(cmd) and 00010000b ;bit 4=record not found ret z ;try again if record was found but ;read/written with error resto1: ;restore to track 0 and seek again ld A,(IX+seekrt) ;get seek rate mask or 00001100b ;head lysical 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 ; ; inbues A=relative sector in host buffer ; returns HL=start of CP/M sector ; uses B,HL,DE mkbufad: 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 DEaramter table ; If E (logical disk) is zero, then getden assumes the density hasn't ; changed (if it has, then we can't do a warm boot-table is wrong getden: ld A,0d0h ;reset FDC out (cmd),A ld A,D call getparm if mini if not special sedisk type OR A jr z,codeok ;some SD disks have old loaders here sub 0e5h ;code for a normal single density disk cp 3 ret nc ;not our code byte codeok: ld (IX+density),A or A jr z,snglspt ld A,ddpspt ;physical sectors on one side of Dta for (blksec) ;0 = valid data wrtpend: db 0 ;write pending from buffer iodma: dw 80h ;current dma address retryc: db 0 ;number of retries left curfpy: db 0 ;current selected physical floppy drive head: db 0 ;head control = 0 or 1 oper: db 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 ; disk error will eventually have all kinoad, restore, verify track 0 out (cmd),A tk0wait: in A,(cmd) and 00000100b ;at track 0 jr z,tk0wait xor A out (trk),A ;back at track 0 ld (IX+drvtrk),A ;update track table ret page ; ; sidesec is the read/write preparation for dof returns carry flag set if sector no 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 ld A,(iotrk) ,(iodma) ret ; ; 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,DEt 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 if not mini ld (IX+density),A ;track zero always single density endif inc A D jr putpspt snglspt: ld A,26d ;single density physical sectors putpspt: ld (IX+pspt),A xor A ret ;no errors page ; ; Floppy disk driver storage ; iotrk: ds 1 ;current track for current disk iosec: ds 1 ;current logical sector for D 0 ;operation (read/write) to be performed next trkstor: db 0 ;storage for iotrk during a flush hwptr: dw dskparm ;storage for pointer to current hw parameters page ; ; disk buffers ; These are not part of the floppy driver module as such and ; s 1!V:] (J\͒< !QQ2|! DM~\͍ ].!QQ2i!]V!XQ7 (22A8bF!V7 F2͗!xV!Q7 (G2A8b!Q7 )F:2 :] (:k2~ >2͗!xVÛF!QADVA loa th syste fil int memor startin a som buffe locatio (normall 2000H) Th loade the determine th loa addres o th CP/ syste an blockmove i t tha address Th loade als fill i tabl i th SUPERBIOtrac onl fro th sourc dis t th destination Afte runnin LDRGEN yo mus transfe valid CPM.SYS file to the disk for it to be bootable. Customizing the loader: Th loade i .CO fil whic execute a 100H I yo name as a command parameter to LDRGEN: LDRGEN B:CUSTMLDR.COM Th loade sourc i include fo you use Th loagica functio o th loade i findin fil o th defaul dis ca b use t suppor loadin o syste file froNCED MICRO DIGITAL LDRGEN VER 2.0 for the Super Quad Z80 SBC with eight inch drives Enter source drive (A,B,C,D) or type if in memoryPlace source disk in drive and type Enter destination drive (A,B,C,D) or type to rebootPlace dest SUPRBIOS loader operation Th SUPERBIO make us o syste fil loade t brin th syste int memor o col boot Th loade i allowe t b maximu o C80 byte long I th standar implementation th loa whic contain ma o wher o th dis th fil CPM.SY i located Thi informatio i necessar s tha th SUPERBIO ca reloa th CC an BDO o war boot Tha i wh yo mus no chang densit o th syste dis i i i  wis t boo of dis othe tha flopp drive yo mus integrat customize BIO fo th loader Th BIO i org' a 500Ƞ wit standar BIO jum table an mus suppor consol outpu an al dis function excep writ (fo th boo volum t volatil syste volum (e.g memor disk) Modif th loade s tha afte th syste i loade an blockmoved th coldboo routin return t th loader The rea th syste fil fro th boo volum an writ theCOPYRIGHT (C) 1982, ADVANCED MICRO DIGITAL o&)__> ?> ?F~?#VO͈|~2w! $'**j! "v2>!4(KNzy=.[DM~2: 8!'V7 Fç<2:(͆͂(:wination disk on drive and type Physical error in disk operation - type to continue, anything else to quitLDRGEN successfulBad drive specification (A,B,C,D)Can'nt open file: Error in reading file: de look fo th fil CPM.SY o flopp driv (tha is tha driv whic repond t th physica lin Driv Selec ) I th fil i no present th loade wil respon wit a erro messag t th terminal Otherwise th loade wil floppy sinc disk o differen densit hav th CPM.SY fil i differen places an changin dis density makes a warm boot impossible. Th LDRGE progra i th equivalen t SYSGE i standar system I transfer th oute  singl boo disk). Sinc th loade i .CO file yo ca debu i b runnin th loade a norma transien progra unde you debugger Whe th custo loade i debugged i ca b LDRGEN' ont dis b passing the file t th syste dis usin BDO calls.  ; -- NEW MACRO LIBRARY -- NSPT EQU 51 ;NUMBER OF SECTORS/TRACK NTPD EQU 77 ;NUMBER OF TRACKS/DISK ; ; SAVE MACRO SAVE SPECIFIED REGISTERS ; ; SAVE R1,R2,R3,R4 ; ; R1-R4 MAY BE B,D,H OR PSW SAVED IN ORDER SPECIFIED ; IF REGS ARE OMITTED SAVE B,> IF NUL R EXITM ENDIF POP R ENDM ELSE IRPC REG,HDB POP REG ENDM ENDIF ENDM ; ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; CHARIN MACRO CONSOLE INPUT TO A ; ; CHARIN ADDR ; CHARIN MACRO ADDR MVI C,1 T MACRO LOCAL EXIT MVI C,11 CALL 5 ORA A JZ EXIT MVI A,0FFH EXIT: ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; INPUT MACRO INPUT CHARACTER STRING FROM CONSOLE ; ; INPUT ADDR,BUFLEN ; ; ADDR START OF TEXT BUFFERTERAL'> ; ; PRINT ADDR,$ (ASCII OUTPUT UNTIL $) ; PRINT ADDR,L,H (HEX OUTPUT L CHARACTERS) ; PRINT ADDR,L,A (ASCII OUTPUT L CHARACTERS) ; ; LITERALS MUST BE IN SINGLE QUOTES 'LIT' ; IF LITERAL CONTAINS CONTROL CODES ENTIRE STRING IN <> BRACKE IF NOT NUL ?STRING LXI D,?STRING ;;POINTER TO STRING ENDIF MVI C,9 CALL 5 ;;BDOS ENTRY ELSE IF NOT NUL ?STRING LXI H,?STRING ;;POINTER TO STRING ENDIF MVI C,LEN ;;LENGTH OF STRING PLOOP: PUSH B PUSH H IF TC=H MOV A,M ;;GET A B RIGHT 4 CALL OUTCHR RESTORE PSW OUTCHR: ANI 0FH ;;MASK 4 BITS ADI 90H ;;ADD OFFSET DAA ;;DEC ADJUST ACI 40H ;;ADD OFFSET DAA ;;DEC ADJUST MOV E,A ;;TO E FOR OUTPUT MVI C,2 ;;CONOUT JMP 5 ;;CALL BDOS HEXEND: HEXOUT MACRO ?ADDX D ;;GET A CHAR ORA A ;;CHECK FOR END OF BUFFER RZ SUI '0' ;;CHECK < 0 AND CONVERT TO HEX RC ADI '0'-'G' ;;CHECK > F RC ADI 6 JP IN2 ;;NO BETWEEN A AND F ADI 7 RC IN2: ADI 10 ORA A ;;CLEAR CARRY MOV C,A ;;HEX DIGIT TO C MUT ADDR ; ; IF ADDR OMITTED, NUMBER ASSUMED TO BE IN HL, ELSE LOADED TO HL ; LEADING ZEROS SUPRESSED. MAXIMUM NUMBER 65,767 ; DECOUT MACRO ADDR LOCAL ENDDEC,DX JMP ENDDEC @DECOUT:SAVE ;;PUSH STACK LXI B,-10 ;;RADIX FOR CONVERSION LXI D,-. . . . . . . . . . . . ; ; DECIN MACRO CONVERT A NUMBER IN MEMORY FROM ASCII TO BINARY ; ; DECIN ADDR ; ; ADDR POINTS TO MEMORY LOCATION OF START OF NO, IF ; ARG OMITTED POINTER ASSUMED LOADED TO HL ; MACRO RETURNS WITH CARRY SET IF ALPHABETIC D AND H ; SAVE MACRO R1,R2,R3,R4 IF NOT NUL R1&R2&R3&R4 IRP R,<,,,> IF NUL R EXITM ENDIF PUSH R ENDM ELSE IRPC REG,BDH PUSH REG ENDM ENDIF ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; ;;CONSOLE INPUT CALL 5 ;;CALL BDOS IF NOT NUL ADDR STA ADDR ENDIF ENDM ; ; ; . . . . . . . . . . . . . . ... ... . .. . . . . . . . . ; ; CHAROUT MACRO CONSOLE OUTPUT FROM A ; ; CHAROUT ADDR ; CHAROUT MACRO ADDR IF NOT NUL ADDR LDA  ; BUFLEN LENGTH OF BUFFER (DEFAULT IS 127) ; INPUT MACRO ADDR,BUFLEN MVI C,10 IF NOT NUL ADDR LXI D,ADDR ;;SET BUFFER ADDRESS ENDIF IF NOT NUL BUFLEN MVI A,BUFLEN ;;SET BUFFER LENGTH STAX D ELSE MVI A,127 STAX D ;;SET BUFFER DEFTS ; MACRO ALSO ASSEMBLES ; CR = CARRIAGE RETURN ; LF = LINE FEED ; BEL = BELL CODE ; ; MACRO ASSUMES ADDR ALREADY LOADED TO HL IF ARGUMENT OMITTED ; PRINT MACRO ?STRING,LEN,TC LOCAL @OVER,@MESS,PLOOP,PASTCR,@CRLF CR SET 0DH LF SET 0AH YTE HEXOUT ;;CONV TO HEX & OUTPUT ELSE MOV E,M ;;GET A BYTE MVI C,2 ;;OUT FROM E CALL 5 ENDIF POP H POP B INX H DCR C ;;DECR LENGTH JNZ PLOOP ;;CONTINUE TILL LEN 0 ENDIF ENDIF ENDIF ENDM ; ; . . . . . . . . . . . . . .R IF NOT NUL ?ADDR LDA ?ADDR ENDIF CALL HEXPRN ENDM HEXOUT ADDR ENDM ; ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; HEXIN MACRO CONVERT A NUMBER IN MEMORY FROM HEX TO BINARY ; ; IF NO ARGUMENT MACRO ASSUMES ADDR OFVI B,0 ;;ZERO TO B DAD H DAD H DAD H DAD H ;;SHIFT LEFT 4 DAD B ;;ADD IN NEW DIGIT INX D ;;INCR BUFFER POINTER JMP IN1 ;;RETURN FOR MORE INPUT OVERSUB: HEXIN MACRO ?ADDR IF NOT NUL ?ADDR LXI D,?ADDR ;;LOAD BUFFER ADDR ELSE XCH1 ;;THIS BECOMES NO DIVIDED BY RADIX DX DAD B ;;SUBTRACT 10 INX D JC DX LXI B,10 DAD B ;;ADD RADIX BACK IN ONCE XCHG MOV A,H ORA L ;;TEST FOR ZERO CNZ @DECOUT ;;RECURSIVE CALL MOV A,E ADI '0' ;;CONVERT FROM BCD TO HEX MOV E,A CHAR FOUND ; CONVERSION STOPS WHEN CHAR LESS THAN ZERO IS FOUND. ; BINARY NUMBER IS LEFT IN HL, MAXIMUM 65,767 ; LEAST SIGNIFICANT 8 BITS OF NUMBER IN A. ; DECIN MACRO ADDR LOCAL DLOOP,OVERSUB JMP OVERSUB @DECIN: LXI D,0 ;;ZERO DE XCHG ;;RESTORE MACRO RESTORE REGISTERS (INVERSE OF SAVE) ; ; RESTORE R1,R2,R3,R4 ; ; R1-R4 MAY BE B,D,H OR PSW RESTORED IN ORDER SPECIFIED ; IF REGS OMITTED RESTORE H,D AND B ; RESTORE MACRO R1,R2,R3,R4 IF NOT NUL R1&R2&R3&R4 IRP R,<,,,ADDR ENDIF MVI C,2 ;;CONOUT MOV E,A ;;CHAR TO E CALL 5 ;;CALL BDOS ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; CHARSTAT MACRO CHECK CONSOLE STATUS ; ; RETURN TRUE (FF) IF CHAR READY FALSE (0) IF NOT ; CHARSTAAULT MAXIMUM ENDIF CALL 5 ;;BDOS ENTRY ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; PRINT MACRO PRINT A STRING ON CONSOLE ; ; PRINT (CARRIAGE RETURN, LINE FEED) ; PRINT 'LITERAL' ; PRINT <'LITERAL',CR,LF,'SECOND LI BEL SET 07H IF NUL ?STRING&LEN&TC JMP PASTCR @CRLF: DB CR DB LF DB '$' PASTCR: LXI D,@CRLF MVI C,9 CALL 5 ELSE IF NUL LEN&TC JMP @OVER @MESS: DB ?STRING DB '$' @OVER: LXI D,@MESS MVI C,9 CALL 5 ;;BDOS ENTRY ELSE IF NUL TC  . . . . . . . . . . . . . . ; ; HEXOUT MACRO CONVERT BINARY NO AND OUTPUT TO CONSOLE ; ; HEXOUT ADDR ; ; NUMBER ASSUMED IN A IF NO ARGUMENT ; HEXOUT MACRO ADDR LOCAL OUTCHR,HEXEND JMP HEXEND HEXPRN: SAVE PSW RRC RRC RRC RRC ;;SHIFT HEX STRING IN HL ; ANSWER LEFT IN HL WITH LEAST SIGNIFICANT 8 BITS IN A ; CARRY SET ON ERROR. CONVERSION STOPS WHEN ZERO IS ; FOUND IN HEX STRING. ; HEXIN MACRO ADDR LOCAL IN1,IN2,OVERSUB JMP OVERSUB @HEXIN LXI H,0 ;;ZERO NUMBER IN1: LDAG ENDIF CALL @HEXIN MOV A,L ;;LEAST SIGNIFICANT 8 BITS TO A ENDM HEXIN ADDR ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; DECOUT MACRO CONVERT A POSITIVE INTEGER TO DECIMAL AND OUTPUT ; TO THE CONSOLE. ; ; DECO;;TO E FOR OUTPUT CHAROUT ;;CONSOLE OUTPUT RESTORE ;;POP STACK RET ENDDEC: DECOUT MACRO ?ADDR IF NOT NUL ?ADDR LHLD ?ADDR ENDIF CALL @DECOUT ;;CALL THE SUBROUTINE ENDM DECOUT ADDR ENDM ; ; ; ; . . . . . . . . . . . . . . . .  ADDR POINTER TO DE, ZERO TO HL DLOOP: LDAX D ;;GET A ASCII DIGIT SUI '0' ;;CONVERT TO BCD AND TEST ANA A ;;RESET CARRY RM ;;TERMINATE CONVERSION IF < ZERO CPI 10 ;;CHECK LEGITIMATE DIGIT (0-9) CMC ;;COMPLEMENT CARRY RC ;;RET WITH CAR. ; ; MOVE MACRO MOVE A BLOCK FROM SOURCE TO DEST ; ; MOVE SOURCE,DEST,COUNT ; ; SOURCE TO HL MACRO ASSUMES REGISTERS ALREADY ; DEST TO DE LOADED IF ARG OMITTED ; COUNT TO BC ; MOVE MACRO SOURCE,DEST,COUNT LOCAL OVERSUB JMP OVERSUB @MOVE:T ; ; CONSTANT OMITTED, FILL WITH 0 ; END OMITTED, FILL ONE BYTE ; FILL MACRO START,STOP,CONST LOCAL @FILL,BLKLEN BLKLEN SET STOP-START+1 LXI H,START ;;LOAD START ADDR IF NOT NUL STOP IF BLKLEN > 255 LXI B,BLKLEN ;;LOAD BLOCK LENGTH ELRINGS OF SAME LENGTH SET CARRY IF EQUAL ; ; MATCH STR1,'LITERAL STRING' ; MATCH STR1,STR2,LENGTH ; MATCH ; ; DE POINTS TO STR1 MACRO WILL LOAD REG IF ARG ; HL POINTS TO STR2 PRESENT ; C CONTAINS LENGTH ; ; SUBTRACT STR2 FROM STR1 AND SET FLAG;RETURN INX H INX D ;;INCR STRING POINTERS JMP M1 ;;TRY SOME MORE OVERSUB: MATCH MACRO ?STR1,?STR2,?LEN LOCAL LITSTR,ENDLIT IF NUL ?STR1&?STR2&?LEN CALL @MATCH ELSE IF NOT NUL ?STR1 LXI D,?STR1 ;;LOAD STRING1 POINTER ENDIF IF NULD SET CARRY IF FOUND ; ; INSTR STRING,LENGTH,SUBSTR ; ; HL POINTS TO STRING ; DE POINTS TO SUBSTRING ; B CONTAINS STRING LENGTH ; C CONTAINS SUBSTRING LENGTH ; ; MACRO RETURNS POINTER TO END OF SUBSTRING IN HL ; INSTR MACRO STRING,LENGTH,SULITSTR,ENDLIT IF NOT NUL ?STR LXI H,?STR ENDIF MVI B,?LEN MVI C,ENDLIT-LITSTR LXI D,LITSTR CALL @INSTR JMP ENDLIT LITSTR: DB ?SUBSTR ENDLIT: ENDM INSTR STRING,LENGTH,SUBSTR ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; DISKIO MACRO EXECUTE BDOS DISK ACCESS PRIMITIVES ; ; DISKIO FUNCTION,PARAMETER ; ; NO FUNCTION ENTRY PARAM ; ; 12 LIFTHEAD ; 13 INITIAL ; 14 LOGIN DISK NO 0 - 1 ; 15 OPEN FCB ; 16 CLOSE FCB ; 17 SESET 22 RENAME SET 23 ?LOGIN SET 24 ?DRIVE SET 25 SETDMA SET 26 ?ALLOC SET 27 ; ?C SET FUNCTION IF NOT NUL PARAMETER LXI D,PARAMETER ENDIF MVI C,?C CALL 5 ;;BDOS ENTRY ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . .RY SET IF ERROR INX D ;;INCR ADDR POINTER DAD H ;;SHIFT LEFT 1 PUSH H ;;SAVE RESULT DAD H DAD H ;;SHIFT LEFT 2 POP B ;;NO * 2 TO B DAD B ;;HL NOW CONTAINS 10*NO MOV C,A ;;ADD PRODUCT TO DIGIT MVI B,0 DAD B JMP DLOOP ;;BACK FOR MOV A,B ORA C RZ ;;EXIT COUNT ZERO MOV A,M ;;GET A BYTE STAX D ;;STORE IT INX H INX D DCX B JMP @MOVE ;;BACK TO MOVE LOOP OVERSUB: MOVE MACRO SRC,?D,?C IF NOT NUL SRC LXI H,SRC ENDIF IF NOT NUL ?D LXI D,?D ENDIF IF NOTSE MVI C,BLKLEN ENDIF IF NOT NUL CONST MVI E,CONST ;;LOAD CONST IF NOT NULL ELSE MVI E,0 ENDIF @FILL: MOV M,E ;;STORE A BYTE INX H ;;INCR MEMORY POINTER IF BLKLEN > 255 DCX B ;;DECR COUNT MOV A,C ;;TEST LIMIT ORA B JNZ @FILLS, ZERO INDICATES MATCH. ; NORMALLY THE SECOND ARG IS A LITERAL STRING AND THE LENGTH ; IS OMITTED. IF THE LEN ARG IS PRESENT THE SECOND STRING ; ARG IS ASSUMED TO BE A MEMORY ADDR. IF ALL ARGUMENTS OMITTED ; REGISTERS ASSUMED ALREADY LOADED. ; M ?LEN ;;TEST FOR LITERAL MVI C,ENDLIT-LITSTR ;;LENGTH OF LITERAL STRING LXI H,LITSTR ;;POINTER TO LITERAL CALL @MATCH JMP ENDLIT LITSTR: DB ?STR2 ;;LITERAL STRING ENDLIT: ;;END OF STRING ELSE IF NOT NUL ?STR2 LXI H,?STR2 ;;LOAD POINTERBSTR LOCAL OVERSUB,S1,SSX JMP OVERSUB @INSTR: MOV A,B ;;STRING LENGTH SUB C ;;SUBTRACT SUBSTR LENGTH CMC ;;COMP CARRY RNC ;;ERROR RETURN SUBSTR > STRING MOV B,A ;;NEW STRING LIMIT TO B S1: SAVE MATCH RESTORE JZ SSX ;;MATCH IF ZE. . . . ; ; SCAN MACRO SCAN A STRING UNTIL A CHAR IS FOUND, SKIP BLANKS ; AND CONTROL CHARACTERS ; ; CARRY SET IF NUMERIC, CARRY OFF IF ALPHABETIC ; ; SCAN MACRO ADDR LOCAL OVERSUB JMP OVERSUB @SCAN: MOV A,M ;;GET A BYTE CPI 21H ;;SPACARCH FCB ; 18 SERNXT FCB ; 19 DELETE FCB ; 20 READ FCB ; 21 WRITE FCB ; 22 MAKE FCB ; 23 RENAME FCB ; 24 ?LOGIN ; 25 ?DRIVE ; 26 SETDMA BUFFER ; 27 ?ALLOC ; SEE CP/M INTERFACE GUIDE FOR DETAILED INFORMATION ON THE ; DISK ACC . ; ; CALLBIOS MACRO CALL BIOS ROUTINES DIRECTLY ; ; CALLBIOS FUNCTION,PARAM ; CALLBIOS MACRO FUNCT,PARAM LOCAL @CALL ; DCOLD SET 00H DWBOOT SET 03H DSTAT SET 06H DCONIN SET 09H DCONOUT SET 0CH ;;CHAR IN C DLIST SET 0FH ;;CHAR IN C DPUNC ANOTHER DIGIT OVERSUB: DECIN MACRO ?ADDR IF NOT NUL ?ADDR LXI H,?ADDR ENDIF CALL @DECIN ;;CALL THE SUBROUTINE MOV A,L ;;LEAST SIGNIFICANT HALF OF NO TO A ENDM DECIN ADDR ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . .  NUL ?C LXI B,?C ENDIF CALL @MOVE ;;CALL THE MOVE SUBROUTINE ENDM MOVE SOURCE,DEST,COUNT ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; FILL MACRO - FILL A BLOCK OF MEMORY WITH A CONSTANT ; ; FILL START,STOP,CONSTAN ;;CONTINUE ELSE DCR C JNZ @FILL ENDIF ELSE IF NUL CONST MVI M,0 ;;STORE A ZERO ELSE MVI M,CONST ;;STORE SINGLE BYTE ENDIF ENDIF ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; ; MATCH MACRO COMPARE 2 STATCH MACRO STR1,STR2,LEN LOCAL OVERSUB,M1 JMP OVERSUB @MATCH: INR C ;;PRE INCREMENT COUNT (IT MIGHT BE ZERO) M1: DCR C ;;DECR LENGTH COUNT RZ ;;RETURN IF MATCH FOUND LDAX D ;;GET A BYTE FROM ONE STRING SUB M ;;COMPARE WITH OTHER RNZ ; TO STRING2 ENDIF MVI C,?LEN ;;LOAD STRING LENGTH CALL @MATCH ;;CALL MATCH SUBROUTINE ENDIF ENDIF ENDM MATCH STR1,STR2,LEN ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; INSTR MACRO SEARCH STRING FOR SUBSTRING ANRO ON RET ANA A ;;RESET CARRY DCR B ;;BYTES LEFT RM ;;FINISHED IF MINUS, NO MATCH INX H ;;INCR STRING POINTER JMP S1 ;;TRY AGAIN SSX: MVI B,0 ;;SET D TO 0 DAD B STC ;;SET CARRY RET OVERSUB: INSTR MACRO ?STR,?LEN,?SUBSTR LOCAL E OR LESS? RP INX H ;;INCR POINTER JMP @SCAN ;;KEEP SEARCHING OVERSUB: SCAN MACRO ?ADDR IF NOT NUL ?ADDR LXI H,?ADDR ENDIF CALL @SCAN ;;CALL SUBROUTINE CPI 3AH ;;NUMBER OR ALPHA ENDM SCAN ADDR ENDM ; ; . . . . . . . . . . . . ESS PRIMITIVES ; ; DISKIO READ,FCB (TYPICAL MACRO CALL) ; DISKIO MACRO FUNCTION,PARAMETER LIFTHEAD SET 12 INITIAL SET 13 LOGIN SET 14 OPEN SET 15 CLOSE SET 16 SEARCH SET 17 SERNXT SET 18 DELETE SET 19 READ SET 20 WRITE SET 21 MAKE  H SET 12H DREADER SET 15H DHOME SET 18H DSELDSK SET 1BH DSETTRK SET 1EH DSETSEC SET 21H ;;SECTOR NO IN C DSETDMA SET 24H ;;DMA ADDR IN BC DREAD SET 27H DWRITE SET 2AH ; ?F SET FUNCT IF NOT NUL PARAM MVI C,PARAM ENDIF LHLD 1 ;;ADDR OF B MOV A,H CMP D ;;COMPARE HIGH BYTES JNZ @END MOV A,L CMP E ;;COMPARE LOW BYTES @END: ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; DJZ MACRO DOUBLE PRECISION TEST HL AND JUMP ON ZERO ; DJZ MACRO ADDR MOV A,H ORAOINTER LXI D,INCR DAD D ;;DOUBLE ADD SHLD POINTER ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; FILFCB MACRO FILL IN THE ID FIELDS OF FCB ; ; FILFCB FCB,IDSTRING ; ; IDSTRING CONTAINS FILE NAME AND TYPE (FILNAM.TYP) AX D ;;GET ID BYTE CPI 0 ;;ZERO END OF FIELD RZ CPI ' ' ;;SPACE END OF FIELD RZ CPI '.' ;;PERIOD TYPE SEPARATOR JZ F4 ;;DO TYPE MOV M,A ;;STORE NAME BYTE INX H INX D ;;INCR POINTERS DCR C ;;DECR MAXIMUM COUNT JP F3 ;;LOOP BACIF CALL @FLFCB XCHG ENDM FILFCB FCB,IDSTRING ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; SETTRK MACRO SET AND TEST TRACK NUMBER ; ; CARRY SET IF > NTPD-1 ; SETTRK MACRO TRKNO LOCAL ENDTRK IF NOT NUL TRKNO . . . . . . . . . . . ; ; HALF MACRO DIVIDES A 16 BIT NUMBER BY 2 ; HALF MACRO I LOCAL OVER JMP OVER @HALF: XRA A ;;CLEAR CARRY MOV A,H RAR ;;SHIFT UPPER HALF MOV H,A MOV A,L RAR ;;SHIFT LOWER HALF MOV L,A RET OVER: HALF MACRO=!v"z!w6!u#+w+wz >ZxG}o|g"|! :m c p!"xp ~#c*|!:m ʅ xä SYNCRONIZATION ERROR$ {°~#o}oҼüÅ*zZ# :m m! ~ #* DM! x  wIOS MVI L,?F ;;JUMP OFFSET SHLD @CALL+1 ;;MODIFY CALL ADDR @CALL: CALL 0 ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; DLOAD MACRO DOUBLE PRECISION INDEXED LOAD HL ; ; LOAD (ADDR + INDX) TO HL ; DLOAD MACRO ADDR,IND L JZ ADDR ENDM ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; DSTORE MACRO DOUBLE PRECISION INDEXED STORE HL ; ; STORE (HL) IN (ADDR + INDX) ; DSTORE MACRO ADDR,INDX IF NUL INDX SHLD ADDR ELSE SAVE H LHLD INDX XCHG  ; CARRY SET IF ERROR (NAME TOO LONG) ; FILFCB MACRO FCB,IDSTRING LOCAL OVERSUB,F1,F2,F3,F4,F5,F6 JMP OVERSUB @FLFCB: MVI M,0 ;;CLEAR FIRST BYTE OF FCB INX H PUSH H ;;SAVE POINTER TO NAME MVI C,11 ;;SIZE OF ID FIELD MVI A,' ' ;;SPACE TK STC ;;SET CARRY NAME TOO LARGE RET F4: INX D ;;SKIP THE PERIOD MOV A,C ORA A JZ F6 ;;TEST C FOR ZERO F5: INX H DCR C JNZ F5 ;;INDEX TO TYPE FIELD F6: MVI C,3 ;;SIZE OF TYPE FIELD F7: LDAX D ;;GET ID BYTE CPI 0 ;;ZERO? RZ ;LDA TRKNO ENDIF CPI NTPD CMC JC ENDTRK MOV C,A ;;TRACK NO TO C CALLBIOS DSETTRK ENDTRK: ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; SETSEC MACRO SET AND TEST SECTOR NUMBER ; ; RETURN WITH CARRY SET < 1 OR > NSP ?I IF NOT NUL ?I LHLD ?I ENDIF CALL @HALF ENDM HALF I ENDM ; ; ; INXM 16 BIT MEMORY INCREMENT ; ; HL LEFT WITH INCREMENTED VALUE ; INXM MACRO ADDR LHLD ADDR INX H SHLD ADDR ENDM #!N#F! D!_>0w#w1!`4~:60+4*"e@u READY FOR "SYSGEN" OR "SAVE 00 CPM00.COM"$*|  CONSTRUCTING 00k CP/M vers 2.2$X IF NUL INDX LHLD ADDR ELSE LHLD INDX LXI D,ADDR DAD D MOV E,M INX H MOV D,M XCHG ENDIF ENDM ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; CPHL MACRO SUBTRACT DE FROM HL AND SET FLAGS ; CPHL MACRO LOCAL @END  LXI H,ADDR DAD D RESTORE D MOV M,E INX H MOV M,D ENDIF ENDM ; ; . . . . . . . . . . . . . . . . . . . . . . . . . . . . ; ; INDEX MACRO INDEX AN ADDRESS POINTER BY A CONSTANT ; ; INDEX POINTER,INCR ; INDEX MACRO POINTER,INCR LHLD PO A F1: MOV M,A ;;FILL NAME WITH SPACES INX H DCR C JNZ F1 POP H ;;RESTORE NAME POINTER MVI C,8 ;;MAXIMUM SIZE OF NAME F2: LDAX D ;;GET BYTE FROM ID FIELD CPI ' ' ;;LEADING SPACES? JNZ F3 INX D ;;SKIP LEADING SPACES JMP F2 F3: LD;FINISHED CPI ' ' ;;SPACE? RZ MOV M,A ;;STORE TYPE BYTE INX H INX D ;INCR POINTERS DCR C ;;DECR MAX COUNT JNZ F7 ;;LOOP BACK RET OVERSUB: FILFCB MACRO ?FCB,?ID IF NOT NUL ?ID LXI D,?ID ENDIF IF NOT NUL ?FCB LXI H,?FCB ENDT ; SETSEC MACRO SECNO LOCAL ENDSEC IF NOT NUL SECNO LDA SECNO ENDIF ORA A ;CHECK ZERO STC JZ ENDSEC CPI NSPT+1 ;CHECK > NSPT CMC JC ENDSEC MOV C,A ;MOVE TO C CALLBIOS DSETSEC ENDSEC: ENDM ; . . . . . . . . . . . . . . . . . ,COPYRIGHT (C) DIGITAL RESEARCH, 1979 1] ʑ?ʑ! __0 r))) O @|r}r.g))å{u INVALID MEMORY SIZE$!$ʡ~/w/wʔ|g*"z|?¸>@G!>0w#w!4~:60+4~u!N#F! x, #  \X COPYRIGHT (C) 1979, DIGITAL RESEARCH _͌> ͒> Ò> Ò͘~#͌ì _2<2#~?  xDIR ERA TYPESAVEREN USER!yO#< Ty#O 321y_͸2y2ͽ:˜1͘A͌>>͌92^ :¥.!_~#fow]!v"!çREAD ERRORçNO FILE^:ÆNO SPACE^ :Ty!B*O=?_s#"^sG!~Ypsp2mÆÆf ͧÆFILE EXISTS _: É: :ʉ=2)ͽÉ T!@k!}|q  O͐  : E  B 2 >: b # : y! 4 5~yy 5 6y Ґ ^H @Oy H  H : – ͬ   #H : !  H ù  H  H $O͐ : 2 *C N#  yx # *DM*s#r*s#ryOxG*0MD!!N: E G>O: \ S *C  :q n& ^#V> O^ "*}:*)= ":O:o"*C  *C !ͮ ~2~2ͦ :2ͮ : O:w:w |g}o *# : :/GyO>2!q*C " ͡  ʔ*J Ҕ^ :Oyʃ?|x | s-|N-# S:2E !~Яw > T   D ^ 6k -äPYy 5*{zBK52T *C G ͻ : w ̈́ n> 2;O ^ DM;}H> "*C  ::dd slO s#r:E ͊ :==»y==»*Ww# *" ͸ *:G#š" ͸ :!w4 i w: Z!E ~=26):B  " *)*)Q;*"E :;:A  2A QÓQÜQ*C }/_|/*W}_*"}o|g":ʑ*C 6:ʑw:2E* *E }DQ>2>ͦ!q:_  !p+q.*   !q*&!p+q*2!p+q*2!p+q*22!p+q*!p+q*!p+q*!p+q*2!p+q* !2:2a{_:ʖ:>Ľʖ:=2–!B!6#5ʖ:Ľ!ͬʧ )!F#xʺ~0wëw!" !~6ͽ:ý(! ! ~ 3#0 Wx x   G ~ # 3x~#B!Y~ɯ2:=!ý:=!:ý^T!~  6?#ˆ:`O> K{͘A͒>:͒͢>:͒͢xK > K > ͒x =qf^!~2>`~22\!!B!~> >#0~O#Cx2͘1)ͽÂf zͧÆBAD LOADCOMf^: ! Â$$$ SUB  x : 2 p & x ~+é 7 2 H ! >w _ : ! 5ͤ N k ͱ ¦ ͱ xʊ #N x : ! 2 ͤ ! 5™ #wO ~x½  p H    y< < ʑ  : !qMD # ) :B O! yoxg*:B O }!N#F "*#*s#r^  ~!J  ! J *:o$*C ~i 6i w**{#z r+s{ozg**͕ **  , w͜ ͸ Ͳ ! !N#F$**O !~#ڋ>*C w~#+w#w+ɯ2E 22 i  ^ *C :~w~͔͔# #  2*C !!~~#~O~G#n,-.‹! w! yG!x͢.:E <ʄ! q!pQ:E <. ʄ$.:E <ʄ i 6}2E x N! ~态O>G~G!~G} *C !r#r#r ^ ͥ_y#x#{óadjmrux}çìûpñns ns<nskLns{?      00k CP/M vers 2.2 1!21 ͻ}ͧͬ,I*lDMͻ:k:j<1y{0!B0}y|zx0y0{00 #͘*~ ""͌#>?͌͘ =_.:;<> Oo$>!Y2*O"ʉ@G:ʐ:wÖx2p0ʹ#*©6?ëw˜0ï#6 ¹.0#*6?w0#6 #6"  ͢ØÆ^ BRͧ9!5‚#~Y‚#"T<ÆALL (Y/N)?^ Tʧ͘!6!~ڇ w4!Y~ʆ͌†t=ʆf ^ T 2o&)|+!<ͧ"C {2!"E 9" 1A 22!ty)K!G_^#V*C   ~E , &-AGMS  !!ô!ô!Bdos Err On : $Bad Sector$Select$File R/O$ :B A2 ! ~6 2E > ! ^#V w#P :B O|^#V#"##"##"##"!O *!O *|!6ʝ 6>*w#w*w#w'û *! J * ""!N#F*^#V*~#foyx *{_zW+ *"**#"͕  : 2 Þ y<_WyOxOxG* ~V5dw^  :ʈNÎ N#Fyʝ*}|\#u* #DM*6# x±**s#r͡ *6#6  ^ >:A #~$=2E k͌  w ~>2!E 5T *C !"C  "C !w# F! w͌ x 2͢ *C  ~<wʃG:!ʎì 4~ʶ ¬:<ʶ$ ʶïZͻ   x >2>2ͻ :!Z2:E w ̈́ ͊ Ͳ  >s+p+q-*C  ͥ!!q#p#w*:B O Y G }*MD "ã:!B w!>2*C ~=2u:B 2~2wE:A *C w>" !""2B !" !r QQQâ~?ͦ ~?r Q *"C Q- Q͜QüQr Q$Q* Oͧ>~ͻ>2!"2!"28!"9:O R![?boot  ç!y2fyʒ>0G!h~ϰwi&))))3!jq!kq ~2koi`"l~Oj#!h~w !kw ?L:f>gA DI$@ A$@$$@H! "!$$" @B$!!!DH$$"H @@BHH  !$$A"D@ "A" "BHA " !$ D B I $ !$$ H@BD D$ 1) Assemble SUPRBIOS.MAC with M80 (Microsoft Macro-80). 2 Determin th lin addres fo th BIOS Th standar SUPERBIO i org' a F200H Calculat you highes RA addres availabl t th SUPERBIO an subtrac E00 t geote. MOVCPM 60 * SAVE 34 CPM60.COM 5) Integrate the new BIOS and CP/M into the CPM.SYS file. DDT CPM60.COM NEXT PC 2300 0100 -M980,1F7F,10 (Mov th CC an BDOӠ t 100Ƞ) if using an offset .COM file (betages to the CCP and BDOS portions of CPM.SYS) Th ne dis shoul b bootabl i i ha ha th loade SYSGEN' on it. .z80 ; org at 0 code relative, control location at link time jp ramhome jp ramsel jp rsettrk jp rsetsec jp rsetdma jp ramread jp ramwrite ret nop nop ;no flush needed db 'RAMDISK ' ;module name for display in more advanced loader ram <257K memory db 7 ;BLM db 0 ;EXM dw 16*banks-1 ;if using 1K blocks dw 63 ;64 directories should be enough db 0c0h ;two directory blocks db 0 dw 0 ;no directory check dw 0 ;no system tracks ramalv: 2*nbanks-1 ;for 1K blocks ram11000000b and B ;get two high order bits of address dec A ;if bank addressed at 4000h jr nz,onetran ;DMA address is masked by memory bank ld A,C or A jr z,dblread ;must do write through secondary buffer ld DE,secbuf ld BC,128  yxzӉxӊY?28L28L8 >:fIyۉ:fV{ۋ:fcxۈ HI DIA!$$$ $" "$D ! $"  $AB " BDD $$D!"DI$!$BH!"IB I$"D HD" " $"! @H !BI " I  $I$I$DI$ !I$@"$"$! $I$I(   th lin address Example syste ha 2 memory-mappe vide boar residing at F800H-FFFFH. F800h-E00H = EA00H for the SUPERBIOS. 3 Us Microsoft-compatibl linke (LINK L80 LINKMT etc t lin SUPRBIOS.REL LIN wil generter alternative!) -ISUPRBIOS.COM -R1600 i usin .HE fil (bes t avoid calculat th offse t mak the .HEX file load at 1700. Load address = EA00H, offset =1700H-EA00H = 2E00H -ISUPRBIOS.HEX -R2E00 .pa Mak sur yo rea;--------------------------------------------------------------------------- ; ; SUPERBIOS implementation example - Memory disk ; ;-------------------------------------------------------------------------- nbanks equ 4 ;number of 16K banks availablehome: ld C,0 rsettrk: ld A,C ld (ramtrk),A ret rsetsec: ld A,C ld (ramsec),A ret rsetdma: ld (ramdma),BC ret ramsel: ld HL,ramdph ret page 60 ; Disk tables for memory disk - see CP/M 2 Alteration Guide for details ramdph: dw trk: ds 1 ramsec: ds 1 ramdma: ds 2 page ;------------------------------------------------------------------------- ; ; The only actual i/o involved is blockmoves between the memory bank ; and the user's DMA area. If the DMA area is masked by the bldir ;move from DMA to secondary buffer ld HL,secbuf ;make onetran think this is DMA address ld C,A ;read/write flag jr onetran dblread: ld HL,secbuf call onetran ;read from bank to secondary buffer ld DE,(ramdma) ld HL,secbuf ld@$@B B HH II$@DI ABI$"$H$H@$$I! H*  $H@@A I $D!!$I"BI"I"@$BIIH$$$$BBI$@BI!"$$BIB@!  ! !! D 15D715E0AB :100A700015E615EC15F515FE1504160A1611162CBB :100A80000E17161D1626162D16411647164D160E54 :100A9000155316040C040C9B1 Regenerating the SUPERBIOS for a different memory size Th SUPERBIO normall reside i 62 CP/ syste wit 6 ˠ o RAM Th extr 2 come fro th fac tha th BIOӠ i relatively large and includes a 1Kbyte deblocking buffer.at a offse .CO͠ file while with L80 you get a .HEX file. LINK: L80: LIN SUPRBIOS[LEA00 L8 SUPRBIOS[P:EA00],SUPRBIOS/N/X/E 4 Creat relocate CP/ usin patche MOVCP͠ a pe Digital Research n th BIO i correctl - 1700 shoul b th BIO jum table. -G0 A>ERA CPM.SYS A>SAV 3 CPM.SY (I yo hav modifie th BIO yo mus sav howeve man page ar necessar t includ th BIO i th .SY file Ther ar 2 p memory equ 16h ;SBC memory control port bnkslct equ 40h ;bank select for memory disk rambase equ 4000h ;bank address - 4000h recommended dirbuf equ 0F900h ;for standard system secbuf equ 0F980h ;use floppy deblocking buffer for two-stage transfer 0,0,0,0 ;no sector translate dw dirbuf ;use dirbuf in floppy module dw ramdpb dw 0 ;no directory check dw ramalv ;allocation vector ramdpb: dw 128 ;128 sectors per track - each 16K bank is a one ;track db 3 ;BSH - use 1K blocks ifank ; address, we must transfer through a secondary buffer. ; ;------------------------------------------------------------------------- ramread: ld C,0 ;read/write flag jr ramio ramwrite: ld C,0ffh ramio: ld HL,(ramdma) ld B,H ld A,  BC,128 ldir ;move from secondary buffer to user DMA ret ;A set to 0 in onetran page onetran: call bankon ;turn on memory bank ld A,(ramsec) srl A ld DE,rambase rr E ;put low order bit of A (odd number of sectors) add A,D ;in E and set at position (ramtrk) setbnk: out (bnkslct),A ;for boards with one bit per bank ret bankoff: xor A out (bnkslct),A ;turn of memory board ld A,00101111b ;turn on 4000h bank of SBC memory ret end  SUPERBIOS distribution diskette contents: CPM.SYS i memor imag o CP/͠ wit th SUPERBIOS Customer wh hav no purchase CP/ fro Advance Micr Digita wil receiv CPM.SY wit th SUPERBIOӠ i desired Th堠 procedur堠 fo incorporatin砠 ᠠ ne BIOӠ i describe䠠 i NEWSIZE.DOC. FORMAT.COM i th SUPERBIO flopp dis forma program I wil onl ru . SBCBOOT.ASM i th sourc fil fo th col loade o trac zer sector one, which is brought in by the monitor PROM. SBCBOOT.HEX i th assemble SBCBOOT.ASM fo installatio i customized loaders. LDRBDOS.MAommand & fdc status register TK EQU CMD+1 ; fdc track register SECMD EQU CMD+2 ; fdc sector register DAL EQU CMD+3 ; fdc data port WAIT EQU 014H ; hardware wait for fdc intrq + drq ; & drive select - restore latch ; ; BUFF EQU 80H  base + sectors/2 in D ld D,A ld A,C ;readwrite flag ld BC,128 or A jr nz,dowrite ;write operation ex DE,HL ;set to read to user DMA dowrite: ldir call bankoff ;restore SBC memory xor A ret ;return with no errors bankon: CC an䠠 BDOӠ zeroe out Se堠 CPMINSTA.DOà fo installatio procedure. USER.DOC give basi informatio necessar fo th operatio o CP/ wit th SUPERBIOS a wel a descriptio o th SUPE QUA SBC bu wil ru unde th previou BIOS Interna detail o th disk formats are described in FORMAT.DOC. LDRGEN.COM i th equivalen o SYSGEN.CO i norma CP/ system C i th sourc fil fo th logica (non-hardwar dependent) portion of the loader. LDRBIOS.MAC i th sourc fil fo th hardwar driver t mak th loade wor wit th SUPE QUAĠ flopp dis  MACLIB Z80 ; ; ;COLD BOOT LOADER FOR CP/M 2.2 ; FOR THE Z80 SBC ;LAST UPDATE 5/15/82 ; mini equ 0 ;set to 0ff for mini ; RTYN EQU 10 ; disk io retries SEEKRT EQU 1 ; rate 0=3ms, 1=6ms, 2=10ms, 3=20ms CDISK EQU 4 ; last disk se ; default dma buffer ORG 0 ; ; WBOOT: MVI A,01101111B OUT 16H lda nsects mov d,a lxi h,100h if mini mvi e,1 ;start with sector 1 for mini else mvi e,2 endif RBLK1: if mini lxi b,dal else LXI B,8000H+DAL ; endif MO ;turn on 16K bank at 4000h ;can use A,B,DE ld A,00101101b ;turn off 4000h bank on SBC out (memory),A ld A,(ramtrk) ;each track is one 16K bank dec A ld B,A ld A,1 jr z,setbnk ;bank 0 shift: add A,A djnz shift ;A now has one bito th content o al th .DO files- CPMINSTA.DOC NEWSIZE.DOC FORMAT.DOC INTRFACE.DOC SUPRBIOS.MAC i th sourc fil fo th SUPERBIOS I ca b edite䠠 an reassemble i modificatio o th  LDRGEN.CO͠ transfer th SUPERBIOӠ col star loade fro sourc (usuall disk t destination Detail o th loade operatio ar i LOADER.DOC. FORMAT.ASM is the source file for FORMAT.COMcontroller. lected by the ccp BELL EQU 07 ; ding MAXDSK EQU 1 ; largest disk number MONIT EQU 0F033H ; monitor boot error entry point if mini loader equ 180h else loader equ 100h endif cmdstatus equ 100h-4 sectors equ 100h-2 ; CMD EQU 0CH ; fdc c V A,E ; get sector OUT SECMD ; set sector MVI A,088H ; get operation OUT CMD NOP READLOOP: IN WAIT ; wait for drq or intrq ORA A ; was it intrq ? JP IODONE INI JR READLOOP IODONE: IN CMD MOV C,A SBCD CMDSTATUS ORA gen END .z80 true equ 0ffffh false equ 0 mini equ false ;true for minifloppy BIOS special equ false ;true for 8"-5" special board m48tpi equ false ;true for 48tpi mini drives m96tpi equ false ;true for 96tpi mini drives ; board hardware equates cmdspt 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 ; disk hardware parameter o---------------------------------------------- ; This is the seek rate constant!! seekrt, above, is an offset! seekrate equ 1 ;6ms for 8", 12ms for 5" ;seek rate 0=3ms, 1=6ms, 2=10ms, 3=15ms ;these times double for minifloppies ; ; BIOS s 16 ;space for four entries page ; ; Seldsk selects the logical disk in C (0-15) ; Seldsk will flush the previous disk if it is in a different driver ; module than the new disk. Seldsk also returns an error if the ; selected disk has not had a drialled ld H,A sub B jr z,samemod ;different disk but same module, don't flush ld B,H push BC push DE ld D,12h ;flush vector call dskjmp ;flush current drive pop DE pop BC or A jr nz,badsel ;error in flushing disk inc A ;make nB ; JRNZ BOOTERROR DCR D ; one less blockr if mini JZ goloader ; exit when zero else jz loader endif INR E mvi a,26+1 CMP E JRNZ RBLK1 BOOTERROR: SDED SECTORS MVI A,01001111B OUT 16H LDA CMDSTATUS JMP MONIT if :100000003E6FD3163A7E00572100011E02010F8079 :100010007BD30E3E88D30C00DB14B7F22200EDA296 :1000200018F6DB0C4FED43FC00B0200A15CA0001A6 :100030001C3E1BBB20D7ED53FE003E4FD3163AFCAF :0400400000C333F0D6 :02007E0018E583 :0000000000  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 ffsets density equ 0 ;0=single, 1=single side double D, 2= 2S2D seekrt equ 1 ;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 parjump 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 ; ; warm boot table ; filled ver installed seldsk:: ld A,(curdsk) cp C jr nz,chgdsk ;selecting a disk different from the current ld B,0 ;no other modules have been selected frstime:: ld D,3 jr dskjmp ;if same disk then do normal select for DPH chgdsk:: ld DE,drvtbon-zero to indicate a new disk module ld H,B ;module address page samemod:: ld B,A ;B=0 if last disk in same module ld L,3 ;seldsk offset push BC inc DE ;(DE) = driver number ld A,(DE) push DE call jphl ;do select pop DE pop BC mini goloader: lxi H,loader lxi D,100h ;move loader from 180h to 100h for mini lxi B,1000h ;largest loader could be ldir jp 100h endif ORG 07eH nsects: if mini db 4 else db 24 endif dens: db 0e5h ;density flag patched by sys 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 ddpmlen 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 retries equ 10 ;retry count for disk operations page 60 ;--------------------------in by CPMLDR ; ; contains entries of form dw track, db first sector, db last sector ; it is a map of where the image of the CCP and BDOS reside on disk ccpstart:: dw start-1600h ;CP/M boot address bdosjmp:: dw start-0dfah ;BDOS jump bootbl:: dl ;drvtbl is always on 256 byte boundary add A,A ld E,A ld A,(DE) ;driver module for current disk ld B,A ld A,C add A,A ld E,A ;address of new disk driver page ld A,(DE) ;driver module for new disk or A jr Z,badsel ;new disk not inst ld A,H or L ret z ;bad select from driver ld A,(DE) ;driver number and 7fh ;reset first time flag ld (DE),A ld A,C ;succesfully selected disk ld (curdsk),A ret badsel:: ld HL,0 ret ; ; Sectran input:: Logical sector in BC, t,(curdsk) ;current logical drive getvec:: ld HL,drvtbl dskcon:: add A,A ld E,A ld A,D ;low order byte of vector supplied ld D,0 add HL,DE ld D,(HL) ;high order byte of jump vector inc HL ld E,A ;vector lsb ld A,(HL) ;driver number eA,(rdrtbl) ;reader driver jr gordr punch:: ld A,(puntbl) gordr:: or A ret z ld H,A ld L,0 jp (HL) page ;----------------------------------------------------------------------- ; ; Hardware configuration table ; org 100h-2 iodma:: dntbl:: db 0 ;no punch installed 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:: ld SP,100 ;use default buffer  pop HL ;boottbl pointer ld C,(HL) ;first sector dec C ;will be incremented before setsec inc HL ld B,(HL) ;last sector inc HL ld (bootptr),HL ;save pointer pop HL ;DMA pop DE ;old sectors push BC ;new sectors push HL t low memory ld HL,(bdosjmp) ld (6),HL ;normal BDOS jump ld HL,wboota ld (1),HL ;warm boot jump ld A,0c3h ;'JP' intruction ld (0),A ld (5),A ld HL,bootbl ld (bootptr),HL ;reset pointer for next warm boot ld HL,drvtbl+3 ld b,15der, other parameters per CP/M ; A=0 serial port 0; A=1 serial port 1; A=2 parallel (list only) org cpuio*256 cpu:: ;standard console/list routines for CPU serial ports jp pserin ; jp serin ;these three go direct to serial jp serout ; jp lout (C),B ret 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 lstout1:: call plserout or A ld A,B jr z,lstout1 dec C out (C),E ret pollst:: cp 2tput, 4-0 input out (piobc),A xor A out (piobd),A ld (frstpar),A ;reset first time flag 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 polpliranslate 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 retx DE,HL jphl:: jp (HL) ;go to driver curdsk:: db 0 ;currently selcted logical drive page ; Console/list vectors const:: ld D,0 jr conjmp conin:: ld D,3 jr conjmp conout:: ld D,6 jr conjmp list:: ld D,9 jr lstjmp listst:: ld D,0b 80h ;this is the low order byte ;of the 80h default drvtbl equ $+1 ;logical drive assignment dw fpy ;floppy page dw fpy ;default floppies 0-3 dw fpy+81h dw fpy+82h db 83h ds 23d ;space for drives E::-P:: contbl equld 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 nxttrk:: push HL ;un ;DMA page nxtsec:: pop HL ;DMA push HL ld B,H ld C,L ;move to BC call setdma pop HL ;last DMA pop BC ;sector data ld A,B ;last sector to read inc C ;read next sector cp C jr c,nxttrk ;done with last sector ld DE,128  ;reset all drives but A:: to not logged unlog:: set 7,(HL) inc HL inc HL djnz unlog ld HL,(ccpstart) ld A,(cdisk) ld C,A jp (HL) ;go to CP/M bootptr:: dw bootbl ;initial track value bootxlt:: dw 0 ;boot disk sector translate tstout jp pollst db 'SBCIO ' ;module name for display pserin:: ;poll serial in-return A=0ff if char ready, else 0 add A,A inc A ;A=command port ld C,A in A,(C) and 1 ret z ;no character waiting ld A,0ffh ret serin:: ld  jr z,polplist plserout:: add A,A ;serial out poll 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:: st 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  setdma:: ld (iodma),BC ;shared among all drivers ret page home:: ld D,0 jr dskjmp settrk:: ld D,6 jr dskjmp setsec:: ld D,9 jr dskjmp read:: ld D,0ch jr dskjmp write:: ld D,0fh dskjmp:: ;go to correct disk routine ld Ach lstjmp:: ld A,(iobyte) and 11000000b ;get list field rlca rlca ;make 0-3 ld HL,lsttbl jr dskcon conjmp:: ;get jump for console drivers ld A,(iobyte) and 00000011b ;get console field ld HL,contbl jr dskcon reader:: ld  $+1 dw cpu dw cpu ;default=serial 0 db 1 ;alternate=serial 1 ds 3 ;space for two more console drivers lsttbl equ $+1 dw cpu dw cpu+2 ;default=parallel db 1 ;alternate=serial 1 ds 4 rdrtbl:: db 0 ;no reader installed puitialized data-sector count push HL ;current DMA ;read sectors of next track ld HL,(bootptr) ;point to bootbl entry ld C,(HL) inc HL ld B,(HL) ;BC=track inc HL push HL ld A,B or C jr z,bootdone ;last track done call settrkadd HL,DE ;update DMA push BC push HL ld B,0 ;C=sector to read (<256) ld DE,(bootxlt) call sectran ld C,L ld B,H call setsec call read or A jr nz,booterr ;physical read error jr nxtsec bootdone:: ;CP/M read from disk, seable page booterr:: ld DE,badbootmsg call pmsg halt ;must reset system badbootmsg:: db 'Warm boot error-reset system' crlf:: db 0dh,0ah,'$' page cpuio equ (($-start-1)/256)+1 ; ; Console/list drivers ; All have entry A=driver numbB,A call pserin ld A,B jr z,serin ;loop until character received add A,A ld C,A in A,(C) and 7fh ;mask high order bit ret serout:: ld B,C ;character to output add A,A inc A ld C,A serst:: in A,(C) and 4 jr z,serst dec C ;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 ou not been initialized page ; miscellaneous character i/o routines pmsg:: ;equivalent to BDOS function 9 (print) ld A,(DE) cp '$' ret z ld C,A inc DE push DE call conout pop DE jr pmsg phex:: ;print A in hex push AF rra ngle 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 inity (1K block) dw 26 ;sectors per track db 3 ;block shift (log2[block size/128]) db 7 ;block mask ([block size/128]-1) db 0 ;extent mask dw 242 ;highest block on disk (numbered from 0) dw 63 ;directory entries-1 db 0c0h ;alloc0 -first0fh db 0 dw (tracks*ddpspt)-1 ;each of 76 tracks has ddpspt 2K blocks if mini dw 127 else dw 255 endif if mini db 0c0h else db 0f0h endif db 0 dw 32 dw 1 page trans:: ;single density translate table db 1,7,13,19,25,5,11,17,2check on drive A:: notfirst:: ld E,C ;save logical disk 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) ;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 ble ;this may be first physical i/o out (trk),A 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 ret z ;a 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) 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 irra rra rra call hex1 pop AF hex1:: and 0fh add A,90h daa adc A,40h daa ld C,A jp conout fpyio equ (($-start-1)/256)+1 ;make line up on page boundary ; ; Floppy disk drive driver module ; org fpyio*256 fpy:: ; floppy driver ju DD endif db 0 ;track drive currently set at endm page ; ; CP/M disk tables fDPHbase:: dw trans,0,0,0 dw dirbuf,fdpbase dw chk00,all00 dw trans,0,0,0 dw dirbuf,fdpbase dw chk01,all01 dw trans,0,0,0 dw dirbuf,fdpbase dw chk02 two bits for two blocks for Dir db 0 ;alloc1 dw 16 ;checked directories dw 2 ;track offset (system tracks) page ssdddpb:: ;single sided double density dw 8*ddpspt ;128 byte sectors per track db 4 db 0fh db 0 dw (tracks*ddpspt/2)-1 3,3,9,15,21 ;sectors 1-13 db 2,8,14,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 page ; ; Fseldsk selects the physical floppy in A (0-3) ; B=0 if  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 xpage ; ; 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:: lready there ld A,C out (data),A ld A,(IX+seekrt) ;seek rate mask or 1ch ;seek with verify di out (cmd),A in A,(wait) ei rla jr c,seekerr ;no INTRQ from FDC in A,(cmd) and 10011001b ;seek error, CRC error, or incomplete jr nz ;get first sector in block ld (blksec),A add A,hstcnt 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 buffen buffer jr nc,movwrt ;and A to relative sector if in buffer ;not in buffer but might be 2nd 1K of ;an unallocated 2K data block ld A,(blk2sec) cp D ;iosec jr nz,wrtdbl ;unless first sector of 2nd 1K in ;unallocated data bmp 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 4 if (mini and not special) db 1 ;si,all02 dw trans,0,0,0 dw dirbuf,fdpbase dw chk03,all03 ; ; 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 dens ;each of 76 tracks has ddpspt/2 2K blocks if mini dw 63 else dw 127 endif if mini db 80h else db 0c0h endif db 0 dw 32 dw 1 dsdddpb:: ;double sided double density dw 16*ddpspt ;one track consists of both sides db 4 db last disk selected was a different floppy ; C=logical disk the floppy corresponds to fseldsk:: ld D,A ;physcial floppy ld A,B ;zero if last selected was floppy cp 128 ;first select after cold boot? jr nz,notfirst ld C,B ;make density or 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 HL,DE ld (HL),C inc HL ld (HL),B dec HL dec HL sbc HL,DE  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 ta,seekerr ;seek successful ld (IX+drvtrk),C ret seekerr:: ld E,1ch ;seek command call diskerror jr seek2 page ; write writes the sector to the selected disk fwrite:: ld IX,(hwptr) ;restore IX to parameter block ld A,(IX+density) r movwrt:: call mkbufad ;get correct address in buffer ex DE,HL ldir ld A,0ffh ld (wrtpend),A ;write pending cpl ;return with no errors ret directry:: ;write to a directory sector ;the disk may be removed after this ;so lock call inbuf2 ;checks iotrk=blktrk jr c,wrtdbl call fflush ;previously unallocated data or A ret nz jr movwrt ;and write this sector wrtsngl:: ld A,(iosec) ld (psec),A ld A,0A3h ;second byte of OUTI instruction ld (iotra ;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,(iodity) ;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 pre the necessary sector ; it assumes that the head has already settled on the correct track ; (and that the head has been selected on the correct side!) ; and that the bytes in rdwrite for R/W and sector size have been filled diskio:: ld A,retries  will give a 15 ms delay ld E,A ld A,(IX+density) or A ld D,1 ;one sector i/o transfer for single denisty jr z,dmasingl ;use the CP/M DMA buffer in single density ld HL,hstbuf ;use host buffer for double density operations ld D,hstcnt ;numbetual 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 reriterr:: 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,siderr call pmsg ld A,(head) call phex pdrv:: ld DE,d ;at track 0 jr z,tk0wait xor A out (trk),A ;back at track 0 ld (IX+drvtrk),A ;update track table ret page ; ; sidesec is the read/write preparation for double density ; sidesec computes the correct physical sector and side ; sidesec::  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,(blkdn+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 call sidesec ;set up for new i/o call readprep ;do read to buffer or A rrvtrk) push HL ld HL,(blkdrvtrk) ld (iodrvtrk),HL ;set drive to select and track ld A,(blksec) call sideflsh ;set up head bit and sector for flush call strtsel ;do physical flush pop HL ld (iodrvtrk),HL ;restore selected drive and tracvious 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 ld (retryc),A iotry:: ld A,0d0h ;force interrupt no conditions out (cmd),A ld A,(oper) ld B,A ld C,data ;prepare for indirect I/O intruction ex (SP),HL ;waste some time ex (SP),HL ex (SP),HL ex (SP),HL di ;no interrupts from hr 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 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 ; disk error rverr call pmsg ld A,(curfpy) call phex ld DE,crlf call pmsg ld A,255 ret ; ; Restore is called from a disk operation with A=retries left ; restore:: ld (retryc),A in A,(cmd) and 00010000b ;bit 4=record not found ret z ;try aga ld A,(iosec) and not(hstcnt-1) ;computer first CP/M sector in block ld (blksec),A sideflsh:: ;called to set up for a flush rept hstshft rrca endm ;A=physical sector number, but it may ;be on the second side ld B,(IX+pspt) rvtrk) 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 oet 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 k 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+densbyte of INI instruction ld (iotran+1),A ;patch rdwrite routine ld A,08ch ;sector read command ld (oper),A page strtsel:: call seldrv ;physically select drive and head call seek ;step to correct track ; ; diskio actually reads or writesere to end of transfer in A,(cmd) and 20h ;bit 5=head loaded rrca rrca rrca ;move bit 5 to bit 2 cpl and B ; the purpose of these manipulations has been ; to set bit 2 of the FDC command if the head ; isn't settled. Bit 2t-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 call diskerror call seek or A jr z,iotry ;if nonzero then hopeless seek error ret ; ; rdwrite does the acwill eventually have all kinds of nice messages ; diskerror:: ld A,(retryc) dec 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 pwin if record was found but ;read/written with error resto1:: ;restore to track 0 and seek again ld A,(IX+seekrt) ;get seek rate mask or 00001100b ;head load, restore, verify track 0 out (cmd),A tk0wait:: in A,(cmd) and 00000100b  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 ;  f contents of buffer for use by flush ; also saves hardware pointer and sets buffer valid flag ; returns HL=start of sector in buffer, DE=DMA address, BC=128, A=0 mkbufad:: ld (blkptr),IX ld HL,(iodrvtrk) ld (blkdrvtrk),HL ld A,(iosec) ld B,A  shft1 ret page ; ; Getden attempts to find the density of the disk in drive (D) ; by trying to read the current track address in both densities ; If the attempt is successful, Getden will update the ; dens, pspt, and drvtrk fields of the paramtersity 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 if not mini ld (IX+density),A ;track zero always single density endif inc A if mini ld (IX+dens 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 lallocated 2K block psec:: ds 1 ;current physical sector bufvalid:: db 0ffh ;buffer contains valid data for (blksec) ;0 = valid data wrtpend:: db 0 ;write pending from buffer retryc:: db 0 ;number of retries left newfpy:: db 0 ;new floppy to ' siderr:: db ' side $' drverr:: db ' drive $' page ; ; disk buffers ; These are not part of the floppy driver module as such and ; should be shared by all disk modules as much as possible org fpy+500h coldboot:: dirbuf:: ;coldboot code lirprn call pmsg jr lastmsg serprn:: push AF ld DE,serpmsg call pmsg pop AF add A,31h ld C,A call conout lastmsg:: ld DE,sign3 call pmsg page ld E,0 if not special ld BC,8000h ;get density of boot floppy ld A,(drvtbl) ld H,A lb 'Default console is serial port $' prnmsg:: db 0dh,0ah,'Default printer is $' parprn:: db 'parallel printer driver$' serpmsg:: db 'serial port $' sign3:: db 0dh,0ah,0ah,'$' page twodec:: ;convert A < 100 to two ASCII digits in BC ld BC86 ; ; end  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  table ; If E (logical disk) is zero, then getden assumes the density hasn't ; changed (if it has, then we can't do a warm boot-table is wrong getden:: ld A,E or A jr z,logdin ;logical drive A:: bit 7,D jr z,logdin ;drive already logged inity),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 ogdin:: ld A,D ;drive already logged in ld (curfpy),A call getparm ld A,(IX+density) jr codeok ; drive can't change density page ; ; Floppy disk driver storage ; iodrvtrk:: curfpy:: db 0 ;current selected physical floppy drive iotrk:: dbe selected tempfpy:: db 0 ;storage for current floppy while checking ;density of new one head:: db 0 ;head control = 0 or 1 oper:: db 0 ;operation (read/write) to be performed next hwptr:: dw dskparm ;storage for pointer to current hw parametves in the directory buffer xor A ld (iobyte),A ;back to default routing ld (cdisk),A ;user 0, drive A:: ld DE,signon call pmsg ld A,(wboota+2) ;warm boot vector add A,6 srl a srl A ;A=memory size in K call twodec ;get ASCII digitsd L,3 ;select vector ld A,(drvtbl+1) or 80h ;set flag for first logon call jphl ;select boot drive in BIOS ld A,H or L jp z,booterr ;can`t select system drive endif jp bootdone ;set up low memory and go to CCP page signon:: db 0dh,0ah,',0ff0ah nxtten:: inc B sub C jr nc,nxtten add A,C add A,30h ld C,A ld A,30h add A,B ld B,A ret hstbuf equ dirbuf+128 ;sector deblocking buffer ds 1024+128-($-dirbuf) chk00:: ds 32 ;the check an allocation vectors are assigned ret ; ; 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 call fflush ;getden uses buffer 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 and 7fh ld (curfpy),A call getparm if mini if not special set 3,A ;set double den 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 ;code for a normal single density disk cp 3 jr c,codeok ld DE,badcode ;not our code byte call pmsg s 1 ;current track for current disk blkdrvtrk:: ds 2 ;drive and track for deblocking buffer iosec:: ds 1 ;current logical sector for DD, physical for SD blksec:: ds 1 ;first logical sector in current host blk2sec:: ds 1 ;8th CP/M sector in an uners blkptr:: dw dskparm ;pointer to paramters for block drive ; error messages badcode:: db 'Can''t recognize density of disk in$' rderr:: db 'Read$' wrterr:: db 'Write$' skerr:: db 'Seek$' trkerr:: db ' error on track $' secerr:: db ' sector $ for memory size push BC ld C,B call conout pop BC call conout ld DE,sign2 call pmsg ld A,(contbl+1) ;default console add A,31h ;make 1-2 ld C,A call conout ld DE,prnmsg call pmsg ld A,(lsttbl+1) cp 2 jr c,serprn ld DE,paSuper Quad CP/M v X2.0',0dh,0ah if special db 'Special 8"-5" BIOS',0dh,0ah endif if mini db 'for ' if m48tpi db '48' else db '96' endif ' tpi minifloppies',0dh,0ah endif db 0dh,0ah,'$' sign2:: db 'K CP/M 2.2 installed',0dh,0ah,0ah d all00:: ds 86 ;to physical floppies 0-3 ;if fewer than four drives are connected, or if ;some drives are single sided, these areas can ;be reduced chk01:: ds 32 all01:: ds 86 chk02:: ds 32 all02:: ds 86 chk03:: ds 32 all03:: ds !  Affects: Reassembl o th BIO usin recen release o MACRO- 80. Change: Chang th fiel 'seeker t 'seekerr an 'diskerr t 'diskerror'. Each error occurs once. .pa SUPERBIOS software update number 2  write Thi wil mak th fil writ fro Wordsta incredibly slow. Affects: SUPERBIOӠ modification wit additiona dis drive modules. Change: Delet th cod i th 'seldsk: routin afte th lin ste disk eithe b purchas o CP/ fro Advance Micr Digita o b followin th steps outlined in CPMINSTA.DOC- Us FORMAT.CO t forma blan dis i th desire forma (Standar eigh inc singl densit disk generall don'  .pa Operation of the SUPERBIOS: Th SUPERBIO behave i genera a an norma CP/ system However yo mus no chang densit o disk withou doin control-C Thi i becaus th SUPERBIO check onl onc afte each warm boice Th distributio versio ha th paralle printe a th default Th defaul printe ca b change b patchin th byt i CPM.SY wit DDT (byt 1829 - se t fo parallel fo serial). Th syste display th defaul printngl side doubl density the yo ca ru fourt driv if it is also single sided. Thi limitatio come fro th fac tha ther i n roo i th BIOӠ fo th allocatio vecto necessar fo fou doubl side disks I yo nee5/29/82 File: SUPRBIOS.MAC Bug:Certai application program (e.g Wordstar mak selec call o th defaul driv befor writin eac secto o th outpu file(s) I th defaul dis fo Words 'j z,samemod u t th labe 'samemod:' I you adde dis drive modul share th hos buffe wit th flopp module yo wil hav t inser cod t cal th fflus routin befor you modul re Welcome to the SUPERBIOS Thi i onl a introduction Se th followin file fo additional information: FORMAT.DOC for detailed information on the disk format. CPMINSTA.DOà fo installatio o th systenee refomatting) Plac you syste dis i A an th destinatio disk in B:. Run LDRGEN from A to B. Us PIР t transfe th fil CPM.SY fro t B Fo optimu performance CPM.SY shoul b th firs fil yo writ ot to see what density each disk is. I general yo ma chang syste disk a an tim provided: 1) The system disks are the same density. 2) CPM.SYS is the first file on each disk. I yo wis t chang densit oe o col boot Th printe ma b change a an tim t th alternat b changin th iobyt a locatio 3 STAԠ LST:=CRT wil selec th alternate printer, STAT LST:=TTY: restores the default. NOTICE: A shipped th t ru fou drives o whic mor ths tw ar doubl sided yo wil hav t chang th SUPERBIO Allocatio Vecto t th sam siz a vecto 0 an generat 61K CP/M by the procedure outlined in NEWSIZE.DOC.  SUPERBIOS software update number 1 5/27/82 File: SUPRBIOS.MAC Bug: Tw typin error i th BIO sourc fil caus error i th MACRO-8 assemble versio check label fo more than six characters. ta i i differen drive modul tha th outpu fil dis (e.g Wordsta o har dis an th fil o floppy) th select t th defaul driv wil caus flus o th flopp buffe o eac secto ad o write int th buffer.  fo user wh already own CP/M. NEWSIZE.DOà t regenerat th syste fo differen memor size. INTRFACE.DOC for information on modifying the BIOS. Generating a new system disk: Assumin yo alread hav bootabl sy t an syste disk Thi i becaus th syste mus acces thi fil o eac war boo (control-C) an th acces i muc faste i th fil i o th outermos track o th dis (file ar writen to a new disk from the outer tracks in).  syste disk yo mus reboot the system (push the reset button and type control-C). Printer Selection: Th SUPERBIOӠ contain cod t driv bot th paralle printe interfac an th seria interfac a th CP/͠ lis dev SUPERBIO ca suppor eigh inc doubl side doubl densit drive o th firs tw drive an ) I th thir driv driv i als doubl side doubl density the yo canno ru fourt drive I th thir driv i si" ; ; 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 ; ----- N ; 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 +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 R ; 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 (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 RLX 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 0FF 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 0ED 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 MACRO ?D @CHK ?D DB 0FDH,96H,?D ENDM SBCX MACRO ?D @CHK ?D DB 0DDH,9EH,?D ENDM SBCY MACRO ?D @CHK ?D DB 0FDH,9EH,?D ENDM ANDX MACRO ?D @CHK ?D DB 0DDH,0A6H,?D ENDM ANDY MACRO ?D @CHK ?D DB 0FDH,0A6H,?D ENDM XORX MACR ----- --- ; ; 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 LDANNNN ; 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),I 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 ) 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,ADD 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) RAR80H) '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 H,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 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 O ?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 ?I ; 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 NNNY 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 (IXD 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-$ 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 OUTR 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 ; S 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 H,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 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 # 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 B 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 MACIY 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  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 RLY MACRO ?D @CHK ?D DB 0FDH, 0CBH, ?D, 3EH ENDM RLD MACRO DB 0EDH, 6FH ENDM RRD MACRO DB 0EDH, 67H ENDM 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 CRO ?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 MACR 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, 00?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 SRAENDM 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 DO ?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 PH + ?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 R 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 S$ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L