flat assembler
Message board for the users of flat assembler.

Index > OS Construction > [CONTRIB] hand rolled FAT12 image [WIP]

Author
Thread Post new topic Reply to topic
bitshifter



Joined: 04 Dec 2007
Posts: 796
Location: Massachusetts, USA
bitshifter 10 Dec 2020, 20:34
i have spent lots of time in hex editor with FAT12/16 images
here is the result of my hard work, FAT16 coming soon
this builds standard 1.44MB FAT12 image with folders and files
try it out, leave a reply
Code:
;fasm
;i286
use16
org 0

;FAT12 32mb (256mb for 64kb clusters)
;FAT16 2gb (4gb for 64kb clusters)

;media:         3.5" floppy diskette
;capacity:      1.44mb (hory shet!)
;format         FAT12

;fact: 2880*512=1474560
;fact: 1024*1000*1.44=1474560

;reserved sectors start here:

;sector0
db 0EBh                ;0000 jmp short ...
db 3Ch                 ;0001 ... (jmp_to - jmp_from)
;jmp_from:
db 90h                 ;0002 nop (pad for 3 byte jmp)
db 'MSWIN4.1'          ;0003 oem name
dw 512                 ;000B bytes per sector
db 1                   ;000D sectors per cluster
dw 1                   ;000E reserved sector count
db 2                   ;0010 FAT count
dw 224                 ;0011 root entry count
dw 2880                ;0013 total sector count
db 0F0h                ;0015 media descriptor
dw 9                   ;0016 sectors per FAT
dw 18                  ;0018 sectors per track
dw 2                   ;001A heads per cylinder
dd 0                   ;001C hidden sector count
dd 0                   ;0020 total sectors count (>64k)
db 0                   ;0024 drive number
db 0                   ;0025 reserved byte
db 29h                 ;0026 extended boot signature
dd 0                   ;0027 serial number
db 'NO NAME    '       ;002B volume label
db 'FAT12   '          ;0036 file system
;jmp_to:

;boot code goes here:

mov ax,0003h
int 10h

mov ax,0E00h + '!'
mov bx,0007h
int 10h

mov ah,00h
int 16h

int 19h
int 18h
jmp $

rb ((512-2)-($-$$))  ;pad from here up to (but not including) 01FE with 0's
db 55h                  ;01FE boot signature
db 0AAh                 ;01FF boot signature

;more reserved sectors go here:

;resv:
rb ((512*1)-($-$$))     ;pad out for reserved sectors

;;;;;;;;;;;;;;;;;;;;;;;;
;hidden sectors go here:
;;;;;;;;;;;;;;;;;;;;;;;;

hide:
rb ((512*0)-($-hide))

;FAT tables go here:

;cluster0 = media descriptor 00F0 + 0F00 = 0FF0
;cluster1 = reserved 000F + 0FF0 = 0FFF

;unused clusters should be set to zero

;FAT12
;clusters >= 0FF8 signify end of chain
;clusters == 0FF7 signify bad cluster

;FAT16
;clusters >= FFF8 signify end of chain
;clusters == FFF7 signify bad cluster

;sector1
fat1:
;
db 0F0h ;cluster 0
db 0FFh ;cluster 0,1
db 0FFh ;cluster 1
;
db 0FFh ;cluster 2
db 0FFh ;cluster 2,3
db 0FFh ;cluster 3
;
db 0FFh ;cluster 4
db 00Fh ;cluster 4,5
db 000h ;cluster 5
;
rb ((512*9)-($-fat1))

;sector10
fat2:
;
db 0F0h
db 0FFh
db 0FFh
;
db 0FFh
db 0FFh
db 0FFh
;
db 0FFh
db 00Fh
db 000h
;
rb ((512*9)-($-fat2))

;cluster 0 reserved (and .. for folder with no parent)
;cluster 1 reserved
;cluster 2 folder (and .)
;cluster 3 file 1
;cluster 4 file 2

