NES on FPGA 2024/02/18

ファイルを使え! SDカードとFATファイルシステム

 テストプログラムが数十KB程度ならシリアルポートで転送しても1秒かからないので問題にならないが、 SNESのプログラムだと数MBにもなるので転送じゃ時間がかかってしょうがない。 Altera DE1ボードにはSDカードスロットが付いていることもあり、 SDカードからSDRAMにプログラムを読み込んで実行することにしました。

 またFAT16を実装して、PCでSDカードにファイルを置いたものをそのまま読めるようにしました。

 さらにSDHCカードが容易に入手できるので、SDHCカードサポートとFAT32も実装しました。

_
▼ SDカード (SPIモード)

 DE1ボードのマスタークロックは50MHzなので、 1/2でSDカードへのアクセスクロックは25MHzとしました。 DE1の配線の都合もありSPIモードのみの動作で、とりあえずreadのみ実装。

 SDSCcard_ctrl_SPImode.sflp とSDカード情報読み取りサンプル。

%i "SDSCcard_ctrl_SPImode.h"
%i "seg7_ctrl.h"

circuit SDCARD_test
{
	input SW<10>;
	output HEX0<7>, HEX1<7>;

	output SD_CSn; // SD Card CSn
	output SD_CLK; // SD Card Clock
	output SD_CMD; // SD Card Command & Dout
	input  SD_DAT; // SD Card Data

	SDSCcard_ctrl_SPImode sdcard;
	seg7_ctrl seg70, seg71;

	stage_name sdget { task do(); }

	SD_CSn = sdcard.CSn;
	SD_CLK = sdcard.CLK;
	SD_CMD = sdcard.CMD;
	sdcard.DAT = SD_DAT;

	HEX1 = seg71.con(sdcard.rdata<7:4>).oSEG;
	HEX0 = seg70.con(sdcard.rdata<3:0>).oSEG;

	generate sdget.do();

	stage sdget {
		if(sdcard.ack){
			// CSD
		//	sdcard.read(0x000000||0b0||SW<6:0>);
			// MBR(第一パーティションエントリ)
			sdcard.read(0x000001||SW<7:0>);
			finish;
		}
	}
}

_
▼ SDカード (SDバスモード) 2016/07/09

 基本的にデータはSDカードからSDRAMへロードします。 SDカードのアクセスについては、従来はSPIモードでアクセスしており、 数十KBのデータであれば一瞬でロードできていました。 しかしSNESのデータについては4MBほどあるものもあり、 ロードに数秒かかっている状況でした。 そこで、DE2-115ボードのSDカードコネクタではデータバスが4本ともFPGAと接続されていることもあり、 SDカードのSDバスモード(4bit bus mode)を利用することによって、 ロード時間短縮できないかと思い立ち、実装したものです。

 結果としては、4MBのデータロードに7秒かかっていたものを、3秒に短縮することができました。 今回の実装ではいわゆる通常のSDカード(SDSC)のみサポートし、 SDHC、SDXCは未サポートです。 SDSCの仕様ではデフォルトスピードで12.5MB/sまでいけるようですが、 今回の実装ではシングルブロックモードのみの使用のため、 コマンドの度にビジー時間が長く1.3MB/s程度しか出ません。 マルチブロックリードを活用することでもっと速度は上げられますが、 FATファイルシステムとの兼ね合いもあり、今回はこれで我慢します。

 トップモジュール

inout  wire [3:0] SD_DAT,	//	SD Card Data
inout  wire SD_CMD,		//	SD Card Command Signal
output wire SD_CLK,		//	SD Card Clock
input  wire SD_WP_N,		//	SD Card Write Protect

wire sd_cmd_out, sd_cmd_en;

	assign SD_CMD = sd_cmd_en ? sd_cmd_out : 1'bz;

 接続部とテスト

//--------------------- SD_Card Interface ------------------
	SDSCcard_ctrl_SDmode sdcard;
	output SD_CLK;    // SD Card Clock
	output SD_CMD_en; // SD Card CMD Enable
	output SD_CMD;    // SD Card Command
	input  SD_RES;    // SD Card Response
	input  SD_DAT<4>; // SD Card Data

	SD_CLK    = sdcard.CLK;
	SD_CMD_en = sdcard.CMD_en;
	SD_CMD    = sdcard.CMD;
	sdcard.RES = SD_RES;
	sdcard.DAT = SD_DAT;

	stage sdget {
		if(sdcard.ack){
			// MBR(第一パーティションエントリ)
			// 0x1FE -> 0x55
			// 0x1FF -> 0xAA
			sdcard.read(0x000001FF);
			finish;
		}
	}

 SDSCcard_ctrl_SDmode.sflp

 なお、Terasic DE0 FPGAボードについてもSDバスモードが使用できます。 これについては、DE0の古い回路図にはDAT1とDAT2が接続されていないように書かれているため、 使用できるかどうか噂レベルでしか聞いていなかったのですが、 DE0の新しい回路図ではちゃんとデータバスが4本とも接続されているように書かれており、 実際に基板を見ても接続されているようでした。

