NES on FPGA 19:21 2004/11/28

その他

 デバッグ用のインタフェースを記述しています。

_
▼ IRトレース

 内部ブロックRAMが余ったので、 CPUの命令レジスタをトレースする部分をくっつけました。 過去256命令を記録したものをシリアルポートから取得できます。

 現在は確認できていませんが、 ハードウエアエラーや未定義命令などでトレース結果が役に立ちそうです。

! すくねえ…
すくねえ…

_
▼ 7セグメントLED

 _
|_|  ←こいつ
|_|.

 8セグメントとは言わないんでしょうか。 評価キットの取り扱い説明書にあるピン配置で表示してみてもサッパリだったので調べなおしました。

CQ出版社 Spartan-IIE300評価キット向け

instruct seg7_set any{
   seg_data==0x0 : seg7 = 0b00111111;
   seg_data==0x1 : seg7 = 0b00000110;
   seg_data==0x2 : seg7 = 0b01011011;
   seg_data==0x3 : seg7 = 0b01001111;
   seg_data==0x4 : seg7 = 0b01100110;
   seg_data==0x5 : seg7 = 0b01101101;
   seg_data==0x6 : seg7 = 0b01111101;
   seg_data==0x7 : seg7 = 0b00000111;
   seg_data==0x8 : seg7 = 0b01111111;
   seg_data==0x9 : seg7 = 0b01100111;
   seg_data==0xA : seg7 = 0b01110111;
   seg_data==0xB : seg7 = 0b01111100;
   seg_data==0xC : seg7 = 0b00111001;
   seg_data==0xD : seg7 = 0b01011110;
   seg_data==0xE : seg7 = 0b01111001;
   seg_data==0xF : seg7 = 0b01110001;
}

_
▼ 楽にFPGAとデータ送受信したい! 2019/05/26

 USB-Blaster経由でPC側のソフトとFPGA間のデータ通信を活用しましょう、という話です。 今回の対象FPGAボードは、USB-Blaster回路が載っているTerasic社製のDE0,DE1,DE2,DE0-CV等になります。 なおUSB-BlasterIIについてはまだうまく使えてません。

 FPGA側にPCのユーザプログラムからデータを流し込むために、 最初はRS-232経由でUARTを使っていました。 しかし標準的な230,400baudで実効速度が約20kB/sしか出ず、 ケーブルの取り回しも面倒でした。 さらにDE0でUARTするためにはRS-232コネクタを増設する必要があります。 そしてある程度の速度も欲しい。 SDカード経由というのも、やっぱりデータの差し替えが面倒です。 ちなみにUSB-Blasterはドライバ設定でVCP(Virtual COM Port)としても使えますが、 実効速度としては約60kB/sくらいでした。

 そこで、VirtualJTAGを使って通信する方法を探っていました。 具体的な方法はかず氏がまとめていらっしゃいます [Terasic DE0ボードでのUSB通信A]。 今回対象としているUSB-Blaster回路にはFTDIのチップが使用されていて、 FTDIのD2XXドライバを自作プログラムで使用すればFPGAとUSB経由で繋がります。 さらにFPGA内のVirtualJTAGの回路を使うようにHDLでインスタンスすれば、 JTAGのコマンドを使ってJTAGレジスタを操作できます。 このJTAGレジスタとユーザ回路を接続して、ユーザプログラムとUSB経由でデータを送受信するわけです。

 VirtualJTAGの使い方等は上記サイトを参考にして頂くとして、 今回は数Mバイト程度のデータをFPGAに送信するために工夫してみました。 DE0向けのHDLと送受信のためのC++コードのサンプルを置いておきます。

