; Extended Z80 CBIOS for Z80-Simulator ; ; Copyright (C) 1988-2007 by Udo Munk ; ; This version supports the TIMEDAT date/time information needed ; by QP/M, to support time/date stamps for files. This BIOS ; requires a patch installed in z80pack release 1.14, later ; versions already include the improved clock circuit. ; MSIZE EQU 64 ;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 CCP EQU 3400H+BIAS ;base of ccp BDOS EQU CCP+806H ;base of bdos BIOS EQU CCP+1600H ;base of bios NSECTS EQU (BIOS-CCP)/128 ;warm start sector count CDISK EQU 0004H ;current disk number 0=A,...,15=P IOBYTE EQU 0003H ;intel i/o byte ; ; I/O ports ; CONSTA EQU 0 ;console status port CONDAT EQU 1 ;console data port PRTSTA EQU 2 ;printer status port PRTDAT EQU 3 ;printer data port AUXDAT EQU 5 ;auxiliary data port FDCD EQU 10 ;fdc-port: # of drive FDCT EQU 11 ;fdc-port: # of track FDCS EQU 12 ;fdc-port: # of sector FDCOP EQU 13 ;fdc-port: command FDCST EQU 14 ;fdc-port: status DMAL EQU 15 ;dma-port: dma address low DMAH EQU 16 ;dma-port: dma address high ; CLKCMD EQU 25 ;clock command CLKDAT EQU 26 ;clock data ; ; clock commands ; GETSEC EQU 0 ;get seconds GETMIN EQU 1 ;get minutes GETHOU EQU 2 ;get hours GETDAY EQU 5 ;get day of month GETMON EQU 6 ;get month GETYEA EQU 7 ;get year CLKTOG EQU 0FFH ;toggle clock BCD/binary ; ORG BIOS ;origin of this program ; ; jump vector for individual subroutines ; JP BOOT ;cold start WBOOTE: JP WBOOT ;warm start JP CONST ;console status JP CONIN ;console character in JP CONOUT ;console character out JP LIST ;list character out JP PUNCH ;punch character out JP READER ;reader character in JP HOME ;move head to home position JP SELDSK ;select disk JP SETTRK ;set track number JP SETSEC ;set sector number JP SETDMA ;set dma address JP READ ;read disk JP WRITE ;write disk JP LISTST ;return list status JP SECTRAN ;sector translate ; JP CLOCK ;get time/date from system clock ; ; fixed data tables for four-drive standard ; IBM-compatible 8" SD disks ; ; disk parameter header for disk 00 DPBASE: DEFW TRANS,0000H DEFW 0000H,0000H DEFW DIRBF,DPBLK DEFW CHK00,ALL00 ; disk parameter header for disk 01 DEFW TRANS,0000H DEFW 0000H,0000H DEFW DIRBF,DPBLK DEFW CHK01,ALL01 ; disk parameter header for disk 02 DEFW TRANS,0000H DEFW 0000H,0000H DEFW DIRBF,DPBLK DEFW CHK02,ALL02 ; disk parameter header for disk 03 DEFW TRANS,0000H DEFW 0000H,0000H DEFW DIRBF,DPBLK DEFW CHK03,ALL03 ; ; sector translate vector for the IBM 8" SD disks ; TRANS: DEFB 1,7,13,19 ;sectors 1,2,3,4 DEFB 25,5,11,17 ;sectors 5,6,7,8 DEFB 23,3,9,15 ;sectors 9,10,11,12 DEFB 21,2,8,14 ;sectors 13,14,15,16 DEFB 20,26,6,12 ;sectors 17,18,19,20 DEFB 18,24,4,10 ;sectors 21,22,23,24 DEFB 16,22 ;sectors 25,26 ; ; disk parameter block, common to all IBM 8" SD disks ; DPBLK: DEFW 26 ;sectors per track DEFB 3 ;block shift factor DEFB 7 ;block mask DEFB 0 ;extent mask DEFW 242 ;disk size-1 DEFW 63 ;directory max DEFB 192 ;alloc 0 DEFB 0 ;alloc 1 DEFW 16 ;check size DEFW 2 ;track offset ; ; fixed data tables for 4MB harddisks ; ; disk parameter header HDB1: DEFW 0000H,0000H DEFW 0000H,0000H DEFW DIRBF,HDBLK DEFW CHKHD1,ALLHD1 HDB2: DEFW 0000H,0000H DEFW 0000H,0000H DEFW DIRBF,HDBLK DEFW CHKHD2,ALLHD2 ; ; disk parameter block for harddisk ; HDBLK: DEFW 128 ;sectors per track DEFB 4 ;block shift factor DEFB 15 ;block mask DEFB 0 ;extent mask DEFW 2039 ;disk size-1 DEFW 1023 ;directory max DEFB 255 ;alloc 0 DEFB 255 ;alloc 1 DEFW 0 ;check size DEFW 0 ;track offset ; ; messages ; SIGNON: DEFM '64K CP/M Vers. 2.2 (Z80 XCBIOS V1.3 for Z80SIM, ' DEFM 'Copyright 1988-2007 by Udo Munk)' DEFB 13,10,0 ; LDERR: DEFM 'BIOS: error booting' DEFB 13,10,0 ; ; timedat buffer ; TIMDAT: DEFB 1 ;day DEFB 1 ;month DEFB 78 ;year DEFB 0 ;hour DEFB 0 ;minute DEFB 0 ;second ; ; end of fixed tables ; ; utility functions ; ; prepare clock data ; CLOCK: LD A,GETHOU ;get hours OUT (CLKCMD),A IN A,(CLKDAT) LD (TIMDAT+3),A LD A,GETMIN ;get minutes OUT (CLKCMD),A IN A,(CLKDAT) LD (TIMDAT+4),A LD A,GETSEC ;get seconds OUT (CLKCMD),A IN A,(CLKDAT) LD (TIMDAT+5),A LD A,GETDAY ;get day of month OUT (CLKCMD),A IN A,(CLKDAT) LD (TIMDAT+0),A LD A,GETMON ;get month OUT (CLKCMD),A IN A,(CLKDAT) LD (TIMDAT+1),A LD A,GETYEA ;get year OUT (CLKCMD),A IN A,(CLKDAT) LD (TIMDAT+2),A LD HL,TIMDAT ;return time/date buffer address in HL RET ; ; print a 0 terminated string to console device ; pointer to string in HL ; PRTMSG: LD A,(HL) OR A RET Z LD C,A CALL CONOUT INC HL JP PRTMSG ; ; individual subroutines to perform each function ; simplest case is to just perform parameter initialization ; BOOT: LD SP,80H ;use space below buffer for stack LD HL,SIGNON ;print message CALL PRTMSG XOR A ;zero in the accum LD (IOBYTE),A ;clear the iobyte LD (CDISK),A ;select disk zero LD A,CLKTOG ;toggle clock to decimal OUT (CLKCMD),A JP GOCPM ;initialize and go to cp/m ; ; simplest case is to read the disk until all sectors loaded ; WBOOT: LD SP,80H ;use space below buffer for stack LD C,0 ;select disk 0 CALL SELDSK CALL HOME ;go to track 00 ; LD B,NSECTS ;b counts # of sectors to load LD C,0 ;c has the current track number LD D,2 ;d has the next sector to read ; note that we begin by reading track 0, sector 2 since sector 1 ; contains the cold start loader, which is skipped in a warm start LD HL,CCP ;base of cp/m (initial load point) LOAD1: ;load one more sector PUSH BC ;save sector count, current track PUSH DE ;save next sector to read PUSH HL ;save dma address LD C,D ;get sector address to register c CALL SETSEC ;set sector address from register c POP BC ;recall dma address to b,c PUSH BC ;replace on stack for later recall CALL SETDMA ;set dma address from b,c ; drive set to 0, track set, sector set, dma address set CALL READ OR A ;any errors? JP Z,LOAD2 ;no, continue LD HL,LDERR ;error, print message CALL PRTMSG DI ;and halt the machine HALT ; no error, move to next sector LOAD2: POP HL ;recall dma address LD DE,128 ;dma=dma+128 ADD HL,DE ;new dma address is in h,l POP DE ;recall sector address POP BC ;recall number of sectors remaining, ;and current trk DEC B ;sectors=sectors-1 JP Z,GOCPM ;transfer to cp/m if all have been loaded ; more sectors remain to load, check for track change INC D LD A,D ;sector=27?, if so, change tracks CP 27 JP C,LOAD1 ;carry generated if sector<27 ; end of current track, go to next track LD D,1 ;begin with first sector of next track INC C ;track=track+1 ; save register state, and change tracks CALL SETTRK ;track address set from register c JP LOAD1 ;for another sector ; end of load operation, set parameters and go to cp/m GOCPM: LD A,0C3H ;c3 is a jmp instruction LD (0),A ;for jmp to wboot LD HL,WBOOTE ;wboot entry point LD (1),HL ;set address field for jmp at 0 ; LD (5),A ;for jmp to bdos LD HL,BDOS ;bdos entry point LD (6),HL ;address field of jump at 5 to bdos ; LD BC,80H ;default dma address is 80h CALL SETDMA ; LD A,(CDISK) ;get current disk number LD C,A ;send to the ccp JP CCP ;go to cp/m for further processing ; ; ; simple i/o handlers ; ; console status, return 0ffh if character ready, 00h if not ; CONST: IN A,(CONSTA) ;get console status RET ; ; console character into register a ; CONIN: IN A,(CONDAT) ;get character from console RET ; ; console character output from register c ; CONOUT: LD A,C ;get to accumulator OUT (CONDAT),A ;send character to console RET ; ; list character from register c ; LIST: LD A,C ;character to register a OUT (PRTDAT),A RET ; ; return list status (00h if not ready, 0ffh if ready) ; LISTST: IN A,(PRTSTA) RET ; ; punch character from register c ; PUNCH: LD A,C ;character to register a OUT (AUXDAT),A RET ; ; read character into register a from reader device ; READER: IN A,(AUXDAT) RET ; ; ; i/o drivers for the disk follow ; ; move to the track 00 position of current drive ; translate this call into a settrk call with parameter 00 ; HOME: LD C,0 ;select track 0 JP SETTRK ;we will move to 00 on first read/write ; ; select disk given by register C ; SELDSK: LD HL,0000H ;error return code LD A,C CP 4 ;FD drive 0-3? JP C,SELFD ;go CP 8 ;harddisk 1? JP Z,SELHD1 ;go CP 9 ;harddisk 2? JP Z,SELHD2 ;go RET ;no, error ; disk number is in the proper range ; compute proper disk parameter header address SELFD: OUT (FDCD),A ;selekt disk drive LD L,A ;L=disk number 0,1,2,3 ADD HL,HL ;*2 ADD HL,HL ;*4 ADD HL,HL ;*8 ADD HL,HL ;*16 (size of each header) LD DE,DPBASE ADD HL,DE ;HL=.dpbase(diskno*16) RET SELHD1: LD HL,HDB1 ;dph harddisk 1 JP SELHD SELHD2: LD HL,HDB2 ;dph harddisk 2 SELHD: OUT (FDCD),A ;select harddisk drive RET ; ; set track given by register c ; SETTRK: LD A,C OUT (FDCT),A RET ; ; set sector given by register c ; SETSEC: LD A,C OUT (FDCS),A RET ; ; translate the sector given by BC using the ; translate table given by DE ; SECTRAN: LD A,D ;do we have a translation table? OR E JP NZ,SECT1 ;yes, translate LD L,C ;no, return untranslated LD H,B ;in HL INC L ;sector no. start with 1 RET NZ INC H RET SECT1: EX DE,HL ;HL=.trans ADD HL,BC ;HL=.trans(sector) LD L,(HL) ;L = trans(sector) LD H,0 ;HL= trans(sector) RET ;with value in HL ; ; set dma address given by registers b and c ; SETDMA: LD A,C ;low order address OUT (DMAL),A LD A,B ;high order address OUT (DMAH),A ;in dma RET ; ; perform read operation ; READ: XOR A ;read command -> A JP WAITIO ;to perform the actual i/o ; ; perform a write operation ; WRITE: LD A,1 ;write command -> A ; ; 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 ; WAITIO: OUT (FDCOP),A ;start i/o operation IN A,(FDCST) ;status of i/o operation -> A RET ; ; the remainder 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"). ; ; scratch ram area for BDOS use ; BEGDAT EQU $ ;beginning of data area DIRBF: DEFS 128 ;scratch directory area ALL00: DEFS 31 ;allocation vector 0 ALL01: DEFS 31 ;allocation vector 1 ALL02: DEFS 31 ;allocation vector 2 ALL03: DEFS 31 ;allocation vector 3 ALLHD1: DEFS 255 ;allocation vector harddisk 1 ALLHD2: DEFS 255 ;allocation vector harddisk 2 CHK00: DEFS 16 ;check vector 0 CHK01: DEFS 16 ;check vector 1 CHK02: DEFS 16 ;check vector 2 CHK03: DEFS 16 ;check vector 3 CHKHD1: DEFS 0 ;check vector harddisk 1 CHKHD2: DEFS 0 ;check vector harddisk 2 ; ENDDAT EQU $ ;end of data area DATSIZ EQU $-BEGDAT ;size of data area ; END ;of BIOS