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 ; ;EXX 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 ;[ ] 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 DE,(CORE_BUFFERS.SECTOR_BUFFER + BOOT_SECTOR.SectorsPerFAT16) LD A,E OR D JR NZ,.skip_high ; LD (.UsesVarsFAT32),A /* 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 #FFFF<<5 = #1FFFE0 = 0000 0000 0001 1111 1111 1111 1110 0000 #FFFF номер записи #1FFFE0 смещение на запись в файле директории #1FFFE0 & #1FC000 смещение на нужный блок по #4000 байтов #1FFFE0 & #3FFF Адрес нужной позиции в кэш (#1FFFE0 & #1FC000)<<2 двигаем байт 2 и 3 чтоб получить номер блока H L 0000 1011 1101 0001 3025 0001 0111 1010 0010 0000 3025*32 0001 0100 0000 0000 0000 and #1FC000 0011 1010 0010 0000 addr in page H L 1111 1111 1111 1111 65535 0001 1111 1111 1111 1110 0000 65535*32 L Xh Xl 0001 1111 1100 0000 0000 0000 and #1FC000 0011 1010 0010 0000 addr in page 1 0111 1010 001 0000 0001 0111 1010 0010 0000 */ ; Прочитать список каталога ; [x] fat32 ;!TEST LOADDIR: ;!TODO optimize CALL LOAD_SAVE_DIR_PREPARE .next: PUSH AF EX AF,AF' JR NZ,.read_dir ; root dir or not ; root 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,DIRPAGE.size LD (CORE_BUFFERS.FM_BUF.FS_REC.F_SIZE),HL ; .read_dir: LD HL,DIRPAGE.buffer ; куда LD DE,DIRPAGE.size ; сколько XOR A ; дескриптор CALL READ ; чтение из файла EX AF,AF' LD (SAVEDIR.DIRSIZE),DE ; число прочит. байтов POP AF OUT (SLOT3),A EX AF,AF' 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: 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 ; Прочитать список каталога ; Вход: ; (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L), (CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_H) ; [ ] ID записи, который должен попасть в КЭШ 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 PUSH AF ; LD A,(CORE_BUFFERS.FS_Buffer.DRIVE) LD (CORE_BUFFERS.FM_BUF.DRIVE),A ;;;;;;;; ;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) ; XOR A LD D,#40 LD E,A LD HL,(CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L) EXX LD D,A LD E,A LD HL,(CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_H) OR H OR L EXX OR H OR L ;;;;;;;; PUSH AF CALL NZ,.CalcDirSize ; LD (CORE_BUFFERS.FM_BUF.FS_REC.F_SIZE),DE EXX LD (CORE_BUFFERS.FM_BUF.FS_REC.F_SIZE + 2),DE POP AF EX AF,AF' POP AF RET ; .CalcDirSize: ; calc dir size in clusters LD DE,0 ;LD HL,(CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L) ;EXX ; LD HL,(CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_H) .loop: ; ; ;EXX 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 ;RL C EXX ; RRCA JR NC,.loop1 ; .loop2: ; SLA E RL D EXX RL E RL D ;RL C EXX ; SRL B RR C JR NC,.loop2 ; <-- DE*BC*A = DE':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 чтоб получить номер блока 3025 #0BD1 номер записи #017A20 смещение на запись в файле директории #017A20 & #1FC000 = #014000 смещение на нужный блок по #4000 байтов #017A20 & #3FFF = #3A20 Адрес нужной позиции в кэш (#017A20 & #1FC000)<<2 = #50000 двигаем байт 2 и 3 чтоб получить номер блока 1011 1101 0001 0001 1101 0001 0000 1110 1000 1000 0000 0111 0100 0100 0000 0011 1010 0010 A E 00000001 11010001 + 10000000 11101000 01000000 01110100 00100000 00111010 0010 0000 0011 1010 E A 0011 1010 0010 0000 0001 0111 1010 0010 0000 0000 0011 1010 0010 0000 0001 0100 0000 0000 0000 XOR A PUSH IX POP DE RR D ; RR E RRA RR E RRA RR E RRA */ ;----------------------------------------------------------------------; ; [ ] 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,(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,CORE_BUFFERS.HANDBUF LD BC,CORE_BUFFERS.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 .SAVEDIR: EXX PUSH DE EXX ; [ ] big dir передавать откуда и сколько байтов изменилось в кэш, чтоб не писать на диск лишнего CALL SAVEDIR POP DE RET ;----------------------------------------------------------------------; ; Сбросить кеш каталога на диск. ; вход: iy=структура дескриптора ; [ ] big dir получать откуда и сколько байтов изменилось в кэш, чтоб не писать на диск лишнего 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 ; [ ] доделать передачу ID записи директории и загрузки по ней нужного куска в кэш ;!TODO FAT procedures ;----------------------------------------------------------------------; ; Вход: ; HL - ID записи, который должен попасть в КЭШ ; Выход: A - Страница, которая была в SLOT3 до вызова ; ZF' - RootDir LOAD_SAVE_DIR_PREPARE: ; [ ] Вход: HL - ID записи, который должен попасть в КЭШ ; [ ] Выход: HLIX - смещение в файле каталога на нужный блок по #4000 байтов ; 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 H,A ;LD L,A ;LD IX,0 LD B,A ; от начала файла CALL MOVE_FP SET_PAGE_X DIRPAGE AND A PUSH AF ; LD A,(CORE_BUFFERS.FS_Buffer.DRIVE) LD (CORE_BUFFERS.FM_BUF.DRIVE),A ;;;;;;;; XOR A LD D,#40 LD E,A LD HL,(CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L) EXX LD D,A LD E,A LD HL,(CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_H) OR H OR L EXX OR H OR L ;;;;;;;; PUSH AF CALL NZ,.CalcDirSize ; LD (CORE_BUFFERS.FM_BUF.FS_REC.F_SIZE),DE EXX LD (CORE_BUFFERS.FM_BUF.FS_REC.F_SIZE + 2),DE POP AF EX AF,AF' POP AF RET ; .CalcDirSize: ; calc dir size in clusters LD DE,0 ;LD HL,(CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_L) ;EXX ; LD HL,(CORE_BUFFERS.FM_BUF.FS_REC.FIRST_CLUSTER_H) .loop: ; ; ;EXX 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 ;RL C EXX ; RRCA JR NC,.loop1 ; .loop2: ; SLA E RL D EXX RL E RL D ;RL C EXX ; SRL B RR C JR NC,.loop2 ; <-- DE*BC*A = DE':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 чтоб получить номер блока */ ;----------------------------------------------------------------------;