;db 11110000     ;media descriptor     (00F0)
;db 11111111     ;reserved             (00FF)
;dx 111111111111 ;end of cluster chain (0FFF)
;dx 111111111111 ;end of cluster chain (0FFF)
;dx 111111111111 ;end of cluster chain (0FFF)

;root directory goes here:

;file attributes:
;READONLY     equ 01h
;HIDDEN       equ 02h
;SYSTEM       equ 04h
;VOLUMEID     equ 08h
;DIRECTORY    equ 10h
;ARCHIVE      equ 20h

;first byte of file name:
;0E5h = file was deleted
;0 = end of root directory

;sector19
root:
db 'FOLDER     ';file name (11 bytes)
db 10h          ;file attributes
db 0            ;reserved byte
db 0            ;creation time (1/10 seconds, range 0..199)
dw 0            ;creation time (hour/minute/seconds*2)
dw 0            ;creation date (year-1980/month/day)
dw 0            ;last accessed date
dw 0            ;high 16 bits of first cluster (FAT12/FAT16 always 0)
dw 0            ;last modification time
dw 0            ;last modification date
dw 02h          ;low 16 bits of first cluster (0 = empty file)
dd 0            ;file size (in bytes)
db 'FILE1   TXT'
db 20h
db 0
db 0
dw 0
dw 0
dw 0
dw 0
dw 0
dw 0
dw 03h
dd data2.size
rb ((32*224)-($-root))

;file data goes here:

;sector33
data0:
db '.          '
db 10h
db 0
db 0
dw 0
dw 0
dw 0
dw 0
dw 0
dw 0
dw 02h
dd 0
db '..         '
db 10h
db 0
db 0
dw 0
dw 0
dw 0
dw 0
dw 0
dw 0
dw 00h
dd 0
db 'FILE2   TXT'
db 20h
db 0
db 0
dw 0
dw 0
dw 0
dw 0
dw 0
dw 0
dw 04h
dd data3.size
rb (512-($-data0))

;sector34
data2:
db 'Hello from file 1'
db 0Dh ;CR
db 0Ah ;LF
.size = ($-data2)
rb (512-($-data2))

;sector35
data3:
db 'Hello from file 2'
db 0Dh ;CR
db 0Ah ;LF
.size = ($-data3)
rb (512-($-data3))

;sector36
times ((512*2880)-($-$$)) db 0
    

_________________
Coding a 3D game engine with fasm is like trying to eat an elephant,
you just have to keep focused and take it one 'byte' at a time.
Post 10 Dec 2020, 20:34
View user's profile Send private message Reply with quote
DimonSoft



Joined: 03 Mar 2010
Posts: 1228
Location: Belarus
DimonSoft 10 Dec 2020, 22:45
Actually, it’s possible to wrap these things into macros. For me the hardest (most dirty) piece was perhaps the one that chooses parameters for FAT16/FAT32 disks based on the tables from specification. Nothing hard logically but I wanted to have it done by preprocessor, so, after writing a few auxiliary macros, I got something along these lines:
Code:
    if_le nSectors,     8'400, 'Disk is too small for FAT16.'
    spc equ 2
    if_g  nSectors,    32'680, spc equ 4
    if_g  nSectors,   262'144, spc equ 8
    if_g  nSectors,   524'288, spc equ 16
    if_g  nSectors, 1'048'576, spc equ 32
    if_g  nSectors, 2'097'152, spc equ 64
    if_g  nSectors, 4'194'304, 'Disk is too large for FAT16.'    
where if_g and if_le are:
Code:
  macro if_le x*, c*, action&
  \{
    rept (((x) - (c) - 1) and (1 shl 63)) shr 63 \\{ action \\}
  \}

  macro if_g x*, c*, action&
  \{
    rept (((c) - (x)) and (1 shl 63)) shr 63 \\{ action \\}
  \}    
It could easily be done at assembler stage but I wanted to do this stuff later:
Code:
      unpack VolumeID \# @Params, tpl,\
                                  BPB_SecPerClus = spc,\
                                  BPB_TotSec32   = nSectors,\
                                  BPB_FATSz32    = (((nSectors) - 32) + (128 * spc)) / (128 * spc + 1),\
                                  Params    
