* * * * * * * * * * * * * * * * * * * * * * * CBIOS FOR AMPRO CP/M 2.2 SYSTEMS * * THIS BIOS IS FOR THE USE OF OWNERS * * OF AMPRO COMPUTER SYSTEMS. ANY OTHER * * USE IS PROHIBITED. * * COPYRIGHT (C) 1984 AMPRO COMPUTERS, INC.* * * * * * * * * * * * * * * * * * * * * * * YES EQU 1 NO EQU 0 ZCPR3 EQU YES ; purpose: the cp/m 2.2 bios for the ampro cpu. based on ; cbios.asm and deblock.asm, modified only as ; necessary. ; differences from standard cp/m bios: ; ; 1) track number is a byte, not a word ; 2) keeps track of last trk accessed, seeks only when ; necessary (and invokes idread before seeks). ; 3) prints a signon message ; 4) disk accessing for two sided disks uses a cylinder ; approach to minimize the need for seeks. ; 5) there is an additional entry point that unlogs all disks ; 6) support for virtual disk allows format translation ; 7) limited iobyte support has been included ; 8) support for zcpr has been included ; VERS EQU 16 ; version of this bios ; revision log: ; ;version 1.6 29-apr-95 RJB Corrected BIOS overflow by optimizing ; the IOINIT routine. ; ;version 1.5 3-mar-85 RJB Optimized head load delay. ; ; 22-jan-85 RJB Changed con & tty status routines to ; use "ALLSENT" bit rather than TBE. ; Removed buffer flush on warm boot. ; ;version 1.4 24 july 84 : changed motor-on routine to wait ; 1 revolution after successful ; id read. Added mask of MSB ; to TTY and CRT inputs. ; ;version 1.3 5 april 84 : fixed crt and tty routines ; modified for latest zcpr3 ; ;version 1.2 5 march 84 : optimized motor on delay ; changed default initialization ; changed to support zcpr3 ; ;version 1.1 20 february 84 : added single density support for ; 256 and 512 byte sectors jww ; added one second motor on delay ; ;version 1.0 12 february 84 : production release ; MSIZE EQU 61 ;cp/m version memory size in kilobytes BIAS EQU (MSIZE-20)*1024 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 ; Z-80 equates OTIR80 EQU 0B3EDH ; OTIR (0edh,0b3h) ; cp/m to host disk constants WRALL EQU 0 ;write to allocated WRDIR EQU 1 ;write to directory WRUAL EQU 2 ;write to unallocated ORG BIOS ;origin of this program NSECTS EQU ($-CCP)/128 ;warm start sector count ; ampro hardware equates ; port addresses STBSET EQU 2 ;sets print strobe STBCLR EQU 3 ;clears print strobe PIO1 EQU 001H ;parallel printer port CTCA EQU 40H CTCA0 EQU CTCA CTCA1 EQU 050H CTCA2 EQU 060H CTCA3 EQU 070H SIO1 EQU 080H SIODPA EQU SIO1 SIODPB EQU 088H SIOCPA EQU 084H SIOCPB EQU 08CH STAT EQU 0C4H ;disk controller command/status register RTRK EQU STAT+1 ;disk controller track register RSEC EQU STAT+2 ;disk controller sector register RDAT EQU STAT+3 ;disk data port CMND EQU 0C0H ;disk controller command/status register WTRK EQU CMND+1 ;disk controller track register WSEC EQU CMND+2 ;disk controller sector register WDAT EQU CMND+3 ;disk data port HLDELAY EQU 35 ; Head load delay CONT EQU 00H ;disk flag and control port ; mask equates TBE EQU 04H ;dart xmit buffer empty RDA EQU 01H ;dart receive data available DCD EQU 08H ;dart data carrier detect CTS EQU 20H ;dart clear to send ; char equates CR EQU 0DH ;carriage return (^m) LF EQU 0AH ;line feed (^j) TAB EQU 009H ;tab (^i) BSP EQU 08H ;backspace (^h) DEL EQU 7FH ;character delete CAN EQU 18H ;line cancel (^x) NAK EQU 15H ; (^u) ; misc equates CTS EQU 020H ;clear to send DELSEND EQU 28 TIMEOUT EQU 100 DDLSPT EQU 40 FRESTOR EQU 8 ; spin-up disabled on all commands FSEEK EQU 01CH FSTEPIN EQU 05CH FREADS EQU 088H FWRITES EQU 0A8H ;write precomp on FRDADDR EQU 0C8H AMSSDD EQU 086H AMDSDD EQU 0C6H SSDD96 EQU 087H DSDD96 EQU 0C7H ; jump vectors 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 PUNCH ;punch character out JMP READER ;reader character in 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 WRITE ;write disk JMP LISTST ;return list status JMP SECTRAN ;sector translate ; ampro specific bios calls JMP UNLOG ;unlog all disks JMP GETEDSK ;get pointer to e disk storage JMP IOINIT ; set new i/o parameters ORG BIOS+40H CTCVAL: DB 47H,13,47H,208,3,3,3,3 ; ctc0 values SIOAVAL:DB 4,46H,5,0EAH,3,0C1H,0,0,0,0 SIOBVAL:DB 4,86H,5,0EAH,3,0C1H,0,0,0,0 NDSKS: DB 4 ; four drives allowed STPRAT: DB 3,0,0,0 ; step rates of four drives, ; 2nd - 4th not used yet IOBYT: DB 81H AUTOCMD:DB 7,'STARTUP',0 ORG AUTOCMD+10 HSA: DB 0 ;lsb: 1 = yes, 0 = no HSB: DB 1 VER: DB VERS ; version of this bios. ORG BIOS+80H DPBASE: DW XLT0,0,0,0 DW DIRBUF,DPARM,CSV0,ALV0 DW XLT0,0,0,0 DW DIRBUF,DPARM,CSV1,ALV1 DW XLT0,0,0,0 DW DIRBUF,DPARM,CSV2,ALV2 DW XLT0,0,0,0 DW DIRBUF,DPARM,CSV3,ALV3 DW XLT1,0,0,0 ;the e disk DW DIRBUF,EPARM,CSV4,ALV4 SPARM: ;a single-sided ampro disk DW 40 ;sec/trk DB 4 ;block shift DB 15 ;block mask DB 1 ;extent mask DW 94 ;disk size -1 DW 63 ;directory max DB 128 ;alloc 0 DB 0 ;alloc 1 DW 16 ;check size DW 2 ;offset DPARM: ;a double-sided ampro disk DW 40 ;sec/trk DB 4 ;block shift DB 15 ;block mask DB 1 ;extent mask DW 194 ;disk size -1 DW 127 ;directory max DB 192 ;alloc 0 DB 0 ;alloc 1 DW 32 ;check size DW 2 ;offset DPARM96: ; 96 tpi double sided DW 40 ;sec/trk DB 4 ;block shift DB 15 ;block mask DB 0 ;extent mask DW 394 ;disk size -1 DW 255 ;directory max DB 240 ;alloc 0 DB 0 ;alloc 1 DW 64 ;check size DW 2 ;offset XLT0: ; 48 tpi skew table DB 1,2,3,4,5,6,7,8,9,10 ; the following storage should not be moved for e disk to work. ; a call to bios function getedisk returns the address of eparm. ; the type tab entry is thus defined as the returned value -1, ; and the translate table value as the returned value+15. TYPETAB: DS 4 ;type of disk n ; encoding is as follows: ; bit 7: 0 = sd, 1 = dd ; bit 6: 0 = ss, 1 = ds ; bits 3-2: 0 = 1k alloc, 1 = 2k alloc ; bits 1-0: 0 = 128, 1 = 256, 2 = 512 DB 082H ;same as kaypro EPARM: ;kaypro disk DW 40 ;sec/trk DB 3 ;block shift DB 7 ;block mask DB 0 ;extent mask DW 194 ;disk size -1 DW 63 ;directory max -1 DB 240 ;alloc 0 DB 0 ;alloc 1 DW 16 ;check size DW 1 ;offset EDSD: DB 1 ; default drive b: XLT1: ;translate table for e disk DB 0,1,2,3,4,5,6,7,8,9 DS 10 GETEDSK: LXI H,EPARM RET IOINIT: LXI H,CTCVAL LXI B,0240H ; CTC0 DW OTIR80 LXI B,0250H ; CTC1 DW OTIR80 LXI B,0260H ; CTC2 DW OTIR80 LXI B,0270H ; CTC3 DW OTIR80 LXI B,0A84H ; DART A DW OTIR80 LXI B,0A8CH ; DART B DW OTIR80 LDA IOBYT STA IOBYTE RET PUTS: ;send bytes to console until zero encountered MOV A,M ;fetch char ORA A ;done? RZ ;yes if it's a zero byte INX H ;set up for next byte MOV C,A CALL CONOUT ;sent it to the console JMP PUTS WBERR: LXI H,BOOTMSG WBERR1: CALL PUTS JMP WBOOT BOOTMSG: DB CR, LF, 'Boot failed!', 7, 0 NXTTRK: PUSH B MVI C,1 CALL SETTRK POP B MVI C,0 RET WBOOT: ;simplest case is to read the disk until all sectors loaded ; warning: this bios can only read or write single density ; disks, not cold or warm boot from them. XRA A ;0 to accumulator ; STA HSTACT and STA UNACNT were removed as they caused any sectors ; that were left in the write buffers to be thrown away on a warm ; boot. STA HSTSID ;assume side zero LXI SP,80H ;use space below buffer for stack CALL UNLOG ; warm boot consists of reading the ccp and bdos in from the ; system tracks: 1600h of code. only double density disks may ; be warm booted on an ampro system. the ten sectors ; on logical track zero (track 0 side 0) and one track on ; logical track one (track 0 side 1) are read to ccp. MVI C,0 CALL SELDSK ;auto select disk type MOV A,H ORA L JZ WBERR ;couldn't do it MVI C,0 CALL SETTRK MVI B,NSECTS ;number of sectors to read MVI C,1 ;first sector LXI H,CCP WBLOOP: PUSH B ;save sector count PUSH H CALL SETSEC ;set the sector for next read POP B ;fetch dma address PUSH B ;save a copy CALL SETDMA CALL READ ;error check? ORA A JNZ WBERR POP H LXI D,128 DAD D ;update dma address POP B INR C ;point to next sector MOV A,C CPI DDLSPT CZ NXTTRK DCR B ;decrement loop counter JNZ WBLOOP ;get 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 point 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 ;get current disk number MOV C,A ;send to the ccp JMP CCP ;go to cp/m for further processing ;home the selected disk HOME: MVI C,0 ;set the desired track to zero CALL SETTRK LDA HSTWRT ;check for pending write ORA A JNZ HOMED STA HSTACT ;clear host active flag HOMED: RET SELDSK: ;select disk MOV A,C ;selected disk number STA SEKDSK ;seek disk number STA CPMDSK ;working variable CPI 4 ;good disk number? JZ SELEDSK ;always works for e disk LXI H,NDSKS CMP M JNC SELERR ;if not, return error ; disk number is in the proper range (0..3). ; see if disk has been accessed yet - if not, read the ; directory track to determine if single or double sided, ; load all disk access tables as appropriate MOV A,E ; test for new mount RAR JC SELEND ; not a new mount ; first access, see if double sided CALL GETTYPE ;ignore result, just use pointer PUSH H ;save pointer into type table MVI A,3 STA TRIES ;try it three times ACCESS: ; first assume it's a double sided double density disk POP H ;get type table ptr PUSH H MVI M,AMDSDD ;set type = dsdd-512 CALL SETUP ;select drive and side (don't care) CALL RESTORE CPI 255 JZ SELERR1 ;disk timeout MVI A,2 ; this side STA CPMTRK CALL SEEK ;note seek always seeks on side 0 first. JNZ TRYSS ; check for double sided LDA IDSAVE+2 ; sector CPI 17 JC TRYSS LDA IDSAVE+3 ; size CPI 3 ; 96 tpi has 1024 byte sectors JNZ SELOK POP H ; get type table pointer PUSH H MVI M,DSDD96 JMP SELOK ; seek failed, probably an id read error. change to ; first side and try again... TRYSS: POP H PUSH H MVI M,AMSSDD ;set type = ssdd-512 LXI H,CPMTRK DCR M CALL SEEK JNZ TRYAGN LDA IDSAVE+3 ; size CPI 3 ; 96 tpi drives have 1024 byte sectors JNZ SELOK POP H ; get type table pointer PUSH H MVI M,SSDD96 JMP SELOK ; seek failed, maybe a single density disk (only acceptable in e drive) TRYAGN: LXI H,TRIES ;can't read side zero either? DCR M JZ SELERR1 ;quit if last time JMP ACCESS ;else try again ; if we get here, we had a successful id read. ; set up tables... SELOK: POP H ;get rid of saved pointer CALL SELEND ;use selend as a subroutine (wow) LXI D,10 ;and offset to parm table entry DAD D PUSH H ;save pointer CALL GETTYPE POP H ;restore ptr CPI AMSSDD ;ssdd? LXI B,SPARM ;assume single sided JZ SETSSID CPI AMDSDD ; double sided 48? LXI B,DPARM ; ds 48 and ss 96 share dparm JZ SETSSID CPI SSDD96 JZ SETSSID LXI B,DPARM96 ; and fall through SETSSID: LDAX B ; get logical sectors per track STA CPMSPT MOV M,C ;and fix the table INX H MOV M,B ;table now set up ; compute proper disk parameter header address SELEND: ; set deblocker variables CALL GETTYPE MOV B,A ; save it a moment ANI 3 ; mask sector size STA SECSHF ; sector shift MOV C,A ; set counter MVI A,1 DB0: ADD A DCR C JNZ DB0 DCR A STA SECMSK ; sector mask MOV A,B ; get type byte ANI 4 ; test block size 0=1k, 1=2k MVI A,8 ; assume 1k JZ DB1 ; if so ADD A ; must be 2k DB1: STA MUNACT ; initial unacnt value LDA SEKDSK ;get disk number back GETDPT: MVI H,0 MOV L,A ;put it in hl DAD H DAD H DAD H DAD H LXI D,DPBASE ;base of parm block DAD D ;hl=.dpb(curdsk) RET SELEDSK: ;log in parameters for the e disk LDA EPARM-1 ;fetch type byte MOV B,A ;save it in b ANI 03H ;mask type nibble ORA A JZ SELE0 CPI 1 JZ SELE1 CPI 2 JZ SELE2 SELE3: ; 1024 byte sectors MOV A,B ; get type byte ANI 20H ; look for continuous sector numbering MVI A,0 JZ SELE3X LDA EPARM ; get logical sectors per track RAR RAR RAR ANI 1FH ; mask off trash SELE3X: STA ESECADJ JMP SELEND SELE0: ;128 byte single density MOV A,B ;get type byte back ANI 020H ;look for continuous sector numbering MVI A,0 JZ SELE0X ;exit if duplicate numbering LDA EPARM ;fetch logical sectors per track SELE0X: STA ESECADJ JMP SELEND SELE1: ;256 byte sector, 1k allocation (whatever) MOV A,B ;get type byte back ANI 020H ;look for continuous sector numbering MVI A,0 JZ SELE1X ;exit if duplicate numbering LDA EPARM ;fetch logical sectors per track RAR ;divide by 2 for physical sectors ANI 07FH SELE1X: STA ESECADJ JMP SELEND SELE2: ;512 byte sector, 2k allocation (ampro) MOV A,B ;get type byte back ANI 020H ;look for continuous sector numbering MVI A,0 JZ SELE2X ;exit if duplicate numbering LDA EPARM ;fetch logical sectors per track RAR RAR ;right shift two bits ANI 03FH SELE2X: STA ESECADJ JMP SELEND SELERR1: ;one thing on the stack POP H SELERR: ;disk select failed LXI H,0 RET SETTRK: ;set track given by register c MOV A,C STA SEKTRK STA CPMTRK RET SETSEC: ;set sector given by register c MOV A,C STA SEKSEC ;sector to seek STA CPMSEC RET SETDMA: ;set dma address given by bc MOV H,B MOV L,C SHLD DMAADR RET SECTRAN: ;translate sector number bc MOV H,B MOV L,C RET READ: ;read the selected cp/m sector CALL GETTYPE ANI 3 ; size JZ READHST ; if 128 bytes XRA A STA UNACNT MVI A,1 STA READOP ;read operation STA RSFLAG ;must read data MVI A,WRUAL STA WRTYPE ;treat as unalloc JMP RWOPER ;to perform the read WRITE: ;write the selected cp/m sector CALL GETTYPE ANI 3 JZ WRITEHST ; if 128 bytes XRA A ;0 to accumulator 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 ; for edsk, we need to check to see if sekdsk is the e disk. ; if so, then unacnt will be set according to the disk type. ; for ampro disks, its always blksiz/128. LDA MUNACT STA UNACNT LDA SEKDSK ;disk to seek STA UNADSK ;unadsk = sekdsk LDA SEKTRK STA 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 if 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 LDA SEKTRK CMP M ;sektrk = unatrk? JNZ 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? ; edsk: following code compares to cpmspt (40 for ampro disks) ; make this a variable. PUSH B ;save bc in case we needed it PUSH PSW ;save the value to be compared LDA SEKDSK CPI 4 ;edisk? LDA CPMSPT MOV B,A JNZ EMATCH LDA EPARM ;fetch table spt (convenient, eh?) MOV B,A EMATCH: POP PSW CMP B ;count cp/m sectors POP B ;restore bc register JC NOOVF ;skip if no overflow ; overflow to next track MVI M,0 ;unasec = 0 LDA UNATRK INR A STA UNATRK ;unatrk = unatrk+1 NOOVF: ;match found, mark as unnecessary read XRA A ;0 to accumulator STA RSFLAG ;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 RWOPER: ;enter here to perform the read/write XRA A ;zero to accum STA ERFLAG ;no errors (yet) PUSH B ;save in case LDA SECSHF MOV B,A LDA SEKSEC ;compute host sector SLOOP: ORA A ;carry = 0 RAR ;shift right DCR B JNZ SLOOP POP B ;restore STA SEKHST ;host sector to seek ; active host sector? LXI H,HSTACT ;host active 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? jz samedt ; indicate not same disk mvi a,0ffh sta chgdsk jmp nomatch samedt: ; same disk, same track? LXI H,HSTTRK LDA SEKTRK CMP M ;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 HSTWRT ;host written? ORA A LDA HSTDSK ;select host as disk to work on STA CPMDSK LDA HSTTRK STA CPMTRK CNZ WRITEHST ;clear host buff FILHST: ;may have to fill the host buffer LDA SEKDSK STA HSTDSK STA CPMDSK LDA SEKTRK STA HSTTRK STA CPMTRK LDA SEKHST STA HSTSEC LDA RSFLAG ;need to read? ORA A CNZ READHST ;yes, if 1 XRA A ;0 to accum STA HSTWRT ;no pending write MATCH: ;copy data to or from buffer ; edsk: sector mask (secmsk) must be a variable for edisk and ; is calculated by (hstsiz/128)-1. this is three for ampro, ; kaypro, and other 512-byte sectors, and 1 for 256 byte sectors. PUSH B ;save reg LDA SECMSK MOV B,A LDA SEKSEC ;mask buffer number ANA B ;least signif bits POP B ;restore bc contents MOV L,A ;ready to shift MVI H,0 ;double count DAD H DAD H DAD H DAD H DAD H DAD H DAD H ; hl has 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 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 moved 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 ;buffer written LDA HSTDSK STA CPMDSK LDA HSTTRK STA CPMTRK CALL WRITEHST LDA ERFLAG RET WRITEHST: ;cpmdsk = host disk #, cpmtrk = host track #, ;hstsec = host sect #. write "hstsiz" bytes ;from hstbuf and return error flag in erflag. ;return erflag non-zero if error XRA A STA RWHOST JMP HOSTIO READHST: ;cpmdsk = host disk #, cpmtrk = host track #, ;hstsec = host sect #. read "hstsiz" bytes ;into hstbuf and return error flag in erflag. MVI A,1 STA RWHOST HOSTIO: CALL SETUP ;output to drive select register MVI A,10 STA TRIES WMI: ;where am i? CALL MAPTRK CALL GETTRK ;what track do we want? CMP M CNZ SEEK ;if not there, go there JNZ RWFAIL ;in case seek fails ; track should be ok, but we need to send it anyway in ; case the last unit was different (there's only one track ; register). then load sector and do it... CALL GETTRK OUT WTRK CALL GETSEC ; check for dsdd to add sector bias if not 'e' drive MOV E,A ; save it for a moment LDA CPMDSK CPI 'E' -41H ; check for 'e' drive MOV A,E ; restore sector number JZ XYZ ; no sector bias for 'e' drive PUSH D ; save sector number in e reg. CALL GETTYPE POP D ANI 0C0H ; isolate dd and ds indicators CPI 0C0H ; check dd and ds MOV A,E JNZ XYZ ; no bias ADI 16 ; double sided bias XYZ: OUT WSEC CALL SETUP ;select unit and real side CALL GETBUF LDA RWHOST ;see if read (1) or ORA A ; write (0) JZ WRDAT ;branch for writes ; falling through implies this is a read MVI A,FREADS ;read sector command CALL RDATA JNZ RWFAIL RET ;return to bdos, read ok RWFAIL: LXI H,TRIES DCR M ;one less retry JZ DABORT ;error return CALL MAPTRK MVI M,255 ;force read address JMP WMI ;try again if there DABORT: MVI A,01 ;set error flag STA ERFLAG RET ;return to bdos w/error WAIT: LXI H,50*167 ; 50 ms. WTL: DCX H MOV A,H ORA L JNZ WTL RET WRDAT: PUSH H CALL DWAIT ;wait for permission POP H MVI A,FWRITES ;make it a write command CALL OUTCMD ;wait for cmd to start CALL WR ; write the disk JMP WRTERR ; check for errors and return WR: IN STAT ; get fdc status MOV B,A ; save it for eventual return RAR ; rotate busy bit into carry RNC ; write command is finished RAR ; rotate data request into carry JNC WR ; wait for data request MOV A,M ; get a byte OUT WDAT ; give it to the fdc INX H ; bump the pointer JMP WR ; again WRTERR: MOV A,B ; get fdc status ANI 05CH ;check for errors JNZ RWFAIL RET ; rdata: read data routine. on entry, hl contains buffer, ; a contains read command (which may be read address) RDATA: PUSH PSW PUSH H CALL DWAIT POP H POP PSW CALL OUTCMD ;wait for cmd to start CALL RD ; read the disk JMP RDERR ; check for errors and return RD: IN STAT ; get fdc status MOV B,A ; save status for eventual return RAR ; rotate busy bit to carry RNC ; controller has finished RAR ; rotate data request to carry JNC RD ; wait for drq IN RDAT ; get byte from fdc MOV M,A ; put it in memory INX H ; bump the pointer JMP RD ; again RDERR: MOV A,B ; fdc status ANI 01CH ;check for errors RET OUTCMD: CALL MOTOR ; insure motor on OC0: OUT CMND ; to fdc MVI A,19 ; wait 66.5 us. for command to set up OC1: DCR A JNZ OC1 RET ; MOTOR-UP-TO-SPEED FOR AMPRO BIOS MOTOR: PUSH H ; SAVE BUFFER POINTER PUSH PSW ; SAVE COMMAND IN STAT ; STATUS RAL ; ROTATE MOTON INTO CARRY JC MOTEND ; MOTORS ALREADY ON, FORGET IT IN RSEC ; GET THE SECTOR NUMBER STA SECTOR ; SAVE IT CALL MT2 ; READ AN ID MOV C,A ; SAVE ID # A MOMENT MT3: CALL MT2 ; READ ANOTHER ID CMP C ; SAME AS THE FIRST? JNZ MT3 ; TIL SAME ID READ TWICE LDA SECTOR ; GET SECTOR NUMBER OUT WSEC ; TO 1770 MOTEND: POP PSW ; GET COMMAND POP H ; GET POINTER RET ; READ AN ID AND RETURN ITS NUMBER IN A ; MT2: CALL DWAIT ; WAIT FOR CONTROLLER READY MVI A,FRDADDR ; READ ADDRESS COMMAND LXI H,IDSAVE ; PUT IT HERE CALL OC0 ; READ NEXT ID FIELD CALL RD ; READ THE 1770 CALL RDERR ; CHECK FOR GOOD READ ANI 0CH ; RNF OK WITH BLANK DISK LDA IDSAVE+2 ; ID # RZ ; GOOD READ JMP MT2 ; TRY FOR A GOOD ONE ; procedure dwait: ; wait for permission to write a register DWAIT: LXI H,0 MVI A,TIMEOUT STA TOCNT DWLP: IN STAT ANI 1 JZ DWDONE DCX H MOV A,H ORA L JNZ DWLP ;keep waiting LXI H,TOCNT DCR M LXI H,0 JNZ DWLP MVI A,0D0H ;force int OUT CMND ;give up on waiting MVI A,255 RET DWDONE: IN STAT ;fetch status again RET RESTORE: ;issue a restore command to the controller CALL DWAIT CPI 255 RZ ;timeout, don't bother MVI A,FRESTOR LXI H,STPRAT ORA M CALL OUTCMD CALL DWAIT CALL WAIT ; let drive settle down MVI A,FSTEPIN LXI H,STPRAT ORA M CALL OUTCMD CALL WAIT CALL MAPTRK MVI M,0 RET SEEK: ;seek to alternate track XRA A ;assume side zero STA HSTSID CALL SETUP ;select unit and side (zero is ok) LXI H,IDSAVE ;use id buffer MVI A,FRDADDR CALL RDATA RNZ ;quit if error IN RSEC ;fetch current track again OUT WTRK ;and tell 1770 where we are CALL GETTRK ;adjust if necessary (and set up side) OUT WDAT ;and tell the fdc where to go CALL SETUP ;set unit and real side CALL DWAIT MVI A,FSEEK ;worst case seek command LXI H,STPRAT ORA M CALL OUTCMD CALL DWAIT ;wait for it to finish ANI 18H ;isolate possible failures RNZ ;seek failed, return w/error ; seek worked, save track in table and return CALL MAPTRK CALL GETTRK ;get physical track MOV M,A XRA A ;ensure zero flag is set RET ;return w/success UNLOG: ;reset logged in disks (allows changing disk type) LXI H,-1 SHLD LTRACK SHLD LTRACK+2 RET MAPTRK: ;this routine returns the ltrack pointer in hl LDA CPMDSK MOV E,A MVI D,0 LXI H,LTRACK DAD D RET SETUP: ;this routine writes to the drvsel register LDA CPMDSK ;fetch unit id CPI 4 ;e disk? PUSH B ;save bc JZ SETEDSK INR A ;setup for decr loop MOV B,A MVI A,1 ;selbits mask SETUP1: DCR B ;are we done? JZ SETUP2 ADD A ;shift selbit left one JMP SETUP1 SETEDSK: LDA EDSD ; e disk drive MOV C,A INR C XRA A STC SEDL: RAL DCR C JNZ SEDL SETUP2: ;selbits now in a ORI 040H ;turn off eprom LXI H,HSTSID ;point to side select ORA M ;or that in, too MOV B,A CALL GETTYPE RLC ;single density? JNC SETUP3 ;branch if so, else XRA A ;clear accum JMP SETUP4 SETUP3: MVI A,20H ;load single density mask SETUP4: ORA B ;get rest of select back OUT CONT push psw lda chgdsk ora a jz nochange mvi c,hldelay hlwait: mvi b,189 hlwait2: cmp m dcr b jnz hlwait2 dcr c jnz hlwait mov a,c sta chgdsk nochange: pop psw POP B ;restore saved reg RET GETTYPE: ;get the type of a disk. ; encoding is as follows: ; bit 7: 0 = sd, 1 = dd ; bit 6: 0 = ss, 1 = ds ; bits 3-2: 0 = 1k alloc, 1 = 2k alloc ; bits 1-0: b reg value (bytes/sector) LDA CPMDSK MOV E,A MVI D,0 LXI H,TYPETAB DAD D MOV A,M RET GETSEC: ;convert logical sector to physical sector PUSH H CALL GETTYPE ANI 3 ; 128 byte sector? LDA CPMSEC ;nope, do mapping JZ GOTSDS LDA HSTSEC GOTSDS: PUSH PSW ;save sector LDA CPMDSK CALL GETDPT ;fetch pointer to xlt table MOV E,M INX H MOV D,M XCHG ;translate table now in hl POP PSW ;restore desired sector MOV E,A MVI D,0 DAD D MOV A,M ;get physical sector from table MOV E,A ;save it LDA CPMDSK CPI 4 ;was it e disk? JNZ GSEXIT LDA HSTSID ;which side? ORA A JZ GSEXIT ;side zero, ignore LDA ESECADJ ;else get adjustment ADD E MOV E,A ;put it back for move GSEXIT: MOV A,E ;move real sector to a POP H RET GETBUF: ;get the dma address CALL GETTYPE ANI 3 ; 128 byte sectors? LXI H,HSTBUF ;used for dd RNZ LHLD DMAADR ;else use real dma address... RET GETTRK: ;this routine converts logical to physical trk PUSH H CALL GETTYPE LXI H,HSTSID ;point to where we keep it RLC RLC ;test for single sided LDA CPMTRK ;fetch desired logical track JNC SEEK1 ;if single side, leave it ; we now must convert to real sectors and sides - divide by two ; and make the lsb be the side. the seek command doesn't know ; about sides, and verifies track only. read and write presumably ; should have the side select set properly (as should idread). RAR ;put side bit in carry JNC SEEK1 ;branch if side zero MVI M,10H ;else set mask for later JMP SEEK2 SEEK1: MVI M,0 ;set side zero SEEK2: POP H ;restore entry value ANI 7FH ;make it reasonable RET ; logical device physical device assignments ; -------------- --------------------------- ; con: crt: or tty: ; reader: tty: ; punch: tty: ; list: crt: or tty: or lpt: CONST: ;console status, returns 0ffh if character ready, else 00h LDA IOBYTE ;check device assignment ANI 11B ;keep con bits only JZ TTYIST ;check appropriate input status JMP CRTIST ;no third or fourth choices CONIN: ;console character into register a LDA IOBYTE ANI 11B JZ TTYIN JMP CRTIN CONOUT: ;console character output from register c LDA IOBYTE ANI 11B JZ TTYOUT JMP CRTOUT READER: ;read character into register a from reader device JMP TTYIN ;no choices supported PUNCH: ;punch character from register c JMP TTYOUT ;no choices supported LISTST: ;return list status, 0ffh if ready, else 00h LDA IOBYTE ;check device assignment ANI 11000000B ;keep lst bits only JNZ LSTST1 ;tty? JMP TTYOST ;check tty output status LSTST1: ANI 01000000B ;crt? JZ LPTST ;no other choice but lpt JMP CRTOST ;check crt output status LIST: ;list character output from register c CALL LISTST ;wait till ready to send JZ LIST LDA IOBYTE ;check device assignment ANI 11000000B ;keep lst bits only JZ TTYOUT CPI 01000000B JZ CRTOUT JMP LPTOUT ;no fourth choice CRTOST: ;crt output status, return 0ffh if ready to send, 00h if not ;crt output buffer status now checked MVI A,01H ; Check "all sent" bit in register 1 OUT SIOCPA ; . IN SIOCPA ; . ANI 01H ; . RZ ;transmit buffer not ready LDA HSA ;see if cts h/s required ORA A JZ CRTRDY ;if 0, no h/s needed ;crt cts handshake signal status now checked MVI A,10H OUT SIOCPA ;update uart status IN SIOCPA ;fetch status ANI CTS RZ ;cts not active CRTRDY: ORI 255 ;show ready to end RET CRTIST: ;crt input status, return 0ffh if data ready, 00h if not IN SIOCPA ;fetch status ANI RDA RZ ;not ready ORI 255 ;got something, signal its presence RET CRTOUT: CALL CRTOST ;ok to send? JZ CRTOUT ;nope, wait MOV A,C ;character to register a OUT SIODPA RET CRTIN: CALL CRTIST ;ready? JZ CRTIN ;nope, wait IN SIODPA ;else fetch it ani 7fh ;strip parity bit RET LPTOUT: ;printer character output from register c CALL LPTST ;printer ready? JZ LPTOUT ;nope, wait MOV A,C OUT PIO1 ;set up the data OUT STBSET ;send a data strobe OUT STBCLR ; (data doesn't matter) RET LPTST: ;return list status, 0ffh if ready, else 00h MVI A,10H ;update uart status OUT SIOCPB IN SIOCPB ;read printer busy signal ANI 10H RZ ;not ready ORI 255 ;show ready RET TTYOST: ;tty output status, return 0ffh if ready to send, 00h if not ;tty output buffer status now checked MVI A,01H ; Check "all sent" bit in register 1 OUT SIOCPB ; . IN SIOCPB ; . ANI 01H ; . RZ ;transmit buffer not ready LDA HSB ;see if cts h/s required ORA A JZ TTYRDY ;if 0, no h/s needed ;tty cts handshake signal status now checked MVI A,10H OUT SIOCPB ;update uart status IN SIOCPB ;fetch status ANI CTS RZ ;cts not active TTYRDY: ORI 255 ;show ready to send RET TTYIST: ;tty input status, return 0ffh if data ready, 00h if not IN SIOCPB ;fetch status ANI RDA RZ ;not ready ORI 255 ;got something, signal its presence RET TTYOUT: CALL TTYOST ;ok to send? JZ TTYOUT ;nope, wait MOV A,C ;character to register a OUT SIODPB RET TTYIN: IN SIOCPB ANI RDA ;char ready? JZ TTYIN ;nope, wait IN SIODPB ;else fetch it ani 7fh ;strip parity bit RET ; the following code is one-time only BOOT: ;cold boot parameter initialization MVI A,40H ;turn off eprom OUT CONT LDA IOBYT ; get iobyte value STA IOBYTE LXI SP,80H CALL IOINIT LXI H,LOGMSG CALL PUTS ;put sign-on msg on screen CALL UNLOG IF ZCPR3 ;the following code is required for zcpr3 ;expath equ 40h ;ext file search-path base ;z3whl equ 4bh ; wheel byte ;z3cl equ 0ff00h ;multi-cmd buffer storage ;z3cls equ 200 ;..and buffer length ;z3env equ 0fe00h ;named directory (d/u) storage ;shstk equ 0fd00h ;base of 32 byte shell buffers ;z3msg equ 0fd80h ;zcpr3 messages JMP ZBOOT ;go to movement routines * SYSTEM SEGMENT: SYSTEM.ENV * AUTHOR: RICHARD CONN ; program: sysenv.asm ; author: richard conn ; version: 1.0 ; date: 22 feb 84 ; previous versions: none ; ; this version revised for 61k ampro and to assemble with asm.com ; for addition to the ampro bios. 6 apr 84 jww ; ; sysenv is the definition for my zcpr3 environment, and it is loaded ; as my zcpr3 environment descriptor by z3ldr. sysenv is named to sys.env ; after assembly to permit this. ; ; ; environment definitions ; ; maclib z3base ; maclib sysenv ;* 61k zcpr3 for ampro ;**************************************************************** ;* * ;* z3base.lib -- base addresses for zcpr3 system on ampro * ;* bookshelf computer by echelon, inc. * ;* * ;* these addresses are used by the following system * ;* segments: * ;* * ;* segment function * ;* ------- -------- * ;* ampboot boot system from floppy disk * ;* bdosz customized bdos * ;* cbiosz customized bios * ;* zcpr3 zcpr3 command processor * ;* *.env all environment descriptors * ;* *.fcp all flow command packages * ;* *.iop all input/output packages * ;* *.ndr all named directory definition files * ;* *.rcp all resident command packages * ;* * ;* * ;* memory map of system: * ;* * ;* address range size function * ;* ------------- ------- -------- * ;* 0 - ff 256 b standard cp/m buffers except * ;* 40 - 4a 11 b for zcpr3 external path * ;* 4b 1 b wheel byte * ;* 100 - d7ff ~54 k tpa * ;* d800 - dfff 2 k zcpr3 command processor * ;* e000 - eeff 3.5k bdosz * ;* ef00 - fcff 3.5k cbiosz with buffers * ;* fd00 - fd00 0 k resident command package * ;* fd00 - fd00 0 k flow command package * ;* fd00 - fd00 0 b memory-based named directory * ;* fd00 - fd7f 128 b zcpr3 shell stack * ;* fd80 - fdcf 80 b zcpr3 message buffers * ;* byte 0: error flag (z/nz) * ;* byte 1: if (8 levels) * ;* byte 2: if active (8 levels) * ;* byte 3: z3 cmd status * ;* 00b - normal * ;* 01b - shell * ;* 10b - error * ;* bytes 4&5: error address if 10b * ;* byte 6: program error code * ;* byte 7: zex message byte * ;* 00b - normal * ;* 01b - z3 prompt * ;* 10b - suspend intercept * ;* byte 8: zex running flag (0=no) * ;* bytes 9-10: address of next * ;* char for zex to return * ;* bytes 11-12: address of first * ;* char in zex memory- * ;* based file buffer * ;* byte 13: sh control byte * ;* bit 0: enable shcmt * ;* bit 1: enable shecho * ;* bit 7: enable shell * ;* entry wait * ;* bytes 14-15: shell scratch * ;* bytes 10h-2fh: error cmd * ;* bytes 30h-39h: registers * ;* bytes 3ah-3fh: reserved * ;* bytes 40h-4fh: user-defined * ;* fdd0 - fdff 48 b zcpr3 external fcb * ;* fe00 - feff 256 b environment descriptors * ;* bytes 00h-7fh: z3 parameters * ;* bytes 80h-ffh: z3 terminal cap * ;* ff00 - ffcf 208 b multiple command line buffer * ;* ffd0 - ffff 48 b zcpr3 external stack * ;* * ;**************************************************************** ; ; true and false ; ;false equ 0 ;true equ not false ;* ;* zcpr3 base equates ;* ; ; 1. version numbers, memory size, and cp/m base address ; ; the following equates define the version numbers of the zcpr3 ; command processor and the cbiosz. they also explicitly state the size ; of the tpa for inclusion in the cbiosz header printed at cold boot. ; Z3REV EQU 30 ; zcpr3 rev number ;msize equ 54 ; size of tpa ; ; base - base address of user's cp/m system (normally 0 for dr version) ; this equate allows easy modification by non-standard cp/m (eg,h89) ; ;base equ 0 ; ; 2. processor selection ; ; the following equate selects the use of the 8080/8085 micro or ; the z80 micro for the target for zcpr3. note that selecting the ; 8080/8085 should be done only if you have an 8080 or 8085. if you have ; a z80, by all means select this one since the code is much smaller and ; you can cram more features into the system as a result. ; if the processor is an 8080 or 8085, set this equate to true. ; if the processor is a z80, set it to false. ; ;i8080 equ false ; ; 3. external path ; ; the following equates define the address of the zcpr3 external ; path and the number of two-byte elements contained in this path (maximum). ; if there is no zcpr3 external path, both of these values should be set to 0. ; EXPATH EQU 40H ; external path EXPATHS EQU 5 ; 5 2-byte path elements ; (path size = expaths*2 + 1) ; ; 4. wheel byte ; ; the following equate defines the address of the zcpr3 wheel byte. ; if there is no zcpr3 wheel byte, this value should be set to 0. ; Z3WHL EQU 4BH ; wheel byte address ; ; 5. ccp location ; ; the following equate defines the address of the zcpr3 command ; processor. this address must be supplied. ; ;ccp equ 0d800h ; zcpr3 command processor ; ; 6. rcp location ; ; the following equates define the address of the zcpr3 resident ; command package and its size in 128-byte blocks. if there is no ; zcpr3 resident command package, both of these values should be 0. ; RCP EQU 00000H ; resident command package RCPS EQU 00 ; 00 128-byte blocks (0k bytes) ; ; 7. iop location ; ; the following equates define the address of the zcpr3 input/output ; package and its size in 128-byte blocks. if there is no zcpr3 input/output ; package, both of these values should be 0. ; IOP EQU 00000H ; redirectable i/o package IOPS EQU 00 ; 00 128-byte blocks (0k bytes) ; ; 8. fcp location ; ; the following equates define the address of the zcpr3 flow command ; package and its size in 128-byte blocks. if there is no zcpr3 flow command ; package, both of these values should be 0. ; FCP EQU 00000H ; flow command package FCPS EQU 0 ; 0 128-byte blocks (0k bytes) ; ; 9. env location ; ; the following equates define the address of the zcpr3 environment ; descriptor and its size in 128-byte blocks. if there is no zcpr3 environment ; descriptor, both of these values should be 0. ; Z3ENV EQU 0FE00H ; environment descriptors Z3ENVS EQU 2 ; size of environment descriptor in 128-byte blocks ; ; 10. shell stack ; ; the following equates define the address of the zcpr3 shell stack, ; the number of entries permitted in the zcpr3 shell stack, and the size ; of each entry in the shell stack in terms of bytes. if there is no zcpr3 ; shell stack, all three values should be 0. ; SHSTK EQU 0FD00H ; zcpr3 shell stack SHSTKS EQU 4 ; number of shsize-byte shell stack entries SHSIZE EQU 32 ; size of a shell stack entry ; (stack size = shstks * shsize) ; ; 11. zcpr3 messages ; ; the following equate defines the address of the zcpr3 message buffer. ; this buffer is always 80 bytes long. if there is no zcpr3 message buffer, ; this address should be 0. ; Z3MSG EQU 0FD80H ; zcpr3 message buffer ; ; 12. external fcb ; ; the following equate defines the address of the zcpr3 external fcb. ; this buffer is always 36 bytes long. if there is no zcpr3 external fcb, ; this address should be 0. ; EXTFCB EQU 0FDD0H ; zcpr3 external fcb ; ; 13. named directory buffer ; ; the following equates define the address and size (in terms of 18-byte ; entries) of the zcpr3 named directory buffer. if there is no such buffer, ; both of these values should be 0. ; Z3NDIR EQU 00000H ; zcpr3 named directory area Z3NDIRS EQU 00 ; 00 18-byte named directory elements permitted ; (ndir size = z3ndirs*18 + 1 for trailing 0) ; ; 14. command line ; ; the following equates define the address and size (in terms of bytes) ; of the zcpr3 command line buffer (formerly called the multiple command line ; buffer under zcpr2). if there is no such buffer, both of these values should ; be 0. ; Z3CL EQU 0FF00H ; zcpr3 command line buffer Z3CLS EQU 200 ; size of command line buffer ; ; 15. external stack ; ; the following equate defines the address of the zcpr3 external stack. ; this stack is always 48 bytes in size. if there is no such stack, this ; value should be 0. ; EXTSTK EQU 0FFD0H ; zcpr3 external stack ; ; 16. user equates ; ; the following equates are available for the implementer's target ; system. these are implementation-defined. ; ;* ;* end of zcpr3 base equates ;* ; ; include environment descriptor ; ; org 100h ; origin ENV: JMP 0 ; leading jmp ; sysenv ; end ; library: sysenv.lib ; author: richard conn ; version: 1.0 ; date: 22 feb 84 ; previous versions: none ; ; sysenv is the definition for the ampro zcpr3 environment. ; ;sysenv macro ; ; environment descriptor ; if inline, there is a leading jmp just before this ; ENVORG1: DB 'Z3ENV' ; environment id DB 2 ; class 2 environment (internal) DW EXPATH ; external path address DB EXPATHS ; number of 2-byte elements in path DW RCP ; rcp address DB RCPS ; number of 128-byte blocks in rcp DW IOP ; iop address DB IOPS ; number of 128-byte blocks in iop DW FCP ; fcp address DB FCPS ; number of 128-byte blocks in fcp DW Z3NDIR ; ndr address DB Z3NDIRS ; number of 18-byte entries in ndr DW Z3CL ; zcpr3 command line DB Z3CLS ; number of bytes in command line DW Z3ENV ; zcpr3 environment descriptor DB Z3ENVS ; number of 128-byte blocks in descriptor DW SHSTK ; shell stack address DB SHSTKS ; number of shsize-byte entires in shell stack DB SHSIZE ; size of a shell stack entry DW Z3MSG ; zcpr3 message buffer DW EXTFCB ; zcpr3 external fcb DW EXTSTK ; zcpr3 external stack DB 0 ; quiet flag (1=quiet, 0=not quiet) DW Z3WHL ; address of wheel byte DB 4 ; processor speed in mhz DB 'E'-'@' ; maximum disk DB 31 ; maximum user DB 1 ; 1=ok to accept du, 0=not ok DB 0 ; crt selection (0=crt 0, 1=crt 1) DB 0 ; printer selection (n=printer n) DB 80 ; width of crt 0 DB 24 ; number of lines on crt 0 DB 22 ; number of lines of text on crt 0 DB 80 ; width of crt 1 DB 24 ; number of lines on crt 1 DB 22 ; number of lines of text on crt 1 DB 80 ; width of printer 0 DB 66 ; number of lines on printer 0 DB 58 ; number of lines of text on printer 0 DB 1 ; form feed flag (0=can't formfeed, 1=can) DB 102 ; width of printer 1 DB 66 ; number of lines on printer 1 DB 58 ; number of lines of text on printer 1 DB 1 ; form feed flag (0=can't formfeed, 1=can) DB 80 ; width of printer 2 DB 66 ; number of lines on printer 2 DB 58 ; number of lines of text on printer 2 DB 1 ; form feed flag (0=can't formfeed, 1=can) DB 80 ; width of printer 3 DB 66 ; number of lines on printer 3 DB 58 ; number of lines of text on printer 3 DB 1 ; form feed flag (0=can't formfeed, 1=can) DB 'SH ' ; shell variable filename DB 'VAR' ; shell variable filetype DB ' ' ; filename 1 DB ' ' ; filetype 1 DB ' ' ; filename 2 DB ' ' ; filetype 2 DB ' ' ; filename 3 DB ' ' ; filetype 3 DB ' ' ; filename 4 DB ' ' ; filetype 4 DS 128-($-ENVORG1+3) ; make exactly 128 bytes long ; (+3 compensates for leading jmp) ; ; terminal capabilities data ; ENVORG2: DB ' ' ;name of terminal (none) DB 'E'-'@' ;cursor up DB 'X'-'@' ;cursor down DB 'D'-'@' ;cursor right DB 'S'-'@' ;cursor left DB 00 ;cl delay DB 00 ;cm delay DB 00 ;ce delay DB 0 ;cl string DB 0 ;cm string DB 0 ;ce string DB 0 ;so string DB 0 ;se string DB 0 ;ti string DB 0 ;te string DS 32-($-ENVORG2) ; make exactly 32 bytes long ; ; end of environment descriptor ; ; endm CMDSET: DW Z3CL+4 ;point to first char in command buf DB Z3CLS ;buffer size DW 0 ;buffer empty PATH: DB '$',0 ;current drive and user 0 DB 1,'$' ;drive 'a' and current user DB 1,0 ;drive 'a' and user 0 DB 1,15 ;drive 'a' and user 15 DB '$',15 ;current drive and user 15 DB 0 ;end of path ZERO: ; clear (hl) for (b) bytes XRA A ; clear a to zero ZL: MOV M,A ; move it to memory INX H ; bump pointer DCR B ; count down JNZ ZL ; until zero RET LDIR: ; move bc bytes from (hl) to (de) MOV A,M STAX D INX H INX D DCX B MOV A,B ORA C JNZ LDIR RET ZBOOT: LXI B,3 ;move data structures to storage areas LXI H,CMDSET LXI D,Z3CL CALL LDIR LXI B,10 LXI H,AUTOCMD LXI D,Z3CL+3 CALL LDIR LXI B,11 ; number of bytes in path LXI H,PATH LXI D,EXPATH CALL LDIR LXI H,Z3WHL ; clear wheel byte MVI M,0 LXI H,SHSTK ; clear shell stack MVI M,0 LXI H,Z3MSG MVI B,80 CALL ZERO LXI H,ENV LXI D,Z3ENV LXI B,128+32 CALL LDIR ENDIF ; zcpr3 XRA A ;zero in the accum STA CDISK ;select disk zero STA HSTACT ;host buffer inactive STA UNACNT ;clear unalloc count STA HSTSID ;assume side zero JMP GOCPM ;initialize and go to cp/m LOGMSG: DB CR,LF,LF,'AMPRO ' DB MSIZE/10 +'0',MSIZE MOD 10 +'0','k CP/M vers 2.2' DB CR,LF,' BIOS Version ',VERS/10+'0','.',VERS MOD 10+'0' DB CR,LF,0 ORG BOOT UNINIT EQU $ SEKDSK: DS 1 ;seek disk number SEKTRK: DS 1 ;seek track number SEKSEC: DS 1 ;seek sector number HSTDSK: DS 1 ;host disk number HSTTRK: DS 1 ;host track number HSTSEC: DS 1 ;host sector number CPMDSK: DS 1 ;single density dsk parm CPMTRK: DS 1 ; and trk CPMSEC: DS 1 ; and sector SEKHST: DS 1 ;seek shr secshf HSTACT: DS 1 ;host active flag HSTWRT: DS 1 ;host written flag UNACNT: DS 1 ;unalloc rec cnt UNADSK: DS 1 ;last unalloc disk UNATRK: DS 1 ;last unalloc track UNASEC: DS 1 ;last unalloc sector CPMSPT: DS 1 ; logical sectors per track SECMSK: DS 1 ; sector mask SECSHF: DS 1 ; sector shift MUNACT: DS 1 ; unallocated count value CHGDSK: ds 1 ; changed disk flag ERFLAG: DS 1 ;error reporting RSFLAG: DS 1 ;read sector flag READOP: DS 1 ;1 if read operation WRTYPE: DS 1 ;write operation type DMAADR: DS 2 ;last dma address HSTBUF: DS 1024 ;host buffer ; ampro bios-specific storage IDSAVE: DS 6 ;read address buffer area LTRACK: DS 5 ;last track accessed TRIES: DS 1 ;number of times to do it RWHOST: DS 1 ;local read/write flag HSTSID: DS 1 ;host disk side select mask TOCNT: DS 1 ;timeout loop counter SECTOR: DS 1 ;temporary storage ; special e disk parameters - filled in when e disk is ; first selected, and used in deblocking. ESECADJ: DS 1 ;sector number adjust for side 1 DIRBUF: DS 128 ;directory access buffer ALV0: DS 50 CSV0: DS 64 ALV1: DS 50 CSV1: DS 64 ALV2: DS 50 CSV2: DS 64 ALV3: DS 50 CSV3: DS 64 ALV4: DS 50 CSV4: DS 64 ENDDAT EQU $ DATSIZ EQU $-UNINIT RESERVE EQU 0FD00H ; memory reserved above here REMAINS EQU RESERVE-ENDDAT END BIOS