; MACRO WAIT_HDD LD BC,IDE.Read.Status .loop: IN A,(C) BIT IDE.CtrlBit.Busy,A JR NZ,.loop ENDM ;______________________________________________________________________: ; ; GET_BPB_OFFSET: ; ;LD A,SYS_PAGE ; ;LD HL,MS_BPB ; PUSH AF ; PUSH HL ; LD B,1 ; LD IX,#0000 ; LD DE,#0000 ; CALL FN_HDD_READ ; POP IX ; POP AF ; PUSH AF ; PUSH IX ; LD DE,#01BE ;!HARDCODE смещение от начала сектора для таблицы разделов ; ADD IX,DE ; ; ; EX AF,AF' ; IN A,(SLOT3) ; EX AF,AF' ; OUT (SLOT3),A ; ; ; LD E,(IX+8) ; первый сектор (LBA) начала раздела (DWORD) ; LD D,(IX+9) ; LD L,(IX+10) ; LD H,(IX+11) ; ; ; EX AF,AF' ; OUT (SLOT3),A ; EX AF,AF' ; ; ; PUSH HL ; POP IX ; POP HL ; POP AF ; RET HD_BPB_PREP: ; [x] 27/01/2024 теперь режим спектрума работает с любым разделом HDD ;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 LD B,A IN A,(SLOT3) EX AF,AF' LD A,SYS_PAGE OUT (SLOT3),A LD A,(SYS_PAGE.CURRENT_HDD) INC A JR NZ,.configured ; LD A,(SYS_PAGE.HD_IDF_ADR.sectors) LD E,A LD D,#00 LD IX,#0000 JR .done ; .configured: LD IX,(SYS_PAGE.HDD_PARTITION_OFFSET+2) LD DE,(SYS_PAGE.HDD_PARTITION_OFFSET) .done: EX AF,AF' OUT (SLOT3),A LD A,B LD B,#01 ; HD_PREPARE: PUSH AF PUSH HL CALL HD_CALC_SECS JR C,.error ; 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 ; .error: POP HL POP AF SCF 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 ; [x] 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.CMD.ATA.ReadSectorsWithRetry ; OUT (C),A AND A RET FN_HDD_READ_BPB: CALL HD_WAIT RET C CALL HD_BPB_PREP JR NC,FN_HDD_READ.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 FN_HDD_READ.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 .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.CMD.ATA.ReadSectorsWithRetry OUT (C),A .L2: WAIT_HDD ;BIT IDE.CtrlBit.DataRequest,A AND IDE.CtrlByte.DataRequest JR Z,.RET_PortY ; ;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,.L2 ; LD A,SYS_PAGE OUT (SLOT3),A EX AF,AF' LD H,high SYS_PAGE.RAM_TABLE LD L,A LD A,(HL) OUT (SLOT3),A EX AF,AF' LD HL,#C000 JR .L2 ; .RET_PortY: 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 ; 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.CMD.ATA.WriteSectorsWithRetry OUT (C),A HD_WR_L2: WAIT_HDD BIT IDE.CtrlBit.DataRequest,A JR 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 H,high SYS_PAGE.RAM_TABLE LD L,A LD A,(HL) OUT (SLOT3),A EX AF,AF' LD HL,#C000 ; !HARDCODE JR HD_WR_L2 ;!FIXIT пока работает только с одним каналом (по-старому) FN_HDD_RECAL: LD A,IDE.Drive.Master LD BC,IDE.Write.DeviceHead OUT (C),A LD A,IDE.CMD.ATA.ExecuteDeviceDiagnostic CALL HD_CMD_EXE ;AND A CP IDE.CtrlByte.Error RET Z LD BC,IDE.Read.Error IN A,(C) CP 1 ; !HARDCODE RET Z SCF RET ;????? глянуть ; RET C ; LD A,#1F ; RECALIBRATE ; CALL HD_CMD_EXE ; RET ; [x] 28/01/2024 работает со всеми каналами FN_HDD_TEST_IDE: LD E,#00 ; TEST Secondary Chanel LD A,IDE.Chanel.Secondary OUT (IDE.Chanel.Set),A CALL .TEST_CHANEL SLA E SLA E ; TEST Primary Chanel LD A,IDE.Chanel.Primary OUT (IDE.Chanel.Set),A CALL .TEST_CHANEL ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 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 C,SLOT3 IN B,(C) LD A,SYS_PAGE OUT (SLOT3),A ; LD A,(SYS_PAGE.CURRENT_HDD) OUT (C),B CP #FF JR Z,.exit AND 1 JR Z,.exit LD A,IDE.Chanel.Secondary OUT (IDE.Chanel.Set),A ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .exit: LD A,E AND A SCF RET Z ; HDD absent ! AND A RET .TEST_CHANEL: 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 ; RET NZ SET 1,E 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 DEC B IN A,(C) ; IDE.Read.Counter CP L RET NZ INC C ELSE LD BC,IDE.Write.Sector OUT (C),H LD BC,IDE.Read.Counter IN A,(C) CP L RET NZ LD BC,IDE.Read.Sector ENDIF IN A,(C) ; IDE.Read.Sector 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 - .CylinderLow ; 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 - .CylinderHigh ; CP H ; RET ; [x] 07/01/2024 bit0 - master/slave, bit1: Primary/Secondary, 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 2 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 1 ; 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 ; CALL SET_BPB_OFFSET .exit: POP HL POP BC EI RET ; .Error: POP AF SCF JR .exit ; [x] 27/01/2024 адаптирована для корректной работы с FN_HDD_PART FN_HDD_INIT: LD C,SLOT3 IN B,(C) LD A,SYS_PAGE OUT (SLOT3),A ; LD A,(SYS_PAGE.CURRENT_HDD) OUT (C),B INC A JR Z,FN_HDD_PART ; !FIXIT сделать тут выбор первого попавшегося из SYS.IDE_0-3 CALL TEST_HDD_DRV SCF RET NZ ; 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.CMD.ATA.IdentifyDevice ;!FIXIT переделать OUT (C),A WAIT_HDD AND IDE.CtrlByte.DataRequest ;JR NZ,.L2 SCF RET Z ;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) ; число секторов .HDD_CONFIGURED: LD BC,IDE.Write.Counter OUT (C),A LD A,D OUT (SLOT3),A LD A,IDE.CMD.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 .loop: LD BC,IDE.Read.Status IN A,(C) AND IDE.CtrlByte.Busy JR Z,.EXIT DEC DE LD A,D OR E JR NZ,.loop POP AF POP BC POP DE SCF RET ; .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 ; LBA 28 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 ; [x] 27/01/2024 теперь режим спектрума работает с любым разделом HDD SET_BPB_OFFSET: LD A,SYS_PAGE LD HL,SYS_PAGE.MS_BPB LD IX,#0000 LD DE,#0000 LD B,1 CALL FN_HDD_READ ; EX AF,AF' IN A,(SLOT3) EX AF,AF' OUT (SLOT3),A ; LD A,(SYS_PAGE.CURRENT_HDD) RRCA RRCA AND 3 INC A LD B,A ; ; ; смещение от начала сектора для таблицы разделов c первым сектором LBA для первого раздела LD HL,SYS_PAGE.MS_BPB - _sMBR_PARTITION_RECORD + _sBOOT_SECTOR.PARTITION_TABLE LD DE,_sMBR_PARTITION_RECORD .loop: ADD HL,DE DJNZ .loop ; LD A,_sMBR_PARTITION_RECORD.Start_LBA ADD L LD L,A LD DE,SYS_PAGE.HDD_PARTITION_OFFSET LD C,_sMBR_PARTITION_RECORD.Size_LBA - _sMBR_PARTITION_RECORD.Start_LBA LDIR ; [x] 07/07/2024 fix bug with select empty partition record EX DE,HL XOR A LD B,_sMBR_PARTITION_RECORD.Size_LBA - _sMBR_PARTITION_RECORD.Start_LBA .loop2: DEC HL OR (HL) DJNZ .loop2 SUB 1 ; EX AF,AF' OUT (SLOT3),A EX AF,AF' RET ; 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 - ГЛЮК ;