; MACRO WAIT_HDD LD BC,IDE.Read.Status .loop: IN A,(C) BIT IDE.ControlBit.Busy,A JR NZ,.loop ENDM ;______________________________________________________________________: ; ;-- HD_BPB_PREP: LD D,A IN A,(SLOT3) EX AF,AF' LD A,SYS_PAGE OUT (SLOT3),A LD A,(SYS_PAGE.HD_IDF_ADR.sectors) LD E,A EX AF,AF' OUT (SLOT3),A LD A,D LD D,#00 LD IX,#0000 LD B,#01 HD_PREPARE: PUSH AF PUSH HL CALL HD_CALC_SECS JR NC,.L1 POP HL POP AF SCF RET .L1: LD A,B LD BC,IDE.Write.Counter ; Установить число секторов для записи OUT (C),A IF IDE_Optimization INC C OUT (C),L INC C OUT (C),E INC C OUT (C),D ELSE LD BC,IDE.Write.Sector OUT (C),L ; СЕКТОР LD BC,IDE.Write.CylinderLow OUT (C),E ; дорожка low LD BC,IDE.Write.CylinderHigh OUT (C),D ; дорожка high ENDIF LD BC,IDE.Read.Control IN A,(C) AND #F0 ; !!!!! посмотреть OR H INC B ; IDE.Write.DeviceHead OUT (C),A POP HL ; BUFER & PAGE POP AF AND A RET NEXT_ADD_SEC: PUSH AF LD A,B LD BC,IDE.Write.Counter ; Установить число секторов для записи OUT (C),A IF IDE_Optimization DEC B INC C IN A,(C) ; IDE.Read.Sector ADC A,E INC B OUT (C),A ; IDE.Write.Sector DEC B INC C IN A,(C) ; IDE.Read.CylinderLow ADC A,D INC B OUT (C),A ; IDE.Write.CylinderLow DEC B INC C IN A,(C) ; IDE.Read.CylinderHigh ADC A,0 INC B OUT (C),A ; IDE.Write.CylinderHigh LD BC,IDE.Read.Control IN A,(C) ELSE LD BC,IDE.Read.Sector IN A,(C) ADC A,E INC B OUT (C),A ; IDE.Write.Sector LD BC,IDE.Read.CylinderLow IN A,(C) ADC A,D INC B OUT (C),A ; IDE.Write.CylinderLow LD BC,IDE.Read.CylinderHigh IN A,(C) ADC A,0 INC B OUT (C),A ; IDE.Write.CylinderHigh LD BC,IDE.Read.Control IN A,(C) ENDIF LD D,A ADC A,0 AND #0F LD E,A LD A,D AND #F0 OR E INC B OUT (C),A ; IDE.Write.DeviceHead POP AF RET ; При исполнении производится вся подготовка к ; операциям чтения/записи вычисление ; цилиндров/головок/секторов и занесение их в регистры винчестера ; далее программа может сама только подать команду читать/писать и ; самостоятельно производить считывание/запись данных в винчестер. ; Команда удобна для работы программ в реальном времени, когда необходимо ; кроме чтения/записи данных производить какие либо иные действия. FN_HDD_PREPARE: ; ПОДГОТОВКА К ВНЕШНИМ ОПЕРАЦИЯМ R/W AND A ; чтоб сбросить CF если он стоит и B=0 INC B DEC B RET Z CALL HD_WAIT RET C CALL HD_PREPARE RET C ;!TEST EX AF,AF' LD A,#BF ; check buffer address in SLOT3 SUB H JR C,.SetCommand EX AF,AF' SAFE_PORTY EXX LD C,SLOT3 IN B,(C) EXX OUT (SLOT3),A EX AF,AF' .SetCommand: LD BC,IDE.Write.Command LD A,IDE.ATA.ReadSectorsWithRetry ; OUT (C),A AND A RET FN_HDD_READ_BPB: CALL HD_WAIT RET C CALL HD_BPB_PREP JR NC,HD_RD_L1 RET ; FOR LBA ONLY - NEXT_READ ; HL - bufer, A - page ; B - numer of sectors ; DE - add_par (next+DE) (d.b. 1 for NEXT) FN_HDD_READ_NEXT: AND A INC B DEC B RET Z ; ret if 0 sectors CALL HD_WAIT RET C CALL NEXT_ADD_SEC JR HD_RD_L1 ; HL - BUFER, A - PAGE FN_HDD_READ: AND A INC B DEC B RET Z CALL HD_WAIT CALL NC,HD_PREPARE RET C HD_RD_L1: EXX LD C,SLOT3 IN B,(C) EXX OUT (SLOT3),A EX AF,AF' SAFE_PORTY LD BC,IDE.Write.Command LD A,IDE.ATA.ReadSectorsWithRetry OUT (C),A HD_RD_L2: WAIT_HDD BIT IDE.ControlBit.DataRequest,A JR NZ,HD_READ_CONT ZERO_PORTY HD_RET: EXX OUT (C),B EXX LD BC,IDE.Read.Error IN A,(C) AND A SCF RET NZ EX AF,AF' AND A RET HD_READ_CONT: LD BC,IDE.Read.Data .loop_read1: DUP 16 INI ; всего 16 раз INI - оптимально. EDUP JR NZ,.loop_read1 .loop_read2: DUP 16 INI ; всего 16 раз INI - оптимально. EDUP JR NZ,.loop_read2 LD A,H OR L JR NZ,HD_RD_L2 LD A,SYS_PAGE OUT (SLOT3),A EX AF,AF' LD HL,SYS_PAGE.RAMD_FAT LD L,A LD A,(HL) OUT (SLOT3),A EX AF,AF' LD HL,#C000 ; !!!!! JR HD_RD_L2 ; HL - BUFER, A - PAGE FN_HDD_WRITE: AND A INC B DEC B RET Z CALL HD_WAIT RET C CALL HD_PREPARE RET C EXX LD C,SLOT3 IN B,(C) EXX OUT (SLOT3),A EX AF,AF' LD BC,IDE.Write.Command LD A,IDE.ATA.WriteSectorsWithRetry OUT (C),A HD_WR_L2: WAIT_HDD BIT IDE.ControlBit.DataRequest,A JP Z,HD_RET LD BC,IDE.Write.Data LD D,32 ;!HARDCODE зависит от счётчика DUP в HD_WR_LOOP HD_WR_LOOP: DUP 16 OUTI ; всего 16 раз OUTI - оптимально. EDUP DEC D JR NZ,HD_WR_LOOP LD A,H OR L JR NZ,HD_WR_L2 LD A,SYS_PAGE OUT (SLOT3),A EX AF,AF' LD HL,SYS_PAGE.RAMD_FAT LD L,A LD A,(HL) OUT (SLOT3),A EX AF,AF' LD HL,#C000 ;!!!!! JR HD_WR_L2 FN_HDD_RECAL: LD A,IDE.Drive.Master LD BC,IDE.Write.DeviceHead OUT (C),A LD A,IDE.ATA.ExecuteDeviceDiagnostic CALL HD_CMD_EXE AND A BIT IDE.ControlBit.Error,A RET Z LD BC,IDE.Read.Error IN A,(C) CP 1 ; !!!!! глянуть RET Z SCF RET ;????? глянуть ; RET C ; LD A,#1F ; RECALIBRATE ; CALL HD_CMD_EXE ; RET FN_HDD_TEST_IDE: LD E,#00 LD BC,IDE.Write.DeviceHead LD A,IDE.Drive.Master OUT (C),A CALL TEST_HDD_DRV JR NZ,NO_HDD1 SET 0,E NO_HDD1: LD BC,IDE.Write.DeviceHead LD A,IDE.Drive.Slave OUT (C),A CALL TEST_HDD_DRV JR NZ,NO_HDD2 SET 1,E NO_HDD2: LD A,E AND A SCF RET Z ; HDD absent ! AND A RET ;-----------------------------------[DIFFERENT] ; Не должна портить регистр E!!! TEST_HDD_DRV: ; EXP_HDD.ASM variant LD HL,#01FE ; ????? LD BC,IDE.Write.Counter OUT (C),L IF IDE_Optimization INC C OUT (C),H ; IDE.Write.Sector DEC C INC B IN A,(C) ; ????? IDE.Write.Counter+#100 CP L RET NZ INC C ELSE LD BC,IDE.Write.Sector OUT (C),H LD BC,IDE.Write.Counter+#100 IN A,(C) CP L RET NZ LD BC,IDE.Write.Sector+#100 ENDIF IN A,(C) ; ????? IDE.Write.Sector+#100 CP H RET /* TEST_HDD_DRV: ; EXTENDED.ASM variant LD HL,#00FF ;????? LD BC,IDE.Write.CylinderLow OUT (C),L IF IDE_Optimization INC C OUT (C),H ; IDE.Write.CylinderHigh INC B DEC C IN A,(C) ; ????? Тут регистр BC = #0254 - что за порт такой и что оттуда прочитается? CP L RET NZ INC C ELSE LD BC,IDE.Write.CylinderHigh OUT (C),H LD BC,#0254 ;???!!!! IN A,(C) CP L RET NZ LD BC,#0255 ;???!!!! ENDIF IN A,(C) ; ????? Тут регистр BC = #0255 - что за порт такой и что оттуда прочитается? CP H RET */ FN_HDD_INIT: LD BC,IDE.Write.DeviceHead LD A,IDE.Drive.Master OUT (C),A CALL TEST_HDD_DRV JR NZ,.ABSENT ; .L3: WAIT_HDD LD BC,IDE.Write.Command LD A,IDE.ATA.IdentifyDevice ;!FIXIT переделать OUT (C),A WAIT_HDD BIT IDE.ControlBit.DataRequest,A JR NZ,.L2 SCF RET .ABSENT: LD BC,IDE.Write.DeviceHead LD A,IDE.Drive.Slave OUT (C),A CALL TEST_HDD_DRV JR Z,.L3 SCF RET ; .L2: LD BC,IDE.Read.Data LD HL,SYS_PAGE.HD_IDF_ADR IN A,(SLOT3) LD D,A LD A,SYS_PAGE OUT (SLOT3),A INIR INIR ; B = 0 LD H,B LD L,B LD A,(SYS_PAGE.HD_IDF_ADR.sectors) ; число секторов LD C,A ;LD HL,0 ;LD B,H LD A,(SYS_PAGE.HD_IDF_ADR.heads) ; число головок .loop: ADD HL,BC DEC A JR NZ,.loop LD (SYS_PAGE.HD_IDF_ADR.sec_cyl),HL WAIT_HDD LD BC,IDE.Read.Control IN A,(C) AND #10 LD B,A LD A,(SYS_PAGE.HD_IDF_ADR.heads) ; число головок DEC A AND #0F OR IDE.Drive.Master OR B LD H,A LD A,(SYS_PAGE.HD_IDF_ADR.LBA_CHS) ;BIT 1,A AND %0000'0010 JR Z,.NO_LBA SET 6,H .NO_LBA: LD BC,IDE.Write.DeviceHead OUT (C),H LD A,(SYS_PAGE.HD_IDF_ADR.sectors) ; число секторов LD BC,IDE.Write.Counter OUT (C),A LD A,D OUT (SLOT3),A LD A,IDE.ATA.InitializeDeviceParameters ; SET HDD PARAMETERS ;CALL HD_CMD_EXE ;RET HD_CMD_EXE: CALL HD_WAIT RET C LD BC,IDE.Write.Command OUT (C),A HD_WAIT: PUSH DE PUSH BC PUSH AF LD DE,0 HD_WAIT1: LD BC,IDE.Read.Status IN A,(C) AND IDE.ControlByte.Busy JR Z,HD_W_EXIT DEC DE LD A,D OR E JR NZ,HD_WAIT1 POP AF POP BC POP DE SCF RET HD_W_EXIT: POP AF POP BC POP DE AND A RET ; ;EXTENDED.ASM Version ; HDD_LBA: ;???!!!! ; POP BC ; LD L,E ; LD E,D ; LD D,XL ; XOR A ; LD H,A ; RET ; HD_CALC_SECS: ; LD A,XH ; AND A ; SCF ; RET NZ ; ошибка, слишком большой HDD ; PUSH BC ; LD BC,IDE.Write.DeviceHead ; DEC B ; IN A,(C) ; BIT 6,A ; JR NZ,HDD_LBA ; ; POP BC ;EXP_HDD.ASM Version HD_CALC_SECS: PUSH BC LD BC,IDE.Read.Control IN A,(C) AND %0100'0000 POP BC JR Z,.CHS ; LBA LD L,E LD E,D LD D,XL LD A,XH AND #0F ; ограничение на ~127 гигов LD H,A RET ; CHS .CHS: LD A,XH AND A SCF RET NZ ; ошибка, слишком большой HDD ; IX,DE - абсолютный номер сектора PUSH IX POP HL ; IN A,(SLOT3) LD C,A LD A,SYS_PAGE OUT (SLOT3),A LD A,C LD (SYS_PAGE.COPY_SLOT3),A ; HL,DE - номер сектора ; BC - число секторов на цилиндре LD BC,(SYS_PAGE.HD_IDF_ADR.sec_cyl) ; число секторов на цилиндре LD A,16 ; HL,DE разделить на BC SCF .DIV_LOOP: EX DE,HL ADD HL,HL EX DE,HL ADC HL,HL ; SBC HL,BC ; сравнить HL и BC JR NC,.NO_ADD ; переноса не было - +1! ADD HL,BC DEC A JR NZ,.DIV_LOOP JR .DIV_END .NO_ADD: INC DE DEC A JR NZ,.DIV_LOOP .DIV_END: ; DE - результат, HL - остаток ; DE - цилиндр LD A,(SYS_PAGE.HD_IDF_ADR.sectors) ; A - число секторов на дорожке ; HL - номер сектора в цилиндре LD C,A ;LD BC,(MS_BPB+S_P_T) ; ЧИСЛО СЕКТОРОВ НА ДОРОЖКЕ XOR A LD B,A .LOOP: SBC HL,BC INC A JR NC,.LOOP ; DEC A ; A - головка ADD HL,BC ; L - сектор INC L LD H,A ; HL - HEAD,SEC ; LD A,(SYS_PAGE.COPY_SLOT3) OUT (SLOT3),A AND A RET ; [ ] 07/01/2024 bit0: Primary/Secondary, bit1 - master/slave, bit2..3: использующийся раздел в MBR ; !TODO сделать работу с переменными биоса SYS_PAGE.IDE_0..3 FN_HDD_PART: DI PUSH BC PUSH HL ; EX AF,AF' IN A,(SLOT3) EX AF,AF' ; LD C,A AND 1 LD A,IDE.Chanel.Primary JR Z,.SET_CH LD A,IDE.Chanel.Secondary .SET_CH: OUT (IDE.Chanel.Set),A ; LD A,C PUSH AF AND 2 ; LD A,IDE.Drive.Slave JR NZ,.SET_Master_Slave ; LD A,IDE.Drive.Master .SET_Master_Slave: LD BC,IDE.Write.DeviceHead OUT (C),A CALL TEST_HDD_DRV JR NZ,.Error CALL FN_HDD_INIT.L3 JR C,.Error ; POP BC LD A,SYS_PAGE OUT (SLOT3),A ; LD A,B LD (SYS_PAGE.CURRENT_HDD),A ; EX AF,AF' OUT (SLOT3),A ; AND A .exit: POP HL POP BC EI RET ; .Error: POP AF SCF JR .exit ; ENDMODULE ;************************************************ ; ????? ; DB 'HDD_DRV_END' ; Вход: ; C - команда ; 0 - INIT - входных пар нет => A - число поддерживаемых дисков. ; 1 - RESET - выбор диска A - номер диска от 0 => ; 2 - (STATUS) !!!!! TEST? ; 3 - MEDIA CHECK - A - номер диска => A = 0 - old. #FF - new (всегда #FF) !!!!! PREPARE??? ; 4 - READ BPB - A - диск HL - адрес в текущей странице. ; 5 - READ - A - диск, IX:DE сектор, HL - адрес, B - число секторов ; 6 - WRITE - '' - ; 7 - PART ; 8 - READ_NEXT ; ; ошибки - CF - A - ошибка ; ; 0 - нет ошибки ; 1 - неверная команда ; 2 - неверный номер диска ; 3 - неверный формат (не MS-DOS) ; 4 - нет готовности ; 5 - ошибка позиционирования ; 6 - сектор не найден ; 7 - ошибка CRC ; 8 - защита записи ; 9 - ошибка чтения ; 10 - ошибка записи ; 11 - ГЛЮК ;