/* FAT32 ファイルシステム fopen(file_n) ファイルを開く read() 開いているファイルのデータをシーケンシャルに取得 セクタサイズ512バイト、クラスタサイズ128(64kB)(4GB)〜1024(512kB)(32GB) Rev.2 FATの終了にfinishを追加 Rev.3 Linuxでフォーマットしたものへの対応 */ circuit FAT32 { // デバイスとの接続 instrout sread(sadrs); output sadrs<41>; input sack, sdata<8>; // ファイル操作 instrin fopen(target_file); input target_file<8>; reg_wr file_n<8>; instrin read; output fdata<8>, eof; reg_wr eof_reg, err_reg; output ack, err; output dbg<8>; reg_wr dbg_reg<8>; output dbg32<32>; reg_wr dbg32_reg<32>; reg_ws reset; reg_wr sector_FAT<32>, sector_RDE<32>, sector_DAT<32>; reg_wr cluster_n<7>; // クラスタあたりセクタ数 reg_wr DIR_FstClusHI_H<8>, DIR_FstClusHI_L<8>; reg_wr DIR_FstClusLO_H<8>, DIR_FstClusLO_L<8>; reg_wr first_cluster; reg_wr cadrs<32>, dadrs<9>; stage_name init { task do(); } stage_name open { task do(file_n); } stage_name sector_read { task do(); } if(reset){ generate init.do(); reset := 0b0; } ack = sack & ^(init.do | open.do | sector_read.do); err = err_reg; fdata = sdata; eof = eof_reg; // target_file番目のファイルを開く instruct fopen par{ generate open.do(target_file); } // 開いているファイルのデータをシーケンシャルに取得 instruct read par{ if((dadrs==9#0b0) & ^eof_reg){ generate sector_read.do(); } else sread(cadrs || dadrs); dadrs++; } // FAT32の初期化 stage init { reg_wr sector_BPB_L<8>, sector_BPB_H<8>; sel sector_BPB<16>; reg_wr sec_hidden_L<8>, sec_hidden_H<8>; sel sec_hidden<16>; reg_wr sec_resv_L<8>; reg_wr sec_perfat_L<8>; first_state st1_1; par{ sector_BPB = sector_BPB_H || sector_BPB_L; sec_hidden = sec_hidden_H || sec_hidden_L; } state st1_1 if(sack){ // PT_LbaOfs 1/4 // MBRから第一パーティションセクタを取得 // ddコマンドでは見えない。本来は4バイト。 sread(0b0||0x00000001C6); goto st1_2; } state st1_2 if(sack){ // PT_LbaOfs 2/4 sector_BPB_L := sdata; sread(0b0||0x00000001C7); goto st2; } state st2 if(sack){ // BPB_SecPerClus sector_BPB_H := sdata; // BPBからクラスタあたりセクタ数を取得 // PT_LbaOfs * 512 + 13 sread(0x0000 || sdata || sector_BPB_L || 0b0 || 0x0D); goto st3_1; } state st3_1 if(sack){ // BPB_HiddSec 1/4 cluster_n := sdata<6:0>; // 0x04(4GB)〜0x20(32GB) // BPBから隠しセクタ数(開始セクタ)を取得。本来は4バイト。 sread(0x0000 || sector_BPB || 0b0 || 0x1C); goto st3_2; } state st3_2 if(sack){ // BPB_HiddSec 2/4 sec_hidden_L := sdata; sread(0x0000 || sector_BPB || 0b0 || 0x1D); goto st4_1; } state st4_1 if(sack){ // BPB_RsvdSecCnt 1/2 sec_hidden_H := sdata; // BPBから予約セクタ数を取得。 sread(0x0000 || sector_BPB || 0b0 || 0x0E); goto st4_2; } state st4_2 if(sack){ // BPB_RsvdSecCnt 2/2 sec_resv_L := sdata; sread(0x0000 || sector_BPB || 0b0 || 0x0F); goto st5_1; } state st5_1 if(sack){ // BPB_FATSz32 1/4 sector_FAT := (0x0000 || sec_hidden) + (0x0000 || sdata || sec_resv_L); // オーバーしないように // BPBからFAT当りのセクタ数を取得。 sread(0x0000 || sector_BPB || 0b0 || 0x24); goto st5_2; } state st5_2 if(sack){ // BPB_FATSz32 2/4 sec_perfat_L := sdata; // BPBからFAT当りのセクタ数を取得。 sread(0x0000 || sector_BPB || 0b0 || 0x25); goto st7; } state st7 if(sack){ // (BPB_RootEntCnt) 1/2 sector_RDE := sector_FAT + (0x0000 || sdata<6:0> || sec_perfat_L || 0b0); // BPBからルートディレクトリエントリ数を取得。FAT32では0。 sread(0x0000 || sector_BPB || 0b0 || 0x12); goto st8; } state st8 if(sack){ sector_DAT := sector_RDE + (0x0000 || 0b0000 || sdata || 0b0000); finish; } } // ファイルを開く stage open { reg_wr rde_adrs<9>; // このサイズで持てるファイル数が決まる reg_wr target_count<8>; first_state st1; state st1 par{ rde_adrs := sector_RDE<4:0> || 0b0000; target_count := 0x00; goto st2; } state st2 if(sack){ // ルートディレクトリのエントリを取得 sread(sector_RDE<31:5> || rde_adrs || 0b00000); goto st3; } state st3 if(sack){ if( (sdata==0x00) | // 未使用 (sdata==0x2E) | // . or .. (sdata==0x05) | (sdata==0xE5) ) // 削除済み { rde_adrs++; goto st2; } else goto st4; sread(sector_RDE<31:5> || rde_adrs || 0b01011); } state st4 if(sack){ alt{ sdata<1> | // 隠し属性 sdata<2> | // システム属性 sdata<3> | // ボリューム属性 sdata<4> : par{ // ディレクトリ属性 rde_adrs++; goto st2; } target_count==file_n : goto st5; else : par{ target_count++; rde_adrs++; goto st2; } } // 最初のfat_nを取得 sread(sector_RDE<31:5> || rde_adrs || 0b11010); } state st5 if(sack){ DIR_FstClusLO_L := sdata; sread(sector_RDE<31:5> || rde_adrs || 0b11011); goto st6; } state st6 if(sack){ DIR_FstClusLO_H := sdata; sread(sector_RDE<31:5> || rde_adrs || 0b10100); goto st7; } state st7 if(sack){ DIR_FstClusHI_L := sdata; sread(sector_RDE<31:5> || rde_adrs || 0b10101); goto st8; } state st8 if(sack){ DIR_FstClusHI_H := sdata; eof_reg := 0b0; err_reg := 0b0; dadrs := 0; first_cluster := 0b1; goto st1; finish; } } stage sector_read { reg_wr sec_idx<7>; sel fat_n<32>, fat_id<32>; reg_wr next_DIR_FstClusLO_L<8>, next_DIR_FstClusLO_H<8>; first_state st_rdy; par{ fat_n = DIR_FstClusHI_H || DIR_FstClusHI_L || DIR_FstClusLO_H || DIR_FstClusLO_L; fat_id = (sector_FAT<24:0> || 7#0b0) + fat_n; } // クラスタ途中でも次のファイルを開けるように必ずst_rdyに戻ること state st_rdy if(sack) alt{ first_cluster : par{ sel cluster<32>; cluster = fat_n - 0x00000002; sel cluster_shift<32>; // cluster_n クラスタあたりセクタ数 sel cluster_nn<3>; any(i=0;i<7;i++){ cluster_n : cluster_nn = i; } cluster_shift = cluster << cluster_nn; cadrs := sector_DAT + cluster_shift; sec_idx := 0; first_cluster := 0b0; goto st_read; } // 4(4GB)〜32(32GB)セクタ読み終わったら // 次のクラスタ位置をFATから取得 sec_idx==cluster_n : par{ // sec_idx := 0; first_clusterによってクリアされる sread(0b0000000 || fat_id || 0b00); first_cluster := 0b1; goto st_fat_1; } else : par{ // 次のセクタを取得 cadrs++; goto st_read; } } state st_read par{ // セクタを読み込む sread(cadrs || 9#0b0); sec_idx++; goto st_rdy; finish; } state st_fat_1 if(sack){ next_DIR_FstClusLO_L := sdata; sread(0b0000000 || fat_id || 0b01); goto st_fat_2; } state st_fat_2 if(sack){ next_DIR_FstClusLO_H := sdata; sread(0b0000000 || fat_id || 0b10); goto st_fat_3; } state st_fat_3 if(sack){ DIR_FstClusHI_L := sdata; sread(0b0000000 || fat_id || 0b11); goto st_fat_4; } state st_fat_4 if(sack){ DIR_FstClusLO_L := next_DIR_FstClusLO_L; DIR_FstClusLO_H := next_DIR_FstClusLO_H; DIR_FstClusHI_H := sdata; goto st_fatcheck; } state st_fatcheck par{ any{ (fat_n<31:3>==(0x0FFFFFF8)<31:3>) : par{ // 0x0FFFFFF8-F 最終クラスタ eof_reg := 0b1; finish; } (fat_n==0x00000000) | // 未使用クラスタ (fat_n==0x00000001) | // 予約クラスタ (fat_n==0x0FFFFFF7) : // 不良クラスタ par{ eof_reg := 0b1; err_reg := 0b1; finish; } } goto st_rdy; } } }