which is preprocessor-based (unpack is an automaton-based macro to parse key-value stuff supporting nested values like <<42, 'a', 0>, x, <Hello!>>), so doing “table lookup” at preprocessor stage was my only option.
Post 10 Dec 2020, 22:45
View user's profile Send private message Visit poster's website Reply with quote
bitshifter



Joined: 04 Dec 2007
Posts: 796
Location: Massachusetts, USA
bitshifter 13 Dec 2020, 07:12
ok cool, thanks for the ideas
right now im playing with some constants and debugging them
i adapted the 'display' example from fasm manual to help debug
Code:
macro trace trace_param* {
        display `trace_param # ': '
        trace_bits = 32
        repeat (trace_bits / 4)
                nibble_offset = % * 4 ;counts by 4, from 4 to N (4,8,12,16,20,24,28,32)
                nibble_value = '0' + ((trace_param shr (trace_bits - nibble_offset)) and 0Fh)
                if nibble_value > '9'
                        nibble_value = nibble_value + 'A' - '9' - 1
                end if
                display nibble_value
        end repeat
        display 13,10
}

MEDIA_CYLINDERS_PER_DISK equ 1
trace MEDIA_CYLINDERS_PER_DISK

MEDIA_HEADS_PER_CYLINDER equ 2
MEDIA_HEADS_PER_DISK equ (MEDIA_HEADS_PER_CYLINDER * MEDIA_CYLINDERS_PER_DISK)
trace MEDIA_HEADS_PER_DISK

MEDIA_TRACKS_PER_HEAD equ 80
MEDIA_TRACKS_PER_DISK equ (MEDIA_TRACKS_PER_HEAD * MEDIA_HEADS_PER_DISK)
trace MEDIA_TRACKS_PER_DISK

MEDIA_SECTORS_PER_TRACK equ 18
MEDIA_SECTORS_PER_DISK equ (MEDIA_SECTORS_PER_TRACK * MEDIA_TRACKS_PER_DISK)
trace MEDIA_SECTORS_PER_DISK

MEDIA_BYTES_PER_SECTOR equ 512
MEDIA_BYTES_PER_DISK equ (MEDIA_BYTES_PER_SECTOR * MEDIA_SECTORS_PER_DISK)
trace MEDIA_BYTES_PER_DISK    


output:
Code:
flat assembler  version 1.73.09  (16384 kilobytes memory)
MEDIA_CYLINDERS_PER_DISK: 00000001
MEDIA_HEADS_PER_DISK: 00000002
MEDIA_TRACKS_PER_DISK: 000000A0
MEDIA_SECTORS_PER_DISK: 00000B40
MEDIA_BYTES_PER_DISK: 00168000
2 passes, 0.3 seconds, 1474560 bytes.    
Post 13 Dec 2020, 07:12
View user's profile Send private message Reply with quote
bitshifter



Joined: 04 Dec 2007
Posts: 796
Location: Massachusetts, USA
bitshifter 13 Dec 2020, 07:31
@DimonSoft
I think you can simplify your macro's by using N shr 63 and 1
No need to mask before the shift, just do it later, saves one shift
I would keep the mask for when 128bit comes along and breaks it
Post 13 Dec 2020, 07:31
View user's profile Send private message Reply with quote
DimonSoft



Joined: 03 Mar 2010
Posts: 1228
Location: Belarus
DimonSoft 13 Dec 2020, 12:38
bitshifter wrote:
@DimonSoft
I think you can simplify your macro's by using N shr 63 and 1
No need to mask before the shift, just do it later, saves one shift
I would keep the mask for when 128bit comes along and breaks it

As far as I know, FASM internally has 65 bits whatever that means. There probably was another reason but I can’t remember it right now. Got your point, thanks, I’ll think about it.
Post 13 Dec 2020, 12:38
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.