title 'LDRBIOS for CP/M 3.0' ; Port Address Equates maclib z180reg.inc maclib config.inc ; IDE Task File Register Definitions IDEDat equ IDEBASE+0 ; Data Register IDEErr equ IDEBASE+1 ; Error Register IDEFeat equ IDEBASE+1 ; Feature Register IDESCnt equ IDEBASE+2 ; Sector Count IDESNum equ IDEBASE+3 ; Sector Number IDECLo equ IDEBASE+4 ; Cylinder Low IDECHi equ IDEBASE+5 ; Cylinder High IDESDH equ IDEBASE+6 ; Drive and Head IDECmd equ IDEBASE+7 ; Command / Status ; IDE Hard disk commands: CmdHome equ 10h ; Recalibrate CmdRd equ 20h ; Read Sector CmdWr equ 30h ; Write Sector CmdInit equ 91h ; Initialize Drive Params CmdId equ 0ECh ; Read ID CmdSF equ 0EFh ; Set Feature ; Partition Table Structures PART_TYPE equ 4 PART_START equ 8 PART_SIZE equ 12 ; Partition table id ; (see http://www.win.tue.nl/~aeb/partitions/partition_types-1.html) PARTID1_FAT16 equ 00EH PARTID2_FAT16 equ 006H PARTID_CPM equ 052H TIMEOUT equ 1000 cr equ 13 lf equ 10 .z80 cseg ; BIOS Jump vector. ?boot: jp boot ; initial entry on cold start ?wboot: jp wboot ; reentry on program exit, warm start ?const: jp const ; return console input status ?conin: jp conin ; return console input character ?cono: jp conout ; send console output character ?list: jp list ; send list output character ?auxo: jp auxout ; send auxilliary output character ?auxi: jp auxin ; return auxilliary input character ?home: jp home ; set disks to logical home ?sldsk: jp seldsk ; select disk drive, return disk parameter info ?sttrk: jp settrk ; set disk track ?stsec: jp setsec ; set disk sector ?stdma: jp setdma ; set disk I/O memory address ?read: jp read ; read physical block(s) ?write: jp write ; write physical block(s) ?lists: jp listst ; return list device status ?sctrn: jp sectrn ; translate logical to physical sector ?conos: jp conost ; return console output status ?auxis: jp auxist ; return aux input status ?auxos: jp auxost ; return aux output status ?dvtbl: jp devtbl ; return address of device def table ?devin: jp cinit ; change baud rate of device ?drtbl: jp getdrv ; return address of disk drive table ?mltio: jp multio ; set multiple record count for disk I/O ?flush: jp flush ; flush BIOS maintained disk caching ?mov: jp move ; block move memory to memory ?tim: jp time ; Signal Time and Date operation ?bnksl: jp bnksel ; select bank for code execution and default DMA ?stbnk: jp setbnk ; select different bank for disk I/O DMA operations. ?xmov: jp xmove ; set source and destination banks for one operation jp 0 ; reserved for future expansion jp 0 ; reserved for future expansion jp 0 ; reserved for future expansion ;---------------------------------------------------------------------- hwini_tab: db (hwini0_e-$)/2 ;count db rcr,CREFSH ;configure DRAM refresh db dcntl,CWAITIO ;wait states db ccr,M_NCD ;No Clock Divide db cmr,PHI_X2 ;X2 Clock Multiplier db omcr,~M_IOC ;Operation Mode Control Register ;MMU db cbr,SYS$CBR ;Common Base Register db cbar,USR$CBAR ;Common Base Area Register ;ASCI0 db asext1,0 ;disable BRG db stat1,00000000b ;disable RX, TX interrupt, disable CTS1 db cntlb1,10000000b;PS:10 DR:16 Rate:1 --> BR = Phi/160 db cntla1,01100101b;RE TE RTS:0 8N2 hwini0_e: db 0 ;stop mark db 0,0,0,0,0,0,0,0 ; msg_boot: db cr,lf,'CPMLDR error: Unable to locate CP/M partition',cr,lf,0 ;------------------------------------------------------------------------------- ; CP/M 3 Disk definition macros maclib cpm3slr.lib ; dpb mcaro ; The dph macro from the lib depends on GENCPM dphldr macro ?trans,?dpb,?csize,?asize,?dirbcb,?dtabcb local ?csv,?alv dw ?trans ; translate table address db 0,0,0,0,0,0,0,0,0 ; BDOS Scratch area db 0 ; media flag dw ?dpb ; disk parameter block if nul ?csize dw 0 ; permanently mounted, no checksum vector else if ?csize = 0 dw 0 else dw ?csv ; checksum vector endif endif if nul ?asize dw 0 ; no alloc vector else if ?asize = 0 dw 0 else dw ?alv ; allocation vector endif endif dw ?dirbcb dw ?dtabcb dw 0ffffh ; no hash db 0 ; hash bank if not nul ?csize if ?csize <> 0 ?csv ds ?csize ; checksum vector endif endif if not nul ?asize if ?asize <> 0 ?alv ds ?asize ; allocation vector endif endif endm ;------------------------------------------------------------------------------- ; dphldr translate$table, - disk parameter header ; disk$parameter$block, ; checksum$size, (optional) ; alloc$size (optional) ; dir$bcb ; data$bcb dph0: dphldr 0,dpbsimhd512,0,0,bcb,bcb bcb: db 0ffh rept 9 db 0 endm dw buffer ; dpb physical$sector$size, - disk parameter block ; physical$sectors$per$track, ; number$tracks, ; block$size, ; number$dir$entries, ; track$offset, ; checksum$vec$size (optional) dpbsimhd512: dpb 512,8,2048,4096,1024,6,8000h ;------------------------------------------------------------------------------- wboot: ; jump vector locations not used const: conin: list: auxout: auxin: write: listst: conost: auxist: auxost: devtbl: cinit: getdrv: multio: flush: time: bnksel: setbnk: xmove: ret ;------------------------------------------------------------------------------- ; output bytes to ports ; ; hl: tables of port,value pairs: ; db n, port1,val1, port2,val2,... portn,valn ; ... ; db 0 ; Terminate table ioini1l: push bc jr io1_nxt io1_lp: ld c,(hl) ;port address inc hl otim jr nz,io1_lp io1_nxt: ld b,(hl) ;count inc hl inc b djnz io1_lp pop bc ret ;------------------------------------------------------------------------------- ; print message @ up to a null ?pmsg: ld a,(hl) or a ret z ld c,a push hl call ?cono pop hl inc hl jr ?pmsg ;------------------------------------------------------------------------------- boot: ; Init CPU, MMU, ASCI0 ld hl,hwini_tab call ioini1l ; Init disk partition call read_parttbl or a jr nz,boot_err ; check_signature ld hl,buffer+512-1 ld a,0aah cp (hl) ; Test, if it has a valid MBR jr nz,boot_err dec hl cpl ; a=055h cp (hl) ; jr nz,boot_err ; Find CP/M paartition ; Look for first CP/M partition and save partition offset ld hl,buffer+512-2-64+PART_TYPE ; Point to partition type of first first partition table entry ld de,16 ld b,4 ; Max # of partition table entries ploop: ld a,PARTID_CPM sub (HL) ; Test for CP/M Partition jr nz,pnext ld bc,4 add hl,bc ; Point to partition start (lba) ld de,ptab_start ldir ret ;a=0 pnext: add hl,de djnz ploop boot_err: ld hl,msg_boot call ?pmsg halt_loop: halt jr halt_loop ;------------------------------------------------------------------------------- conout: in0 a,(stat1) and M_TDRE jr z,conout out0 (tdr1),c ld a,c ret ;------------------------------------------------------------------------------- move: ex de,hl ; we are passed source in DE and dest in HL ldir ; use Z80 block move instruction ex de,hl ; need next addresses in same regs ret ;------------------------------------------------------------------------------- ; Select Disk Drive. ; Return address of disk parameter header in seldsk: ld hl,dph0 ret ; Home selected drive. Treated as SETTRK(0). home: ld bc,0 ; same as set track zero ; Set Track. Saves track address from in @trk. settrk: ld (@trk),bc ret ; Set Sector. Saves sector number from in @sect. setsec: ld (@sect),bc ret ; Set Disk Memory Address. Saves DMA address from in @dma. setdma: ld (@dma),bc ret ; Translate sector address. Not needed. Return physical=logical. sectrn: ld l,c ld h,b ret ;----------------------------------------------------------------- chk_to: xor a ; to_l: dec a jr nz,to_l ; dec hl ; 4 ld a,h ; 4 or l ; 4 ret nz ; 10/5 ccf ; 3 ret ; 9 ;------------------------------------------------------------------------------- ; Wait for ready signal with time out ; return: ; a = 0 if ok ; a = ff if timeout wait_rdy_to: push hl ld hl,TIMEOUT wrdy_l: in a,(IdeCmd) xor 01000000b and 11000000b ; clears carry jr z,wrdy_e call chk_to jr nc,wrdy_l wrdy_e: pop hl sbc a,a ret ;------------------------------------------------------------------------------- do_ide_cmd: out (IdeCmd),a ; call wait_rdy_to ret c in a,(IdeCmd) and 10001001b ; ret ;------------------------------------------------------------------------------- ; Read partition table read_parttbl: ld hl,ptab_start ld b,8 rp_l: ld (hl),0 inc hl djnz rp_l ld hl,buffer ld (@dma),hl ; fall thru ;------------------------------------------------------------------------------- ; Read a sector ; compute logical block number (lba) --> cf-controller ; TODO: sectors per track from dpb ; lba = track * 8 + sector read: ld iy,ptab_start xor a ld hl,(@trk) add hl,hl adc a,a ; *2 add hl,hl adc a,a ; *4 add hl,hl adc a,a ; *8 ld de,(@sect) add hl,de adc a,0 ld e,a call wait_rdy_to ld a,(iy+0) ; add partition start add a,l out (IdeSNum),a ld a,(iy+1) adc a,h out (IdeCLo),a ld a,(iy+2) adc a,e out (IdeCHi),a ld a,(iy+3) adc a,0 and 00FH or 0E0H out (IdeSDH),a ld hl,(@dma) ld a,1 ; number of sectors to read out (IdeSCnt),a ; set sector count ld a,CmdRd out (IdeCmd),a ; command: read sector data ld bc,IdeDat ; I/O address wdrq: in a,(IdeCmd) ; wait for DRQ to become active bit 3,a jr z,wdrq inir ; read 512 data bytes (2 x 256) inir wnb: ; wait while busy in a,(IdeCmd) ; rlca jr c,wnb rrca ; restore status and 10001001b ; Busy, DRQ, or Error? ret z ; return 0, if everything is ok ld a,1 ret ;------------------------------------------------------------------------------- ptab_start: dw 0,0 @trk: dw 0 @sect: dw 0 @dma: dw 0 buffer: end