;------------------------------------------------------------------------------ ;- IDE Routines for Z80 Project by Phil Ruston 2005 --------------------------- ;------------------------------------------------------------------------------ ide_read_sector: call ide_wait_busy_ready ;make sure drive is ready to proceed ret nc call ide_setup_lba ;tell drive what sector is required ld a,%10010111 ;kb irqmask=1,/cs1=1,/cs0=0,a0:a2=7 out (ide_control_port),a ld a,$20 out (ide_port_lo),a ;$20 = ide 'read sector' command ide_srex: call ide_wait_busy_ready ;make sure drive is ready to proceed ret nc call ide_test_error ;ensure no error was reported ret nc call ide_wait_buffer ;wait for full buffer signal from drive ret nc call ide_read_buffer ;grab the 256 words from the buffer scf ;carry = 1 on return = operation ok ret ;----------------------------------------------------------------------------- ide_write_sector: call ide_wait_busy_ready ;make sure drive is ready to proceed ret nc call ide_setup_lba ;tell drive what sector is required ld a,%10010111 ;kb irqmask=1,/cs1=1,/cs0=0,a0:a2=7 out (ide_control_port),a ld a,$30 out (ide_port_lo),a ;$30 = ide 'write sector' command call ide_wait_busy_ready ret nc call ide_test_error ;ensure no error was reported ret nc call ide_wait_buffer ;wait for buffer ready signal from drive ret nc call ide_write_buffer ;send 256 words to drive's buffer call ide_wait_busy_ready ;make sure drive is ready to proceed ret nc call ide_test_error ;ensure no error was reported ret nc scf ;carry = 1 on return = operation ok ret ;----------------------------------------------------------------------------- ide_get_id: call ide_wait_busy_ready ret nc ld a,%10010110 ;kb irqmask=1,/cs1=1,/cs0=0,a0:a2=6 out (ide_control_port),a ld a,%10100000 out (ide_port_lo),a ;select master device call ide_wait_busy_ready ret nc ld a,%10010111 ;kb irqmask=1,/cs1=1,/cs0=0,a0:a2=7 out (ide_control_port),a ld a,$ec out (ide_port_lo),a ;$ec = ide 'id drive' command jr ide_srex ;----------------------------------------------------------------------------- ide_soft_reset ld a,%10001110 ;kb irqmask=1,/cs1=0,/cs0=1,a0:a2=6 out (ide_control_port),a ;select 2nd status/reset/irq register ld a,%00000110 ;no interrupts, reset drive = 1 out (ide_port_lo),a ld a,%00000010 ;no interrupts, reset drive = 0 out (ide_port_lo),a call ide_wait_busy_ready ret ;-------------------------------------------------------------------------------- ; IDE internal subroutines ;-------------------------------------------------------------------------------- ide_wait_busy_ready: ld a,%10010111 ;kb irqmask=1, /cs1=1,/cs0=0, a0:a2=7 out (ide_control_port),a ;select status register ld de,0 ide_wbsy: ld b,5 ide_dlp: djnz ide_dlp inc de ld a,d or e jr z,ide_to in a,(ide_port_lo) ;read error reg and %11000000 ;mask off busy and rdy bits xor %01000000 ;we want busy(7) to be 0 and rdy(6) to be 1 jr nz,ide_wbsy scf ;carry 1 = ok ret ide_to: xor a ;carry 0 = timed out ret ;---------------------------------------------------------------------------- ide_test_error: scf ld a,%10010111 ;kb irqmask=1,/cs1=1,/cs0=0,a0:a2=7 out (ide_control_port),a in a,(ide_port_lo) bit 0,a ;test error bit ret z bit 5,a jr nz,ide_err ;test write error bit ld a,%10010001 ;kb irqmask=1, /cs1=1,/cs0=0, a0:a2=1 out (ide_control_port),a ;return error code in a in a,(ide_port_lo) ;read error flags ide_err: or a ;carry 0 = error ret ;if a = 0, ide busy timed out ;----------------------------------------------------------------------------- ide_wait_buffer: ld a,%10010111 ;kb irqmask=1, /cs1=1,/cs0=0, a0:a2=7 out (ide_control_port),a ;set to read status register ld de,0 ide_wdrq: ld b,5 ide_blp: djnz ide_blp inc de ld a,d or e jr z,ide_to2 in a,(ide_port_lo) ;wait for drive's 512 byte read buffer bit 3,a ;to fill (or ready to fill) jr z,ide_wdrq scf ;carry 1 = ok ret ide_to2: xor a ;carry 0 = timed out ret ;------------------------------------------------------------------------------ ide_read_buffer: push ix ld ix,ide_sector_buffer ld a,%10010000 ;kb irqmask=1,/cs1=1,/cs0=0,a0:a2=0 out (ide_control_port),a ld b,0 ;256 words (512 bytes per sector) idebufrd: in a,(ide_port_lo) ;low byte of word first ld (ix+1),a in a,(ide_port_hi) ;then high byte of word ld (ix),a inc ix inc ix djnz idebufrd pop ix ret ;----------------------------------------------------------------------------- ide_write_buffer: push ix ld ix,ide_sector_buffer ld a,%10010000 ;kb irqmask=1,/cs1=1,/cs0=0,a0:a2=0 out (ide_control_port),a ld b,0 ;256 words (512 bytes per sector) idebufwt: ld a,(ix) out (ide_port_hi),a ;set up high latched byte before ld a,(ix+1) out (ide_port_lo),a ;writing word with write to low byte inc ix inc ix djnz idebufwt pop ix ret ;----------------------------------------------------------------------------- ide_setup_lba: ld a,%10010010 ;kb irqmask=1,/cs1=1,/cs0=0,a0:a2=2 out (ide_control_port),a ld a,1 out (ide_port_lo),a ;set sector count = 1 ld a,%10010011 ;kb irqmask=1,/cs1=1,/cs0=0,a0:a2=3 out (ide_control_port),a ld a,(ide_lba0) out (ide_port_lo),a ;set lba 0:7 ld a,%10010100 ;kb irqmask=1,/cs1=1,/cs0=0,a0:a2=4 out (ide_control_port),a ld a,(ide_lba1) out (ide_port_lo),a ;set lba 8:15 ld a,%10010101 ;kb irqmask=1,/cs1=1,/cs0=0,a0:a2=5 out (ide_control_port),a ld a,(ide_lba2) out (ide_port_lo),a ;set lba 16:23 ld a,%10010110 ;kb irqmask=1,/cs1=1,/cs0=0,a0:a2=6 out (ide_control_port),a ld a,(ide_lba3) and %00001111 ;lowest 4 bits used only or %11100000 ;to enable lba mode out (ide_port_lo),a ;set lba 24:27 + bits 5:7=111 ret ;-----------------------------------------------------------------------------