;ÚÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¿ ;³ FORMAT - Disk Format Utility for Sprinter ³ ;³ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ³ ;³ by Sayman 2021 ³ ;ÀÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÙ DEVICE ZXSPECTRUM128 Start_addr = 0x8100 INCLUDE "include/estex_h.asm" INCLUDE "include/head_short.inc" INCLUDE "include/macro.s" INCLUDE "build.inc" LoaderStart: JP main ;=================================================== INCLUDE "console.asm" INCLUDE "printf.asm" INCLUDE "muldiv.asm" ;=================================================== ;[]=========================================================================[] ;[] Converting latin symbols a...z to upper registry [] ;[] IN: A - symbol for convert [] ;[] OUT: A - converted symbol [] ;[]=========================================================================[] CapsLetter: CP "a" ;<"a" JR C,.not_lat CP "z"+1 ;>"z" JR NC,.not_lat AND %11011111 ;set D5 for upper registry RET .not_lat: AND A SCF RET ;=================================================== main: DI PUSH IX LD A,(ix-3) SYS ESTEX_fclose CALL Check_Vmode ;check text mode and (if not) set it CALL GetXY LD DE,about_Msg.ptr CALL cPrint POP HL CALL ParseCL CALL confirmation LD DE,Process_Msg.ptr CALL cPrint CALL prepare JR NC,.ok_drive ; LD A,"\a" ; bell SYS ESTEX_pchar LD DE,ProcessErr_Msg.ptr CALL cPrint LD B,#0D ;.UNKNOWN_FORMAT JP quit0 ; .ok_drive: CALL calc_bpb CALL gen_serial LD BC,0x0105 ;read 1 sector LD HL,0 LD IX,0 LD A,(FMTDISK) LD DE,buff RST 0x18 ;get start sector via read (drv) LD D,IXH ;this function return next sector LD E,IXL LD A,D OR E JR NZ,.next0 DEC HL .next0: DEC DE ;and correct it (-1) ;!FIXIT çñ ¯à®¨á室¨â? ­¥â £ à ­â¨¨, çâ® ¤®á ¡ã¤¥â ¢ë¤ ¢ âì á«¥¤ãî騩 ᥪâ®à ¢ á«¥¤ãîé¨å ¢¥àá¨ïå LD (BPB.hide_sectors+2),HL LD (BPB.hide_sectors),DE LD HL,buff PUSH HL LD DE,buff+1 LD BC,512 XOR A LD (HL),A LDIR SYS ESTEX_getver PUSH DE LD A,D LD DE,BPB.OEM+4 CALL ConvNumTxt8 POP DE LD A,E LD DE,BPB.OEM+6 CALL ConvNumTxt8 ;write boot sector, init first FAT sector, write it ;clear buff (zeroed), write other FAT sectors ;repeat for FAT copy ;write zeroed ROOT directory LD IX,0 LD HL,0 ;boot sector LD A,(FMTDISK) LD BC,0x0106 ;save boot sector LD DE,BPB RST 0x18 CALL init_fat LD IX,(BPB.reserved_secs) LD HL,0 PUSH IX PUSH HL CALL wr_fat0 ;write first sector of FAT CALL clear_buff POP HL POP IX INC IX ;next FAT sector CALL wr_fat1 ;write other FAT sectors CALL init_fat LD IX,(BPB.reserved_secs) ;low bits LD DE,(BPB.fat_sectors) ADD IX,DE LD HL,0 PUSH HL PUSH IX CALL wr_fat0 CALL clear_buff POP IX POP HL PUSH HL PUSH IX INC IX CALL wr_fat1 POP IX POP HL LD DE,(BPB.fat_sectors) ADD IX,DE LD A,(BPB.root_handles) LD B,A CALL wr_fat1.loop0 LD DE,ProcessOK_Msg.ptr CALL cPrint CALL showInfo ; CALL Return_Vmode ; XOR A LD B,0 JP quit0 wr_fat0: LD A,(FMTDISK) LD BC,0x0106 ;save FAT sector LD DE,buff RST 0x18 ;next sector not returned!!! RET wr_fat1: LD A,(BPB.fat_sectors) LD B,A DEC B ;-first FAT sector .loop0: PUSH BC PUSH HL PUSH IX LD BC,0x0106 LD A,(FMTDISK) LD DE,buff RST 0x18 POP IX POP HL POP BC INC IX ;next sector (low) DJNZ .loop0 RET init_fat: LD HL,buff LD (HL),0xf8 ;init FAT INC HL LD (HL),0xff ;first 2 reserved clusters INC HL LD (HL),0xff INC HL LD A,(fat12_flg) OR A RET NZ LD (HL),0xff ;0xfff8, 0xffff for FAT16 RET clear_buff: LD HL,buff LD DE,buff+1 LD BC,512 XOR A LD (HL),A LDIR RET showInfo: LD HL,(sectors+2) LD DE,(sectors) PUSH HL PUSH DE LD (DskInfo_Msg.sectors),DE LD (DskInfo_Msg.sectors+2),HL LD A,(BPB.cluster_size) RRA LD B,0 LD C,A JR NC,.next0 LD BC,512 LD A,"B" LD (DskInfo_Msg.u_sym),A .next0: LD (DskInfo_Msg.u_size),BC POP DE POP HL LD C,E ;/256 LD E,D LD D,L LD H,0 LD B,H SRL D ;/8 RR E SRL D RR E SRL D RR E LD (DskInfo_Msg.mb),DE LD HL,(BPB.serial_id) LD DE,(BPB.serial_id+2) LD (DskInfo_Msg.serial),DE LD (DskInfo_Msg.serial+2),HL LD A,(fat12_flg) OR A JR Z,.next1 LD A,"2" LD (DskInfo_Msg.FS+20),A .next1: LD DE,DskInfo_Msg.ptr CALL cPrint ;bugfix with last printed line with colors ;scrolling in console set color column... CALL GetXY ;get YX in DE LD HL,0x0150 LD B,D LD C,E CALL winClearScr RET ;=================================================== ;need to get the size of the disk in sectors and check for FAT12 limitation prepare: LD A,(FMTDISK) ; CP 2 JR NC,.begin ; PUSH AF SYS ESTEX_diskinfo JP C,Usage POP AF ; .begin: LD BC,0x0008 ;B = subcommand, C = IOCTL func. LD DE,0x55aa ;IOCTL requires Magic num RST 0x18 ;HLDE = disk size in sectors ; LD (cfg),A EX AF,AF AND #F0 LD (BPB.drv_code),A ; EX AF,AF ; LD A,H ; OR L CALL testDskSize ; CF = 0, ­®à¬ «ì­®¥ § ¢¥à襭¨¥ ; CF = 1, ®è¨¡ª  ; EXX LD (BPB.sec_per_trk),BC LD (BPB.heads),DE EXX RET ;calculate boot sector (BPB) parameters calc_bpb: LD DE,(BPB.root_handles) LD B,5 .loop0: RL D RL E DJNZ .loop0 ;root_size (256) * 32 (element size) LD HL,0 CALL div512 ;root_size/512 (sector size) LD (rootSectors),DE ;root size in sectors LD HL,(sectors) LD DE,(sectors+2) LD BC,(BPB.reserved_secs) SBC HL,BC EX DE,HL LD BC,0 SBC HL,BC LD BC,(clusters) PUSH HL PUSH DE CALL div32 ;(sectors-reserved_sectors) / max_clusters AND A ;clear flags LD BC,0x0780 ;max 64 sectors for cluster LD A,E .loop1: RLC C ;128 sectors (64kb) not supported CP C JR C,.next_calc0 DJNZ .loop1 .next_calc0: LD A,C LD (BPB.cluster_size),A ;cluster size in sectors POP DE POP HL LD B,0 CALL div32 PUSH DE LD DE,(BPB.reserved_secs) ADD HL,DE ;+reserverd sectors LD (BPB.reserved_secs),HL POP DE LD A,(fat12_flg) OR A JR Z,.calc_fat16 LD H,D LD L,E ADD HL,HL ADD HL,DE ;*3 SRL H RR L ;/2 EX DE,HL LD HL,0 JR .next_calc1 .calc_fat16: LD HL,0 RL E RL D RL L RL H .next_calc1: CALL div512 LD A,B OR C JR Z,.next_calc2 INC DE .next_calc2: LD (BPB.fat_sectors),DE EX DE,HL ADD HL,HL LD B,H LD C,L EX DE,HL LD HL,(sectors) LD DE,(sectors+2) SBC HL,BC EX DE,HL LD BC,0 SBC HL,BC EX DE,HL LD BC,(BPB.reserved_secs) SBC HL,BC EX DE,HL LD BC,0 SBC HL,BC EX DE,HL LD BC,(rootSectors) SBC HL,BC LD BC,0 EX DE,HL SBC HL,BC LD A,(BPB.cluster_size) LD B,0 LD C,A CALL div32 LD (DskInfo_Msg.units),DE LD DE,(BPB.reserved_secs) ADD HL,DE LD (BPB.reserved_secs),HL RET testDskSize: ;EX AF,AF LD A,H OR L LD (sectors),DE LD (sectors+2),HL ;save temporary sectors JR NZ,.bigdsk ; PUSH HL .tstsmall: LD BC,0xf800+1 ;else, check for fat16 <32M LD H,D ;save in DE small sectors LD L,E SBC HL,BC POP HL JR NC,.bigdsk ;>32M (set Flag) LD BC,0x7800+1 ;else check for limit for fat12 EX DE,HL ;15M LD (BPB.small_sectors),HL SBC HL,BC RET NC ;>15M XOR A INC A LD (fat12_flg),A LD A,'2' LD (BPB.fat_id+4),A LD BC,0x0fef LD (clusters),BC RET ; .bigdsk: ;EX AF,AF ;LD (BigDskFlg),A LD (BPB.big_sectors),DE LD (BPB.big_sectors+2),HL ; check max size for fat16 #3FFD00 sectors (512b) 4ÿ193ÿ152 + 512 + 1+16? ; PC - 7F600000 The FAT file system is limited to 65,525 clusters /* ;!FIXIT ¯¥à¥áç¨â âì Name Bytes Sectors DATA 2ÿ147ÿ123ÿ200 max 4 193 600 FATx2 262 144 512 ROOT DIR 512..2ÿ097ÿ152 1..4096 RESERVED min 512 min 1 ; The FAT file system is limited to 65,525 clusters - 0x3FFD40 sectors FAT TABLES SIZE: 131ÿ072 x 2 = 262 144 = #200 ROOT DIR SIZE: 8 192 #10 RESERVED SECTORS SIZE: 5 x 512 = 2 560 5 */ LD BC,#FD00 + 1 EX DE,HL SBC HL,BC EX DE,HL LD BC,#003F SBC HL,BC CCF RET ; ‚ë室­ë¥ §­ ç¥­¨ï: ; D - ¤¥­ì ; E - ¬¥áïæ ; IX - £®¤ ; H - ç á ; L - ¬¨­ãâë ; B - ᥪ㭤ë ; C - ¤¥­ì ­¥¤¥«¨ gen_serial: ld c,#21 ;!HARDCODE Dss.SysTime rst #10 ;!HARDCODE ToDSS ; ex de,hl add ix,de ld (BPB.serial_id + 2),ix ; ld a,d ld d,b xor c .loop: rra djnz .loop ; ld e,h ld h,l ld l,e ; ld e,a add hl,de ; ld e,l ; ld l,h ; ld h,e ld (BPB.serial_id),hl ret ; gen_serial: CALL Randomize ; CALL GetRnd ; LD (BPB.serial_id),A ;first 8bit (2 bits sec. 6 bits min.) ; LD L,A ; CALL GetRnd ; LD H,A ; PUSH HL ; .year: LD L,0 ; LD A,R ; RRA ; XOR L ; LD (BPB.serial_id+1),A ; CALL Rand16 ; POP BC ; ADD HL,BC ; LD (BPB.serial_id+2),HL ; RET ; ; from PQ-DOS formatter ; Randomize: SYS ESTEX_systime_get ; LD A,B ;seconds ; LD (rand1),A ; LD A,L ;minutes ; LD (rand2),A ; LD A,IXL ; LD (gen_serial.year+1),A ; LD A,R ; RRA ; LD (rand3),A ; CALL GetRnd ; LD L,A ; CALL GetRnd ; LD H,A ; LD (seed),HL ; RET ; GetRnd: LD A,(rand1) ; LD D,A ; LD A,(rand2) ; LD (rand1),A ; ADD A,D ; LD D,A ; LD A,(rand3) ; LD (rand2),A ; ADD A,D ; RRCA ; LD (rand3),A ; RET ; Rand16: LD DE,(seed) ;Seed is usually 0 ; LD A,D ; LD H,E ; LD L,253 ; OR A ; SBC HL,DE ; SBC A,0 ; SBC HL,DE ; LD D,0 ; SBC A,D ; LD E,A ; SBC HL,DE ; JR NC,Rand ; INC HL ; Rand: LD (Rand16+1),HL ; RET ; ; ParseCL: LD A,(HL) ;cmd line size OR A ;0 = no params JP Z,Usage ;goto help message INC HL INC HL ;first param LD A,(HL) LD C,A INC HL LD A,(HL) CP ':' ;must be dsk: (like C:) JP NZ,Usage ;if not, goto help message LD A,C CALL CapsLetter JP C,Usage ;drive letter is not a letter LD (warn_Msg.dsk),A ;store it in messages LD (Process_Msg.dsk),A ;* LD (ProcessErr_Msg.dsk),A ;* SUB 'A' ; .set_A: LD (FMTDISK),A .loop_x: INC HL LD A,(HL) OR A RET Z CP space JR NZ,.loop_x .loop1: CP "/" JR Z,.next0 CP "-" JR Z,.next0 JP Usage .next0: INC HL LD A,(HL) CP "?" JP Z,Usage POP HL JP Usage confirmation: CALL GetXY LD DE,warn_Msg.ptr CALL cPrint EI HALT SYS ESTEX_waitkey DI RES 5,A CP "Y" LD B,0 ;.NO_ERROR JP NZ,quit0 ;exit to DOS CALL PrintLF RET PrintLF: PrintChar cr PrintChar lf RET ;--------------- ;from FN ;Convert 8bit num to text ;IN: ; A - 8 bit num ; DE - buffer ;--------------- ConvNumTxt8: PUSH IX PUSH BC LD IX,ConvertFlg RES 7,(IX+#00) LD C,100 CALL ConNumb8 LD C,10 CALL ConNumb8 ADD A,"0" LD (DE),A INC DE POP BC POP IX RET ConNumb8: LD B,#2F INC B SUB C JR NC,$-2 ADD A,C EX AF,AF' LD A,B CP #30 JR Z,$+6 SET 7,(IX+#00) BIT 7,(IX+#00) JR Z,$+4 LD (DE),A INC DE EX AF,AF' RET ConvertFlg: DB #0 ;------------------------------------------------------------------------------- badClustErr: PrintChars badClust_Msg ;LD B,-2 LD B,#0D ; .UNKNOWN_FORMAT JR quit0 Usage: LD DE,usage_Msg.ptr CALL cPrint ; PrintChars usage_Msg LD B,0 quit0: PUSH BC CALL Return_Vmode POP BC SYS ESTEX_exit JP $ ;=================================================== FMTDISK: DB 0 ;formatting disk BigDskFlg: DB 0 ;big disk (>32Mb) flag cfg: DB 0 rootSectors: DW 0 sectors: DS 4 ;tmp value of sectors on the disk clusters: DW 0xffef fat_sectors: DW 0 system_sectors: DW 0 fat12_flg: DB 0 serial: DW 0,0 ;Volume Serial Number ; rand1: DB 0 ; rand2: DB 0 ; rand3: DB 0 ; seed: DB 0 ALIGN 256 BPB: .JMP: DB 0xeb,0xfe,0x00 ; § é¨â  ®â ¡ ª« ­¨§¬  (§ £à㧪  á í⮣® ¤¨áª  ­  PC ¯à¨¢¥¤¥â ª § ¢¨á ­¨î. JMP $) .OEM: DB "DSS . " .sector_size: DW 512 ;+11 ; sector size in bytes .cluster_size: DB 0 ;+13 ; cluster size in sectors .reserved_secs: DW 5 ;+14 ; reserved sector .fat_ncopy: DB 2 ;+16 ; # copy`s of FAT .root_handles: DW 256 ;+17 ; root size (records on root) .small_sectors: DW 0 ;+19 ; # of sectors (<32Mb) .media_id: DB 0xf8 ;+21 ; Media ID .fat_sectors: DW 0 ;+22 ; # sectors for one copy of FAT .sec_per_trk: DW 0 ;+24 ; sectors per track .heads: DW 0 ;+26 ; # of heads ; extended boot-record .hide_sectors: DWORD 0 ;+28 ; # of hidden sectors .big_sectors: DWORD 0 ;+32 ; # of sectors (>32Mb) .drv_code: DW 0x80 ;+36 ; drive code (0x80 for HDD) .eboot_sig: DB 0x29 ;+38 ; extended boot signature (?) .serial_id: DS 4 ;+39 ; Volume serial .vol_name: DB "NO NAME " ;+43 ; Volume label .fat_id: DB "FAT16 " ;+54 ; FAT id (FAT12 or FAT16) BPBsize = $-BPB INCBIN "x86_boot.bin" ; !FIXIT ã¡à âì /* about_Msg: db cr,lf,"Format utility version 0.3.",BUILD_COUNT_T," (",BUILD_DAY_T,".",BUILD_MONTH_T,".",BUILD_YEAR_T,")" db cr,lf,"by Miroshnichenko Alexander aka Sayman@SprinterTeam",cr,lf,0 .ptr: dw about_Msg */ ;=================================================== about_Msg: DB cr,lf,"Format utility version 0.3.",BUILD_COUNT_T," (",BUILD_DAY_T,".",BUILD_MONTH_T,".",BUILD_YEAR_T,")" DB cr,lf,"by Miroshnichenko Alexander aka Sayman, (c) 2021.\r\nBug fixes by Anatoliy Belyanskiy, Sprinter Team, 2026.",cr,lf,0 .ptr: DW about_Msg usage_Msg: DB cr,lf,"This utility performs logical formatting and initializes the file system on the disks." DB cr,lf,col_cmd,col_red,"WARNING!!!",col_cmd,col_white," This version is limited for ",col_cmd,col_green,"2Gb",col_cmd,col_white," for FAT16 FS!" DB cr,lf,cr,"usage:" DB cr,lf,"FORMAT volume [key1] [key2] [keyN]" DB cr,lf," keys are:" DB cr,lf,tab,"in this version supported only /? key for help." DB cr,lf,cr,lf,0 .ptr: DW usage_Msg warn_Msg: DB cr,lf,cr,lf,col_cmd,col_red,"WARNING: ALL DATA ON YOR HARD DISK DRIVE ",col_cmd,col_violet,"%c:",col_cmd,col_red," WILL BE LOST!",col_cmd,col_white,cr,lf DB cr,lf,"Proceed with Format [Y/N]?",0 .ptr: DW warn_Msg .dsk: DB 0 Process_Msg: DB cr,lf DB cr,lf,"Quick formatting disk %c:...",0 .ptr: DW Process_Msg .dsk: DB 0 ProcessErr_Msg: DB cr,lf,cr,lf,col_cmd,col_red,"ABORTED: CAN'T FORMAT DRIVE ",col_cmd,col_violet,"%c:",cr,lf,col_cmd,col_yellow,"FAT16 does not support drives larger than 2GB.",cr,lf,cr,lf,0 .ptr: DW ProcessErr_Msg .dsk: DB 0 ProcessOK_Msg: DB "Done.",cr,lf,cr,lf,0 .ptr: DW ProcessOK_Msg DskInfo_Msg: DB "Formatted disk parameters:",cr,lf DB "Total sectors: ",tab,col_cmd,col_magenta,"%lu",col_cmd,col_white,cr,lf DB "Total size: ",tab,col_cmd,col_magenta,"%uMb",col_cmd,col_white,cr,lf DB "Units: ",tab,tab,col_cmd,col_magenta,"%u",col_cmd,col_white,cr,lf DB "Unit size: ",tab,col_cmd,col_magenta,"%u%c",col_cmd,col_white,cr,lf .FS: DB "File system: ",tab,col_cmd,col_magenta,"FAT16",col_cmd,col_white,cr,lf DB "Serial: ",tab,col_cmd,col_magenta,"%02x-%02x",col_cmd,col_white,cr,lf DB "Label: ",tab,tab,col_cmd,col_magenta,"NO LABEL",col_cmd,col_white,cr,lf,cr,lf,0 .ptr: DW DskInfo_Msg .sectors: DS 4 .mb: DW 0 .units: DW 0 .u_size: DW 0 .u_sym: DB "K",0 .serial: DS 4 badClust_Msg: DB cr,lf,"Bad cluster size.",cr,lf,cr,lf,0 ;WARNING: ALL DATA ON YOR HARD DISK DRIVE Z: WILL BE LOST! buff EQU ( high $ + ((low $)