_
▼ FAT16

 SDカードをFAT16でフォーマットしたものをそのままFPGAで読めるようにとりあえずreadのみ実装。 6502のアセンブラで実装するという手もあったんですが、 SFLで記述した方が楽そうだったのではたしてソフトマクロでの実装となりました。 32MB〜2GBまでのFAT16にフォーマットされたSDカードをサポート。

 FAT16.sflp とファイルをSDRAMに読み込むサンプル。

%i "sdram_ctrl.h"
%i "SDSCcard_ctrl_SPImode.h"
%i "FAT16.h"

circuit FAT16_test
{
	output SD_CSn; // SD Card CSn
	output SD_CLK; // SD Card Clock
	output SD_CMD; // SD Card Command & Dout
	input  SD_DAT; // SD Card Data

	sdram_ctrl sdram;
	reg_ws reset;

	SDSCcard_ctrl_SPImode sdcard;
	FAT16 fat;

	stage_name card2ram { task do(); }

	if(reset){
		generate card2ram.do();
		reset := 0b0;
	}

	SD_CSn = sdcard.CSn;
	SD_CLK = sdcard.CLK;
	SD_CMD = sdcard.CMD;
	sdcard.DAT = SD_DAT;

	instruct fat.sread sdcard.read(fat.sadrs);
	fat.sack = sdcard.ack;
	fat.sdata = sdcard.rdata;

	stage card2ram {
		reg_wr c2rdata<8>, tA<22>;

		first_state st1;
		state st1 if(fat.ack){
			fat.fopen(0x00); // 1つめのファイルを指定
			tA := 0;
			goto st2;
		}
		state st2 if(fat.ack){
			fat.read();
			goto st3;
		}
		state st3 if(fat.ack){
			c2rdata := fat.fdata;
			fat.read();
			goto st4;
		}
		state st4 if(fat.ack & sdram.ack){
			sdram.write(tA, fat.fdata||c2rdata);
			tA++;

			if(fat.eof) finish;
			else goto st2;
		}
	}
}

 今後何かSDカードを使ってログを取るようなことが必要になったらwriteも実装しようかな。

_
▼ SDHCカード (SPIモード) 2024/02/03

 もはや2GB以下のSDカードは中古での入手しかなくなり、SDHCカードが容易に購入できるようになったので、 扱っているプロジェクトでもSDHCカードを使用できるようにコントローラを実装。

 SDHCcard_ctrl_SPImode.sflp

_
▼ SDHCカード (SDモード) 2024/02/18

 SDHCカードもSDバスモードを実装。 SPIモードに比べて読み込み速度は1.6倍になった。

 SDHCcard_ctrl_SDmode.sflp

_
▼ FAT32 2024/02/03

 SDHCをフォーマットするとFAT32となるので、FAT16に続きFAT32も実装。 4GB〜32GBまでのFAT32にフォーマットされたSDHCカードをサポート。 これで容易にSDHCカード経由でファイルをやり取りできるようになった。 ファイルサイズ4MBでのSDカードでのリードが10secだったのに対し、 SDHCカードのSPIモードでのリードは5sec、SDモードでのリードは3secと、 読み込み時間を半分以下にできた。

 FAT32.sflp

_
▼ 参考

SD Simplified Specifications
MMC/SDCの使いかた
AVR工作室 MMCの実験
SDカード
SDカードのSPIモードの初期化に関する諸々
FATファイルシステムのしくみと操作法
FAT FS フォーマットの実装についての覚え書き
FAT32ファイルシステム読解
PIC16F1シリーズを使ってSDカードを制御する2 書き込み・読み込み
PIC16F18346でSDHCカードを使ってみた (MCC不使用)
RX マイコン SDHI を使った SD モードドライバー
SDカードを使ってみよう
PICを使ってSDカードを操作
SDカードから1セクタ読み取るまでの手順解説−WentWayUp
SH7144でSDカードコントローラを試作


Copyright(C) pgate1 All Rights Reserved.