/* FAT16 ファイルシステム fopen(file_n) ファイルを開く read() 開いているファイルのデータをシーケンシャルに取得 セクタサイズ512バイト、クラスタサイズ1(32MB)〜64(2GB) Rev.2 FATの終了にfinishを追加 Rev.3 Linuxでフォーマットしたものへの対応 */ circuit FAT16 { // デバイスとの接続 instrout sread(sadrs); output sadrs<32>; 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>; reg_ws reset; reg_wr sector_FAT<16>, sector_RDE<16>, sector_DAT<16>; reg_wr cluster_n<7>; // クラスタあたりセクタ数 reg_wr DIR_FstClusLO_H<8>, DIR_FstClusLO_L<8>; reg_wr first_cluster; reg_wr cadrs<23>, 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++; } // FAT16の初期化 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_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){ // MBRから第一パーティションセクタを取得 // ddコマンドでは見えない。本来は4バイト。 sread(0x000001C6); // 1/4 goto st1_2; } state st1_2 if(sack){ sector_BPB_L := sdata; sread(0x000001C7); // 2/4 goto st2; } state st2 if(sack){ sector_BPB_H := sdata; // BPBからクラスタあたりセクタ数を取得 sread(0x0||0b000|| sdata || sector_BPB_L || 0b0 || 0x0D); goto st3_1; } state st3_1 if(sack){ cluster_n := sdata<6:0>; // 0x01(32MB)〜0x40(2GB) // BPBから隠しセクタ数(開始セクタ)を取得。本来は4バイト。 sread(0x0||0b000|| sector_BPB || 0b0 || 0x1C); // 1/4 goto st3_2; } state st3_2 if(sack){ sec_hidden_L := sdata; sread(0x0||0b000|| sector_BPB || 0b0 || 0x1D); // 2/4 goto st4; } state st4 if(sack){ sec_hidden_H := sdata; // BPBから予約セクタ数を取得。本来は2バイト。 sread(0x0||0b000|| sector_BPB || 0b0 || 0x0E); goto st5_1; } state st5_1 if(sack){ sector_FAT := sec_hidden + (0x00||sdata); // オーバーしないように // BPBからFAT当りのセクタ数を取得。1/2バイト。 sread(0x0||0b000|| sector_BPB || 0b0 || 0x16); goto st5_2; } state st5_2 if(sack){ // 2017/09/09追加 sec_perfat_L := sdata; // BPBからFAT当りのセクタ数を取得。2/2バイト。 sread(0x0||0b000|| sector_BPB || 0b0 || 0x17); goto st7; } state st7 if(sack){ sector_RDE := sector_FAT + (sdata<6:0> || sec_perfat_L || 0b0); // BPBからルートディレクトリエントリ数を取得 2017/09/09追加 sread(0x0||0b000|| sector_BPB || 0b0 || 0x12); goto st8; } state st8 if(sack){ sector_DAT := sector_RDE + (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(0x0||0b000|| sector_RDE<15: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(0x0||0b000|| sector_RDE<15: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(0x0||0b000|| sector_RDE<15:5> || rde_adrs || 0b11010); } state st5 if(sack){ DIR_FstClusLO_L := sdata; sread(0x0||0b000|| sector_RDE<15:5> || rde_adrs || 0b11011); goto st6; } state st6 if(sack){ DIR_FstClusLO_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<16>, fat_id<24>; first_state st_rdy; par{ fat_n = DIR_FstClusLO_H || DIR_FstClusLO_L; fat_id = (sector_FAT || 0x00) + (0x00 || fat_n); } // クラスタ途中でも次のファイルを開けるように必ずst_rdyに戻ること state st_rdy if(sack) alt{ first_cluster : par{ sel cluster<16>; cluster = fat_n - 0x0002; sel cluster_shift<23>; // cluster_n クラスタあたりセクタ数 sel cluster_nn<3>; any(i=0;i<7;i++){ cluster_n : cluster_nn = i; } cluster_shift = (0b0000000 || cluster) << cluster_nn; cadrs := (0b0000000||sector_DAT) + cluster_shift; sec_idx := 0; first_cluster := 0b0; goto st_read; } // 1(32M)〜64(2G)セクタ読み終わったら // 次のクラスタ位置をFATから取得 sec_idx==cluster_n : par{ // sec_idx := 0; first_clusterによってクリアされる sread(0x0||0b000 || fat_id || 0b0); 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){ DIR_FstClusLO_L := sdata; sread(0x0||0b000 || fat_id || 0b1); goto st_fat_2; } state st_fat_2 if(sack){ DIR_FstClusLO_H := sdata; goto st_fatcheck; } state st_fatcheck par{ any{ (fat_n<15:3>==(0xFFF8)<15:3>) : par{ // 0xFFF8-F eof_reg := 0b1; finish; } (fat_n==0x0000) | // 未使用クラスタ (fat_n==0x0001) | // 予約クラスタ (fat_n==0xFFF7) : // 不良クラスタ par{ eof_reg := 0b1; err_reg := 0b1; finish; } } goto st_rdy; } } }