//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ; FAT 12-16 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ;[BEGIN] ;//MODULE: FAT_X ;//CREATE: 19-05-1998 AUTHOR: Denis Parinov ;//UPDATE: 24-10-1999 DNS Restore module ;--------------------------------------------------------------- ;Rev Date Name Description ;--------------------------------------------------------------- ;RY01 16-11-1999 DNS ERROR READING FAT CHAIN ;RX01 10-02-1999 DNS UPGRADE FAT CASH ;--------------------------------------------------------------- ; Установить начальный кластер для чтения ; [x] fat32 ;!TEST R_CLUST: LD HL,#0001 LD (G_CLUST.low),HL DEC L LD (G_CLUST.high),HL RET ; [x] fat32 ;!TEST ; найти первый свободный кластер ;!TODO проверить перебор кластеров ; выход: HL - младший номер свободного кластера ; HL' - старший номер свободного кластера G_CLUST: ; .low+1: LD HL,#0001 .loop: INC HL ; номер кластера LD A,L OR H ; [x] fat32 EXX .high+1: LD HL,#0000 JR NZ,.no_inc INC HL .no_inc: EXX ; CALL READ_FROM_FAT ; прочитать из кеша FAT-а номер след. кластера CP DSS_Error.sys.DISK_FULL SCF RET Z ; EXX LD A,D OR E EXX OR D OR E JR NZ,.loop LD (G_CLUST.low),HL EXX LD (G_CLUST.high),HL EXX RET ; Прикрепить к последнему кластеру цепочки новый пустой кластер ; Вход: HL':HL - номер кластера к которому прикрепить пустой ; Выход: HL':HL - номер кластера к которому прикрепился пустой ; DE':DE - номер пустого кластера ; [x] fat32 ;!TEST INC_FAT: PUSH HL ; текущий кластер EXX PUSH HL ; текущий кластер EXX ; CALL G_CLUST ; EXX POP DE ; текущий кластер EXX POP DE ; текущий кластер RET C ; HL':HL - свободный кластер, DE':DE - текущий кластер ; EX DE,HL EXX EX DE,HL EXX ; CALL WRITE_TO_FAT.Custom ; записать в кеш FAT-а номер кластера ;!FIXIT <нет контроля ошибки> ; PUSH HL EX DE,HL EXX PUSH HL EX DE,HL EXX ; CALL WRITE_TO_FAT ; записать в кеш FAT-а номер кластера ;!TEST ;!TODO 2/12/23 ; [ ] баг с избыточной записью WRITE_FAT_TABLE? ;CALL WRITE_FAT_TABLE ; подкл. банку кеша FAT и записать его на диск ; EXX POP DE EX DE,HL EXX POP DE EX DE,HL ; AND A RET ;RX01 ; вход: de = младшее слово номера кластера для сравнения с FAT_Max_Cluster ; de' = старшее слово номера кластера для сравнения с FAT_Max_Cluster (только для fat32) ; [x] fat32 ;!TEST CHECK_CLUSTER_IS_SMALLER: LD A,(FatBuffer.FAT_TYPE) XOR FAT_TYPE.x32 JR NZ,.low ; Z=0 проверяем младшее слово номера кластера ; проверяем старшее слово номера кластера EXX EX DE,HL LD HL,(FatBuffer.MaxClusterHigh) ; CF = 0 SBC HL,DE EX DE,HL EXX LD A,DSS_Error.sys.DISK_FULL ;RET C RET NZ ; если FatBuffer.MaxClusterHigh - hl' != 0, то кластер корректный ; проверяем младше слово номера кластера .low: EX DE,HL LD HL,(FatBuffer.MaxClusterLow) ; CF = 0 SBC HL,DE EX DE,HL LD A,DSS_Error.sys.DISK_FULL RET ; ;------------------------------------------------------------------------------------------------ ; Прочитать из кеша FAT-а номер след. кластера ; вход: hl - номер кластера (младшее слово) ; hl' - номера кластера (старшее слово. только для FAT32) ; выход: hl - номер кластера (младшее слово) ; hl' - номера кластера (старшее слово) ; de - номер след. кластера (младшее слово) ; de' - номер след. кластера (старшее слово) ; если DE':DE = 0, то кластер HL':HL свободен ; CF - конец цепочки ;------------------------------------------------------------------------------------------------ ;[x] fat32 ;!TEST READ_FROM_FAT: CALL CHECK_CLUSTER_IS_SMALLER RET C ; SET_PAGE_X FATPAGE ; PUSH HL PUSH AF LD A,(FatBuffer.FAT_TYPE) CP FAT_TYPE.x16 JR C,.FAT12 JR NZ,.FAT32 ; fat16, просто читать след. номер .FAT16: CALL GET_FAT16_CELL LD E,(HL) ; прочитать номер кластера INC HL LD D,(HL) ; LD HL,SERVICE_SECTORS.FAT16 .exit: POP AF OUT (SLOT3),A ; обнуляем CF и устанавливаем код ошибки = DssErr.sys.NO_ERROR XOR A ; проверка на служ. кластеры SBC HL,DE POP HL EXX LD H,A LD L,A LD D,A LD E,A EXX RET ; .FAT12: CALL GET_FAT12_CELL LD E,(HL) INC HL LD D,(HL) LD HL,SERVICE_SECTORS.FAT12 JR NC,.Correct_2 .Correct_1: LD A,E AND #F0 DUP 4 ; вправо на 4 битa RR D RRA EDUP LD E,A JR .exit ; .Correct_2: LD A,D AND #0F LD D,A JR .exit ; .FAT32: EXX PUSH HL EXX ; CALL GET_FAT32_CELL ; прочитать младшее слово номера кластера LD E,(HL) INC HL LD D,(HL) INC HL ; прочитать старшее слово номера кластера LD A,(HL) INC HL EX AF,AF' LD A,(HL) EXX AND #0F LD D,A EX AF,AF' LD E,A EXX ; обнуляем CF и устанавливаем код ошибки = DssErr.sys.NO_ERROR XOR A ; проверка на служ. кластеры младшего слова кластера LD HL,SERVICE_SECTORS.FAT32.Low SBC HL,DE ; проверка на служ. кластеры старшего слова кластера EXX LD HL,SERVICE_SECTORS.FAT32.High SBC HL,DE POP HL EXX POP BC LD A,B OUT (SLOT3),A RET ;------------------------------------------------------------------------------------------------ ; Записать в кеш FAT-а номер кластера ; вход: hl = младшее слово номера кластера в который записать ; hl' = старшее слово номера кластера в который записать (только для fat32) ; de = младшее слово номера кластера которое вписать ; de' = старшее слово номера кластера которое вписать (только для fat32) ; выход: HL':HL такие же как и на входе ; .Custom: ; HL':HL и DE':DE такие же как и на входе ;------------------------------------------------------------------------------------------------ ; [x] fat32 ;!TEST WRITE_TO_FAT: LD DE,(FatBuffer.ENDCLUS_LOW) ; номер кластера EXX LD DE,(FatBuffer.ENDCLUS_HIGH) ; номер кластера EXX .Custom: PUSH DE EXX PUSH DE EXX CALL CHECK_CLUSTER_IS_SMALLER EXX POP DE EXX POP DE RET C ; EXX SET_PAGE_X FATPAGE EXX PUSH HL PUSH AF PUSH DE ; младший номер кластера который вписать ; [x] 2/12/23 FAT не всегда мог записаться на HDD ;LD A,1 ;LD (FatBuffer.CacheUpdated),A ; LD A,(FatBuffer.FAT_TYPE) CP FAT_TYPE.x16 JR C,.FAT12 JR NZ,.FAT32 ; .FAT16: CALL GET_FAT16_CELL POP DE ; младший номер кластера который вписать LD (HL),E ; сохр. в кеше FAT-а INC HL ; номер кластера LD (HL),D .exit: POP AF ; восст. порт POP HL OUT (SLOT3),A ; [x] 2/12/23 FAT не всегда мог записаться на HDD XOR A INC A LD (FatBuffer.CacheUpdated),A ; CF = 0 RET ; .FAT12: ;!FIXIT переделать на переменные FAT_CACHE CALL GET_FAT12_CELL POP DE ; младший номер кластера который вписать JR C,.Correct_1 ; номер нечётный LD (HL),E INC HL LD A,(HL) AND #F0 OR D LD (HL),A JR .exit ; .Correct_1: ; влево на 4 битa PUSH DE EX DE,HL ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,HL EX DE,HL ; LD A,(HL) AND #0F OR E LD (HL),A ; сохр. в кеше FAT-а INC HL ; номер кластера LD (HL),D POP DE JR .exit ; .FAT32: ; [x] fat32 ;!TEST EXX PUSH DE ; старший номер кластера который вписать PUSH HL ; старшее слово номера кластера в который записать EXX CALL GET_FAT32_CELL EXX POP HL ; старшее слово номера кластера в который записать EXX POP DE ; старший номер кластера который вписать POP BC ; младший номер кластера который вписать ; сохр. в кеше FAT-а номер кластера LD (HL),C INC HL LD (HL),B INC HL LD (HL),E INC HL LD (HL),D JR .exit ;;;;;;;;; ;FAT_BLOCK * Sectors_in_Block = SECTOR_OF_FAT ; in: HL - Cache block ; out: C:HL - logical number ; B = 0 ; [x] fat32 ;!TEST GET_SECTOR_OF_FAT: LD A,(FatBuffer.FAT_TYPE) LD B,FAT_CACHE.Degree_32 ;!FIXIT сделать через переменную XOR FAT_TYPE.x32 JR Z,.next LD B,FAT_CACHE.Degree ;!FIXIT сделать через переменную XOR A .next: LD C,A ; .loop: ADD HL,HL ;x2 ADC A,C DJNZ .loop ; LD C,A RET ; GET_SECTOR_OF_FAT: ; XOR A ; LD B,A ; LD C,A ; DUP FAT_CACHE.Degree ; 4 ; ADD HL,HL ;x2 ; ADC A,C ; EDUP ; LD C,A ; LD A,(FatBuffer.FAT_TYPE) ; CP FAT_TYPE.x32 ; RET NZ ; ADD HL,HL ;x2 ; RET NC ; INC C ; RET ;;;;;;;;; ;RE_FAT: ;RX01 ; Прочитать в кеш ХХ секторов FAT-а ; [x] fat32 ;!TEST ; DE - NEW FAT BLOCK READ_FAT_TABLE: PUSH HL PUSH DE LD A,(FatBuffer.CacheUpdated) OR A CALL NZ,WRITE_FAT_TABLE.Start POP DE ; EX DE,HL LD (FatBuffer.CacheBlock),HL ; CALL GET_SECTOR_OF_FAT ; ; BC:HL - номер лог.сектора LD DE,(FatBuffer.FAT1_SEC_L) ADD HL,DE EX DE,HL LD XH,D LD XL,E LD HL,(FatBuffer.FAT1_SEC_H) ; JR NC,.no_inc ; INC HL .no_inc: ADC HL,BC ; HL:IX - SECTOR FAT FOR READING LD A,(FatBuffer.FAT_TYPE) XOR FAT_TYPE.x32 LD BC,FAT_CACHE.Sectors_16 * 256 + Dss.DRV.Read ; рег B * FAT_CACHE.Sector_Size = CASH SIZE JR NZ,.next LD B,FAT_CACHE.Sectors_32 ; рег B * FAT_CACHE.Sector_Size = CASH SIZE .next: LD DE,FATPAGE.cache ; куда ; DE - FAT ADDRESS LD A,(FatBuffer.DRIVE) ; номер диска RST ToDSS.DRV POP HL RET ; Подключить банку кеша FAT и записать его на диск ; [x] fat32 ;!TEST WRITE_FAT_TABLE: SET_PAGE_X FATPAGE PUSH AF CALL .Start ;!TODO нет контроля ошибок POP AF OUT (SLOT3),A RET ; Запись кеша FAT-а на диск .Start: LD HL,(FatBuffer.CacheBlock) ;FAT_BLOCK * Sectors_in_Block = SECTOR_OF_FAT CALL GET_SECTOR_OF_FAT ; B=0, C:HL - смещение в секторах внутри таблицы FAT на начало блока ; [x] fat32 ;!FIXIT LD (.save_hl),HL ;LD B,H ;LD C,L ; LD DE,FAT_CACHE.Sectors_32 LD A,(FatBuffer.FAT_TYPE) CP FAT_TYPE.x32 JR Z,.next LD DE,FAT_CACHE.Sectors_16 ; !FIXIT брать это значение из переменной везде ; .next: ADD HL,DE ;+ SIZE CASH (16 SECTORS) JR NC,.no_inc INC C ; ; C:HL смещение в секторах внутри таблицы FAT на конец блока ; .no_inc: ; конец блока выходит за пределы таблицы? LD B,E ; MAX число секторов для чтения в кэш LD A,(FatBuffer.SectorsPerFAT_H) LD (.sub_A),A ;LD DE,(CORE_BUFFERS.BootSector.SectorsPerFAT16) ; секторов на FAT LD DE,(FatBuffer.SectorsPerFAT_L) AND A LD A,C SBC HL,DE .sub_A+1: SBC A,0 JR C,.WALLFAT ; СF=1: не выходит OR A JR NZ,.ERR ; EX DE,HL ; DE - на сколько секторов конец блока выходит за пределы таблицы. LD HL,FAT_CACHE.Sectors_16 ; !FIXIT брать это значение из переменной везде ; CF = 0 SBC HL,DE ;SBC A,0 JR C,.ERR ;!TODO проверить LD B,L ; число секторов для чтения в кэш .WALLFAT: ; .save_hl+1: LD HL,0 ;LD H,B ;LD L,C ;PUSH HL ; ; B = число секторов LD IX,(FatBuffer.FAT1_SEC_H) LD DE,(FatBuffer.FAT1_SEC_L) ;LD B,A ;LD C,Dss.DRV.Write ; запись секторов PUSH BC ; ; сохраняем первую копию FAT. Вход IX:DE - начало таблицы FAT ; C:HL - смещение внутри таблицы ; B - количество секторов CALL .SAVE_FAT_XX ; [x] если всего одна таблица FAT, то повторной записи не происходит 13/03/2024 POP BC ; B = число секторов, C = старший байт смещения в секторах LD HL,(FatBuffer.FAT1_SEC_H) LD DE,(FatBuffer.FAT2_SEC_H) AND A SBC HL,DE JR NZ,.not_one_FAT LD HL,(FatBuffer.FAT2_SEC_L) LD DE,(FatBuffer.FAT1_SEC_L) ; CF = 0 SBC HL,DE JR Z,.only_one_FAT ; ; сохраняем вторую копию FAT .not_one_FAT: LD IX,(FatBuffer.FAT2_SEC_H) LD DE,(FatBuffer.FAT2_SEC_L) LD HL,(.save_hl) CALL .SAVE_FAT_XX AND A ;!TODO нет контроля ошибок .only_one_FAT: ; .ERR: LD A,0 LD (FatBuffer.CacheUpdated),A RET ; Вход: IX:DE - начало таблицы FAT в секторах ; C:HL - смещение в таблице в секторах ; B - количество секторов .SAVE_FAT_XX: ADD HL,DE ;EX DE,HL JR NC,.no_inc_C INC C ; номер лог. сектора .no_inc_C: LD D,0 LD E,C ADD IX,DE LD D,XH LD E,XL EX DE,HL ; LD H,0 ; LD L,C LD XH,D LD XL,E ; HL:IX - смещение внутри раздела на начало нужного блока FAT LD DE,FATPAGE.cache ; откуда LD A,(FatBuffer.DRIVE) ; номер диска LD C,Dss.DRV.Write JP ToDSS.DRV ;----------------------------------------------------------------------- ;вход: HL':HL - номер кластера ;выход: HL - адрес нужной ячейки в странице FATPAGE ; ;[x] fat32 ;!TEST GET_FAT32_CELL: ; двигаем влево HL':H LD A,H EXX LD C,A LD A,H AND FAT_CACHE.Size_Mask_32 ; #0F LD H,A LD A,C ; LD B,FAT_CACHE.Degree_32 ; 4 сдвига .loop_block: RLCA ; << H RL L ; << L' RL H ; << H' DJNZ .loop_block EXX ; В итоге тут в HL' номер блока FAT ; ; HL - FAT32 OFFSET (FROM CASH) LD A,H AND FAT_CACHE.Size_Mask_32 ; #0F LD H,A ADD HL,HL ADD HL,HL PUSH HL ; [ ] fat32 сохраняем на случай, если READ_FAT_TABLE испортит AND A ; EXX EX DE,HL LD HL,(FatBuffer.CacheBlock) ; BC - BLOCK FAT IN CASH SBC HL,DE CALL NZ,READ_FAT_TABLE ; A != C - READ NEW BLOCK FAT POP HL LD DE,FATPAGE.cache ; начало кеша FAT-а ADD HL,DE ; на ячейку FAT RET ;----------------------------------------------------------------------- ;вход: HL - номер кластера ;выход: HL - адрес нужной ячейки в странице FATPAGE GET_FAT16_CELL: LD A,H LD B,H ;AND #0F AND FAT_CACHE.Size_Mask_16 LD H,A LD A,B ; A=A/16 ; A - BLOCK FAT (1 BLOCK = 8192 BYTES) DUP FAT_CACHE.Degree_16 RRCA EDUP ;AND #0F AND FAT_CACHE.Part_Mask_16 ; ADD HL,HL ; HL - FAT OFFSET (FROM CASH) ; [ ] fat32 поменялся вход в процедуру READ_FAT_TABLE. Раньше номер блока в рег. A передавался ; LD BC,(FatBuffer.CacheBlock) ; BC - BLOCK FAT IN CASH ; CP C LD DE,(FatBuffer.CacheBlock) ; BC - BLOCK FAT IN CASH CP E LD E,A ; CALL NZ,READ_FAT_TABLE ; A != C - READ NEW BLOCK FAT LD DE,FATPAGE.cache ; начало кеша FAT-а ADD HL,DE ; на ячейку FAT RET ;----------------------------------------------------------------------- ;вход: HL - номер кластера ;выход: HL - адрес нужной ячейки в странице FATPAGE ; CF - чётный/нечётный адрес кластера GET_FAT12_CELL: LD D,H LD E,L SRL H RR L ; сдвиг вправо через CF PUSH AF ; сохр. флаг ADD HL,DE ; CLUSTER * 1.5 ; IF FAT_CACHE.Size_12 < #1800 ;!FIXIT оптимизировать LD A,H LD B,H ; AND #1F ;AND FAT_CACHE.Size_Mask_16 ; LD H,A LD A,B ; RLCA RLCA RLCA ;DUP FAT_CACHE.Degree_16 ; RRCA ;EDUP AND #07 ;AND FAT_CACHE.Part_Mask_16 ; ; [ ] поменялся вход в процедуру READ_FAT_TABLE. Раньше номер блока в рег. A передавался ; LD BC,(FatBuffer.CacheBlock) ; BC - BLOCK FAT IN CASH ; CP C LD DE,(FatBuffer.CacheBlock) ; BC - BLOCK FAT IN CASH CP E LD E,A ; CALL NZ,READ_FAT_TABLE ; прочитать в кеш 16 секторов FAT-а ENDIF ; LD DE,FATPAGE.cache ADD HL,DE POP AF RET ;----------------------------------------------------------------------- ;NSECTOR: ; in: HL':HL - CLUSTER ; out: HL:IX - SECTOR ;[x] fat32 ;!TEST CLUSTER_TO_SECTOR: EXX PUSH HL EXX POP DE ; DE:HL - cluster DEC HL DEC HL LD A,(CORE_BUFFERS.BootSector.SectorsPerCluster) XOR 1 JR Z,.skip ; RRA .loop: ADD HL,HL RL E RL D ; RRA JP NC,.loop ; .skip: EX DE,HL LD XL,E LD XH,D LD DE,(FatBuffer.FirstDataSector_L) ; [x] fat32 ;XOR A ; ADD IX,DE ; [x] fat32 LD DE,(FatBuffer.FirstDataSector_H) ;LD D,A ;LD E,A ; ADC HL,DE RET //////////////////////////////////////////////////////////////////////// ; 225 937 408 / 512 = 0x6BBC4 / 4 = 0x1AEF1 ; ;READ SECTORS OF FILE ;HL:DE - FP (in sectors) ; B - Amount sectors ; IX - buffer in RAM ; [ ] fat32 BLOCK_READ: PUSH BC LD (READ.PointerOnBuffer),IX LD A,(CORE_BUFFERS.BootSector.SectorsPerCluster) ;SECTORS PER CLUSTER ; HL:DE / A => DE:BC, H=0, L - остаток CALL DIV_for_SPC PUSH HL ; остаток DIV_for_SPC ; [x] GET/SAVE CLUSTER NUMBER BEFORE/AFTER READ/WRITE PUSH BC ; младшее слово номера кластера PUSH DE ; [x] fat32 старшее слово номера кластера ; EXX LD L,(IY+_sFM.FS_REC.FIRST_CLUSTER_H) ; START CLUSTER High LD H,(IY+_sFM.FS_REC.FIRST_CLUSTER_H+1) LD A,L OR H EXX LD L,(IY+_sFM.FS_REC.FIRST_CLUSTER_L) ; START CLUSTER Low LD H,(IY+_sFM.FS_REC.FIRST_CLUSTER_L+1) OR L OR H JR Z,.fast_exit_4 CALL GetSavedCluster ;HL': HL - известный кластер файла для отсчёта ;DE : BC - оставшееся смещение в файле в кластерах (D=D+1, B=B+1) ; PUSH DE ; [x] оставшееся смещение в файле в кластерах (старшее слово) JR .enter_loop1 ; .fast_exit_5: POP DE .fast_exit_4: ; [x] GET/SAVE CLUSTER NUMBER BEFORE/AFTER READ/WRITE POP DE ; [x] fat32 старшее слово номера кластера POP BC ; POP BC POP DE AND A RET ; [x] fat32 .loop1_big: PUSH BC LD BC,0 .loop1_small: PUSH BC CALL READ_FROM_FAT POP BC JR C,.fast_exit_5 ;RY01 EX DE,HL EXX EX DE,HL EXX .enter_loop1: INC B DEC BC ; ВС - смещение внутри файла в кластерах (младшее слово) DJNZ .loop1_small POP BC ; [x] оставшееся смещение в файле в кластерах (старшее слово) INC B DEC BC DJNZ .loop1_big ;;;; ; ;[x] GET/SAVE CLUSTER NUMBER BEFORE/AFTER READ/WRITE POP DE POP BC ; B - Amount sectors CALL SaveGotCluster ; POP DE ; D = 0, E = остаток DIV_for_SPC POP BC ; B = Amount sectors ; (SP) = (RET) ; работа с остатком от деления LD A,(CORE_BUFFERS.BootSector.SectorsPerCluster) SUB E LD C,A CP B JR C,.skip1 ;SIZE > RESIDUE CLUSTER LD C,B ;SIZE < CLUSTER .skip1: LD A,B SUB C LD B,A PUSH HL ; номер кластера младшая часть PUSH BC PUSH DE CALL CLUSTER_TO_SECTOR POP DE ADD IX,DE JR NC,.skip2 INC HL .skip2: LD DE,(READ.PointerOnBuffer) LD A,(FatBuffer.DRIVE) LD B,C LD C,Dss.DRV.Read RST ToDSS.DRV JR C,.Error ; [ ] fat32 ??? POP BC LD HL,(READ.PointerOnBuffer) LD DE,(CORE_BUFFERS.BootSector.BytesPerSector) ;!TEST LD A,B LD B,C .loop2: ADD HL,DE ;DEC C ;JR NZ,.loop2 DJNZ .loop2 LD (READ.PointerOnBuffer),HL POP DE ;LD A,B OR A RET Z LD B,A ; .loop4: LD HL,CORE_BUFFERS.BootSector.SectorsPerCluster LD A,B SUB (HL) LD B,A LD C,(HL) JR NC,.BLOKRD7 LD B,0 ADD A,(HL) ;0 AND CF LD C,A OR A ;CLEAR CF RET Z ; .BLOKRD7: EX DE,HL PUSH BC CALL READ_FROM_FAT POP BC JR C,.ECL1 ;RY01 EX DE,HL PUSH HL PUSH BC CALL CLUSTER_TO_SECTOR LD DE,(READ.PointerOnBuffer) LD A,(FatBuffer.DRIVE) LD B,C LD C,Dss.DRV.Read RST ToDSS.DRV JR C,.Error POP BC LD HL,(READ.PointerOnBuffer) LD DE,(CORE_BUFFERS.BootSector.BytesPerSector) .loop3: ADD HL,DE DEC C JR NZ,.loop3 LD (READ.PointerOnBuffer),HL POP DE JP .loop4 ; .Error: POP BC POP DE ;SCF RET ; .ECL1: AND A RET ;----------------------------------------------------------------------- ; BLOK_WR.Error: ; POP BC ; ;[x] GET/SAVE CLUSTER NUMBER BEFORE/AFTER READ/WRITE ; POP BC ; ; BLOK_WR.ErrorWrite: ; POP BC ; POP DE ; LD A,DSS_Error.sys.WRITE_ERROR ; SCF ; RET ; ;WRITE SECTORS OF FILE ;HL:DE - FP (in sectors), IX - data in RAM ; B - Amount sectors ; [ ] fat32 BLOK_WR: PUSH BC LD (READ.PointerOnBuffer),IX LD A,(CORE_BUFFERS.BootSector.SectorsPerCluster) ;SECTORS PER CLUSTER ; HL:DE / A => DE:BC, H=0, L - остаток CALL DIV_for_SPC PUSH HL ; остаток DIV_for_SPC ;[x] GET/SAVE CLUSTER NUMBER BEFORE/AFTER READ/WRITE PUSH BC ; младшее слово номера кластера PUSH DE ; [x] fat32 старшее слово номера кластера ; EXX LD L,(IY+_sFM.FS_REC.FIRST_CLUSTER_H) ; START CLUSTER High LD H,(IY+_sFM.FS_REC.FIRST_CLUSTER_H+1) LD A,L OR H EXX LD L,(IY+_sFM.FS_REC.FIRST_CLUSTER_L) ; START CLUSTER LD H,(IY+_sFM.FS_REC.FIRST_CLUSTER_L+1) OR L OR H JR NZ,.FindCluster ; PUSH BC ; младшее слово номера кластера PUSH DE ; [x] fat32 старшее слово номера кластера ; [ ] fat32 CALL G_CLUST JP C,.Error_6 ; LD (IY+_sFM.FS_REC.FIRST_CLUSTER_L),L LD (IY+_sFM.FS_REC.FIRST_CLUSTER_L+1),H ; [ ] fat32 EXX LD HL,0 ;!FIXIT LD (IY+_sFM.FS_REC.FIRST_CLUSTER_H),L ; START CLUSTER High LD (IY+_sFM.FS_REC.FIRST_CLUSTER_H+1),H EXX ; CALL WRITE_TO_FAT ;!TEST ;!TODO 2/12/23 ; [ ] баг с избыточной записью WRITE_FAT_TABLE? ;PUSH HL ;CALL WRITE_FAT_TABLE ; подкл. банку кеша FAT и записать его на диск ;POP HL ; POP DE ; младшее слово номера кластера POP BC ; [x] fat32 старшее слово номера кластера ; INC B INC D ; [x] fat32 PUSH DE JP .enter_loop ;[x] GET/SAVE CLUSTER NUMBER BEFORE/AFTER READ/WRITE .FindCluster: CALL GetSavedCluster ;HL': HL - известный кластер файла для отсчёта ;DE : BC - оставшееся смещение в файле в кластерах (D=D+1, B=B+1) ; PUSH DE ; [x] оставшееся смещение в файле в кластерах (старшее слово) JP .enter_loop ; ; [x] fat32 .loop_big: PUSH BC LD BC,0 .loop: PUSH BC CALL READ_FROM_FAT JR NC,.next ; end of chain - get new cluster ; [ ] fat32 ; PUSH HL ; EXX ; PUSH HL ; EXX CALL INC_FAT ; EXX ; POP HL ; EXX ; POP HL JP C,.Error_6 ; CALL READ_FROM_FAT .next: POP BC EX DE,HL EXX EX DE,HL EXX .enter_loop: INC B DEC BC DJNZ .loop POP BC ; [x] оставшееся смещение в файле в кластерах (старшее слово) INC B DEC BC DJNZ .loop_big ;;;; ; ;[x] GET/SAVE CLUSTER NUMBER BEFORE/AFTER READ/WRITE POP DE POP BC CALL SaveGotCluster ; POP DE POP BC ; (SP) = (RET) ; LD A,(CORE_BUFFERS.BootSector.SectorsPerCluster) SUB E LD C,A CP B JR C,.WR3 ;SIZE > RESIDUE CLUSTER LD C,B ;SIZE < CLUSTER .WR3: LD A,B SUB C LD B,A PUSH HL PUSH BC PUSH DE CALL CLUSTER_TO_SECTOR POP DE ADD IX,DE JR NC,.WR4 INC HL ; DOUBLE 1 .WR4: LD DE,(READ.PointerOnBuffer) LD A,(FatBuffer.DRIVE) LD B,C LD C,Dss.DRV.Write RST ToDSS.DRV LD A,DSS_Error.sys.WRITE_ERROR JR C,.ErrorWrite POP BC LD HL,(READ.PointerOnBuffer) LD DE,(CORE_BUFFERS.BootSector.BytesPerSector) ; .loop2: ADD HL,DE DEC C JR NZ,.loop2 ; LD (READ.PointerOnBuffer),HL POP DE ; LD A,B OR A RET Z ; .big_loop: LD HL,CORE_BUFFERS.BootSector.SectorsPerCluster LD A,B SUB (HL) LD B,A LD C,(HL) JR NC,.WR7 LD B,0 ADD A,(HL) ;0 AND CF LD C,A OR A ;CLEAR CF RET Z .WR7: EX DE,HL PUSH BC CALL READ_FROM_FAT JR NC,.WR9 ;PUSH HL CALL INC_FAT ;POP HL JR C,.ErrorFull ;CALL READ_FROM_FAT .WR9: POP BC EX DE,HL PUSH HL PUSH BC CALL CLUSTER_TO_SECTOR ; DOUBLE 1 LD DE,(READ.PointerOnBuffer) LD A,(FatBuffer.DRIVE) LD B,C LD C,Dss.DRV.Write RST ToDSS.DRV LD A,DSS_Error.sys.WRITE_ERROR JR C,.ErrorWrite POP BC LD HL,(READ.PointerOnBuffer) LD DE,(CORE_BUFFERS.BootSector.BytesPerSector) .loop3: ADD HL,DE DEC C JR NZ,.loop3 LD (READ.PointerOnBuffer),HL POP DE ; JP .big_loop ; .Error_6: POP BC POP BC POP BC POP BC ;[x] GET/SAVE CLUSTER NUMBER BEFORE/AFTER READ/WRITE .ErrorWrite: POP BC POP DE ;LD A,DSS_Error.sys.WRITE_ERROR ;SCF RET ; .ErrorFull: POP BC LD A,DSS_Error.sys.DISK_FULL ;SCF RET ; ;GET/SAVE CLUSTER NUMBER BEFORE/AFTER READ/WRITE ; ; Вход: HL - первый кластер файла (младшее слово) ; ; BC - смещение в файле в кластерах (младшее слово) ; ; Выход: HL - известный кластер файла для отсчёта (младшее слово) ; ; BC - оставшееся смещение в файле в кластерах (младшее слово) ; GetSavedCluster: ; INC B ; ;PUSH DE ; первый кластер файла (старшее слово) ; LD E,(IY+_sFM.KnownCluster_L) ; LD D,(IY+_sFM.KnownCluster_L+1) ; LD A,E ; OR D ; RET Z ; ; ; DEC B ; PUSH DE ; KnownCluster_H ; PUSH HL ; первый кластер файла (младшее слово) ; PUSH BC ; смещение в файле в кластерах ; LD E,(IY+_sFM.KnownOffset_L) ; LD D,(IY+_sFM.KnownOffset_L+1) ; LD A,D ; OR E ; JR Z,.noOptimization_3 ; ; ; POP HL ; смещение в файле в кластерах ; SBC HL,DE ; JR C,.noOptimization_2 ; LD C,L ; LD B,H ; POP DE ; баланс стека ; POP HL ; ; оптимизация: HL - не первый кластер файла, а KnownCluster ; ; BC - расстояние до требуемого смещения от KnownCluster ; ; ; INC B ; RET ; ; ; .noOptimization_3: ; POP BC ; .noOptimization_2: ; POP HL ; .noOptimization_1: ; POP DE ; INC B ; RET ;[x] GET/SAVE CLUSTER NUMBER BEFORE/AFTER READ/WRITE ; Вход: DE - смещение в файле в кластерах (старшее слово) ; BC - смещение в файле в кластерах (младшее слово) ; HL - первый кластер файла (младшее слово) ; HL' - первый кластер файла (старшее слово) ; Выход: HL - известный кластер файла для отсчёта (младшее слово) ; HL' - известный кластер файла для отсчёта (старшее слово) ; DE - оставшееся смещение в файле в кластерах (старшее слово, D=D+1) ; BC - оставшееся смещение в файле в кластерах (младшее слово, B=B+1) ; не портит HL, HL' и DE:BC если оптимизация не сработала ;[ ] fat32 GetSavedCluster: XOR A CP (IY+_sFM.OptimizedClusters) JR Z,.noOptimization_0 ; PUSH DE PUSH HL ; первый кластер файла (младшее слово) ; смещение в файле в кластерах EX DE,HL LD E,(IY+_sFM.KnownOffset_H) LD D,(IY+_sFM.KnownOffset_H+1) ; проверка старшего слова AND A SBC HL,DE JR C,.noOptimization_2 ; PUSH BC EX DE,HL LD H,B LD L,C LD C,(IY+_sFM.KnownOffset_L) LD B,(IY+_sFM.KnownOffset_L+1) ; проверка младшего слова SBC HL,BC LD BC,0 EX DE,HL SBC HL,BC JR C,.noOptimization_3 EX DE,HL LD B,H LD C,L ; DE:BC новое смещение от известного кластера файла (в кластерах) ; LD L,(IY+_sFM.KnownCluster_L) LD H,(IY+_sFM.KnownCluster_L+1) EXX LD L,(IY+_sFM.KnownCluster_H) LD H,(IY+_sFM.KnownCluster_H+1) EXX ; баланс стека POP AF POP AF POP AF ; для цикла DJNZ INC B INC D RET ; .noOptimization_3: POP BC .noOptimization_2: POP HL .noOptimization_1: POP DE .noOptimization_0: INC B INC D RET ;[x] fat32 ;[x] GET/SAVE CLUSTER NUMBER BEFORE/AFTER READ/WRITE SaveGotCluster: LD A,C OR B OR E OR D RET Z ; LD (IY+_sFM.KnownOffset_L),C LD (IY+_sFM.KnownOffset_L+1),B LD (IY+_sFM.KnownOffset_H),E LD (IY+_sFM.KnownOffset_H+1),D ; LD (IY+_sFM.KnownCluster_L),L LD (IY+_sFM.KnownCluster_L+1),H EXX LD (IY+_sFM.KnownCluster_H),L LD (IY+_sFM.KnownCluster_H+1),H EXX ; LD A,1 LD (IY+_sFM.OptimizedClusters),A RET //////////////////////////////////////////////////////////////////////// ;!TODO fat32 ;======================================================================= ;BPB ;LD (FatBuffer.FAT2_SEC_L),HL ;LD (FatBuffer.RootDirFirstSector_L),HL ; first sector DIR ;BPB32 ;LD HL,(CORE_BUFFERS.BootSector+#2C) ;fat32 Первый кластер корневого каталога (обычно 2) 4 байта ;FAT Max Cluster ;LD (FatBuffer.MaxClusterLow),HL ;======================================================================= ;FatCache: ;.Block WORD #0000 ;.Update BYTE 0 ;FAT_Max_Cluster_L: WORD #0FF0 ; макс. число кластеров (без служ.) ;FAT_Max_Cluster_H: WORD #0000 ; макс. число кластеров (без служ.) ;//MODULE: FAT_X ;[END] ;RX01 ;; HL - CLUSTER ;; DE - (CLUSTER) ; ;READ_FROM_FAT EX DE,HL ; LD HL,(FAT_Max_Cluster) ; AND A ; SBC HL,DE ; EX DE,HL ; LD A,10 ; RET C ; PUSH HL ; LD A,(FAT_TYP) ; CP "2" ; JP Z,R_F_F12 ;R_F_F16 LD DE,768 ; DE - CLUSTERS IN CASH ; XOR A ;R_F_00H INC A ; HL - CLUSTER ; SBC HL,DE ; JP NC,R_F_00H ; ADD HL,DE ; ADD HL,HL ; HL - FAT OFFSET (FROM CASH) ; DEC A ; LD BC,(FatCache) ; A - ELEMENT OF CASH ; CP C ; CALL NZ,READ_FAT_TABLE ; LD DE,FAT ; ADD HL,DE ; LD E,(HL) ; INC HL ; LD D,(HL) ; LD HL,#FFEF ; AND A ; SBC HL,DE ; POP HL ; LD A,0 ; RET ; ;R_F_F12 LD D,H ; LD E,L ; ADD HL,HL ; ADD HL,DE ; RR H ; RR L ; PUSH AF ; EX DE,HL ; LD HL,(B_P_S) ; LD B,H ; LD C,L ; ADD HL,HL ; ADD HL,BC ; EX DE,HL ; XOR A ; DE - SIZE SECTOR * 3 ;R_F_00 INC A ; HL - FAT OFFSET ; SBC HL,DE ; JP NC,R_F_00 ; ADD HL,DE ; DEC A ; ; ;WRITE_FAT_TABLE LD HL,(FatCache) ; LD H,0 ; LD (FatCache),HL ; LD E,L ; LD D,H ; ADD HL,HL ; ADD HL,DE ; PUSH HL ; LD B,H ; LD C,L ; INC HL ; INC HL ; INC HL ; LD DE,(S_P_F) ; LD A,3 ; AND A ; SBC HL,DE ; JP C,WR_FAT1 ; EX DE,HL ; LD HL,3 ; AND A ; SBC HL,DE ; JP C,FATERR ; LD A,L ;WR_FAT1 LD H,B ; LD L,C ; LD DE,(FAT_FRM) ; ADD HL,DE ; EX DE,HL ; LD IX,0 ; ADD IX,DE ; LD DE,FAT ; LD HL,0 ; LD B,A ; LD C,6 ; LD A,(DRIVE) ; PUSH BC ; RST #18 ; POP BC ; POP HL ; LD DE,(FAT2_SEC_L) ; ADD HL,DE ; EX DE,HL ; LD IX,0 ; ADD IX,DE ; LD DE,FAT ; LD HL,0 ; LD A,(DRIVE) ; LD C,6 ; RST #18 ; RET ////////////// OLD //////////////// ; HL - CLUSTER ; HL:IX - SECTOR ; CLUSTER_TO_SECTOR: DEC HL ; DEC HL ; EX DE,HL ; LD A,(CORE_BUFFERS.BootSector.SectorsPerCluster) ; LD B,A ; LD HL,0 ; LD IX,0 ; ADD_DE1: ADD IX,DE ; JR NC,ADD_DE2 ; INC HL ; ADD_DE2: DJNZ ADD_DE1 ; LD DE,(FatBuffer.FirstDataSector_L) ;first data sector ; ADD IX,DE ; LD DE,#0000 ; ADC HL,DE ; RET ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////