diff --git a/TMP_CODE.ASM b/TMP_CODE.ASM index 91d1c93..508d5a1 100644 --- a/TMP_CODE.ASM +++ b/TMP_CODE.ASM @@ -1,3 +1,3299 @@ +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +; [ ] RST_FS +;----------------------------------------------------------------------; +; MODULE FAT_FS +MODULE_START EQU $ +;███████████████████████████████████████████████████████████████████████; +;███████████████████████████████████████████████████████████████████████; + + + + + +;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░; +;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░; +; Служебные FAT +;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░; +;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░; + +;----------------------------------------------------------------------; +SET_FSInfo: LD A,(CORE_BUFFERS.FS_Buffer.FAT_TYPE) + CP FAT_TYPE.x32 + RET NZ + ; + LD A,(CORE_BUFFERS.FS_Buffer.UPD_FSINFO) + OR A + RET Z + ; + ; Делаем FSInfo сектор + ; чистим сектор + LD HL,CORE_BUFFERS.SECTOR_BUFFER + LD DE,CORE_BUFFERS.SECTOR_BUFFER+1 + LD (HL),0 + LD BC,512 - 1 ;!HARDCODE размер сектора + LDIR + ; LEAD_SIGNATURE + LD HL,#5252 + LD (CORE_BUFFERS.SECTOR_BUFFER + _sFSinfo.LEAD_SIGNATURE),HL + LD HL,#4161 + LD (CORE_BUFFERS.SECTOR_BUFFER + _sFSinfo.LEAD_SIGNATURE + 2),HL + ; DATA_SIGNATURE + LD HL,#7272 + LD (CORE_BUFFERS.SECTOR_BUFFER + _sFSinfo.DATA_SIGNATURE),HL + LD HL,#6141 + LD (CORE_BUFFERS.SECTOR_BUFFER + _sFSinfo.DATA_SIGNATURE + 2),HL + ; SECTOR_SIGNATURE + LD HL,#AA55 + LD (CORE_BUFFERS.SECTOR_BUFFER + _sFSinfo.SECTOR_SIGNATURE),HL + ; FREE_CLUSTERS_COUNT + LD HL,(CORE_BUFFERS.FS_Buffer.FREE_CLUSTERS_COUNT_L) + LD (CORE_BUFFERS.SECTOR_BUFFER + _sFSinfo.FREE_CLUSTERS_COUNT),HL + LD HL,(CORE_BUFFERS.FS_Buffer.FREE_CLUSTERS_COUNT_H) + LD (CORE_BUFFERS.SECTOR_BUFFER + _sFSinfo.FREE_CLUSTERS_COUNT+2),HL + ; FIRST_FREE_CLUSTER + LD HL,(G_CLUST.low) + LD (CORE_BUFFERS.SECTOR_BUFFER + _sFSinfo.FIRST_FREE_CLUSTER),HL + LD HL,(G_CLUST.high) + LD (CORE_BUFFERS.SECTOR_BUFFER + _sFSinfo.FIRST_FREE_CLUSTER+2),HL + ; Пишем его на винт + XOR A + LD (CORE_BUFFERS.FS_Buffer.UPD_FSINFO),A + JR WRITE_FSinfo +; ; +; Прочитать BPB в SECTOR_BUFFER +READ_BPB: LD C,Dss.DRV.GetBPB + JR RW_SECTOR +; Записать FSinfo из SECTOR_BUFFER +WRITE_FSinfo: LD IX,(CORE_BUFFERS.FS_Buffer.FSINFO_Sector) + LD HL,0 + ;JR WRITE_SECTOR + ; +; Записать сектор из SECTOR_BUFFER +; Вход: HL:IX = Logical Block (sector) +WRITE_SECTOR: LD BC,1*256 + Dss.DRV.Write + JR RW_SECTOR +; Прочитать FSinfo в SECTOR_BUFFER +READ_FSinfo: LD IX,(CORE_BUFFERS.FS_Buffer.FSINFO_Sector) + LD HL,0 +; Прочитать сектор в SECTOR_BUFFER +; Вход: HL:IX = Logical Block (sector) +READ_SECTOR: LD BC,1*256 + Dss.DRV.Read + ; +RW_SECTOR: IN A,(SLOT3) + PUSH AF + IN A,(SLOT0) + OUT (SLOT3),A + ; + LD A,(CORE_BUFFERS.FS_Buffer.DRIVE) + LD DE,CORE_BUFFERS.SECTOR_BUFFER+#C000 + RST ToDSS.DRV + EX AF,AF' + ; + POP AF + OUT (SLOT3),A + EX AF,AF' + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; RD_BPB: CALL READ_BPB +; RET C +; ; +; LD DE,#AA55 ; сигнатура ;R05 +; LD HL,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.MBR_SIGNATURE) ;R08 ;R07 +; ;[ ] CDFS +; ;R05 +; AND A +; SBC HL,DE +; JP NZ,DOS_X_Error.UnknownBPB + ; +FAT_BPB: LD A,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.DRIVE_TYPE) + CP #F0 + JP C,RD_BPB.UnknownBPB + ; PREPARE + XOR A + LD (.UsesVarsFAT32),A + ; + LD H,A + LD L,A + LD D,A + LD E,A + EXX + ; fat32 + LD B,A + LD C,A + LD (CORE_BUFFERS.FS_Buffer.SectorsPerFAT_H),A ; fat32 + ; + LD HL,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.BytesPerSector) + LD (CORE_BUFFERS.FS_Buffer.BytesPerSector),HL + LD A,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.SectorsPerCluster) + LD (CORE_BUFFERS.FS_Buffer.SectorsPerCluster),A + ; calc. first sector FAT + LD HL,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.RESERVED_SECTORS) + LD (CORE_BUFFERS.FS_Buffer.FAT1_SEC_L),HL ; low word first sector FAT #1 + LD (CORE_BUFFERS.FS_Buffer.FAT2_SEC_L),HL ; low word first sector FAT #2 + ; + ; BC = 0 + ; fat32 + LD (CORE_BUFFERS.FS_Buffer.FAT1_SEC_H),BC ; high word first sector FAT #1 ; fat32 + LD (CORE_BUFFERS.FS_Buffer.FAT2_SEC_H),BC ; high word first sector FAT #1 ; fat32 + LD (CORE_BUFFERS.FS_Buffer.RootDirFirstSector_H),BC + ;LD (CORE_BUFFERS.FS_Buffer.END_CHAIN_CLUSTER_H),BC ; fat32 reset variables + ; зануляем параметры директории для первого обращения + ; LD (CORE_BUFFERS.FM_BUF.FIRST_CLUSTER_L),BC + ; LD (CORE_BUFFERS.FM_BUF.FIRST_CLUSTER_H),BC + ; + LD DE,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.SectorsPerFAT16) + LD A,E + OR D + JR NZ,.skip_high + ; + LD (.UsesVarsFAT32),A + EXX + LD DE,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.SectorsPerFAT32 + 2) + LD A,E + EXX + ; + LD (CORE_BUFFERS.FS_Buffer.SectorsPerFAT_H),A + LD DE,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.SectorsPerFAT32) + ; +.skip_high: LD (CORE_BUFFERS.FS_Buffer.SectorsPerFAT_L),DE + LD A,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.Number_of_FATs) ; amount FATs + LD (CORE_BUFFERS.FS_Buffer.Number_Of_FATs),A + CP 1 + JR Z,.one_FAT + JP C,RD_BPB.UnknownBPB + DEC A + ADD HL,DE + LD (CORE_BUFFERS.FS_Buffer.FAT2_SEC_L),HL + EXX + ADC HL,DE + LD (CORE_BUFFERS.FS_Buffer.FAT2_SEC_H),HL + EXX + ;JR NC,.no_inc_BC + ;INC BC +.no_inc_BC:;LD (CORE_BUFFERS.FS_Buffer.FAT2_SEC_H),BC +.one_FAT: ; +.loop1: ADD HL,DE + ;JR NC,.loop1_1 + ;INC BC + EXX + ADC HL,DE + EXX +.loop1_1: DEC A + JR NZ,.loop1 + ; + LD (CORE_BUFFERS.FS_Buffer.RootDirFirstSector_L),HL ; first sector DIR + EXX + ; можно сразу тут загнать старший байт, потому-что дла FAT32 следующий расчёт - это прибавление нуля. + LD (CORE_BUFFERS.FS_Buffer.FirstDataSector_H),HL + EXX + ; + LD BC,(CORE_BUFFERS.FS_Buffer.BytesPerSector) + LD A,B + AND A + ; BytesPerSector/FAT_DIRECTORY_RECORD (32) + RL C + RLA + RL C + RLA + RL C + RLA + ; + LD C,A + LD B,0 ; BC - File handels per sector + ;;;; + IF COMPILE_UNUSED_CODE + LD (CORE_BUFFERS.FS_Buffer.FilesPerSector),A + ENDIF + ; + EX DE,HL + LD HL,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.FilesInRootDIR) ; 0 for fat32 + ; fat32 + LD A,H + OR L + ;JR Z,.skip_loop2 + JR NZ,.filesRoot + ; + INC A + LD (.UsesVarsFAT32),A + DEC A + JR .skip_loop2 + ; +.filesRoot: DEC HL + XOR A + ;NEXTAD2 + ; FilesInRootDIR / FilesPerSector = sectors in RootDir +.loop2: INC A + JP Z,RD_BPB.UnknownBPB + SBC HL,BC + JR NC,.loop2 + ; +.skip_loop2: EX DE,HL + LD C,A ; A - sectors in RootDir + LD B,0 + LD (CORE_BUFFERS.FS_Buffer.DirSizeInSectors),A + + ADD HL,BC ; Start DATA area + LD (CORE_BUFFERS.FS_Buffer.FirstDataSector_L),HL + ; B = 0 + ; + LD HL,(CORE_BUFFERS.FS_Buffer.BytesPerSector) + LD A,(CORE_BUFFERS.FS_Buffer.SectorsPerCluster) + ;!TODO FATcacheSize + ; calc. cluster size + XOR 1 + JR Z,.loop3.end + RRA +.loop3: ADD HL,HL + RRA + JP NC,.loop3 +.loop3.end: ; + LD (CORE_BUFFERS.FS_Buffer.BytesPerCluster),HL + ;LD DE,#8001 ; проверка на размер кластера больше 32 кб - не поддерживается ; !TODO + ;AND A + ;SBC HL,DE + ;JP NC,DOS_X_Error.UnknownBPB ; [ ] fixed bug, thanks to @Romychs (Roman Boykov) +////////////////////////////////////////////////////////////////// +;!TODO не используется значения вычисляемые и сохраняемые в FS_Buffer +; EX DE,HL +; LD HL,#3FFF ;!HARDCODE ;!TODO FATcacheSize +; XOR A +; ;NEXTAD4 ;!FIXIT оптимизировать когда понадобится +;.loop4: INC A +; JP Z,DOS_X_Error.UnknownBPB +; SBC HL,DE +; JR NC,.loop4 +; LD (CORE_BUFFERS.FS_Buffer.ClustersPerBank),A ; A - Clusters per bank (16k) +; +; LD HL,0 +; LD BC,(CORE_BUFFERS.SECTOR_BUFFER + _sBOOT_SECTOR_PARAMS.SectorsPerTrack) ; Sector per track +; LD A,(CORE_BUFFERS.SECTOR_BUFFER + _sBOOT_SECTOR_PARAMS.HEADS) +;.BPB_L1: ; calc. sector per cylinder +; ADD HL,BC +; DEC A +; JR NZ,.BPB_L1 +; LD (CORE_BUFFERS.FS_Buffer.S_X_H),HL +////////////////////////////////////////////////////////////////// + ; fat32 + LD HL,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.SectorsPerDrive) + LD A,H + OR L + LD DE,(CORE_BUFFERS.FS_Buffer.FirstDataSector_L) + JP NZ,.HDDSMAL + ; + EXX + LD HL,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.BPB_BIG_TOTAL_SECTORS_H) + PUSH HL ; Total Sectors high + LD DE,(CORE_BUFFERS.FS_Buffer.FirstDataSector_H) + EXX + LD HL,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.BPB_BIG_TOTAL_SECTORS_L) + PUSH HL ; Total Sectors low + AND A + SBC HL,DE + EXX + SBC HL,DE + PUSH HL + EXX + POP BC + ;JP NC,.HDDBIG + ;DEC BC + JP .HDDBIG + ; +.HDDSMAL: ; CF = 0 + LD BC,0 + PUSH BC ; Total Sectors high + PUSH HL ; Total Sectors low + SBC HL,DE + ; +.HDDBIG: CALL SectorToCluster + ; +.loop7_exit: INC HL + LD (CORE_BUFFERS.FS_Buffer.MaxClusterLow),HL + LD A,L + OR H + JR NZ,.no_inc_bc + INC BC +.no_inc_bc: LD (CORE_BUFFERS.FS_Buffer.MaxClusterHigh),BC + ; + XOR A + LD H,A + LD L,A + LD (CORE_BUFFERS.FS_Buffer.CacheBlock),HL + LD (CORE_BUFFERS.FS_Buffer.CacheUpdated),A + ; A = 0 + LD HL,(CORE_BUFFERS.FS_Buffer.SectorsPerFAT_H) + LD H,A + LD D,H + LD E,L + EXX + LD HL,(CORE_BUFFERS.FS_Buffer.SectorsPerFAT_L) + LD D,H + LD E,L + ; HL':HL = SectorsPerFAT + ; DE':DE = SectorsPerFAT + LD A,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.Number_of_FATs) + DEC A + LD B,A + CALL NZ,ALL_SECTORS_PER_FATs + EXX + PUSH HL + EXX + POP DE + ; DE:HL - sectors per FATs +.loop_mul_end: ; .DirSizeInSectors + .Number_of_FATs * .SectorsPerFAT + LD B,0 + LD A,(CORE_BUFFERS.FS_Buffer.DirSizeInSectors) + LD C,A + ADD HL,BC + JR NC,.no_inc_DE + INC DE +.no_inc_DE: ; .RESERVED_SECTORS + .DirSizeInSectors + .Number_of_FATs * .SectorsPerFAT + LD BC,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.RESERVED_SECTORS) + ADD HL,BC + JR NC,.no_inc_de + INC DE +.no_inc_de: ; Total_Sectors - (.RESERVED_SECTORS + .DirSizeInSectors + .Number_of_FATs * .SectorsPerFAT) + AND A + LD B,D + LD C,E + POP DE ; Total Sectors low + EX DE,HL + SBC HL,DE + EX (SP),HL ; Total Sectors high + SBC HL,BC + POP DE ; Total Sectors low + ; HL:DE = DataSec + ; + LD A,(CORE_BUFFERS.FS_Buffer.SectorsPerCluster) + ; HL:DE / A => DE:BC, H=0, L - остаток + CALL DIV_by_Shifts + ; выясняем разрядность FAT + LD A,D + OR E + JR NZ,.its_FAT32 + ; + LD HL,4084 + SBC HL,BC + JR NC,.its_FAT12 + ; + LD HL,65524 + SBC HL,BC + JR C,.its_FAT32 + ; It's FAT16 + LD A,(.UsesVarsFAT32) + AND A + JP NZ,RD_BPB.UnknownBPB + ; + LD HL,#FFFF + LD A,FAT_TYPE.x16 +.set_vars: EXX + ;!TODO считать тут размер root-директории в байтах и хранить в FS_Buffer? + LD HL,0 + LD (CORE_BUFFERS.FS_Buffer.END_CHAIN_CLUSTER_H),HL + LD (CORE_BUFFERS.FS_Buffer.RootDirStartCluster_L),HL + LD (CORE_BUFFERS.FS_Buffer.RootDirStartCluster_H),HL + LD HL,CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.FAT.LABEL + EXX + LD DE,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.FAT.SERIAL_NUMBER) + LD BC,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.FAT.SERIAL_NUMBER+2) + JR .SET_VARS + ; +.its_FAT12: LD A,(.UsesVarsFAT32) + AND A + JP NZ,RD_BPB.UnknownBPB + ; + LD HL,#0FFF + LD A,FAT_TYPE.x12 + JR .set_vars + ; +.its_FAT32: LD A,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.MainFATnumber) + CP #80 + JR C,.mirrored_FATs ;если все копии FAT используются + ; используется только одна копия FAT + LD HL,(CORE_BUFFERS.FS_Buffer.FAT1_SEC_H) + LD DE,(CORE_BUFFERS.FS_Buffer.SectorsPerFAT_H) + LD D,0 + EXX + LD HL,(CORE_BUFFERS.FS_Buffer.FAT1_SEC_L) + LD DE,(CORE_BUFFERS.FS_Buffer.SectorsPerFAT_L) + AND #0F + LD B,A + CALL NZ,ALL_SECTORS_PER_FATs + ; +.first_FAT_active: + LD (CORE_BUFFERS.FS_Buffer.FAT1_SEC_L),HL + LD (CORE_BUFFERS.FS_Buffer.FAT2_SEC_L),HL + EXX + LD (CORE_BUFFERS.FS_Buffer.FAT1_SEC_H),HL + LD (CORE_BUFFERS.FS_Buffer.FAT2_SEC_H),HL + ; +.mirrored_FATs: LD HL,CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.FAT32.LABEL + ; + EXX + LD HL,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.RootDirStartCluster) + LD (CORE_BUFFERS.FS_Buffer.RootDirStartCluster_L),HL + LD DE,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.RootDirStartCluster+2) + LD (CORE_BUFFERS.FS_Buffer.RootDirStartCluster_H),DE + ; + CALL CLUSTER_TO_SECTOR.no_prepare + LD (CORE_BUFFERS.FS_Buffer.RootDirFirstSector_L),IX + LD (CORE_BUFFERS.FS_Buffer.RootDirFirstSector_H),HL + ; + LD HL,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.FSINFO_Sector) + LD (CORE_BUFFERS.FS_Buffer.FSINFO_Sector),HL + ; + LD A,FAT_TYPE.x32 + LD HL,#0FFF + LD (CORE_BUFFERS.FS_Buffer.END_CHAIN_CLUSTER_H),HL + LD H,L + LD DE,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.FAT32.SERIAL_NUMBER) + LD BC,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.FAT32.SERIAL_NUMBER+2) + ; +.SET_VARS: LD (CORE_BUFFERS.FS_Buffer.FAT_TYPE),A + LD (CORE_BUFFERS.FS_Buffer.END_CHAIN_CLUSTER_L),HL + LD (CORE_BUFFERS.FS_Buffer.BPB_SERIAL_NUMBER),DE + LD (CORE_BUFFERS.FS_Buffer.BPB_SERIAL_NUMBER+2),BC + EXX + LD DE,CORE_BUFFERS.FS_Buffer.BPB_LABEL + LD BC,11 ;!HARDCODE + LDIR + ; + SET_PAGE_X FATPAGE + PUSH AF + LD DE,0 + CALL READ_FAT_TABLE + POP AF + OUT (SLOT3),A + ; + ; Установить начальный кластер для чтения + LD A,(CORE_BUFFERS.FS_Buffer.FAT_TYPE) + CP FAT_TYPE.x32 + JR Z,.set_FSinfo + ; + LD HL,#0001 + LD (G_CLUST.low),HL + DEC L + LD (G_CLUST.high),HL + ; + DEC HL + LD (CORE_BUFFERS.FS_Buffer.FREE_CLUSTERS_COUNT_L),HL + LD (CORE_BUFFERS.FS_Buffer.FREE_CLUSTERS_COUNT_H),HL + XOR A + RET + ; +.set_FSinfo: CALL READ_FSinfo + ; !FIXIT проверка на ошибку + ; + ; проверка одной из сотни сраных сигнатур + LD HL,(CORE_BUFFERS.SECTOR_BUFFER + _sFSinfo.DATA_SIGNATURE) + LD DE,(CORE_BUFFERS.SECTOR_BUFFER + _sFSinfo.DATA_SIGNATURE + 2) + LD BC,#7272 + SBC HL,BC + JR NZ,.error + EX DE,HL + LD DE,#6141 + SBC HL,DE + JR NZ,.error + ; FREE_CLUSTERS_COUNT + LD BC,(CORE_BUFFERS.SECTOR_BUFFER + _sFSinfo.FREE_CLUSTERS_COUNT) + LD DE,(CORE_BUFFERS.SECTOR_BUFFER + _sFSinfo.FREE_CLUSTERS_COUNT+2) + ; CF = 0 + CALL .check_cluster + JR NC,.skip_FFFF + ; + LD B,#FF + LD C,B + LD D,B + LD E,B + ; +.skip_FFFF: LD (CORE_BUFFERS.FS_Buffer.FREE_CLUSTERS_COUNT_L),BC + LD (CORE_BUFFERS.FS_Buffer.FREE_CLUSTERS_COUNT_H),DE + ; + ; FIRST_FREE_CLUSTER + LD BC,(CORE_BUFFERS.SECTOR_BUFFER + _sFSinfo.FIRST_FREE_CLUSTER) + LD DE,(CORE_BUFFERS.SECTOR_BUFFER + _sFSinfo.FIRST_FREE_CLUSTER+2) + ; CF = 0 + CALL .check_cluster + JR C,.error + ; + LD (G_CLUST.high),DE + LD (G_CLUST.low),BC + XOR A +.error: LD (CORE_BUFFERS.FS_Buffer.UPD_FSINFO),A + RET Z + ;!TODO FREE_CLUSTERS_COUNT + ;LD HL,#FFFF + ;LD (CORE_BUFFERS.FS_Buffer.FREE_CLUSTERS_COUNT_L),HL + ;LD (CORE_BUFFERS.FS_Buffer.FREE_CLUSTERS_COUNT_H),HL + ; + XOR A + LD H,A + LD L,2 + LD (G_CLUST.low),HL + LD L,H + LD (G_CLUST.high),HL + RET + ; + ;!TODO MaxCluster - максимально допустимый или на 1 больше максимально допустимого? +.check_cluster: LD HL,(CORE_BUFFERS.FS_Buffer.MaxClusterLow) + SBC HL,BC + LD HL,(CORE_BUFFERS.FS_Buffer.MaxClusterHigh) + SBC HL,DE + RET + ; +.UsesVarsFAT32: DB 0 +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; --> BC:HL - Sector +; <-- BC:HL - Cluster +SectorToCluster: + LD A,B + AND #0F + LD B,A + LD A,(CORE_BUFFERS.FS_Buffer.SectorsPerCluster) + SCF +.loop: RRA + RET C + RR B + RR C + RR H + RR L + JP .loop +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; HL:HL' - first FAT sector +; DE:DE' - sectors per one FAT +; A - number of FATs (counts from 0) +ALL_SECTORS_PER_FATs: + ADD HL,DE + EXX + ADC HL,DE + EXX + DJNZ ALL_SECTORS_PER_FATs + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; Установить первым известным кластером для поиска свободного. +; Установится только если меньше предыдущего +; Вход: HL':HL - cluster +; портит DE, BC' и A +; [x] раньше был шанс упереться в "DISK FULL" если G_CLUST указывал на кластер дальше, чем другой свободный +; [ ] free clusters for FSInfo +SET_NEW_FREE_CLUSTER: + LD A,1 ; увеличить + CALL SET_NEW_FREE_CLUSTERS ; [ ] free clusters for FSInfo + ; CF=0 + ; + EX DE,HL + LD HL,(G_CLUST.low) + SBC HL,DE + EX DE,HL + ; + EXX + LD B,D + LD C,E + EX DE,HL + LD HL,(G_CLUST.high) + SBC HL,DE + EX DE,HL + LD D,B + LD E,C + EXX + RET C + ; + JR G_CLUST.set_new + ; LD (G_CLUST.low),HL + ; EXX + ; LD (G_CLUST.high),HL + ; EXX + ; XOR A + ; INC A + ; LD (CORE_BUFFERS.FS_Buffer.RESET_FSINFO),A + ; RET + +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; найти первый свободный кластер ;!TODO проверить перебор кластеров +; выход: HL - младший номер свободного кластера +; HL' - старший номер свободного кластера +G_CLUST: ; +.low+1: LD HL,#0001 + EXX +.high+1: LD HL,#0000 + EXX +.loop: INC HL ; номер кластера + LD A,L + OR H + ; [x] fat32 + EXX + 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 +.set_new: ; A = 0 + LD (G_CLUST.low),HL + EXX + LD (G_CLUST.high),HL + EXX + INC A + LD (CORE_BUFFERS.FS_Buffer.UPD_FSINFO),A + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; Вход: A - уменьшить (0) или увеличить (!0) число свободных кластеров +SET_NEW_FREE_CLUSTERS: + EX AF,AF + PUSH HL + PUSH DE + EXX + PUSH HL + PUSH DE + LD HL,(CORE_BUFFERS.FS_Buffer.FREE_CLUSTERS_COUNT_H) + LD A,H + AND L + EXX + LD HL,(CORE_BUFFERS.FS_Buffer.FREE_CLUSTERS_COUNT_L) + AND H + AND L + INC A + EXX + JR Z,.no_change + EXX + ; + EX AF,AF + OR A + JR Z,.dec_clusters + ; inc clusters + INC HL + LD A,H + OR L + JR NZ,.set_new + EXX + INC HL + EXX + ; +.set_new: LD A,1 + LD (CORE_BUFFERS.FS_Buffer.UPD_FSINFO),A + ; + LD (CORE_BUFFERS.FS_Buffer.FREE_CLUSTERS_COUNT_L),HL + EXX + LD (CORE_BUFFERS.FS_Buffer.FREE_CLUSTERS_COUNT_H),HL +.no_change: POP DE + POP HL + EXX + POP DE + POP HL + RET + ; +.dec_clusters: LD A,H + OR L + DEC HL + JR NZ,.set_new + EXX + DEC HL + EXX + JP .set_new +; ; +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; Прикрепить к последнему кластеру цепочки новый пустой кластер +; Вход: HL':HL - номер кластера к которому прикрепить пустой +; Выход: HL':HL - номер кластера к которому прикрепился пустой +; DE':DE - номер пустого кластера +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-а номер кластера + ; 02/12/23 баг с избыточной записью WRITE_FAT_TABLE + ;CALL WRITE_FAT_TABLE ; подкл. банку кеша FAT и записать его на диск + ; + EXX + POP DE + EX DE,HL + EXX + POP DE + EX DE,HL + ; + ; [ ] free clusters for FSInfo + XOR A ; уменьшить + CALL SET_NEW_FREE_CLUSTERS ; [ ] free clusters for FSInfo + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; вход: hl = младшее слово номера кластера для сравнения с FAT_Max_Cluster +; hl' = старшее слово номера кластера для сравнения с FAT_Max_Cluster (только для fat32) +CHECK_CLUSTER_IS_SMALLER: + LD A,(CORE_BUFFERS.FS_Buffer.FAT_TYPE) + XOR FAT_TYPE.x32 + JR NZ,.low ; Z=0 проверяем младшее слово номера кластера + ; проверяем старшее слово номера кластера + EXX + EX DE,HL + LD HL,(CORE_BUFFERS.FS_Buffer.MaxClusterHigh) + ; CF = 0 + SBC HL,DE + EX DE,HL + EXX + LD A,DSS_Error.sys.DISK_FULL + RET C + RET NZ + ; проверяем младшее слово номера кластера +.low: EX DE,HL + LD HL,(CORE_BUFFERS.FS_Buffer.MaxClusterLow) + 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 - конец цепочки +;------------------------------------------------------------------------------------------------ +READ_FROM_FAT: CALL CHECK_CLUSTER_IS_SMALLER + RET C + ; + SET_PAGE_X FATPAGE + ; + PUSH HL + PUSH AF + LD A,(CORE_BUFFERS.FS_Buffer.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 + ;!FIXIT fat32 перестраховка + 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 + SRL 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 + POP HL + LD A,0 + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; Вход: HL - Номер первой ячейки кластера в блоке фата +; Портить только HL и A +SET_FAT32_CACHE_BLOCK_CHANGED_REGION: + ;DEC HL + ;LD A,(CORE_BUFFERS.FS_Buffer.FAT_TYPE) + ;CP FAT_TYPE.x16 + 1 + ;JR C,.start + ;DEC HL + ;DEC HL + ; +.start: LD A,H + AND #38 + LD HL,#0108 + JR Z,.set_region + ; +.loop: SLA H + ;AND A + SUB L + JR NZ,.loop + ; +.set_region: LD A,(CORE_BUFFERS.FS_Buffer.CacheUpdated) + OR H + LD (CORE_BUFFERS.FS_Buffer.CacheUpdated),A + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; !TODO optimize +; при записи в кэш значения отмечать через OR в ячейке FS_Buffer.SectorOfCacheBlock +; бит соответствующий куску в странице кэша, который был изменён и потом скидывать на диск +; только те куски, которые были изменены. +; |--------------------| +; | bit | adresses | +; |-----|--------------| +; | 0 | #0000..#07FF | +; | 1 | #0800..#0FFF | +; | 2 | #1000..#17FF | +; | 3 | #1800..#1FFF | +; | 4 | #2000..#27FF | +; | 5 | #2800..#2FFF | +; | 6 | #3000..#37FF | +; | 7 | #3800..#3FFF | +; |--------------------| +; +;------------------------------------------------------------------------------------------------ +; Записать в кеш FAT-а номер кластера +; вход: hl = младшее слово номера кластера в который записать +; hl' = старшее слово номера кластера в который записать (только для fat32) +; .Custom: +; de = младшее слово номера кластера которое вписать +; de' = старшее слово номера кластера которое вписать (только для fat32) +; выход: HL':HL такие же как и на входе +; .Custom: +; HL':HL и DE':DE такие же как и на входе +;------------------------------------------------------------------------------------------------ +WRITE_TO_FAT: LD DE,(CORE_BUFFERS.FS_Buffer.END_CHAIN_CLUSTER_L) ; номер кластера + EXX + LD DE,(CORE_BUFFERS.FS_Buffer.END_CHAIN_CLUSTER_H) ; номер кластера + 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 + AND A + PUSH AF + PUSH DE ; младший номер кластера который вписать + ; [x] 2/12/23 FAT не всегда мог записаться на HDD + ;LD A,1 + ;LD (CORE_BUFFERS.FS_Buffer.CacheUpdated),A + ; + LD A,(CORE_BUFFERS.FS_Buffer.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: ; + ; [ ] ускорение работы с кэшем FAT + CALL SET_FAT32_CACHE_BLOCK_CHANGED_REGION + ; + POP AF ; восст. порт + POP HL + OUT (SLOT3),A + ; [x] 2/12/23 FAT не всегда мог записаться на HDD + ;LD A,#FF + ;LD (CORE_BUFFERS.FS_Buffer.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: EXX + PUSH DE ; старший номер кластера который вписать + PUSH HL ; старшее слово номера кластера в который записать + EXX + CALL GET_FAT32_CELL + EXX + POP HL ; старшее слово номера кластера в который записать + POP DE + PUSH DE ; старший номер кластера который вписать + EXX + POP BC ; старший номер кластера который вписать + POP DE ; младший номер кластера который вписать + ; сохр. в кеше FAT-а номер кластера + LD (HL),E + INC HL + LD (HL),D + INC HL + LD (HL),C + INC HL + LD A,(HL) + AND #F0 + OR B + LD (HL),A + JR .exit +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +;FAT_BLOCK * Sectors_in_Block = SECTOR_OF_FAT +; in: HL - Cache block +; out: C:HL - logical number +; B = 0 +GET_SECTOR_OF_FAT: + LD A,(CORE_BUFFERS.FS_Buffer.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,(CORE_BUFFERS.FS_Buffer.FAT_TYPE) +; CP FAT_TYPE.x32 +; RET NZ +; ADD HL,HL ;x2 +; RET NC +; INC C +; RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +;RE_FAT: +;RX01 +; Прочитать в кеш ХХ секторов FAT-а +; DE - NEW FAT BLOCK +READ_FAT_TABLE: PUSH HL + PUSH DE + LD A,(CORE_BUFFERS.FS_Buffer.CacheUpdated) + OR A + CALL NZ,WRITE_FAT_TABLE.Start + POP DE + ; + EX DE,HL + LD (CORE_BUFFERS.FS_Buffer.CacheBlock),HL + ; + CALL GET_SECTOR_OF_FAT + ; + ; BC:HL - номер лог.сектора + LD DE,(CORE_BUFFERS.FS_Buffer.FAT1_SEC_L) + ADD HL,DE + EX DE,HL + LD XH,D + LD XL,E + LD HL,(CORE_BUFFERS.FS_Buffer.FAT1_SEC_H) + ; JR NC,.no_inc + ; INC HL +.no_inc: ADC HL,BC + ; HL:IX - SECTOR FAT FOR READING + LD A,(CORE_BUFFERS.FS_Buffer.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,(CORE_BUFFERS.FS_Buffer.DRIVE) ; номер диска + RST ToDSS.DRV + POP HL + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; Подключить банку кеша FAT и записать его на диск +WRITE_FAT_TABLE: + SET_PAGE_X FATPAGE + PUSH AF + CALL .Start ;!TODO нет контроля ошибок + POP AF + OUT (SLOT3),A + RET + ; Запись кеша FAT-а на диск +.Start: CALL SET_FSInfo + LD HL,(CORE_BUFFERS.FS_Buffer.CacheBlock) + ;FAT_BLOCK * Sectors_in_Block = SECTOR_OF_FAT + CALL GET_SECTOR_OF_FAT + ; B=0, C:HL - смещение в секторах внутри таблицы FAT на начало блока + LD (.pop_offset_HL),HL + LD DE,FAT_CACHE.Sectors_32 + LD A,(CORE_BUFFERS.FS_Buffer.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 +.no_inc: ; C:HL смещение в секторах внутри таблицы FAT на конец блока + ; + ; конец блока выходит за пределы таблицы? + LD B,E ; MAX число секторов для чтения в кэш + LD A,(CORE_BUFFERS.FS_Buffer.SectorsPerFAT_H) + LD (.sub_A),A + LD DE,(CORE_BUFFERS.FS_Buffer.SectorsPerFAT_L) + AND A + LD A,C + SBC HL,DE +.sub_A+1: SBC A,0 + JR C,.WALLFAT ; СF=1: не выходит + OR A + JP 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: ; +.pop_offset_HL+1: + LD HL,0 + ; B = число секторов + LD IX,(CORE_BUFFERS.FS_Buffer.FAT1_SEC_H) + LD DE,(CORE_BUFFERS.FS_Buffer.FAT1_SEC_L) + PUSH BC + ; сохраняем первую копию FAT. Вход IX:DE - начало таблицы FAT + ; C:HL - смещение внутри таблицы + ; B - количество секторов + CALL .SAVE_FAT_XX + ; [x] если всего одна таблица FAT, то повторной записи не происходит 13/03/2024 + POP BC ; B = число секторов, C = старший байт смещения в секторах + LD HL,(CORE_BUFFERS.FS_Buffer.FAT1_SEC_H) + LD DE,(CORE_BUFFERS.FS_Buffer.FAT2_SEC_H) + AND A + SBC HL,DE + JR NZ,.not_one_FAT + LD HL,(CORE_BUFFERS.FS_Buffer.FAT2_SEC_L) + LD DE,(CORE_BUFFERS.FS_Buffer.FAT1_SEC_L) + ; CF = 0 + SBC HL,DE + JR Z,.only_one_FAT + ; +.not_one_FAT: LD A,(CORE_BUFFERS.FS_Buffer.FAT_TYPE) + CP FAT_TYPE.x32 + JR NZ,.fat_num_2 + ; + LD A,(CORE_BUFFERS.FS_Buffer.Number_Of_FATs) + CP 2 + JR Z,.fat_num_2 + ; сохраняем больше двух копий FAT + LD HL,(CORE_BUFFERS.FS_Buffer.FAT2_SEC_H) + LD DE,(CORE_BUFFERS.FS_Buffer.SectorsPerFAT_H) + LD D,0 + EXX + LD HL,(CORE_BUFFERS.FS_Buffer.FAT2_SEC_L) + LD DE,(CORE_BUFFERS.FS_Buffer.SectorsPerFAT_L) + DEC A +.many_fat_loop: EXX + PUSH HL + PUSH HL + POP IX + EXX + PUSH HL + PUSH BC + EX DE,HL + LD HL,(.pop_offset_HL) + CALL .SAVE_FAT_XX + POP BC + POP HL + ; + LD DE,(CORE_BUFFERS.FS_Buffer.SectorsPerFAT_L) + ADD HL,DE + EXX + LD DE,(CORE_BUFFERS.FS_Buffer.SectorsPerFAT_H) + POP HL + ADC HL,DE + EXX + DEC A + JR NZ,.many_fat_loop + JR .norm_exit + ; + ; сохраняем вторую копию FAT +.fat_num_2: LD IX,(CORE_BUFFERS.FS_Buffer.FAT2_SEC_H) + LD DE,(CORE_BUFFERS.FS_Buffer.FAT2_SEC_L) + LD HL,(.pop_offset_HL) + CALL .SAVE_FAT_XX +.norm_exit: AND A ;!TODO нет контроля ошибок +.only_one_FAT: ; +.ERR: LD A,0 + LD (CORE_BUFFERS.FS_Buffer.CacheUpdated),A + RET + ; Вход: IX:DE - начало таблицы FAT в секторах + ; C:HL - смещение в таблице в секторах + ; B - количество секторов +.SAVE_FAT_XX: ADD HL,DE + 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 XH,D + LD XL,E + ; HL:IX - смещение внутри раздела на начало нужного блока FAT + LD A,(CORE_BUFFERS.FS_Buffer.CacheUpdated) + CP #FF + JR NZ,.SAVE_NOT_ALL_BLOCK + ; + LD DE,FATPAGE.cache ; откуда + LD A,(CORE_BUFFERS.FS_Buffer.DRIVE) ; номер диска + LD C,Dss.DRV.Write + JP ToDSS.DRV + ; +.SAVE_NOT_ALL_BLOCK: + ; A = CORE_BUFFERS.FS_Buffer.CacheUpdated + ; HL:IX - смещение внутри раздела на начало нужного блока FAT + ; B = максимальное число блоков для записи + EXX + LD HL,FATPAGE.cache + LD DE,#0800 ;!HARDCODE размер региона в блоке КЭШа FAT (байтов) + EXX + LD C,A + LD A,B + + LD B,8 ;!HARDCODE количество регионов в блоке КЭШа FAT + LD DE,4 ;!HARDCODE размер региона в блоке КЭШа FAT (секторов) + ; чтоб не насрать за границы FAT +.region_loop: SUB A,E + JR NC,.good_blk + ; максимально допустимый блок для записи меньше, чем хочется + ADD A,E + LD E,A + ; +.good_blk: SRL C + CALL C,.SAVE_FAT_CACHE_REGION + EXX + ADD HL,DE + EXX + ADD IX,DE + JR NC,.no_inc_HL + INC HL +.no_inc_HL: DJNZ .region_loop + RET + ; HL' - Адрес в странице КЭШа + ; HL:IX - смещение внутри раздела на начало нужного РЕГИОНА блока FAT +.SAVE_FAT_CACHE_REGION: + PUSH AF + PUSH DE + PUSH BC + PUSH HL + PUSH IX + ; + EXX + PUSH HL + PUSH HL + EXX + LD B,E ; кол-во секторов + POP DE ; Адрес в странице КЭШа + LD A,(CORE_BUFFERS.FS_Buffer.DRIVE) ; номер диска + LD C,Dss.DRV.Write + RST ToDSS.DRV + ; HL:IX = Sector + Sector counter + ; DE = Address + (Sector counter * Size sector) + EXX + POP HL ; адрес в странице КЭШа + LD DE,#0800 ;!HARDCODE размер региона в блоке КЭШа FAT (байтов) + EXX + ; + POP IX + POP HL + POP BC + POP DE + POP AF + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +;вход: HL':HL - номер кластера +;выход: HL - адрес нужной ячейки в странице FATPAGE +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 ; 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 ; [x] fat32 сохраняем на случай, если READ_FAT_TABLE испортит + AND A + ; + EXX + EX DE,HL + LD HL,(CORE_BUFFERS.FS_Buffer.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) + ; [x] fat32 поменялся вход в процедуру READ_FAT_TABLE. Раньше номер блока в рег. A передавался + ; LD BC,(CORE_BUFFERS.FS_Buffer.CacheBlock) ; BC - BLOCK FAT IN CASH + ; CP C + LD DE,(CORE_BUFFERS.FS_Buffer.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,(CORE_BUFFERS.FS_Buffer.CacheBlock) ; BC - BLOCK FAT IN CASH + ; CP C + LD DE,(CORE_BUFFERS.FS_Buffer.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 +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +;CLUSTER_TO_SECTOR: +; in: HL':HL - CLUSTER +; out: HL:IX - SECTOR +CLUSTER_TO_SECTOR: + EXX + PUSH HL + EXX + POP DE + ; DE:HL - cluster + ; +.no_prepare: PUSH BC + LD BC,-2 + ADD HL,BC + JR C,.no_dec_de + DEC DE +.no_dec_de: ; cluster = cluster - 2 + ; + LD A,(CORE_BUFFERS.FS_Buffer.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,(CORE_BUFFERS.FS_Buffer.FirstDataSector_L) + ; [x] fat32 + ;XOR A + ; + ADD IX,DE + ; [x] fat32 + LD DE,(CORE_BUFFERS.FS_Buffer.FirstDataSector_H) + ;LD D,A + ;LD E,A + ; + ADC HL,DE + POP BC + RET + +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; READ SECTORS OF FILE +; вход: HL:DE - FP (in sectors) +; IY - FM +; IX - buffer in RAM +; B - количество секторов для чтения +BLOCK_READ: LD (READ.PointerOnBuffer),IX + LD A,(CORE_BUFFERS.FS_Buffer.SectorsPerCluster) ;SECTORS PER CLUSTER + LD C,A + PUSH BC ; B - количество секторов для чтения, C - SectorsPerCluster + ; HL:DE / A => DE:BC, H=0, L - остаток + CALL DIV_by_Shifts + PUSH HL ; остаток DIV_by_Shifts + ; GET/SAVE CLUSTER NUMBER BEFORE/AFTER READ/WRITE + PUSH BC ; младшее слово номера кластера + PUSH DE ; [x] fat32 старшее слово номера кластера + ; + CALL CHECK_FIRST_CLUSTER + 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 + ;;;; + ; + ; GET/SAVE CLUSTER NUMBER BEFORE/AFTER READ/WRITE + POP DE ; [x] fat32 старшее слово номера кластера + POP BC ; младшее слово номера кластера + CALL SaveGotCluster + ; + POP DE ; D = 0, E = остаток DIV_by_Shifts + POP BC ; B - количество секторов для чтения, C - SectorsPerCluster + ; (SP) = (RET) + ; работа с остатком от деления + LD A,C + SUB E + LD C,A + CP B ; (SectorsPerCluster - остаток) - количество секторов для чтения + JR C,.skip1 ; SIZE > RESIDUE CLUSTER + LD C,B ; SIZE < CLUSTER +.skip1: LD A,B + SUB C + LD B,A + ; + EXX + PUSH HL ; номер кластера старшая часть + EXX + PUSH HL ; номер кластера младшая часть + PUSH BC ; B = количество секторов на дочитку, C = (SectorsPerCluster - остаток) либо количество секторов для чтения + PUSH DE ; D = 0, E = остаток DIV_by_Shifts + CALL CLUSTER_TO_SECTOR + POP DE ; D = 0, E = остаток DIV_by_Shifts + ADD IX,DE + JR NC,.skip2 + INC HL +.skip2: LD DE,(READ.PointerOnBuffer) + LD A,(CORE_BUFFERS.FS_Buffer.DRIVE) + LD B,C + LD C,Dss.DRV.Read + RST ToDSS.DRV + ; + JR C,.Error + POP BC ; B = количество секторов на дочитку, C = (SectorsPerCluster - остаток) либо количество секторов для чтения + LD HL,(READ.PointerOnBuffer) + LD DE,(CORE_BUFFERS.FS_Buffer.BytesPerSector) + ;!TEST + LD A,B + LD B,C +.loop2: ADD HL,DE + DJNZ .loop2 + ; + LD (READ.PointerOnBuffer),HL + POP DE ; номер кластера младшая часть + EXX + POP HL ; номер кластера старшая часть + EXX + OR A + RET Z ; количество секторов на дочитку = 0? + LD B,A + ; +.loop4: LD HL,CORE_BUFFERS.FS_Buffer.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 + ; HL':HL - номер кластера + CALL READ_FROM_FAT + POP BC + JR C,.ECL1 ;RY01 + ; + EXX + EX DE,HL + PUSH HL ; номер след. кластера (старшее слово) + EXX + EX DE,HL + PUSH HL ; номер след. кластера (младшее слово) + PUSH BC + CALL CLUSTER_TO_SECTOR + LD DE,(READ.PointerOnBuffer) + LD A,(CORE_BUFFERS.FS_Buffer.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.FS_Buffer.BytesPerSector) +.loop3: ADD HL,DE + DEC C + JR NZ,.loop3 + LD (READ.PointerOnBuffer),HL + POP DE ; номер след. кластера (младшее слово) + EXX + POP HL ; номер след. кластера (старшее слово) + EXX + JP .loop4 + ; +.Error: POP BC + POP DE + POP HL + ;SCF + RET + ; +.ECL1: AND A + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; WRITE SECTORS OF FILE +; вход: HL:DE - FP (in sectors) +; IX - data in RAM +; IY - FM +; B - количество секторов для записи +BLOCK_WRITE: LD (READ.PointerOnBuffer),IX + LD A,(CORE_BUFFERS.FS_Buffer.SectorsPerCluster) ;SECTORS PER CLUSTER + LD C,A + PUSH BC ; B - количество секторов для чтения, C - SectorsPerCluster + ; HL:DE / A => DE:BC, H=0, L - остаток + CALL DIV_by_Shifts + PUSH HL ; остаток DIV_by_Shifts + ;[x] GET/SAVE CLUSTER NUMBER BEFORE/AFTER READ/WRITE + PUSH BC ; младшее слово номера кластера + PUSH DE ; fat32 старшее слово номера кластера + ; + CALL CHECK_FIRST_CLUSTER + JR NZ,.FindCluster + ; + PUSH BC ; младшее слово номера кластера + PUSH DE ; fat32 старшее слово номера кластера + ; [x] 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 + ; [x] fat32 + EXX + LD (IY+_sFM.FS_REC.FIRST_CLUSTER_H),L ; START CLUSTER High + LD (IY+_sFM.FS_REC.FIRST_CLUSTER_H+1),H + EXX + ; + XOR A + CALL SET_NEW_FREE_CLUSTERS + ; + CALL WRITE_TO_FAT + ; 02/12/23 ; [ ] баг с избыточной записью WRITE_FAT_TABLE? + ;PUSH HL + ;CALL WRITE_FAT_TABLE ; подкл. банку кеша FAT и записать его на диск + ;POP HL + ; + POP DE ; младшее слово номера кластера + POP BC ; fat32 старшее слово номера кластера + ; + INC B + INC D ; 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 ; оставшееся смещение в файле в кластерах (старшее слово) + 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 + CALL INC_FAT + JP C,.Error_6 + ; [x] избыточное обращение 01/04/2024 + ;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 ; оставшееся смещение в файле в кластерах (старшее слово) + INC B + DEC BC + DJNZ .loop_big + ;;;; + ; + ;[x] GET/SAVE CLUSTER NUMBER BEFORE/AFTER READ/WRITE + POP DE + POP BC + CALL SaveGotCluster + ; + POP DE ; D = 0, E = остаток DIV_by_Shifts + POP BC ; B - количество секторов для чтения, C - SectorsPerCluster + ; (SP) = (RET) + ; + LD A,C + SUB E + LD C,A + CP B ; (SectorsPerCluster - остаток) - количество секторов для чтения + JR C,.skip1 ;SIZE > RESIDUE CLUSTER + LD C,B ;SIZE < CLUSTER +.skip1: LD A,B + SUB C + LD B,A + ; + EXX + PUSH HL ; номер кластера старшая часть + EXX + PUSH HL ; номер кластера младшая часть + PUSH BC ; B = количество секторов на дочитку, C = (SectorsPerCluster - остаток) либо количество секторов для чтения + PUSH DE ; D = 0, E = остаток DIV_by_Shifts + CALL CLUSTER_TO_SECTOR + POP DE ; D = 0, E = остаток DIV_by_Shifts + ADD IX,DE + JR NC,.skip2 + INC HL + ; DOUBLE 1 +.skip2: LD DE,(READ.PointerOnBuffer) + LD A,(CORE_BUFFERS.FS_Buffer.DRIVE) + LD B,C + LD C,Dss.DRV.Write + RST ToDSS.DRV + ; + LD A,DSS_Error.sys.WRITE_ERROR + JR C,.Error_3 + POP BC + LD HL,(READ.PointerOnBuffer) + LD DE,(CORE_BUFFERS.FS_Buffer.BytesPerSector) + ; + LD A,B + LD B,C +.loop2: ADD HL,DE + DJNZ .loop2 + ; + LD (READ.PointerOnBuffer),HL + POP DE ; номер кластера младшая часть + EXX + POP HL ; номер кластера старшая часть + EXX + ; + OR A + RET Z ; количество секторов на дочитку = 0? + LD B,A + ; +.big_loop: LD HL,CORE_BUFFERS.FS_Buffer.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 + ; HL':HL - номер кластера + CALL READ_FROM_FAT + JR NC,.WR9 + CALL INC_FAT + JR C,.ErrorFull + ; [x] избыточное обращение 01/04/2024 + ;CALL READ_FROM_FAT + ; +.WR9: POP BC + EXX + EX DE,HL + PUSH HL ; номер след. кластера (старшее слово) + EXX + EX DE,HL + PUSH HL ; номер след. кластера (младшее слово) + PUSH BC + CALL CLUSTER_TO_SECTOR + ; DOUBLE 1 + LD DE,(READ.PointerOnBuffer) + LD A,(CORE_BUFFERS.FS_Buffer.DRIVE) + LD B,C + LD C,Dss.DRV.Write + RST ToDSS.DRV + ; + LD A,DSS_Error.sys.WRITE_ERROR + JR C,.Error_3 + POP BC + LD HL,(READ.PointerOnBuffer) + LD DE,(CORE_BUFFERS.FS_Buffer.BytesPerSector) +.loop3: ADD HL,DE + DEC C + JR NZ,.loop3 + LD (READ.PointerOnBuffer),HL + POP DE ; номер след. кластера (младшее слово) + EXX + POP HL ; номер след. кластера (старшее слово) + EXX + JP .big_loop + ; +.Error_6: POP BC + POP BC + POP BC +.Error_3: POP BC ;[x] GET/SAVE CLUSTER NUMBER BEFORE/AFTER READ/WRITE + POP BC + POP DE + ;SCF + RET + ; +.ErrorFull: POP BC + LD A,DSS_Error.sys.DISK_FULL + ;SCF + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; 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 если оптимизация не сработала +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 +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; 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 +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +;Расчёт смещения в секторах ;!HARDCODE sector size +GET_OFFSET_IN_SECTORS: + LD H,0 ;!HARDCODE max file size = 8 gb + LD E,(IY+_sFM.F_POSITION+1) + LD D,(IY+_sFM.F_POSITION+2) + LD L,(IY+_sFM.F_POSITION+3) + LD A,E + AND #01 + LD B,A + LD C,(IY+_sFM.F_POSITION) + RR L + RR D + RR E + ;HL:DE FP (in sectors) + ;BC FP residue (in bytes) + OR C + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; 26/06/2024 {64 kb cluster} read only 64kb cluster ; !TODO cluster 64kb +CHECK_64kb_CLUSTER: + LD HL,(CORE_BUFFERS.FS_Buffer.BytesPerCluster) + ; CF=0 + ADC HL,HL + LD A,DSS_Error.sys.WRITE_PROTECT + RET NZ + CCF + RET +;----------------------------------------------------------------------; + + + + + +;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░; +;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░; +; Директории/Файлы +;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░; +;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░; + +;----------------------------------------------------------------------; +; [ ] удаление записи LFN +; +; вход: IX = указатель на текущую запись в странице с каталогом FAT для которой +; надо удалить записи LFS +; [ ] big dir +DELETE_LFN_RECORDS: + PUSH IX + LD A,XH + AND #C0 + DEC A + ;SUB 1 + LD C,A + ; В регистре C маска для определения выхода за пределы страницы + ; +.find_LFN: LD DE, -(FAT_DIRECTORY_RECORD) + LD A,FAT_ATTR.LFS_Entry + ; +.loop: ADD IX,DE + LD A,XH + CP C + JR Z,.beyond_boundaries ; [ ] big dir тут надо подгружать предыдущий DirBlock + ; + LD A,FAT_ATTR.LFS_Entry + CP (IX+FAT_DIRECTORY_RECORD.ATTRIBUT) + JR NZ,.exit + LD (IX+FAT_DIRECTORY_RECORD.NAME),#E5 + JR .loop + ; +.exit: AND A +.beyond_boundaries: ; !TODO подгрузка другой части каталога. пока заглушка + POP IX + RET +;----------------------------------------------------------------------; + + +; [ ] big dir грузить тут начальную страницу в dir cache или перед вызовом? +; [ ] big dir всегда ли при вызове у нас правильные (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L и H) для LOADDIR? +;----------------------------------------------------------------------; +; Поиск записи каталога в списке каталога +; вход: A = атрибут записи (.Custom) +; (CORE_BUFFERS.MASKARE) - маска для поиска +; выход: DE - индекс записи в списке каталога +; IX - адрес найденой записи в SLOT3 +; (HANDBUF) = file's directory record +; CF - каталог не найден +SEARCH: +.Dir: ;LD A,FAT_ATTR.DIRECTORY + LD A,FAT_ATTR.HiddenSysDir + CALL .Custom + RET NC + CP DSS_Error.sys.PATH_NOT_FOUND + 1 + RET C + ; + SCF + LD A,DSS_Error.sys.TOO_MANY_FILES_IN_DIR + RET + ; +.File: LD A,FAT_ATTR.NoDIRnoVolID +.Custom: EX AF,AF' ; A = 76ADLSHR + SET_PAGE_X DIRPAGE + PUSH AF + EX AF,AF' + CPL + CALL SEARCH_RECORD_IN_DIR_CACHE +.for_F_NEXT: JR C,.error + ; + LD D,XH + LD E,XL + LD HL,CORE_BUFFERS.HANDBUF + EX DE,HL + LD BC,CORE_BUFFERS.HANDBUF.SIZE + LDIR + POP AF + OUT (SLOT3),A + AND A + EXX ; record index + RET + ; +.error: POP AF + OUT (SLOT3),A + LD A,DSS_Error.sys.FILE_NOT_FOUND + SCF + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; Вход: +; Выход: DE' +; +SET_RECORD_INDEX_FROM_DIR_BLOCK: + SLA A + EXX + ; record index + LD D,A + LD E,0 + EXX + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +SEARCH_RECORD_IN_DIR_CACHE: + ;CPL + LD C,A + LD A,(CORE_BUFFERS.FS_Buffer.DirBlock) + LD (LOAD_NEXT_DIR_PART_TO_DIR_CACHE.StartPage),A + CALL SET_RECORD_INDEX_FROM_DIR_BLOCK + ; +.loop_big: LD IX,DIRPAGE.buffer +.loop: LD A,(IX + FAT_DIRECTORY_RECORD.NAME) + OR A + SCF + RET Z ; not found + ; + CP #E5 ;!HARDCODE #E5 - запись в директории свободна, так как файл/директория были удалены + JR Z,.next_record + ; + LD A,(IX + FAT_DIRECTORY_RECORD.ATTRIBUT) + LD D,A + AND C +.type+0: JR NZ,.next_record + ; + LD A,C + INC A + JR NZ,.found_attr + ; A=0 + OR D + JR NZ,.next_record + ; +.found_attr: LD HL,CORE_BUFFERS.MASKARE + LD D,XH + LD E,XL + LD B,11 ;!HARDCODE dos name not LFN + EX DE,HL + ; +.loop_compare: LD A,(DE) + CP '?' + JR Z,.next_char + ; + CP (HL) + ;JR NZ,.next_record + JR Z,.next_char + ; +.next_record: EXX + INC DE ; record index + EXX + LD DE,FAT_DIRECTORY_RECORD + ADD IX,DE + JR NC,.loop + ; + CALL LOAD_NEXT_DIR_PART_TO_DIR_CACHE + RET C + JR NZ,.loop_big + SCF + RET + ; + +.next_char: INC HL + INC DE + DJNZ .loop_compare + ; CF=0 + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; LOAD_NEXT_DIR_PART_TO_DIR_CACHE +; !FIXIT root dir in LOADDIR +; !FIXIT если в кэш были изменения? + ; CF=1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +LOAD_NEXT_DIR_PART_TO_DIR_CACHE: + PUSH BC + EXX + PUSH DE ; record index + EX DE,HL + CALL LOADDIR.next + POP DE + EXX + POP BC + ;JR NC,.loop_big ; !FIXIT может быть ошибка чтения или при ZF - конец директории + ;RET + RET C ; если всё перебрали + ; + ; полный обход каталога начиная с загруженной страницы + LD A,(CORE_BUFFERS.FS_Buffer.DirBlock) + AND A + JR NZ,.toStartPage + ; + EXX + LD DE,0 + EXX +.toStartPage: ; +.StartPage+1: CP 0 + ;JR NZ,.loop_big + ;; + ;SCF + ;RET + SCF + CCF + RET ; если всё перебрали + ; +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; [ ] big dir ;!FIXIT начинать проход с начала директории всегда, чтоб не захламлять +; !FIXIT а точно ли в нулевом FM координаты нужной директории? +; скопировать запись в список диска (каталога) de ix iy +; и сбросить кеш каталога на диск +; вход: (HANDBUF) - запись каталога +; выход: DE - record index +WRITE_DIR_HANDLE: + SET_PAGE_X DIRPAGE + ;EX AF,AF' + PUSH AF + LD IX,DIRPAGE.buffer ; IX + ;!TEST 9/11/23 record index + EXX + LD DE,0 + EXX + ; + LD DE,FAT_DIRECTORY_RECORD +.loop: LD A,(IX + FAT_DIRECTORY_RECORD.NAME); IX + OR A + JR Z,.WRITE_LAST_HANDLE + ; + CP #E5 + JR Z,.WRITE_HANDLE + ; + EXX + INC DE ; record index + EXX + ADD IX,DE ; IX, + JR NC,.loop ;!FIXIT количество записей каталога = страница + ; +.error: POP AF + OUT (SLOT3),A + LD A,DSS_Error.sys.ROOT_OVERFLOW + SCF + RET + ; +WRITE_LAST_HANDLE: ;!FIXIT ставить ноль после новой HANDLE и потом писать директорию. Если не конец страницы или всей директории + EXX + INC DE ; record index + LD A,D + OR E + DEC DE + EXX + JR Z,.error ; максимальный номер записи в директории + ; + + CALL WRITE_HANDLE + RET + ; +.WRITE_HANDLE: LD E,XL + LD D,XH + LD HL,CORE_BUFFERS.HANDBUF + LD BC,CORE_BUFFERS.HANDBUF.SIZE + LDIR + ; !FIXIT тут DE может переполниться и стать 0, тогда надо проверить + ; не конец ли это директории вообще, если конец, то надо + ; добавить одну запись с нулём в конец переместив указатель в FM + ; и записав 32 нуля + ; + POP AF + OUT (SLOT3),A + ; !FIXIT проверить расчёт... проверяем, увеличился ли размер данных директории + LD HL,DIRPAGE.buffer + LD BC,(SAVEDIR.DirBlkSize) + DEC BC + ADD HL,BC + AND A + SBC HL,DE + JR NC,.SAVEDIR + ; + ; размер данных директории увеличился + + + ;LD HL,(SAVEDIR.DirBlkSize) + ;LD BC,(CORE_BUFFERS.FS_Buffer.BytesPerCluster) + ;ADD HL,BC + ;LD (SAVEDIR.DirBlkSize),HL + ;AND A + LD HL,DIRPAGE.buffer + EX DE,HL + SBC HL,DE + LD DE,FAT_DIRECTORY_RECORD + ADD HL,DE + LD (SAVEDIR.DirBlkSize),HL + + + +.SAVEDIR: EXX + PUSH DE + EXX + ; [ ] big dir передавать откуда и сколько байтов изменилось в кэш, чтоб не писать на диск лишнего + CALL SAVEDIR + POP DE + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; 20 28 +; FIND "MASKAREA" IN DIRECTORY +; выход: IY:DE - cluster number +; [ ] big dir всегда ли при вызове у нас правильные (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L и H) для LOADDIR? +FINDDIR: SET_PAGE_X DIRPAGE + ; + PUSH AF + ; + ;LD A,(CORE_BUFFERS.FS_Buffer.DirBlock) + ;AND A + ;CALL NZ,LOADDIR ;!FIXIT check error + ; + LD A,#28 ; JR Z,... + LD (SEARCH_RECORD_IN_DIR_CACHE.type),A ; search directory + LD A,FAT_ATTR.DIRECTORY + CALL SEARCH_RECORD_IN_DIR_CACHE + EX AF,AF + LD A,#20 ; JR NZ,... + LD (SEARCH_RECORD_IN_DIR_CACHE.type),A ; search + EX AF,AF + JR C,.error + ; + LD A,(IX + FAT_DIRECTORY_RECORD.NAME) + CP "." + JP NZ,.ADDSPEC + LD A,(IX + FAT_DIRECTORY_RECORD.NAME + 1) + CP "." + JP NZ,.ITs_DIR + ; + LD HL,CORE_BUFFERS.WorkDirectory + LD D,H + LD E,L + INC HL + LD BC,CORE_BUFFERS.WorkDirectory.DEPTH + XOR A + CPIR + JP PO,.error ;[x] 20/11/23 проверка на выход за границы + ; + DEC HL ;R009 + DEC HL + LD BC,CORE_BUFFERS.WorkDirectory.DEPTH + LD A,'\' + CPDR + INC HL + EX DE,HL + ; CF = 0 + SBC HL,DE + EX DE,HL + JR NZ,.MM3 + ; + INC HL +.MM3: LD (HL),0 + JP .ITs_DIR + ; +.error: POP AF + OUT (SLOT3),A + LD A,DSS_Error.sys.PATH_NOT_FOUND + SCF + RET + ; +.ADDSPEC: LD HL,CORE_BUFFERS.WorkDirectory+1 + LD BC,CORE_BUFFERS.WorkDirectory.DEPTH-1 + CALL .CHECK_SLASH + JR C,.error + ;R011 + LD A,B + AND A + JR NZ,.nxt + LD A,C + CP 8+1+3 ;!HARDCODE имя каталога + точка + расширение + JR C,.error +.nxt: ; + LD E,XL + LD D,XH + ; [x] оптимизация по размеру + EX DE,HL + CALL GetName + EX DE,HL + ; +.ITs_DIR: ; fat32 + LD E,(IX + FAT_DIRECTORY_RECORD.FIRST_CLUSTER_H) + LD D,(IX + FAT_DIRECTORY_RECORD.FIRST_CLUSTER_H+1) + LD YH,D + LD YL,E + LD E,(IX + FAT_DIRECTORY_RECORD.FIRST_CLUSTER_L) + LD D,(IX + FAT_DIRECTORY_RECORD.FIRST_CLUSTER_L+1) + POP AF + OUT (SLOT3),A + AND A + RET + ; +.CHECK_SLASH: XOR A + CPIR + ;[x] 20/11/23 проверка на выход за границы + SCF + RET PO + ; + DEC HL + DEC HL + LD A,'\' ; #5C + CP (HL) + INC HL + RET Z + ; + LD (HL),A + INC HL + XOR A ; сброс CF заодно + LD (HL),A + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; Вход: IY - указатель на начало файлового манипулятора +CHECK_ROOT_CLUSTER: + LD A,(CORE_BUFFERS.FS_Buffer.FAT_TYPE) + CP FAT_TYPE.x32 + JR NZ,CHECK_FIRST_CLUSTER + ; + LD HL,(CORE_BUFFERS.FS_Buffer.RootDirStartCluster_L) + LD BC,(CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L) + SBC HL,BC + RET NZ + ; + LD HL,(CORE_BUFFERS.FS_Buffer.RootDirStartCluster_H) + LD BC,(CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_H) + SBC HL,BC + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; вход: IY - указатель на начало файлового манипулятора +; выход: HL':HL - first cluster +; ZF = 0 если первого кластера нет +CHECK_FIRST_CLUSTER: + 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 + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; вход: HL - имя директории +OPENDIR: ; init + ;EX DE,HL + ;XOR A + ;LD H,A + ;LD L,A + ;LD (CORE_BUFFERS.FS_Buffer.DirBlockDrive),A + ;LD (CORE_BUFFERS.FS_Buffer.DirBlockStartCluster_L),HL + ;LD (CORE_BUFFERS.FS_Buffer.DirBlockStartCluster_H),HL + ;IF DIR_BLOCK_CACHE_OPTIMIZE + ; LD (CORE_BUFFERS.FS_Buffer.DIR_BLOCK_CHANGES),HL + ; LD (CORE_BUFFERS.FS_Buffer.DIR_BLOCK_CHANGES + 2),HL + ;ENDIF + ;EX DE,HL + ; + LD IY,CORE_BUFFERS.FM_BUF + LD A,(HL) + OR A + JR NZ,.SUBDIR + ; REROOT + EX DE,HL + LD HL,(CORE_BUFFERS.FS_Buffer.RootDirStartCluster_L) + LD (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L),HL + LD HL,(CORE_BUFFERS.FS_Buffer.RootDirStartCluster_H) + LD (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_H),HL + EX DE,HL +.reroot: CALL LOADDIR ; [ ] big dir + ; CF=0 + LD HL,CORE_BUFFERS.WorkDirectory + LD (HL),'\' + INC HL + LD (HL),#00 + ;AND A + RET + ; +.SUBDIR: CP "." + JR NZ,.SUBDIR2 + ; fat32 + ; !TEST 04/01/2026 + EX DE,HL + CALL CHECK_ROOT_CLUSTER + ;CALL CHECK_FIRST_CLUSTER + EX DE,HL + ; + JR NZ,.no_root ;R005 + ; "cd ." or "cd .." + ;R005 + INC HL + LD A,(HL) + OR A + DEC HL + JR Z,.reroot + ; +.no_root: EXX + LD HL,CORE_BUFFERS.MASKARE + LD DE,CORE_BUFFERS.MASKARE+1 + LD BC,10 ;!HARDCODE + LD (HL),' ' + LDIR + EXX + LD DE,CORE_BUFFERS.MASKARE +.loop: LDI + LD A,(HL) + OR A + JR NZ,.loop + JR .SUBDIR3 + ; +.SUBDIR2: ;EX DE,HL + CALL MASK.name + RET C + ; fat32 +.SUBDIR3: CALL FINDDIR + RET C + ; + EX DE,HL + LD A,(CORE_BUFFERS.FS_Buffer.FAT_TYPE) + CP FAT_TYPE.x32 + JR NZ,.setCluster + ; [ ] big dir + LD A,H + OR L + OR YH + OR YL + JR NZ,.setCluster + ; set root dir for fat32 + LD HL,(CORE_BUFFERS.FS_Buffer.RootDirStartCluster_L) + LD IY,(CORE_BUFFERS.FS_Buffer.RootDirStartCluster_H) +.setCluster: LD (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L),HL + LD (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_H),IY ; fat32 + ; +;-------------; JP LOADDIR +;----------------------------------------------------------------------; +;!TODO optimize +; Прочитать список каталога +; Вход: (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L), (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_H) +LOADDIR: LD HL,0 ;!FIXIT если HL выйдет за размеры директории и DirBlock будет некорректным? +;[-------------] +; Вход: HL - ID записи, который должен попасть в КЭШ +; (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L), (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_H) +.Custom: AND A ; в LOAD_SAVE_DIR_PREPARE посчитается размер каталога директории +;[-------------] +; Вход: HL - ID записи, который должен попасть в КЭШ +; (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L), (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_H) +; CF - не рассчитывать размер директории +.next: CALL LOAD_SAVE_DIR_PREPARE + PUSH AF + EX AF,AF' + JR Z,.LoadRootDirFAT12_16 + ; +.read_dir: LD HL,DIRPAGE.buffer ; куда + LD DE,DIRPAGE.size ; сколько + XOR A ; дескриптор + CALL READ ; чтение из файла + EX AF,AF' + LD (SAVEDIR.DirBlkSize),DE ; число прочит. байтов + POP AF + OUT (SLOT3),A + EX AF,AF' + RET C + ; если DE = 0 + ; (A == FF) & (DE == 0) - в прошлый раз прочитали до конца + ; + LD A,D + OR E + RET NZ + ; читаем с начала + JR LOADDIR +; .no_more: LD A,#FF +; SCF +; RET + ; +.LoadRootDirFAT12_16: + ; [ ] big dir + LD A,(CORE_BUFFERS.FS_Buffer.DirBlock) + AND A + JR Z,.ok + ; + XOR A + LD (CORE_BUFFERS.FS_Buffer.DirBlock),A + RET + ; + ; +.ok: LD HL,(CORE_BUFFERS.FS_Buffer.RootDirFirstSector_H);!TODO возможно, хватит LD HL,0 + LD IX,(CORE_BUFFERS.FS_Buffer.RootDirFirstSector_L); номер лог. сектора + LD A,(CORE_BUFFERS.FS_Buffer.DirSizeInSectors) + LD B,32 ; !HARDCODE sector size 512. 16384/(sector 512). размер root-каталога ; [ ] sector size 512 + CP B + JR NC,.RTD1 + ; + LD B,A ; число секторов +.RTD1: LD A,(CORE_BUFFERS.FS_Buffer.DRIVE) ; номер диска + LD DE,DIRPAGE.buffer ; буфер + LD C,Dss.DRV.Read ; чтение секторов + RST ToDSS.DRV + ; !FIXIT нет проверки на ошибку + ; 21/04/2025 fix мусор в странице каталога, если каталог меньше страницы + BIT 7,D + JR Z,.exit + XOR A + LD (DE),A + ; +.exit: POP AF + OUT (SLOT3),A + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; Вход: HL - ID записи, который должен попасть в КЭШ +; Выход: HLIX - смещение в файле каталога на нужный блок по #4000 байтов +; A - Номер блока DirBlock +; GET_DIRCACHE_BLOCK_ADDR: +; ; HLIX = (HL*32) & #1FC000 смещение на нужный блок по #4000 байтов +; XOR A +; LD XL,A +; LD E,A +; LD A,H +; LD H,E +; AND #FE +; RRA +; RR E +; LD D,A ; DirBlock +; RRA +; RR E +; RRA +; RR E +; LD XH,E +; LD L,A +; LD A,D +; RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; [ ] доделать передачу ID записи директории и загрузки по ней нужного куска в кэш +;!TODO FAT procedures +;----------------------------------------------------------------------; +; Вход: HL - ID записи, который должен попасть в КЭШ +; CF - не считать размер каталога директории (при первом открытии) +; Выход: A - Страница, которая была в SLOT3 до вызова +; ZF' - RootDir FAT12-16 +LOAD_SAVE_DIR_PREPARE: + PUSH AF + ;CALL GET_DIRCACHE_BLOCK_ADDR + ;LD (CORE_BUFFERS.FS_Buffer.DirBlock),A + ; HLIX = (HL*32) & #1FC000 смещение на нужный блок по #4000 байтов + XOR A + LD XL,A + LD E,A + LD A,H + LD H,E + AND #FE + RRA + RR E + LD (CORE_BUFFERS.FS_Buffer.DirBlock),A + RRA + RR E + RRA + RR E + LD XH,E + LD L,A + ; + XOR A ; FILE MANIPULATOR = 0 + LD B,A ; от начала файла + CALL MOVE_FP + SET_PAGE_X DIRPAGE + POP DE + AND A + PUSH AF + ; + LD A,(CORE_BUFFERS.FS_Buffer.DRIVE) + LD (CORE_BUFFERS.FM_BUF.DRIVE),A + ; check fat12-16 root dir + XOR A + LD HL,(CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L) + EXX + LD HL,(CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_H) + OR H + OR L + EXX + OR H + OR L + JR Z,.exit + ; + PUSH AF + SRL E + CALL NC,.CalcDirSize + POP AF +.exit: EX AF,AF' + POP AF + RET + ; + ; calc dir size in clusters +.CalcDirSize: LD DE,0 +.loop: INC DE ; Надеемся тут на то, что спецификация выполняется и переполнения не будет + PUSH DE + CALL READ_FROM_FAT + EX DE,HL + POP DE + EXX + EX DE,HL + EXX + JR NC,.loop + ; + ; DE - размер директории в кластерах + ;!FIXIT можно оптимизнуть кол-во сдвигов + ;0001 0000 0000 0000 max кол-во кластеров + ; пример + ;0000 0000 0000 0111 Clusters + ; 0100 0000 SectorsPerCluster + ;0000 0010 0000 0000 BytesPerSector + ; D' E' D E + ;0000 0000 0000 0011 1000 0000 0000 0000 + ; + LD A,(CORE_BUFFERS.FS_Buffer.SectorsPerCluster) + LD BC,(CORE_BUFFERS.FS_Buffer.BytesPerSector) + ; DE':DE - кол-во кластеров + ; A - размер кластера в секторах + ; BC - размер сектора в байтах + ; --> DE*BC*A = DE':DE для ответа хватит, походу, 4х регистров + EXX + LD DE,0 + EXX + SRL B + RR C + RRCA + JR C,.loop2 + ; +.loop1: SLA E + RL D + EXX + RL E + RL D + EXX + RRCA + JR NC,.loop1 + ; +.loop2: SLA E + RL D + EXX + RL E + RL D + EXX + ; + SRL B + RR C + JR NC,.loop2 + ; <-- DE*BC*A = DE':DE + LD (CORE_BUFFERS.FM_BUF.FS_REC.F_SIZE),DE + EXX + LD (CORE_BUFFERS.FM_BUF.FS_REC.F_SIZE + 2),DE + RET + +/* пример 4 3 2 1 + #FFFF<<5 = #1FFFE0 = 0000 0000 0001 1111 1111 1111 1110 0000 + + #FFFF номер записи + #1FFFE0 смещение на запись в файле директории + #1FFFE0 & #1FC000 смещение на нужный блок по #4000 байтов + #1FFFE0 & #3FFF Адрес нужной позиции в кэш + (#1FFFE0 & #1FC000)<<2 двигаем байт 2 и 3 чтоб получить номер блока +*/ +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +;!TODO optimize +;!TODO .DIRSIZE помешает если в кэш будет другая страница? +;!TODO LOAD_SAVE_DIR_PREPARE возможно не нужен, нужно только установить правильное смещение в FM +;!TODO Может вообще переделать её под работу с КЭШ +;!TODO ; [ ] big dir получать откуда и сколько байтов изменилось в кэш, чтоб не писать на диск лишнего +; +; Сбросить кеш каталога на диск. +; вход: HL - ID записи, которая изменилась в КЭШ +; в кэш должна быть корректная страница директории, DirBlkSize корректный тоже +SAVEDIR: SCF ; не считать размер директории + CALL LOAD_SAVE_DIR_PREPARE + PUSH AF + EX AF,AF' + JR Z,.SaveRootDir + ; +.save_dir: LD HL,DIRPAGE.buffer + ; размер списка каталога size_cash_directory + ;!FIXIT если она нужна, то проверить на баги (например, размер дирректории меньше при открытии и больше после правок) + ; когда будет чтение кусками каталога в кэш, тут ещё счётчик прикрутить +.DirBlkSize+1: LD DE,0 + XOR A ; FM + CALL WRITE + POP AF + OUT (SLOT3),A + RET + ; + ; FAT12-16 +.SaveRootDir: LD HL,(CORE_BUFFERS.FS_Buffer.RootDirFirstSector_H) ;!TODO возможно, хватит LD HL,0 + LD IX,(CORE_BUFFERS.FS_Buffer.RootDirFirstSector_L) + LD A,(CORE_BUFFERS.FS_Buffer.DirSizeInSectors) + LD B,32 ;!HARDCODE sector size 512, Root Dir max size in sectors + SUB B + JR NC,.RTD1S + ; + ADD A,B + LD B,A +.RTD1S: LD A,(CORE_BUFFERS.FS_Buffer.DRIVE) + LD DE,DIRPAGE.buffer + LD C,Dss.DRV.Write + RST ToDSS.DRV + POP AF + OUT (SLOT3),A + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; [ ] big dir +; скопировать запись в список диска (каталога) de ix iy +; и сбросить кеш каталога на диск +; вход: (HANDBUF) - запись каталога +; выход: DE - record index +WRITE_DIR_HANDLE: + SET_PAGE_X DIRPAGE + EX AF,AF' + LD HL,DIRPAGE.buffer + ;!TEST 9/11/23 record index + EXX + LD DE,0 + EXX + ; + LD BC,FAT_DIRECTORY_RECORD +.loop: LD A,(HL) + OR A + JR Z,.WRT_HN2 + ; + CP #E5 + JR Z,.WRT_HN2 + ADD HL,BC + JR NC,.loop ;!FIXIT количество записей каталога = страница + ; + EX AF,AF' + OUT (SLOT3),A + LD A,DSS_Error.sys.ROOT_OVERFLOW + SCF + RET + ; +.WRT_HN2: EX DE,HL + LD HL,CORE_BUFFERS.HANDBUF + LD BC,CORE_BUFFERS.HANDBUF.SIZE + LDIR + EX AF,AF' + OUT (SLOT3),A + ; проверяем, увеличился ли размер данных директории + LD HL,DIRPAGE.buffer + LD BC,(SAVEDIR.DirBlkSize) + DEC BC + ADD HL,BC + AND A + SBC HL,DE + JR NC,.SAVEDIR + ; + ; размер данных директории увеличился + LD HL,(SAVEDIR.DirBlkSize) + LD BC,(CORE_BUFFERS.FS_Buffer.BytesPerCluster) + ADD HL,BC + LD (SAVEDIR.DirBlkSize),HL + AND A +.SAVEDIR: EXX + PUSH DE + EXX + ; [ ] big dir передавать откуда и сколько байтов изменилось в кэш, чтоб не писать на диск лишнего + CALL SAVEDIR + POP DE + RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; Вход: IX - указатель на номер записи в каталоге +; Выход: HL - смещение в SLOT3 на запись в каталоге +; GET_ADDR_IN_DIR_CACHE: +; LD A,3 +; PUSH IX +; POP HL +; RR H +; ; +; RR L +; RRA +; RR L +; RRA +; RR L +; RRA +; LD H,L +; LD L,A +; LD A,H +; OR #C0 +; LD H,A +; RET +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; !TODO оптимизировать постоянные сохранения Dir Cache +; Удаляет запись в каталоге и освобождает занятую цепочку кластеров +; Вход: IX - указатель на удаляемую запись в DIRPAGE +; в КЭШ директории должна быть загружена часть с нужной записью +;!TODO record index. возможно, что может сломаться, если больше страницы +DELETE_REC_FAT: SET_PAGE_X DIRPAGE + EX AF,AF' + LD A,(CORE_BUFFERS.FS_Buffer.DirBlock) + CALL SET_RECORD_INDEX_FROM_DIR_BLOCK + ; DE' - record index + ;CALL DELETE_LFN_RECORDS ; [ ] big dir ; [x] удаление записи LFN + LD (IX + FAT_DIRECTORY_RECORD.NAME),#E5 ; признак удаления файла + ; fat32 + LD L,(IX + FAT_DIRECTORY_RECORD.FIRST_CLUSTER_H) ; № первого кластера + LD H,(IX + FAT_DIRECTORY_RECORD.FIRST_CLUSTER_H+1) + LD A,L + OR H + EXX + LD L,(IX + FAT_DIRECTORY_RECORD.FIRST_CLUSTER_L) ; № первого кластера + LD H,(IX + FAT_DIRECTORY_RECORD.FIRST_CLUSTER_L+1) + OR L + OR H + ; + EX AF,AF' + OUT (SLOT3),A + EX AF,AF' + ; если длина файла нулевая, то дальше ловить тут нечего. + ; [ ] big dir передавать откуда и сколько байтов изменилось в кэш, чтоб не писать на диск лишнего + EX DE,HL ; record index из SET_RECORD_INDEX_FROM_DIR_BLOCK + JP Z,SAVEDIR ; сбросить кеш каталога на диск + ; если размер файла не ноль + PUSH HL ; record index +.loop: ; hl=номер кластера + CALL READ_FROM_FAT ; прочитать из кеша FAT-а номер след. кластера + EXX + PUSH DE ; номер след. кластера + PUSH AF + LD DE,#0000 ; номер кластера + EXX + PUSH DE + ; + CALL SET_NEW_FREE_CLUSTER + ; + LD DE,#0000 ; номер кластера + CALL WRITE_TO_FAT.Custom ; записать в кеш FAT-а номер кластера + POP HL + EXX + POP AF + POP HL + ;EX DE,HL + EXX + ;EX DE,HL + JP NC,.loop + ; + CALL WRITE_FAT_TABLE + ; [ ] big dir передавать откуда и сколько байтов изменилось в кэш, чтоб не писать на диск лишнего + POP HL ; record index + JP SAVEDIR ; сбросить кеш каталога на диск +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; Вход: HL - адрес куда писать +; Выход: HL - адрес следующий после записаного +WRITE_DATE_TIME_FOR_DIRECTORY_RECORD: + ; [ ] VFAT date + PUSH HL + CALL SYSTIME ; узнать тек. дату и время + CALL MK_TIME ; закодировать время/дату + POP HL + ; FAT_DIRECTORY_RECORD.TIME + LD (HL),E ; de=время + INC HL + LD (HL),D + INC HL + ; FAT_DIRECTORY_RECORD.DATE + LD (HL),C ; день + INC HL + LD (HL),B ; месяц + INC HL + RET +;----------------------------------------------------------------------; + + +;----------------------------------------------------------------------; +; Преобразовать имя 8.3 -> 11 формат +; !FIXIT написать нормальное описание входа/выхода +; вход: hl = 8.3 имя +; de = буфер имени 11 симв. формата +; при ошибке CF - недоп. имя +; +; HL - MASK "file*.t??" +; DE - 11 bytes filename +; RET: C=2 FILE WITHOUT EXTENTION +; C=1 FILE WITH EXTENTION +MASK: LD HL,CORE_BUFFERS.TMPNAME +;[-------------] +; вход: hl = 8.3 имя +.name: LD DE,CORE_BUFFERS.MASKARE +;[-------------] +; вход: hl = 8.3 имя +; de = буфер имени 11 симв. формата +.custom: PUSH HL + PUSH DE + LD H,D + LD L,E + INC DE + LD (HL),' ' + LD BC,10 ;!HARDCODE = size (FileName + Extension - 1) + LDIR + POP DE + POP HL + LD A,(HL) + CP '.' ;R007 + SCF ;R007 + JR Z,.MASKB ;R007 + CP ' '+1 +.MASKB: LD A,DSS_Error.sys.INVALID_NAME + RET C + LD BC,#0902 ; B - счетчик +.MASK1: LD A,(HL) + CP ' '+1 + CCF + RET NC + ; + CP '*' + JR Z,.MASK3 + CP '.' + JR Z,.MASK5 + CP '"' + JR Z,.MASK_ERR + CP '+' + JR Z,.MASK_ERR + CP ',' + JR Z,.MASK_ERR + CP '/' + JR Z,.MASK_ERR + CP ':' + JR Z,.MASK_ERR + CP ';' + JR Z,.MASK_ERR + CP '<' + JR Z,.MASK_ERR + CP '=' + JR Z,.MASK_ERR + CP '>' + JR Z,.MASK_ERR + CP '[' + JR Z,.MASK_ERR + CP '\' + JR Z,.MASK_ERR + CP ']' + JR Z,.MASK_ERR + CP '|' + JR Z,.MASK_ERR + CALL UPPER ; a..z -> A..Z +.MASK2: LD (DE),A + INC HL + INC DE + DJNZ .MASK1 + ; +.MASK_ERR: LD A,DSS_Error.sys.INVALID_NAME + SCF + RET + ; +.MASK3: LD A,'?' + INC HL + DJNZ .MASK6 + JR .MASK_ERR + ; +.MASK6: LD (DE),A + INC DE + DJNZ .MASK6 + LD B,1 + JR .MASK1 + ; +.MASK5: LD A,' ' + INC HL + DJNZ .MASK4 + LD B,4 + DEC C + JR NZ,.MASK1 + JR .MASK_ERR + ; +.MASK4: LD (DE),A + INC DE + DJNZ .MASK4 + LD B,4 + DEC C + JR NZ,.MASK1 + JR .MASK_ERR +;----------------------------------------------------------------------; + + + +;----------------------------------------------------------------------; +; SET_FAT_ROOT_DIR_CLUSTER: +; EX DE,HL +; LD HL,(CORE_BUFFERS.FS_Buffer.RootDirStartCluster_L) +; LD (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L),HL +; LD HL,(CORE_BUFFERS.FS_Buffer.RootDirStartCluster_H) +; LD (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_H),HL +; EX DE,HL +; RET +;----------------------------------------------------------------------; + + + + + +;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░; +;??? +;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░; + +;----------------------------------------------------------------------; +;!TODO ? +;GHANDLE: +; PUSH DE +; PUSH HL +; PUSH IX +; CALL TESTDSK +; JP C,G_HAND1 +; CALL LOADDIR +; POP DE +; LD HL,DIR +; LD BC,FAT_DIRECTORY_RECORD +;G_HAND2: +; LD A,D +; OR E +; JP Z,G_HAND3 +; ADD HL,BC +; DEC DE +; JP G_HAND2 +;G_HAND3: +; EXX +; POP DE +; EXX +;G_HAND4: +; EX DE,HL +; LD A,DIRPAGE +; CALL BANK +; EX DE,HL +; LD DE,HANDTA +; +; DUP 32 +; LDI +; EDUP +; +; EXX +; OUT (SLOT3),A +; LD HL,HANDTA +; +; DUP 32 +; LDI +; EDUP +; +; EXX +; POP BC +; DEC BC +; LD A,B +; OR C +; RET Z +; PUSH BC +; JP G_HAND4 +;G_HAND1 POP IX +; POP HL +; POP DE +; RET +;HANDTA BLOCK 32,0 +;----------------------------------------------------------------------; + + + + +MODULE_SIZE EQU $ - MODULE_START +; ENDMODULE +;███████████████████████████████████████████████████████████████████████; +;███████████████████████████████████████████████████████████████████████; +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// FAT_BPB: LD A,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.DRIVE_TYPE) CP #F0 JP C,RD_BPB.UnknownBPB