;[BEGIN] ;//MODULE: FAT ;//CREATE: 19-05-1998 AUTHOR: Denis Parinov ;//UPDATE: 24-10-1999 DNS Restore module ;--------------------------------------------------------------- ;Rev Date Name Description ;--------------------------------------------------------------- ;R08 14-11-2002 DNS IMPROVE BPB-FUNCTION ;R07 17-12-1999 DNS BUG FIX SIGNATURE #55AA AT 510 OFFSET ;RY01 16-11-1999 DNS ERROR READING FAT CHAIN ;RX01 10-02-1999 DNS UPGRADE FAT CASH ;--------------------------------------------------------------- ; [ ] RST_FS ;----------------------------------------------------------------------; FAT_MODULE_START EQU $ 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 ; ; [ ] удаление записи LFN ; ; вход: IX = текущая запись в странице с каталогом FAT для которой ; надо удалить записи LFS DELETE_LFN_RECORDS: PUSH IX LD A,XH AND #C0 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 ; 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 ;----------------------------------------------------------------------; ; Поиск записи каталога в списке каталога ; ; вход: a = атрибут записи ; выход: de = индекс записи в списке каталога ; (HANDBUF) = file's direcory 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 LD C,A LD IX,DIRPAGE.buffer ;!TEST 9/11/23 record index ; оптимизация для индекса записи в списке каталога. ; Понадобится вернуть для перебора каталога > #4000 байт ; EXX ; LD DE,0 ; EXX ; .loop: LD A,(IX+FAT_DIRECTORY_RECORD.NAME) OR A JR Z,.error_file_not_found CP #E5 ;!HARDCODE #E5 - запись в директории свободна, так как файл/директория были удалены JR Z,.next_record LD A,(IX+FAT_DIRECTORY_RECORD.ATTRIBUT) LD D,A AND C 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,MASKARE LD D,XH LD E,XL LD B,11 EX DE,HL .loop_compare: LD A,(DE) CP '?' JR Z,.next_char CP (HL) JR NZ,.next_record ; .next_char: INC HL INC DE DJNZ .loop_compare ; LD D,XH LD E,XL ;!TEST 9/11/23 record index ; EXX ; PUSH DE ; EXX PUSH IX ; LD HL,HANDBUF EX DE,HL LD BC,HANDBUF.SIZE LDIR ;!TEST 9/11/23 record index POP DE ; EX AF,AF' OUT (SLOT3),A EX AF,AF' AND A RET ; .next_record: LD DE,FAT_DIRECTORY_RECORD ;!TEST 9/11/23 record index ; EXX ; INC DE ; EXX ; ADD IX,DE JR NC,.loop .error_too_many_files: EX AF,AF' OUT (SLOT3),A LD A,DSS_Error.sys.TOO_MANY_FILES_IN_DIR SCF RET ; .error_file_not_found: EX AF,AF' OUT (SLOT3),A LD A,DSS_Error.sys.FILE_NOT_FOUND SCF 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 ; ;----------------------------------------------------------------------; ; FIND "MASKAREA" IN DIRECTORY ; [x] fat32 ;!TEST ; выход: IY:DE - cluster number FINDDIR: SET_PAGE_X DIRPAGE ; PUSH AF LD IX,DIRPAGE.buffer .big_loop: LD A,(IX + FAT_DIRECTORY_RECORD.NAME) OR A JR Z,.error CP #E5 JR Z,.next_step LD A,(IX + FAT_DIRECTORY_RECORD.ATTRIBUT) AND FAT_ATTR.DIRECTORY JR Z,.next_step LD HL,MASKARE LD D,XH LD E,XL EX DE,HL LD B,11 ;!HARDCODE .loop: LD A,(DE) CP "?" JR Z,.compared CP (HL) JR NZ,.next_step .compared: INC HL INC DE DJNZ .loop ; LD A,(IX + FAT_DIRECTORY_RECORD.NAME) CP "." JP NZ,.ADDSPEC LD A,(IX + FAT_DIRECTORY_RECORD.NAME + 1) CP "." JP NZ,.IT_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 .IT_DIR ; .next_step: LD BC,FAT_DIRECTORY_RECORD ADD IX,BC JR NC,.big_loop ; .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 ; ; LD BC,256*8 + ' ' ;!HARDCODE ; .MM1: LD A,(DE) ; INC DE ; CP C ; JR Z,.MM2 ; LD (HL),A ; INC HL ; .MM2 DJNZ .MM1 ;x42-40 50-55 ; LD A,(DE) ; INC DE ; CP C ; JR Z,.MM3 ; LD (HL),"." ; INC HL ; LD (HL),A ; INC HL ; LD A,(DE) ; INC DE ; CP C ; JR Z,.MM3 ; LD (HL),A ; INC HL ; LD A,(DE) ; CP C ; JR Z,.MM3 ; LD (HL),A ; .MM2_5: INC HL ; .MM3: LD (HL),0 ; ; JP IT_DIR ; .IT_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 ;----------------------------------------------------------------------; CHECK_ROOT_CLUSTER: EX DE,HL LD HL,(CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L) ;R005 LD A,L OR H LD HL,(CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_H) OR L OR H EX DE,HL RET ;----------------------------------------------------------------------; ; вход: HL - имя директории ; [x] fat32 ;!TEST OPENDIR: LD IY,CORE_BUFFERS.FM_BUF LD A,(HL) OR A JR NZ,.SUBDIR ; .REROOT: LD DE,0 ; !FIXIT ; [ ] CDFS - брать первый кластер из переменной LD (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L),DE LD (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_H),DE CALL LOADDIR ; CF=0 LD HL,CORE_BUFFERS.WorkDirectory LD (HL),'\' INC HL LD (HL),#00 ;AND A RET ; .SUBDIR: CP "." JR NZ,.SUBDIR2 ; fat32 CALL CHECK_ROOT_CLUSTER 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,MASKARE LD DE,MASKARE+1 LD BC,10 ;!HARDCODE LD (HL),' ' LDIR EXX LD DE,MASKARE .loop: LDI LD A,(HL) OR A JR NZ,.loop JR .SUBDIR3 ; .SUBDIR2: CALL MASK.name RET C ; fat32 .SUBDIR3: CALL FINDDIR RET C EX DE,HL LD (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L),HL ; fat32 LD (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_H),IY ; fat32 LD HL,#4000 ;!HARDCODE LD (CORE_BUFFERS.FM_BUF.FS_REC.F_SIZE),HL ;-------------; EX DE,HL ; JP LOADDIR ; Прочитать список каталога ; [x] fat32 ;!TEST LOADDIR: ;!TODO optimize CALL LOAD_SAVE_DIR_PREPARE PUSH AF EX AF,AF' JR NZ,.read_dir LD A,(CORE_BUFFERS.FS_Buffer.FAT_TYPE) CP FAT_TYPE.x32 JR NZ,.LoadRootDir ; fat32 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 ;LD HL,(CORE_BUFFERS.FS_Buffer.BytesPerCluster) ; !FIXIT вычитывать полностью каталог LD HL,#4000 ; размер директории ;!HARDCODE LD (CORE_BUFFERS.FM_BUF.FS_REC.F_SIZE),HL ; .read_dir: LD HL,DIRPAGE.buffer ; куда LD DE,#4000 ; сколько XOR A ; дескриптор CALL READ ; чтение из файла LD (SAVEDIR.DIRSIZE),DE ; число прочит. байтов POP AF OUT (SLOT3),A RET ; .LoadRootDir: 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-каталога CP B JR NC,.RTD1 LD B,A ; число секторов .RTD1: PUSH AF ; 21/04/2025 fix мусор в странице каталога, если каталог меньше страницы LD A,(CORE_BUFFERS.FS_Buffer.DRIVE) ; номер диска LD DE,DIRPAGE.buffer ; буфер LD C,Dss.DRV.Read ; чтение секторов RST ToDSS.DRV ; !FIXIT нет проверки на ошибку ; 21/04/2025 fix мусор в странице каталога, если каталог меньше страницы POP AF JR NC,.exit XOR A LD (DE),A ; .exit: POP AF OUT (SLOT3),A RET ;----------------------------------------------------------------------; ;!TODO FAT procedures ;----------------------------------------------------------------------; LOAD_SAVE_DIR_PREPARE: ;!TODO optimize XOR A ; FILE MANIPULATOR = 0 LD H,A LD L,A LD IX,0 LD B,A ; от начала файла CALL MOVE_FP ; SET_PAGE_X DIRPAGE AND A EX AF,AF' ; LD A,(CORE_BUFFERS.FS_Buffer.DRIVE) LD (IY+_sFM.DRIVE),A ;!FIXIT переделать на работу без IY LD A,(IY+_sFM.FS_REC.FIRST_CLUSTER_L) OR (IY+_sFM.FS_REC.FIRST_CLUSTER_L+1) OR (IY+_sFM.FS_REC.FIRST_CLUSTER_H) OR (IY+_sFM.FS_REC.FIRST_CLUSTER_H+1) ; EX AF,AF' RET ;----------------------------------------------------------------------; ; скопировать запись в список диска (каталога) de ix iy ; и сбросить кеш каталога на диск ; вход: (HANDBUF) - запись каталога WRT_HND: 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,(IX+00) LD A,(HL) OR A JR Z,.WRT_HN2 CP #E5 JR Z,.WRT_HN2 ;ADD IX,BC ADD HL,BC JR NC,.loop ;!FIXIT количество записей каталога = страница ; EX AF,AF' OUT (SLOT3),A LD A,DSS_Error.sys.ROOT_OVERFLOW SCF RET ; .WRT_HN2: ;LD D,XH ;LD E,XL EX DE,HL LD HL,HANDBUF LD BC,HANDBUF.SIZE LDIR EX AF,AF' OUT (SLOT3),A LD HL,DIRPAGE.buffer LD BC,(SAVEDIR.DIRSIZE) DEC BC ADD HL,BC AND A SBC HL,DE JR NC,SAVEDIR LD HL,(SAVEDIR.DIRSIZE) LD BC,(CORE_BUFFERS.FS_Buffer.BytesPerCluster) ADD HL,BC LD (SAVEDIR.DIRSIZE),HL AND A ;JP SAVEDIR ;----------------------------------------------------------------------; ; Сбросить кеш каталога на диск. ; вход: iy=структура дескриптора ; [x] fat32 ;!TEST SAVEDIR: ;!TODO optimize CALL LOAD_SAVE_DIR_PREPARE PUSH AF EX AF,AF' JR NZ,.save_dir ; LD A,(CORE_BUFFERS.FS_Buffer.FAT_TYPE) CP FAT_TYPE.x32 JR NZ,.SaveRootDir ; fat32 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 ; .save_dir: LD HL,DIRPAGE.buffer ; размер списка каталога size_cash_directory ;!FIXIT если она нужна, то проверить на баги (например, размер дирректории меньше при открытии и больше после правок) ; когда будет чтение кусками каталога в кэш, тут ещё счётчик прикрутить .DIRSIZE+1: LD DE,0 XOR A CALL WRITE POP AF OUT (SLOT3),A RET ; .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 ;----------------------------------------------------------------------; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ; [x] fat32 ; 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 ; ; ;R08 ; [x] fat32 ; LD HL,CORE_BUFFERS.SECTOR_BUFFER ; LD DE,CORE_BUFFERS.BootSector ; LD BC,_sBOOT_SECTOR_PARAMS_FAT32 ; size ; LDIR ; FAT_BPB: LD A,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.DRIVE_TYPE) CP #F0 JP C,RD_BPB.UnknownBPB ; XOR A LD (.UsesVarsFAT32),A ; 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 ;[ ] fat32 XOR A LD B,A LD C,A 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.SectorsPerFAT_H),A ; [ ] fat32 ;LD (CORE_BUFFERS.FS_Buffer.END_CHAIN_CLUSTER_H),BC ; [ ] fat32 reset variables ; ; EXX LD H,A LD L,A LD D,A LD E,A EXX 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 ; 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 .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 DIR 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 EX DE,HL LD HL,(CORE_BUFFERS.FS_Buffer.SectorsPerFAT_L) ; DE:HL = SectorsPerFAT ; LD A,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.Number_of_FATs) LD B,A DEC A JR Z,.loop_mul_end ; .Number_of_FATs * .SectorsPerFAT .loop_mul: ADD HL,HL EX DE,HL ADC HL,HL EX DE,HL DJNZ .loop_mul .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 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 JR Z,.first_FAT_active LD B,A ; .fat_calc_loop: ADD HL,DE EXX ADC HL,DE EXX DJNZ .fat_calc_loop ; .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 ; ; DOS_X_Error: ; .UnknownBPB: LD A,DSS_Error.sys.UNKNOWN_FORMAT ; SCF ; RET ; ; .Not_ready: LD A,DSS_Error.sys.NOT_READY ; ; CF = 1 ; RET ; ; ;!TODO к буферам! /* FS_Buffer: ;.MSG: DB 'FAT' .DRIVE: DB #FF .FAT_TYPE: DB #00 ; TYPE FAT (12 - 12bit, 16 - 16bit, 32 - 32bit) ; [x] fat32 .CacheBlock: DW #00 .CacheUpdated: DB #00 ;.SectorsPerBank: DB #00 .RootDirStartCluster_L: DW #0000 .RootDirStartCluster_H: DW #0000 ; [ ] fat32 .FAT1_SEC_L: DW #0000 ; MSD_FAT_SEC first sector FAT (FAT_FRM) .FAT1_SEC_H: DW #0000 ; [ ] fat32 .FAT2_SEC_L: DW #0000 .FAT2_SEC_H: DW #0000 ; [ ] fat32 .SectorsPerFAT_L DW #0000 .SectorsPerFAT_H DB #00 .RootDirFirstSector_L: DW #0000 ; MSD_CAT_SEC first sector DIR .RootDirFirstSector_H: DW #0000 ; MSD_CAT_SEC first sector DIR ; !TODO ограничение в 32 Гига ;!FIXIT не используется .DirSizeInSectors: DB #00 ; DIR_SEC_SIZE .FirstDataSector_L: DW #0000 ; MSD_DAT_SEC low .FirstDataSector_H: DW #0000 ; MSD_DAT_SEC high ; [ ] fat32 было ограничение в 32 Гига .BytesPerCluster: DW #0000 ; CLUSTER_LEN .END_CHAIN_CLUSTER_L: DW #FFFF .END_CHAIN_CLUSTER_H: DW #0FFF ; [ ] fat3 .MaxClusterLow: DW #0000 ; макс. число кластеров (без служ.) .MaxClusterHigh: DW #0000 ; макс. число кластеров (без служ.) ; .BytesPerSector DW #0000 .SectorsPerCluster DB #00 .BPB_SERIAL_NUMBER DW 0,0 .BPB_LABEL BLOCK 11,' ' ; 11 для FAT, 31 для CDFS IF COMPILE_UNUSED_CODE .FilesPerSector: DB #00 ; число файловых записей в секторе .ClustersPerBank: DB #00 ; A - Clusters per bank (16k) (число кластеров на блок ОЗУ) ; ????? это используется? ENDIF ;.READ_PG: DB #00 ;!TODO не используются некоторые значения, но задумка неплохая))) ;.S_X_H: DW #0000 ; количество секторов на цилиндре ; ????? это используется? ; */ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ;███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████; ; FAT_X 12-16-32 ;███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████; ; Удаляет запись в каталоге и освобождает занятую цепочку кластеров ; Вход: IX - указатель на удаляемую запись в DIRPAGE ;!TODO record index. возможно, что может сломаться, если больше страницы DELETE_REC_FAT: SET_PAGE_X DIRPAGE EX AF,AF' CALL DELETE_LFN_RECORDS ; [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' JP Z,SAVEDIR ; сбросить кеш каталога на диск ; если размер файла не ноль .loop: ;EX DE,HL ; hl=номер кластера ;EXX ; EX DE,HL ;EXX 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 JP SAVEDIR ; сбросить кеш каталога на диск ; Установить первым известным кластером для поиска свободного. ; Установится только если меньше предыдущего ; Вход: 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 ; ; [x] fat32 ;!TEST ; найти первый свободный кластер ;!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 ; ; ; ; [x] fat32 ;!TEST ; Прикрепить к последнему кластеру цепочки новый пустой кластер ; Вход: 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-а номер кластера ;!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 ; ; [ ] free clusters for FSInfo XOR A ; уменьшить CALL SET_NEW_FREE_CLUSTERS ; [ ] free clusters for FSInfo RET ;RX01 ; [x] fat32 ;!TEST ; вход: 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 ; ; ;[x] fat32 ;!TEST ;------------------------------------------------------------------------------------------------ ; Прочитать из кеша 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 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 ; ; [x] fat32 ;!TEST ; ; !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: ; [x] fat32 ;!TEST 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 ;;;;;;;;; ; [x] fat32 ;!TEST ;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 ;;;;;;;;; ; [x] fat32 ;!TEST ;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 ; [x] fat32 ;!TEST ; Подключить банку кеша 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 ;----------------------------------------------------------------------- ; ;[x] fat32 ;!TEST ;вход: 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 ;----------------------------------------------------------------------- ;[x] fat32 ;!TEST ;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 //////////////////////////////////////////////////////////////////////// ; [x] fat32 ;!TEST ; 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 ; [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 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 ;;;; ; ;[x] 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 ;----------------------------------------------------------------------- ; [x] fat32 ; вход: IY - FM ; выход: 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 ; [x] fat32 ; WRITE SECTORS OF FILE ; вход: HL:DE - FP (in sectors) ; IX - data in RAM ; IY - FM ; B - количество секторов для записи BLOK_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 старшее слово номера кластера ; ; 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 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 ;LD A,DSS_Error.sys.WRITE_ERROR ;SCF RET ; .ErrorFull: POP BC LD A,DSS_Error.sys.DISK_FULL ;SCF RET ; ;[x] fat32 ;[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 если оптимизация не сработала 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 //////////////////////////////////////////////////////////////////////// ;----------------------------------------------------------------------; ; Вход: HL - адрес куда писать ; Выход: HL - адрес следующий после записаного WRITE_DATE_TIME_TO_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 ;----------------------------------------------------------------------; ;----------------------------------------------------------------------; ;Расчёт смещения в секторах ;!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 ;----------------------------------------------------------------------; FAT_MODULE_SIZE EQU $-FAT_MODULE_START ;//MODULE: FAT ;[END]