; CBIOS for my 8080 microcomputer ; JWD - v3.0 03/05/2026 ; ; Changes in v2.0 ; ; Changed 'nsects' variable to only load 800h bytes (CPP) on warm boot. ; Moved drive initialization to a subroutine. ; Added storage for most recent drive error. ; Added read of ATA error register in the ataerror routine to avoid lockups with ataready. ; ; Changes in v3.0 ; ; Added drivers for second serial port and one parallel printer port ; Changed cpp start to DE00 to allow more room for the serial and parallel drivers ; ; CPU 8080 ; Specify architecture PAGE 0 ; ; ;Physical CF disk LBA to DTS partition layout ; ;Drive n |DSK|| TRK ||SEC | ; xxxxxx00 00000000 00000000 - drive d, track t, sector 0 ; xxxxxx00 00000000 00111111 - drive d, track t, sector 63 ; ;Drive A (0) |DSK|| TRK ||SEC | ; xxxxxx00 0000000 00000000 - drive 0, track 0, sector 0 ; xxxxxx00 00111111 11111111 - drive 0, track 255, sector 63 ; ;Drive B (1) |DSK|| TRK ||SEC | ; xxxxxx00 01000000 00000000 - drive 1, track 0, sector 0 ; xxxxxx00 01111111 11111111 - drive 1, track 255, sector 63 ; ;Drive C (2) |DSK|| TRK ||SEC | ; xxxxxx00 10000000 00000000 - drive 2, track 0, sector 0 ; xxxxxx00 10111111 11111111 - drive 2, track 255, sector 63 ; ;Drive D (3) |DSK|| TRK ||SEC | ; xxxxxx00 11000000 00000000 - drive 3, track 0, sector 0 ; xxxxxx00 11111111 11111111 - drive 3, track 255, sector 63 ; ;Drive E (4) |DSK|| TRK ||SEC | ; xxxxxx01 00000000 00000000 - drive 4, track 0, sector 0 ; xxxxxx01 00111111 11111111 - drive 4, track 255, sector 63 ; ;Drive F (5) |DSK|| TRK ||SEC | ; xxxxxx01 01000000 00000000 - drive 5, track 0, sector 0 ; xxxxxx01 01111111 11111111 - drive 5, track 255, sector 63 ; ;Drive G (6) |DSK|| TRK ||SEC | ; xxxxxx01 10000000 00000000 - drive 6, track 0, sector 0 ; xxxxxx01 10111111 11111111 - drive 6, track 255, sector 63 ; ;Drive H (7) |DSK|| TRK ||SEC | ; xxxxxx01 11000000 00000000 - drive 7, track 0, sector 0 ; xxxxxx01 11111111 11111111 - drive 7, track 255, sector 63 ; ;Drive I (8) |DSK|| TRK ||SEC | ; xxxxxx10 00000000 00000000 - drive 8, track 0, sector 0 ; xxxxxx10 00111111 11111111 - drive 8, track 255, sector 63 ; ;Drive J (9) |DSK|| TRK ||SEC | ; xxxxxx10 01000000 00000000 - drive 9, track 0, sector 0 ; xxxxxx10 01111111 11111111 - drive 9, track 255, sector 63 ; ;Drive K (10) |DSK|| TRK ||SEC | ; xxxxxx10 10000000 00000000 - drive 10, track 0, sector 0 ; xxxxxx10 10111111 11111111 - drive 10, track 255, sector 63 ; ;Drive L (11) |DSK|| TRK ||SEC | ; xxxxxx10 11000000 00000000 - drive 10, track 0, sector 0 ; xxxxxx10 11111111 11111111 - drive 10, track 255, sector 63 ; ;Drive M (12) |DSK|| TRK ||SEC | ; xxxxxx11 00000000 00000000 - drive 10, track 0, sector 0 ; xxxxxx11 00111111 11111111 - drive 10, track 255, sector 63 ; ;Drive N (13) |DSK|| TRK ||SEC | ; xxxxxx11 01000000 00000000 - drive 10, track 0, sector 0 ; xxxxxx11 01111111 11111111 - drive 10, track 255, sector 63 ; ;Drive O (14) |DSK|| TRK ||SEC | ; xxxxxx11 10000000 00000000 - drive 10, track 0, sector 0 ; xxxxxx11 10111111 11111111 - drive 10, track 255, sector 63 ; ; ;CF physical partition geometry ; ;Disks 15 ;Tracks 256 ;Sectors/Track 64 ;Bytes/Sector 512 ;Total disk 8.388MB ; ;CF logical partition geometry ; ;Disks 15 ;Tracks 256 ;Sectors/Track 256 ;Bytes/Sector 128 ;Total disk 8.388MB ; ; Initial stack ; STACK equ 0FFFFh ;Initial stack at top of RAM ; ; BIOS parameters ; DRIVES equ 4 ;Number of logical drives in the system SECSIZE equ 80h ;CP/M sector size MONITOR equ 100h ;System monitor start address ; ; Equates for I/O mapped 8250 serial port ; SERIAL0 equ 0 ;base I/O address of first 8250 UART SERIAL1 equ 8 ;base I/O address of second 8250 UART RXR equ 0 ;Receiver buffer register TXR equ 0 ;Transmitter buffer register IER equ 1 ;Interrupt enable register LCR equ 3 ;Line control register MCR equ 4 ;Modem control register LSR equ 5 ;Line status register ; ; Define monitor serial port ; SER0_STATUS equ SERIAL0+LSR SER0_DATA equ SERIAL0+RXR SER1_STATUS equ SERIAL1+LSR SER1_DATA equ SERIAL1+RXR SER_RXRDY equ 1 ;Mask for rx buffer full SER_TXRDY equ 32 ;Mask for tx buffer empty ; ; Equates for I/O mapped 8211 parallel port ; LPT0 equ 10h ;base I/O address of the parallel port LPT0_DATA equ LPT0 ;TX register LPT0_STAT equ LPT0+1 ;Printer status register LPT0_CTRL equ LPT0+2 ;Printer control register LPTS_BUSY equ 80h ;Mask for printer busy from printer LPTS_ACK equ 40h ;Mask for printer acknowledge from printer LPTS_PE equ 20h ;Mask for paper error from printer LPTS_SLCT equ 10h ;Mask for select from printer LPTS_ERR equ 08h ;Mask for printer error from printer LPTC_IRQ equ 10h ;Mask for interrupt enable LPTC_SLCT equ 08h ;Mask for select to printer LPTC_INIT equ 04h ;Mask for reset to printer LPTC_AUTO equ 02h ;Mask for autofeed to printer LPTC_STRB equ 01h ;Mask for strobe to printer ; ; ATA Drive Definitions ; ATA_CS1 equ 40h ;ATA Drive CS1 address ATA_CS2 equ 80h ;ATA Drive CS2 address ATA_DATA equ ATA_CS1 ;ATA Drive Data Register ATA_ERROR equ ATA_CS1+1 ;ATA Drive Error Register (Read Only) ATA_FEATURES equ ATA_CS1+1 ;ATA Drive Feature Register (Write Only) ATA_SEC_COUNT equ ATA_CS1+2 ;ATA Drive Sector Count Register ATA_SEC equ ATA_CS1+3 ;ATA Drive Sector Number Register ATA_CYL_LOW equ ATA_CS1+4 ;ATA Drive Cylinder LSB Register ATA_CYL_HI equ ATA_CS1+5 ;ATA Drive Cylinder MSB Register ATA_DRV_HEAD equ ATA_CS1+6 ;ATA Drive Device/Head Register ATA_STATUS equ ATA_CS1+7 ;ATA Drive Status Register (Read Only) ATA_COMMAND equ ATA_CS1+7 ;ATA Drive Command Register (Write Only) ; ATA_LBA_BYTE1 equ ATA_CS1+3 ;ATA Bytes 0 through 7 in LBA mode ATA_LBA_BYTE2 equ ATA_CS1+4 ;ATA Bytes 8 through 15 in LBA mode ATA_LBA_BYTE3 equ ATA_CS1+5 ;ATA Bytes 16 through 23 in LBA mode ATA_LBA_BYTE4 equ ATA_CS1+6 ;ATA Bytes 24 through 27 in LBA mode ; ATA_ALT_STATUS equ ATA_CS2+6 ;ATA Drive Alternate Status Register ATA_DEV_CTRL equ ATA_CS2+6 ;ATA Drive Control Register ATA_DEV_ADDRESS equ ATA_CS2+7 ;ATA Drive Address Register ; ATA_LBA0_7 equ ATA_CS1+3 ;ATA Drive LBA Bits 0-7 ATA_LBA8_15 equ ATA_CS1+4 ;ATA Drive LBA Bits 8-15 ATA_LBA16_23 equ ATA_CS1+5 ;ATA Drive LBA Bits 16-23 ATA_LBA24_27 equ ATA_CS1+6 ;ATA Drive LBA Bits 24-27 ; ; ATA Command Options ; CMD_RETRY equ 0 CMD_NO_RETRY equ 1 ; ; ATA Read/Write Commands ; CMD_READ_SECTOR_RETRY equ 20h ;Read sectors in sector count register - retry enabled CMD_READ_SECTOR_NORETRY equ 21h ;Read sectors in sector count register - retry disabled CMD_READ_LONG_RETRY equ 22h ;Reads one sector with ECC bytes, retry enabled CMD_READ_LONG_NORETRY equ 23h ;Reads one sector with ECC bytes, retry disabled CMD_WRITE_SECTOR_RETRY equ 30h ;Write sectors in sector count register - retry enabled CMD_WRITE_SECTOR_NORETRY equ 31h ;Write sectors in sector count register - retry disabled CMD_WRITE_LONG_RETRY equ 32h ;Writes one sector with ECC bytes, retry enabled CMD_WRITE_LONG_NORETRY equ 33h ;Writes one sector with ECC bytes, retry disabled CMD_WRITE_VERIFY equ 3Ch ;Write sectors in sector count register - verify after writing CMD_VERIFY_SECTOR_RETRY equ 40h ;Verify sectors in sector count register - retry enabled, no data CMD_VERIFY_SECTOR_NORETRY equ 41h ;Verify sectors in sector count register - retry disabled, no data CMD_READ_MULTIPLE equ 0C4h ;Read multiple sectors - interrupt when finished CMD_WRITE_MULTIPLE equ 0C5h ;Write multiple sectors - interrupt when finished CMD_READ_BUFFER equ 0E4h ;Read contents of sector buffer CMD_WRITE_BUFFER equ 0E8h ;Write to sector buffer ; ;ATA Control Commands ; CMD_REQUEST_SENSE equ 3 ;Gets extended error for previous command CMD_RECALIBRATE equ 10h ;Reinitialize ATA controller (does nothing with CF) CMD_SEEK equ 70h ;Moves head to track specified (does nothing with CF) CMD_DIAGNOSTIC equ 90h ;Check power mode of the card CMD_INITIALIZE equ 91h ;Allows change to sectors per track and heads per cylinder CMD_STANDBY_IMMEDIATE equ 94h ;Puts card in standby mode without idle timer CMD_STANDBY equ 96h ;Puts card in standby mode after idle until timer expired CMD_CHECK_POWER equ 98h ;Returns power status of the card CMD_SLEEP equ 99h ;Puts card in sleep mode until hardware/software reset CMD_MULTIPLE equ 0C6h ;Enable read/write multiple operations CMD_IDENTIFY equ 0ECh ;Performs self diagnostics on the card CMD_SET_FEATURES equ 0EFh ;Set card features (aka 8-bit mode) ; ;ATA Control Settings ; DEV_CONTROL_SRST equ 04h ;Device Control Register Software Reset DEV_CONTROL_NIEN equ 02h ;Device Control Register Interrupt Enable ; DHR_SLAVE_SELECT equ 10h ;DHR Register select slave (default is master) DHR_LBA_MODE equ 40h ;DHR Register enable LBA mode (default is CHS) ; ;ATA Error Register Flags ; ERROR_BBK equ 80h ;Bad Block Mark (Always 0, not supported on CF) ERROR_UNC equ 40h ;Uncorrectable Data Error ERROR_MC equ 20h ;Media Changed (Always 0) ERROR_IDNF equ 10h ;Sector ID Field Not Found ERROR_MCR equ 08h ;Media Change Requested (Always 0) ERROR_ABRT equ 04h ;Status error or Invalid Command Aborted ERROR_TKN0NF equ 02h ;Track 0 Not Found (Not supported on CF) ERROR_AMNF equ 01h ;Address Mark Not Found (Not supported on CF) ; ;ATA Status Register Flage ; STATUS_BSY equ 80h ;Device Busy STATUS_DRDY equ 40h ;Device Ready STATUS_DWF equ 20h ;Device Write Fault STATUS_DSC equ 10h ;Device Seek Complete STATUS_DRQ equ 08h ;Data Request STATUS_CORR equ 04h ;Corrected Data STATUS_IDX equ 02h ;Index (Not used on CF, Always 0) STATUS_ERR equ 01h ;Command Error ; ;ATA Feature Codes ; FEATURE_8BIT_ON equ 01h ;Enable 8-bit transfers in LBA mode FEATURE_LOOKAHEAD_OFF equ 55h ;Disable read lookahead FEATURE_DEFAULTS_OFF equ 66h ;Disable power-on defaults FEATURE_8BIT_OFF equ 81h ;Disable 8-bit transfers in LBA mode FEATURE_ECC_ON equ 0BBh ;Enable 4 bytes ECC on read/write long FEATURE_DEFAULTS_ON equ 0CCh ;Enable power-on defaults ; ; ccp equ 0de00h ;base of ccp bdos equ ccp+800h ;base of bdos bios equ ccp+1600h ;base of bios cdisk equ 0004h ;current disk number 0=a,... l5=p iobyte equ 0003h ;intel i/o byte ; org bios ;origin of this program ; nsects equ (800h/SECSIZE)+1 ;warm start sector count (loads CPP only) ; ; ;***************************************************** ;* * ;* CP/M to host disk constants * ;* * ;***************************************************** ; blksiz equ 4096 ;CP/M allocation size hstsiz equ 512 ;host disk sector size hstspt equ 64 ;host disk sectors/trk hstblk equ hstsiz/SECSIZE ;CP/M sects/host buff ;cpmspt equ hstblk * hstspt ;CP/M sectors/track (not used due to SPT=256. Changed code.) secmsk equ hstblk-1 ;sector mask secshf equ 2 ;log2(hstblk) = 2 ; ; ;***************************************************** ;* * ;* BDOS constants on entry to write * ;* * ;***************************************************** ; wrall equ 0 ;write to allocated wrdir equ 1 ;write to directory wrual equ 2 ;write to unallocated ; ; 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 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 ; ; fixed data tables for four-drive standard ; 128MB Compact Flash Card ; dpbase: ; disk Parameter header for disk logical 00 (A) dw 0000h, 0000h dw 0000h, 0000h dw dirbf, dpblk dw enddat, all00 ; disk parameter header for disk logical 01 (B) dw 0000h, 0000h dw 0000h, 0000h dw dirbf, dpblk dw enddat, all01 ; disk parameter header for disk logical 02 (C) dw 0000h, 0000h dw 0000h, 0000h dw dirbf, dpblk dw enddat, all02 ; disk parameter header for disk logical 03 (D) dw 0000h, 0000h dw 0000h, 0000h dw dirbf, dpblk dw enddat, all03 ; ; dpblk: ;disk parameter block, common to all disks dw 256 ;SPT - logical sectors per track db 5 ;BSH - block shift factor db 31 ;BLM - block mask db 1 ;EXM - extent mask dw 2039 ;DSM - logical disk size-1 in blocks dw 1023 ;DRM - directory max entries-1 db 0ffh ;AL0 - alloc 0 Reserved directory blocks db 0 ;AL1 - alloc 1 Reserved directory blocks dw 0 ;CKS - check size dw 1 ;OFF - track offset ; ; end of fixed tables ; ; individual subroutines to perform each function ; boot: ;initialize all system hardware lxi sp, STACK ;set stack pointer xra a ;zero in the accum sta iobyte ;clear the iobyte sta cdisk ;select disk zero sta hstact ;host buffer inactive sta unacnt ;clear unalloc count sta disk00 ;default physical to logical disk map inr a sta disk01 inr a sta disk02 inr a sta disk03 ; ; Initialize 8250 serial ports ; ; access baud generator, no parity, 1 stop bit, 8 data bits ; mvi a, 83h out SERIAL0+LCR out SERIAL1+LCR ; ; fixed baud rate of 19200: crystal is 1.843200 Mhz. ; Divisor is 1843200/(16*19200) = 6 ; mvi a, 6 ;fix at 19.2 kbaud out SERIAL0+RXR ;lsb out SERIAL1+RXR ;lsb xra a out SERIAL0+RXR+1 ;msb=0 out SERIAL1+RXR+1 ;msb=0 ; ; access data registers, no parity, 1 stop bits, 8 data bits ; mvi a, 3 out SERIAL0+LCR out SERIAL1+LCR ; ; no loopback, OUT2 on, OUT1 on, RTS on, DTR (LED) on ; mvi a, 0fH out SERIAL0+MCR out SERIAL1+MCR ; ; disable all interrupts: modem, receive error, transmit, and receive ; xra a out SERIAL0+IER out SERIAL1+IER ; ; print bios boot message ; lxi d, bios_boot ;point to boot message call bios_print ;print it ; ; ; Check that ATA controller is presenrt ; mvi a, 0aah ;get test signature out ATA_SEC_COUNT ;store in sector count register xra a in ATA_SEC_COUNT ;retrieve test signature cpi 0aah ;is it correct? jz init_drive ;move along if it is lxi d, bios_nodrv ;otherwise print error call bios_print jmp MONITOR ;Exit to monitor ; init_drive: ; ; Initialize the ATA controller ; call atainit ; ; Set drive to sector zero and seek ; xra a ;zero accumulator out ATA_LBA0_7 ;save in LBA out ATA_LBA8_15 out ATA_LBA16_23 in ATA_LBA24_27 ;get mode control and final lba ani 0f0h ;mask off lba bits out ATA_LBA24_27 ;save everything but lba mvi a, 1 ;set for one sector out ATA_SEC_COUNT mvi a, CMD_SEEK out ATA_COMMAND ;Request Seek command call atabusy ;Wait for command completion ; ; Check that ATA init completed without errors ; call ataerror ;Check ATA error status jz boot_initok ;Boot is good? lxi d, bios_err ;Point to init error message call bios_print ;Print it jmp MONITOR ;Exit to monitor ; boot_initok: lxi d, bios_msg ;Point to boot start message call bios_print ;Print it jmp gocpm ;initialize and go to cp/m ; wboot: ;reload CP/M CPP from disk lxi sp, 80h ;use space below buffer for stack xra a ;zero in the accum sta hstact ;host buffer inactive sta unacnt ;clear unalloc count ; ; Reinitialize the ATA controller ; call atainit ; ; Reload CP/M from disk ; mvi c, 0 ;Select drive 0 call seldsk mvi c, 0 ;Select track 0 call settrk mvi c, 4 ;Select sector 4 call setsec lxi h, ccp ;Get dma position shld dmaadr ;Save dma position mvi a, nsects ;Sector counter sta seccnt ;Store it in memory load01: call read ;read the first block lda seksec ;Get current sector inr a ;Point to next sector mov c, a ;Transfer to c register call setsec ;Set next sector ; lhld dmaadr ;Get DMA address lxi b, SECSIZE ;Get sector size dad b ;Add byte increment shld dmaadr ;Save DMA address ; lda seccnt ;Get sector counter dcr a ;Decrement the sector count sta seccnt ;Save sector counter jnz load01 ;If not zero, do next 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+6 ;bdos entry point shld 6 ;address field of Jump at 5 to bdos ; lxi b, 80h ;default dma address is 80h call setdma ; lda cdisk ;get current disk number mov c, a ;send to the ccp jmp ccp ;go to cp/m for further processing ; ; ; BIOS messages ; bios_boot: db 'JWD 8080 Micro System BIOS Boot v1.0' dw 0d0ah db 0 bios_nodrv: db 'No ATA Controller Detected' dw 0d0ah db 0 bios_err: db 'ATA Controller Error' dw 0d0ah db 0 bios_msg: db 'Booting CP/M 2.2' dw 0d0ah db 0 ; ; ; I/O Handlers ; const: ;console status, return 0ffh if character ready, 00h if not in SER0_STATUS ;read device status ani SER_RXRDY ;rx ready ? jz conno ;exit if not mvi a, 0ffh ;raise signal if ready conno: ret ; conin: ;console character into register a in SER0_STATUS ;read device status ani SER_RXRDY ;rx ready? jz conin ;repeat if no in SER0_DATA ;get character if ready ani 7fh ;strip parity bit ret ; conout: ;console character output from register c in SER0_STATUS ;read device status ani SER_TXRDY ;tx ready? jz conout ;repeat if no mov a, c ;get character to accumulator out SER0_DATA ;send it ret ; list: ;list character from register c call listst ;Check printer ready ani 01h ;Not ready? jz list ;Check again mov a, c ;character to register a out LPT0_DATA ;Put the character on the printer bus mvi a,LPTC_STRB ;Get strobe bit out LPT0_CTRL ;Set the control bits xri LPTC_STRB ;Clear strobe bit out LPT0_CTRL ;Activate strobe signal listw0: in LPT0_STAT ;Get current status ani LPTS_BUSY ;Check busy line jnz listw0 ;Wait until active listw1: in LPT0_STAT ;Get current status ani LPTS_BUSY ;Check busy line jz listw1 ;Wait until inactive ret ; listst: ;return list status (0 if not ready, 1 if ready) in LPT0_STAT ;Get printer status ani LPTS_BUSY + LPTS_ACK + LPTS_PE + LPTS_ERR ;Check status flags cpi 0c8h ;Status ready? jnz liststex ;Exit with status code 0 mvi a, 01h ;Signal ready ret liststex: xra a ;0 is always ok to return ret ; punch: ;punch character from register C in SER1_STATUS ;read device status ani SER_TXRDY ;tx ready? jz punch ;repeat if no mov a, c ;get character to accumulator out SER1_DATA ;send it ret ; ; reader: ;reader character into register a from reader device in SER1_STATUS ;read device status ani SER_RXRDY ;rx ready? jz reader ;repeat if no in SER1_DATA ;get character if ready ani 7fh ;strip parity bit ret ; ; ; Disk I/O Operations ; home: ;home the disk lda hstwrt ;check for pending write ora a jnz homed sta hstact ;clear host active flag homed: ret ; seldsk: ;select disk lxi h, 0000h ;Error return code mov a,c ;selected disk number cpi DRIVES ;Must be between 0 and DRIVES-1 rnc ;Return if carry clear (invalid drive) 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) ret ; 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 mov l,c shld dmaadr ret ; sectran: ;translate the sector given by bc using the ;translate table given by de ;JWD - no translation xchg ;hl=.trans dad b ;hl=.trans (sector) ret ;with value in hl ; ; ;***************************************************** ;* * ;* The READ entry point takes the place of * ;* the previous BIOS defintion for READ. * ;* * ;***************************************************** ; read: ;read the selected CP/M sector 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 ; ;***************************************************** ;* * ;* The WRITE entry point takes the place of * ;* the previous BIOS defintion for WRITE. * ;* * ;***************************************************** ; write: ;write the selected CP/M sector 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 ; mvi a,blksiz/128 ;next unalloc recs sta unacnt lda sekdsk ;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 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 call sektrkcmp ;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? cpi 0 ;check CP/M sectors jnz 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 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 ; ;***************************************************** ;* * ;* Common code for READ and WRITE follows * ;* * ;***************************************************** ; rwoper: ;enter here to perform 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 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? jnz nomatch ; ; same disk, same track? ; 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 hstwrt ;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 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 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 call writehst lda erflag ret ; ;***************************************************** ;* * ;* Utility subroutine for 16-bit compare * ;* * ;***************************************************** ; 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 1s ; inx d inx h ldax d cmp m ;sets flags ret ; ;***************************************************** ;* * ;* WRITEHST performs the physical write to * ;* the host disk, READHST reads the physical * ;* disk. * ;* * ;***************************************************** ; ; ;hstdsk = host disk #, hsttrk = host track #, ;hstsec = host sect #. read "hstsiz" bytes ;into hstbuf and return error flag in erflag. ; readhst: ;perform read operation mvi a, CMD_READ_SECTOR_RETRY ;Set up for sector read call doatacmd ;Execute the read command jz rdhst01 ;Signal read error mvi a, 1 ;error condition sta erflag ;flag an error ret ; rdhst01: lxi b, hstbuf ;Point to sector buffer rdhst02: in ATA_DATA ;Get data byte stax b ;Store data in sector buffer inx b ;Point to next buffer byte in ATA_STATUS ;Check card status ani STATUS_DRQ ;Get data ready status bit jnz rdhst02 ;Get another byte from the card xra a ;Signal no error sta erflag ;save it ret ; ;hstdsk = host disk #, hsttrk = host track #, ;hstsec = host sect #. write "hstsiz" bytes ;from hstbuf and return error flag in erflag. ;return erflag non-zero if error ; writehst: ;perform a write operation mvi a, CMD_WRITE_SECTOR_RETRY ;Set up for sector write call doatacmd ;Execute the read command jz wrhst01 ;Signal read error mvi a, 1 ;error condition sta erflag ;flag an error ret ; wrhst01: lxi b, hstbuf ;Point to sector buffer wrhst02: ldax b ;Get data byte from sector buffer out ATA_DATA ;Send data byte to ATA drive inx b ;Point to next buffer byte in ATA_STATUS ;Check drive status ani STATUS_DRQ ;Get data ready status bit jnz wrhst02 ;Get another byte from the card xra a ;Signal no error sta erflag ;Save it ret ; ; doatacmd: ;Execute ATA READ/Write Command mov b, a ;Save A temporarially call atabusy ;Wait for command completion ; ;Set disk number MSB in LBA ; lda hstdsk ;Get current host disk number lxi h, disk00 ;Point to physical/logical disk map doata01: dcr a ;Decrement host disk number jm doata02 ;Last drive? inx h ;Point to next map jmp doata01 ;Do again doata02: mov a, m ;Get actual drive from map ora a ;Clear carry rar ;Remove lsb of disk number ora a ;Clear carry rar ;Remove lsb of disk number out ATA_LBA16_23 ;Save it in ATA_LBA16-23 mov a, m ;Get actual drive from map ani 3 ;Get two lsb of disk number rrc ;Put them in msb rrc mov c, a ;Save it in C ; ;Set disk number LSB and track MSB in LBA ; lda hsttrk ;Get current host track number ani 0fch ;Remove two lsb bits rrc ;Move over two bits rrc ora c ;Add in drive lsb bits out ATA_LBA8_15 ;Set it in ATA_LBA8_15 lda hsttrk ;Get current host track number ani 3 ;Get two lsb bits of track rrc ;Put them in msb rrc ; ;Set track number LSB and sector in LBA ; mov c, a ;Save it in C lda hstsec ;Get current host sector number ani 3fh ;Remove msb bits just in case ora c ;Add in sector bits out ATA_LBA0_7 ;Set it in ATA_LBA0_7 ; ;Set sector count to 1 ; mvi a, 01 ;Read/Write one sector out ATA_SEC_COUNT ;Set it in ATA drive in ATA_LBA24_27 ;Make sure all other LBA bits are zero ani 0f0h out ATA_LBA24_27 ;set it in ATA_LBA24_27 ; ;Set Read/Write command code ; mov a, b ;restore A out ATA_COMMAND ;Read sector with retry call atabusy ;Wait for command completion call ataready ;Wait for data buffer ready call ataerror ;Check for error condition ret ; ; atainit: ;Initialize the ATA adapter call ataerror ;Check for errors call ataready ;Wait for drive ready call atabusy ;Make sure drive isn't in a busy state in ATA_DEV_CTRL ;Get the ATA device control bits ani DEV_CONTROL_SRST+DEV_CONTROL_NIEN ;Enable software reset, disable interrupts out ATA_DEV_CTRL ;Store in device control register in ATA_DEV_CTRL ;Get the ATA device control bits ani DEV_CONTROL_NIEN ;Turn off software reset out ATA_DEV_CTRL ;Store in device control register call atabusy ;Wait for drive to be ready ; ; Set drive for LBA mode ; in ATA_DRV_HEAD ;Get current DHR bits ori DHR_LBA_MODE ;Set the LBA mode bit out ATA_DRV_HEAD ;Write bits to the DHR register ; ; Enable 8-bit data transfers ; mvi a, FEATURE_8BIT_ON ;Get feature code for 8-bit mode out ATA_FEATURES ;Write 8-bit feature code to features register mvi a, CMD_SET_FEATURES ;Get ready for Features command out ATA_COMMAND ;Request Set Features command call atabusy ;Wait for command completion ret atabusy: ;Wait for the ATA adapter to complete a command in ATA_STATUS ;Get ATA status ani STATUS_BSY ;Mask on busy bit jnz atabusy ;If busy check again ret ;And exit ; ; ataready: ;Wait for ATA to become ready to execute commands in ATA_STATUS ;Get ATA status ani STATUS_DRDY ;Mask on data ready bit jz ataready ;Check again if not ready ret ;And exit ; ; ataerror: ;Check for ATA error status (not zero on error) in ATA_ERROR ;Read the error register sta drverr ;Save error bits in ATA_STATUS ;Get ATA status ani STATUS_ERR ;Mask on command error bit (sets flags) ret ;And exit ; ; ; JWD - Miscellaneous support routines ; ; bios_print: ;Print a message on the console ldax d ;Get char pointed to by D into A cpi 0 ;End of string? jz bios_pend ;Exit if end of string mov c, a ;Move shar into C for console out call conout ;Print it inx d ;Point to next character jmp bios_print ;Repeat bios_pend: ret ;And exit ; ; ;***************************************************** ;* * ;* Unitialized RAM data areas * ;* * ;***************************************************** ; begdat equ $ ;beginning of data area ; 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 ;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 flag readop: ds 1 ;1 if read operation wrtype: ds 1 ;write operation type dmaadr: ds 2 ;last dma address ; seccnt: ds 1 ;sector counter for CP/M loader ; drverr: ds 1 ;last drive error ; ; ; scratch ram area for bdos use ; dirbf: ds 128 ;scratch directory area all00: ds 256 ;allocation vector 0 all01: ds 256 ;allocation vector 1 all02: ds 256 ;allocation vector 2 all03: ds 256 ;allocation vector 3 ; ; Sector buffer ; hstbuf: ds hstsiz ;host buffer ; ; Virtual disk map ; disk00: ds 1 ;physical disk to virtual disk translation disk01: ds 1 ;physical disk to virtual disk translation disk02: ds 1 ;physical disk to virtual disk translation disk03: ds 1 ;physical disk to virtual disk translation ; enddat equ $ ;end of data area datsiz equ $-begdat; ;size of data area ; ; end