FPGA側シリパラ変換部、vjtag_uart.vの一部。

	virtual_jtag vjtag (
		.ir_out(8'h00),
		.tdo(tdo),
		.ir_in(ir_in),
		.tck(tck),
		.tdi(tdi),
		.virtual_state_sdr(virtual_state_sdr),
		.virtual_state_uir(virtual_state_uir)
	);

	always @(posedge p_reset or posedge tck) begin
		if(p_reset) begin
			t_init <= 0;
			t_recv <= 0;
			t_send <= 0;
		end
		else if(virtual_state_uir) begin
			count <= 0;
			t_init <= 1;
			t_recv <= 0;
			ir <= ir_in;
			if(ir_in==8'h42)
				t_send <= 1;
		end
		else if(virtual_state_sdr) begin
			t_init <= 0;
			dr[count] <= tdi;
			count <= count + 1;
			if(count==7) begin
				if(ir==8'h41)
					t_recv <= 1;
				else
					t_send <= 1;
			end
			else begin
				if(ir==8'h41)
					t_recv <= 0;
				else
					t_send <= 0;
			end
		end
	end

FPGA側ユーザ回路、vjtag_test.sflpの一部。 32,768バイトを内蔵メモリに受信して、次に送信するだけのテストサンプルです。

	vjtag_uart vjtag;
	mem ram[32768]<8>;
	reg_wr ram_dout<8>, wadrs<15>, radrs<15>;

	instruct vjtag.init_recv par{
		wadrs := 0;
	}

	instruct vjtag.recv par{
		ram[wadrs] := vjtag.recv_data;
		wadrs++;
	}

	instruct vjtag.init_send par{
		radrs := 0;
	}

	instruct vjtag.send par{
		ram_dout := ram[radrs];
		radrs++;
		generate send_set.do();
	}

	stage send_set {
		par{
			vjtag.send_set(ram_dout);
			finish;
		}
	}

・送信
 ポイントはFT_Writeでまとめて送信するだけ。 USB-Blaster回路は6MHz(実際は内部で逓倍されている)で動作していて、 シリパラ変換(コマンド+データ)のオーバヘッドを考えると、 ざっくり16で割って実効速度は約375kB/s、 USB-BlasterはUSB Full-Speed(12Mbps)で接続されていることもあり、 USBフレームの1ms間隔のオーバヘッドのせいか、 実効速度は約400kB/sになります。 FPGAボード付属のデータ送信デモツールより速いみたいです。

int send_data(FT_HANDLE ftHandle, const int total_size)
{
	MoveIdle(ftHandle);
	MoveIdleToShiftir(ftHandle);
	WriteShiftir(ftHandle, 0x0E); // USER1
	MoveShiftirToShiftdr(ftHandle);
	WriteShiftdr(ftHandle, 0x41); // 独自コマンド:FPGA側受信準備
	MoveShiftdrToShiftir(ftHandle);
	WriteShiftir(ftHandle, 0x0C); // USER0
	MoveShiftirToShiftdr(ftHandle);

	int wdata_num = total_size; // 送信サイズ
	uint16 *send_buf = new uint16[wdata_num];
	// 送信データ準備
	for(int i=0; i<wdata_num; i++){
		uint8 data = rand();
		send_buf[i] = (data << 8) | WR;
	}

	uint32 send_size;
	FT_Write(ftHandle, send_buf, wdata_num*2, &send_size);

	delete[] send_buf;
	return 0;
}

・受信
 コマンドの都合上、1回の受信は63バイトまで(と思う)。 FT_WriteでRコマンド含めて64バイト分送信すると、FT_Readで63バイト受信できます。 USB-BlasterはUSB Full-Speedで接続されていることもあり、 USBフレームの1ms間隔のオーバヘッドが入って、実効速度は約30kB/sになります。 ただしサンプルのままでは余剰分がオーバーリードされるので工夫してください。

int recv_data(FT_HANDLE ftHandle, const int total_size)
{
	MoveIdle(ftHandle);
	MoveIdleToShiftir(ftHandle);
	WriteShiftir(ftHandle, 0x0E); // USER1
	MoveShiftirToShiftdr(ftHandle);
	WriteShiftdr(ftHandle, 0x42); // 独自コマンド:FPGA側送信準備
	MoveShiftdrToShiftir(ftHandle);
	WriteShiftir(ftHandle, 0x0C); // USER0
	MoveShiftirToShiftdr(ftHandle);

	uint16 send_buf[0x20];
	for(int i=0; i<0x20; i++) send_buf[i] = L;

	const int rdata_num = 0x3F; // 0x3Fが最大
	uint8 *recv_buf = new uint8[rdata_num];
	send_buf[0] = RD | rdata_num;

	for(int d=0; d<total_size; d+=rdata_num){
		uint32 send_size;
		FT_Write(ftHandle, send_buf, rdata_num+1, &send_size);
		uint32 recv_size;
		FT_Read(ftHandle, recv_buf, rdata_num, &recv_size);
	}

	delete[] recv_buf;
	return 0;
}
サンプルの実行結果
size 32768 byte

send sum 0x26
send 78ms 410.3kB/s

recv sum 0x26
recv 1061ms 30.2kB/s

 以上のように、USB-BlasterとVirtualJTAG経由でデータ送信できるようになりました。 DE0ボードなら、USBケーブル1本でバスパワー電源と、FPGAコンフィギュレーションと、データ送受信で一挙三得です! データ送信速度は自作SDカードコントローラ並になりました。 使わなくなったSDカードとRS-232ケーブルは窓からポイしましょう。
 ユーザプログラムの例。

 最近のTerasic社FPGAボードであるDE10-NanoやDE1-SoCなどには、CypressのUSBチップを使用したUSB-BlasterII回路が載っています。 動作クロックが24MHz、USB High-Speed(480Mbps)のフレーム間隔が125usなので、 これが使えるようになればUSB-Blasterの3〜8倍程度の実効速度で送受信できそうです。


Copyright(C) pgate1 All Rights Reserved.