SSブログ

ZedBoard Linux (6) [FPGA]

FPGA側にDMA付けてみます。

まずは読むだけのメモリダンプ。
ZedBoardにはアナログRGBのD-SUBコネクタが付いてます。ここに指定したアドレスのデータをメモリダンプさせます。要はフレームバッファー。むか~しのマイコン時代から使われている、画像メモリでプログラムを動かしてデバッグしよう、方式です。
なんでHDMIがあるのにわざわざアナログRGBなんてレガシーな物を…って話ですが、レガシーだからこそ。レガシーなインターフェースって無手順で相手の都合を考えず一方的にデータを送りつけても良い、という使い方ができます。デバッグ当初のまだいろいろ立ち上がってない環境では楽ちんです。相変わらずUART(RS-232C)が使われ続ける理由と似てると思います。
12bitBGRなので、画素のサイズは16bit/pixelにします。4bitは無視。

そして書くだけのメモリフィラー。
こちらはボード上に簡単なデータ入力装置が無いので(マイク端子が楽ですが)指定したアドレスから指定したサイズのメモリにカウンターの値を無理矢理書き込むマスターにしてみます。もしLinuxの管理領域に書き込んだら即暴走。先に確保した128MB以降全部埋めてもLinuxが動き続けるのを確認します。本来はカメラのデータとか音声データを流し込みます。

あと、DMAでメモリから読み出したデータをアナログRGBのタイミングに載せるペリフェラルも用意します。これは昔からAvalon(AlteraのNios)で使ってる物をAPBに焼き直しました。タイミングのパラメータをX.Org(XFree86)のmodelineの値と同じ値が使えるようになってます。が、ちゃんと解像度可変にするにはピクセルクロックも可変にしないとならないので、結局固定です(笑)。まぁモニタの対応周波数内で動かせますがあまり意味ないです。周波数は100MHzにしてます。

とりあえずtopデザイン。tab=4そのままなので見にくいかも。
/************************
 *	top
 ************************/
`timescale 1ns / 1ps
`default_nettype none


//**************************************************************************************************
//	
module top
(
	//	==============================================
	//	Hard Wired
	inout	wire	[53:0]	MIO				,
	input	wire			PS_SRSTB		,
	input	wire			PS_CLK			,
	input	wire			PS_PORB			,
	inout	wire			DDR_Clk			,
	inout	wire			DDR_Clk_n		,
	inout	wire			DDR_CKE			,
	inout	wire			DDR_CS_n		,
	inout	wire			DDR_RAS_n		,
	inout	wire			DDR_CAS_n		,
	output	wire			DDR_WEB			,
	inout	wire	[ 2:0]	DDR_BankAddr	,
	inout	wire	[14:0]	DDR_Addr		,
	inout	wire			DDR_ODT			,
	inout	wire			DDR_DRSTB		,
	inout	wire	[31:0]	DDR_DQ			,
	inout	wire	[ 3:0]	DDR_DM			,
	inout	wire	[ 3:0]	DDR_DQS			,
	inout	wire	[ 3:0]	DDR_DQS_n		,
	inout	wire			DDR_VRN			,
	inout	wire			DDR_VRP			,
	//	==============================================
	//	VGA
	output	wire			VGA_HS			,
	output	wire			VGA_VS			,
	output	wire	[ 4:1]	VGA_B			,
	output	wire	[ 4:1]	VGA_G			,
	output	wire	[ 4:1]	VGA_R			
);
	////////////////////////////
	//	
	//	Property
	parameter	blen	= 16		;	//	burst length
	parameter	qdep	= 8			;	//	queue depth = 2**qdep
	parameter	Xsymb	= 1'bX		;	//	invalid Symbol
	//	Video
	parameter	vodw	= 12	 	;	//	VGA Out Data Width
	parameter	vsdw	= 16	 	;	//	Video Stream Data Width
	parameter	cntw	= 11	 	;	//	Counter Width
	//	AXI
	parameter	axiw	= 6			;	//	ID
	parameter	axaw	= 32		;	//	Address
	parameter	axdw	= 64		;	//	Data
	parameter	axmw	= axdw/8	;	//	Mask
	parameter	axrw	= 2			;	//	Response
	parameter	axlw	= 4			;	//	Length
	parameter	axsw	= 3			;	//	Size
	//	AXI master (static)
	parameter	axbw	= 2			;	//	Burst
	parameter	axcw	= 4			;	//	Cache
	parameter	axpw	= 3			;	//	Prot
	parameter	axkw	= 2			;	//	Lock
	parameter	axqw	= 4			;	//	QoS
	//	APB Slave
	parameter	apaw	= 32		;	//	Address
	parameter	apdw	= 32		;	//	Data
	parameter	apsw	= 4			;	//	Slaves


	////////////////////////////
	//	Clock
	wire			FCLK_CLK0;	//	66.6MHz
	wire			FCLK_CLK1;	//	100MHz
	wire			FCLK_CLK2;	//	166.6MHz
	wire			FCLK_CLK3;	//	200Mhz


	////////////////////////////
	//	EMIO GPIO
	wire	[63:0]	EMIO_GPIO_I;
	wire	[63:0]	EMIO_GPIO_O;
	wire	[63:0]	EMIO_GPIO_T;

	assign	EMIO_GPIO_I	= EMIO_GPIO_O ^ EMIO_GPIO_T;


	////////////////////////////
	//	APB
	wire				apb_pclk				;	//	clock
	wire				apb_presetn				;	//	reset_n
	wire	[apaw-1:0]	apb_paddr				;	//	address
	wire	[apsw-1:0]	apb_psel				;	//	select
	wire				apb_penable				;	//	enalbe
	wire				apb_pwrite				;	//	write
	wire	[apdw-1:0]	apb_pwdata				;	//	w data
	wire	[apdw-1:0]	apb_prdata	[apsw-1:0]	;	//	r data
	wire	[apsw-1:0]	apb_pready				;	//	ready
	wire	[apsw-1:0]	apb_pslverr				;	//	error

	assign	apb_pready	= apb_psel;			//	no-wait
	assign	apb_pslverr	= {apsw{1'b0}};		//	no-error

	assign	apb_prdata[3]	= apb_paddr;	//	unused slave


	////////////////////////////
	//	AXI HP
	wire				axi_hp_aclk		;	//	
	//	Address Write
	wire				axi_hp_awready	;	//	
	wire				axi_hp_awvalid	;	//	
	wire	[axiw-1:0]	axi_hp_awid		;	//	
	wire	[axaw-1:0]	axi_hp_awaddr	;	//	
	wire	[axlw-1:0]	axi_hp_awlen	;	//	
	wire	[axsw-1:0]	axi_hp_awsize	;	//	
	wire	[axbw-1:0]	axi_hp_awburst	;	//	static
	wire	[axcw-1:0]	axi_hp_awcache	;	//	static
	wire	[axpw-1:0]	axi_hp_awprot	;	//	static
	wire	[axkw-1:0]	axi_hp_awlock	;	//	static
	wire	[axqw-1:0]	axi_hp_awqos	;	//	static
	//	Write Data
	wire				axi_hp_wready	;	//	
	wire				axi_hp_wvalid	;	//	
	wire	[axiw-1:0]	axi_hp_wid		;	//	
	wire				axi_hp_wlast	;	//	
	wire	[axdw-1:0]	axi_hp_wdata	;	//	
	wire	[axmw-1:0]	axi_hp_wstrb	;	//	
	//	Write Response
	wire				axi_hp_bready	;	//	
	wire				axi_hp_bvalid	;	//	
	wire	[axiw-1:0]	axi_hp_bid		;	//	
	wire	[axrw-1:0]	axi_hp_bresp	;	//	
	//	Address Read
	wire				axi_hp_arready	;	//	
	wire				axi_hp_arvalid	;	//	
	wire	[axiw-1:0]	axi_hp_arid		;	//	
	wire	[axaw-1:0]	axi_hp_araddr	;	//	
	wire	[axlw-1:0]	axi_hp_arlen	;	//	
	wire	[axsw-1:0]	axi_hp_arsize	;	//	
	wire	[axbw-1:0]	axi_hp_arburst	;	//	static
	wire	[axcw-1:0]	axi_hp_arcache	;	//	static
	wire	[axpw-1:0]	axi_hp_arprot	;	//	static
	wire	[axkw-1:0]	axi_hp_arlock	;	//	static
	wire	[axqw-1:0]	axi_hp_arqos	;	//	static
	//	Read Data
	wire				axi_hp_rready	;	//	
	wire				axi_hp_rvalid	;	//	
	wire	[axiw-1:0]	axi_hp_rid		;	//	
	wire				axi_hp_rlast	;	//	
	wire	[axdw-1:0]	axi_hp_rdata	;	//	
	wire	[axrw-1:0]	axi_hp_rresp	;	//	


	////////////////////////////
	//	clock,reset wiring
	wire	a_reset;
	wire	c_clock;
	wire	c_reset;

	assign	a_reset		= ~apb_presetn;	//	
	assign	c_clock		= FCLK_CLK1;	//	
	assign	c_reset		= 1'b0;			//	
	assign	axi_hp_aclk	= c_clock;		//	


	////////////////////////////
	//	Video
	wire				v_hsync		;	//	H Sync
	wire				v_vsync		;	//	V Sync
	wire	[vodw-1:0]	v_data	 	;	//	data

	wire				tx_kick		;	//	kick
	wire				tx_ready	;	//	ready
	wire				tx_valid	;	//	valid
	wire	[vsdw-1:0]	tx_data 	;	//	data

	assign	VGA_HS	= v_hsync;
	assign	VGA_VS	= v_vsync;
	assign	{VGA_R,VGA_G,VGA_B}	= v_data;


	////////////////////////////
	//	VGA I/F
	vga_if
	#(
		//	Property
		.vodw	(vodw	),		//	parameter	vodw	= 12 	,	//	VGA Out Data Width
		.vsdw	(vsdw	),		//	parameter	vsdw	= 16 	,	//	Video Stream Data Width
		.cntw	(cntw	),		//	parameter	cntw	= 11 	,	//	Counter Width
		//	APB Slave
		.apaw	(apaw	),		//	parameter	apaw	= 32	,	//	Address
		.apdw	(apdw	)		//	parameter	apdw	= 32		//	Data
	)
	voif
	(
		//	==============================================
		//	common
		.a_reset		(a_reset	),		//	input	wire				a_reset		,	//	reset
		.c_clock		(c_clock	),		//	input	wire				c_clock		,	//	clock
		.c_reset		(c_reset	),		//	input	wire				c_reset		,	//	reset
		//	==============================================
		//	VGA
		.v_hsync		(v_hsync	),		//	output	wire				v_hsync		,	//	H Sync
		.v_vsync		(v_vsync	),		//	output	wire				v_vsync		,	//	V Sync
		.v_data			(v_data		),		//	output	wire	[vodw-1:0]	v_data	 	,	//	data
		//	==============================================
		//	Transmit Stream + kick
		.tx_kick		(tx_kick	),		//	output	wire				tx_kick		,	//	kick
		.tx_ready		(tx_ready	),		//	output	wire				tx_ready	,	//	ready
		.tx_valid		(tx_valid	),		//	input	wire				tx_valid	,	//	valid
		.tx_data		(tx_data	),		//	input	wire	[vsdw-1:0]	tx_data 	,	//	data
		//	==============================================
		//	APB
		.apb_pclk		(apb_pclk		),		//	input	wire				apb_pclk	,	//	clock
		.apb_presetn	(apb_presetn	),		//	input	wire				apb_presetn	,	//	reset_n
		.apb_paddr		(apb_paddr		),		//	input	wire	[apaw-1:0]	apb_paddr	,	//	address
		.apb_psel		(apb_psel	[0]	),		//	input	wire				apb_psel	,	//	select
		.apb_penable	(apb_penable	),		//	input	wire				apb_penable	,	//	enalbe
		.apb_pwrite		(apb_pwrite		),		//	input	wire				apb_pwrite	,	//	write
		.apb_pwdata		(apb_pwdata		),		//	input	wire	[apdw-1:0]	apb_pwdata	,	//	data
		.apb_prdata		(apb_prdata	[0]	)		//	output	reg 	[apdw-1:0]	apb_prdata	,	//	data
	);


	////////////////////////////
	//	VGA DMA
	vga_dma
	#(
		//	Property
		.vsdw	(vsdw	),		//	parameter	vsdw	= 16		,	//	Video Stream data width
		.blen	(blen	),		//	parameter	blen	= 16		,	//	burst length
		.qdep	(qdep	),		//	parameter	qdep	= 8			,	//	queue depth = 2**qdep
		//	AXI master
		.axiw	(axiw	),		//	parameter	axiw	= 6			,	//	ID
		.axaw	(axaw	),		//	parameter	axaw	= 32		,	//	Address
		.axdw	(axdw	),		//	parameter	axdw	= 64		,	//	Data
		.axmw	(axmw	),		//	parameter	axmw	= axdw/8	,	//	Mask
		.axrw	(axrw	),		//	parameter	axrw	= 2			,	//	Response
		.axlw	(axlw	),		//	parameter	axlw	= 4			,	//	Length
		.axsw	(axsw	),		//	parameter	axsw	= 3			,	//	Size
		//	AXI master (static)
		.axbw	(axbw	),		//	parameter	axbw	= 2			,	//	Burst
		.axcw	(axcw	),		//	parameter	axcw	= 4			,	//	Cache
		.axpw	(axpw	),		//	parameter	axpw	= 3			,	//	Prot
		.axkw	(axkw	),		//	parameter	axkw	= 2			,	//	Lock
		.axqw	(axqw	),		//	parameter	axqw	= 4			,	//	QoS
		//	APB Slave
		.apaw	(apaw	),		//	parameter	apaw	= 32		,	//	Address
		.apdw	(apdw	),		//	parameter	apdw	= 32		,	//	Data
		//	misc
		.Xsymb	(Xsymb	)		//	parameter	Xsymb	= 1'bX			//	invalid Symbol
	)
	vdma
	(
		//	==============================================
		//	common
		.a_reset		(a_reset	),		//	input	wire				a_reset		,	//	reset
		.c_clock		(c_clock	),		//	input	wire				c_clock		,	//	clock
		.c_reset		(c_reset	),		//	input	wire				c_reset		,	//	reset
		//	==============================================
		//	Transmit Stream + kick
		.tx_kick		(tx_kick	),		//	input	wire				tx_kick		,	//	kick
		.tx_ready		(tx_ready	),		//	output	wire				tx_ready	,	//	ready
		.tx_valid		(tx_valid	),		//	input	wire				tx_valid	,	//	valid
		.tx_data		(tx_data	),		//	input	wire	[vsdw-1:0]	tx_data 	,	//	data
		//	==============================================
		//	Address Read
		.axi_arready	(axi_hp_arready	),		//	input	wire				axi_arready	,	//	
		.axi_arvalid	(axi_hp_arvalid	),		//	output	wire				axi_arvalid	,	//	
		.axi_arid		(axi_hp_arid	),		//	output	wire	[axiw-1:0]	axi_arid	,	//	
		.axi_araddr		(axi_hp_araddr	),		//	output	wire	[axaw-1:0]	axi_araddr	,	//	
		.axi_arlen		(axi_hp_arlen	),		//	output	wire	[axlw-1:0]	axi_arlen	,	//	
		.axi_arsize		(axi_hp_arsize	),		//	output	wire	[axsw-1:0]	axi_arsize	,	//	
		.axi_arburst	(axi_hp_arburst	),		//	output	wire	[axbw-1:0]	axi_arburst	,	//	static
		.axi_arcache	(axi_hp_arcache	),		//	output	wire	[axcw-1:0]	axi_arcache	,	//	static
		.axi_arprot		(axi_hp_arprot	),		//	output	wire	[axpw-1:0]	axi_arprot	,	//	static
		.axi_arlock		(axi_hp_arlock	),		//	output	wire	[axkw-1:0]	axi_arlock	,	//	static
		.axi_arqos		(axi_hp_arqos	),		//	output	wire	[axqw-1:0]	axi_arqos	,	//	static
		//	Read Data
		.axi_rready		(axi_hp_rready	),		//	output	wire				axi_rready	,	//	
		.axi_rvalid		(axi_hp_rvalid	),		//	input	wire				axi_rvalid	,	//	
		.axi_rlast		(axi_hp_rlast	),		//	input	wire				axi_rlast	,	//	
		.axi_rid		(axi_hp_rid		),		//	input	wire	[axiw-1:0]	axi_rid		,	//	
		.axi_rdata		(axi_hp_rdata	),		//	input	wire	[axdw-1:0]	axi_rdata	,	//	
		.axi_rresp		(axi_hp_rresp	),		//	input	wire	[axrw-1:0]	axi_rresp	,	//	
		//	==============================================
		//	APB
		.apb_pclk		(apb_pclk		),		//	input	wire				apb_pclk	,	//	clock
		.apb_presetn	(apb_presetn	),		//	input	wire				apb_presetn	,	//	reset_n
		.apb_paddr		(apb_paddr		),		//	input	wire	[apaw-1:0]	apb_paddr	,	//	address
		.apb_psel		(apb_psel	[1]	),		//	input	wire				apb_psel	,	//	select
		.apb_penable	(apb_penable	),		//	input	wire				apb_penable	,	//	enalbe
		.apb_pwrite		(apb_pwrite		),		//	input	wire				apb_pwrite	,	//	write
		.apb_pwdata		(apb_pwdata		),		//	input	wire	[apdw-1:0]	apb_pwdata	,	//	data
		.apb_prdata		(apb_prdata	[1]	)		//	output	reg 	[apdw-1:0]	apb_prdata	,	//	data
	);


	////////////////////////////
	//	Filler
	fill_dma
	#(
		//	Property
		.blen	(blen	),		//	parameter	blen	= 16		,	//	burst length
		.qdep	(qdep	),		//	parameter	qdep	= 8			,	//	queue depth = 2**qdep
		//	AXI master
		.axiw	(axiw	),		//	parameter	axiw	= 6			,	//	ID
		.axaw	(axaw	),		//	parameter	axaw	= 32		,	//	Address
		.axdw	(axdw	),		//	parameter	axdw	= 64		,	//	Data
		.axmw	(axmw	),		//	parameter	axmw	= axdw/8	,	//	Mask
		.axlw	(axlw	),		//	parameter	axlw	= 4			,	//	Length
		.axsw	(axsw	),		//	parameter	axsw	= 3			,	//	Size
		.axrw	(axrw	),		//	parameter	axrw	= 2			,	//	Response
		//	AXI master (static)
		.axbw	(axbw	),		//	parameter	axbw	= 2			,	//	Burst
		.axcw	(axcw	),		//	parameter	axcw	= 4			,	//	Cache
		.axpw	(axpw	),		//	parameter	axpw	= 3			,	//	Prot
		.axkw	(axkw	),		//	parameter	axkw	= 2			,	//	Lock
		.axqw	(axqw	),		//	parameter	axqw	= 4			,	//	QoS
		//	APB Slave
		.apaw	(apaw	),		//	parameter	apaw	= 32		,	//	Address
		.apdw	(apdw	),		//	parameter	apdw	= 32		,	//	Data
		//	misc
		.Xsymb	(Xsymb	)		//	parameter	Xsymb	= 1'bX			//	invalid Symbol
	)
	filler
	(
		//	==============================================
		//	common
		.a_reset		(a_reset	),		//	input	wire				a_reset		,	//	reset
		.c_clock		(c_clock	),		//	input	wire				c_clock		,	//	clock
		.c_reset		(c_reset	),		//	input	wire				c_reset		,	//	reset
		//	==============================================
		//	Address Write
		.axi_awready	(axi_hp_awready	),		//	input	wire				axi_awready	,	//	
		.axi_awvalid	(axi_hp_awvalid	),		//	output	wire				axi_awvalid	,	//	
		.axi_awid		(axi_hp_awid	),		//	output	wire	[axiw-1:0]	axi_awid	,	//	
		.axi_awaddr		(axi_hp_awaddr	),		//	output	wire	[axaw-1:0]	axi_awaddr	,	//	
		.axi_awlen		(axi_hp_awlen	),		//	output	wire	[axlw-1:0]	axi_awlen	,	//	
		.axi_awsize		(axi_hp_awsize	),		//	output	wire	[axsw-1:0]	axi_awsize	,	//	
		.axi_awburst	(axi_hp_awburst	),		//	output	wire	[axbw-1:0]	axi_awburst	,	//	static
		.axi_awcache	(axi_hp_awcache	),		//	output	wire	[axcw-1:0]	axi_awcache	,	//	static
		.axi_awprot		(axi_hp_awprot	),		//	output	wire	[axpw-1:0]	axi_awprot	,	//	static
		.axi_awlock		(axi_hp_awlock	),		//	output	wire	[axkw-1:0]	axi_awlock	,	//	static
		.axi_awqos		(axi_hp_awqos	),		//	output	wire	[axqw-1:0]	axi_awqos	,	//	static
		//	Write Data
		.axi_wready		(axi_hp_wready	),		//	input	wire				axi_wready	,	//	
		.axi_wvalid		(axi_hp_wvalid	),		//	output	wire				axi_wvalid	,	//	
		.axi_wlast		(axi_hp_wlast	),		//	output	wire				axi_wlast	,	//	
		.axi_wid		(axi_hp_wid		),		//	output	wire	[axiw-1:0]	axi_wid		,	//	
		.axi_wdata		(axi_hp_wdata	),		//	output	wire	[axdw-1:0]	axi_wdata	,	//	
		.axi_wstrb		(axi_hp_wstrb	),		//	output	wire	[axmw-1:0]	axi_wstrb	,	//	
		//	Write Response
		.axi_bready		(axi_hp_bready	),		//	output	wire				axi_bready	,	//	
		.axi_bvalid		(axi_hp_bvalid	),		//	input	wire				axi_bvalid	,	//	
		.axi_bid		(axi_hp_bid		),		//	input	wire	[axiw-1:0]	axi_bid		,	//	
		.axi_bresp		(axi_hp_bresp	),		//	input	wire	[axrw-1:0]	axi_bresp	,	//	
		//	==============================================
		//	APB
		.apb_pclk		(apb_pclk		),		//	input	wire				apb_pclk	,	//	clock
		.apb_presetn	(apb_presetn	),		//	input	wire				apb_presetn	,	//	reset_n
		.apb_paddr		(apb_paddr		),		//	input	wire	[apaw-1:0]	apb_paddr	,	//	address
		.apb_psel		(apb_psel	[2]	),		//	input	wire				apb_psel	,	//	select
		.apb_penable	(apb_penable	),		//	input	wire				apb_penable	,	//	enalbe
		.apb_pwrite		(apb_pwrite		),		//	input	wire				apb_pwrite	,	//	write
		.apb_pwdata		(apb_pwdata		),		//	input	wire	[apdw-1:0]	apb_pwdata	,	//	data
		.apb_prdata		(apb_prdata	[2]	)		//	output	reg 	[apdw-1:0]	apb_prdata	,	//	data
	);


	////////////////////////////
	//	PS
	(* BOX_TYPE = "user_black_box" *)
	ps_module
	ps (
		//	==============================================
		//	Hard Wired
		.processing_system7_0_MIO			(MIO			),
		.processing_system7_0_PS_SRSTB_pin	(PS_SRSTB		),
		.processing_system7_0_PS_CLK_pin	(PS_CLK			),
		.processing_system7_0_PS_PORB_pin	(PS_PORB		),
		.processing_system7_0_DDR_Clk		(DDR_Clk		),
		.processing_system7_0_DDR_Clk_n		(DDR_Clk_n		),
		.processing_system7_0_DDR_CKE		(DDR_CKE		),
		.processing_system7_0_DDR_CS_n		(DDR_CS_n		),
		.processing_system7_0_DDR_RAS_n		(DDR_RAS_n		),
		.processing_system7_0_DDR_CAS_n		(DDR_CAS_n		),
		.processing_system7_0_DDR_WEB_pin	(DDR_WEB		),
		.processing_system7_0_DDR_BankAddr	(DDR_BankAddr	),
		.processing_system7_0_DDR_Addr		(DDR_Addr		),
		.processing_system7_0_DDR_ODT		(DDR_ODT		),
		.processing_system7_0_DDR_DRSTB		(DDR_DRSTB		),
		.processing_system7_0_DDR_DQ		(DDR_DQ			),
		.processing_system7_0_DDR_DM		(DDR_DM			),
		.processing_system7_0_DDR_DQS		(DDR_DQS		),
		.processing_system7_0_DDR_DQS_n		(DDR_DQS_n		),
		.processing_system7_0_DDR_VRN		(DDR_VRN		),
		.processing_system7_0_DDR_VRP		(DDR_VRP		),
		//	==============================================
		//	EMIO
		.processing_system7_0_GPIO_I_pin	(EMIO_GPIO_I	),
		.processing_system7_0_GPIO_O_pin	(EMIO_GPIO_O	),
		.processing_system7_0_GPIO_T_pin	(EMIO_GPIO_T	),
		//	==============================================
		//	Clock
		.processing_system7_0_FCLK_CLK0_pin	(FCLK_CLK0		),
		.processing_system7_0_FCLK_CLK1_pin	(FCLK_CLK1		),
		.processing_system7_0_FCLK_CLK2_pin	(FCLK_CLK2		),
		.processing_system7_0_FCLK_CLK3_pin	(FCLK_CLK3		),
		//	==============================================
		//	APB
		.axi_apb_bridge_0_M_APB_PCLK_pin	(apb_pclk		),
		.axi_apb_bridge_0_M_APB_PRESETN_pin	(apb_presetn	),
		.axi_apb_bridge_0_M_APB_PADDR_pin	(apb_paddr		),
		.axi_apb_bridge_0_M_APB_PSEL_pin	(apb_psel		),
		.axi_apb_bridge_0_M_APB_PENABLE_pin	(apb_penable	),
		.axi_apb_bridge_0_M_APB_PWRITE_pin	(apb_pwrite		),
		.axi_apb_bridge_0_M_APB_PWDATA_pin	(apb_pwdata		),
		.axi_apb_bridge_0_M_APB_PREADY_pin	(apb_pready		),
		.axi_apb_bridge_0_M_APB_PRDATA_pin	(apb_prdata[0]	),
		.axi_apb_bridge_0_M_APB_PRDATA2_pin	(apb_prdata[1]	),
		.axi_apb_bridge_0_M_APB_PRDATA3_pin	(apb_prdata[2]	),
		.axi_apb_bridge_0_M_APB_PRDATA4_pin	(apb_prdata[3]	),
		.axi_apb_bridge_0_M_APB_PSLVERR_pin	(apb_pslverr	),
		//	==============================================
		//	AXI HP0
		.processing_system7_0_S_AXI_HP0_ARREADY_pin	(axi_hp_arready	),
		.processing_system7_0_S_AXI_HP0_AWREADY_pin	(axi_hp_awready	),
		.processing_system7_0_S_AXI_HP0_BVALID_pin	(axi_hp_bvalid	),
		.processing_system7_0_S_AXI_HP0_RLAST_pin	(axi_hp_rlast	),
		.processing_system7_0_S_AXI_HP0_RVALID_pin	(axi_hp_rvalid	),
		.processing_system7_0_S_AXI_HP0_WREADY_pin	(axi_hp_wready	),
		.processing_system7_0_S_AXI_HP0_BRESP_pin	(axi_hp_bresp	),
		.processing_system7_0_S_AXI_HP0_RRESP_pin	(axi_hp_rresp	),
		.processing_system7_0_S_AXI_HP0_BID_pin		(axi_hp_bid		),
		.processing_system7_0_S_AXI_HP0_RID_pin		(axi_hp_rid		),
		.processing_system7_0_S_AXI_HP0_RDATA_pin	(axi_hp_rdata	),
		.processing_system7_0_S_AXI_HP0_ACLK_pin	(axi_hp_aclk	),
		.processing_system7_0_S_AXI_HP0_ARVALID_pin	(axi_hp_arvalid	),
		.processing_system7_0_S_AXI_HP0_AWVALID_pin	(axi_hp_awvalid	),
		.processing_system7_0_S_AXI_HP0_BREADY_pin	(axi_hp_bready	),
		.processing_system7_0_S_AXI_HP0_RREADY_pin	(axi_hp_rready	),
		.processing_system7_0_S_AXI_HP0_WLAST_pin	(axi_hp_wlast	),
		.processing_system7_0_S_AXI_HP0_WVALID_pin	(axi_hp_wvalid	),
		.processing_system7_0_S_AXI_HP0_ARBURST_pin	(axi_hp_arburst	),
		.processing_system7_0_S_AXI_HP0_ARLOCK_pin	(axi_hp_arlock	),
		.processing_system7_0_S_AXI_HP0_ARSIZE_pin	(axi_hp_arsize	),
		.processing_system7_0_S_AXI_HP0_AWBURST_pin	(axi_hp_awburst	),
		.processing_system7_0_S_AXI_HP0_AWLOCK_pin	(axi_hp_awlock	),
		.processing_system7_0_S_AXI_HP0_AWSIZE_pin	(axi_hp_awsize	),
		.processing_system7_0_S_AXI_HP0_ARPROT_pin	(axi_hp_arprot	),
		.processing_system7_0_S_AXI_HP0_AWPROT_pin	(axi_hp_awprot	),
		.processing_system7_0_S_AXI_HP0_ARADDR_pin	(axi_hp_araddr	),
		.processing_system7_0_S_AXI_HP0_AWADDR_pin	(axi_hp_awaddr	),
		.processing_system7_0_S_AXI_HP0_ARCACHE_pin	(axi_hp_arcache	),
		.processing_system7_0_S_AXI_HP0_ARLEN_pin	(axi_hp_arlen	),
		.processing_system7_0_S_AXI_HP0_ARQOS_pin	(axi_hp_arqos	),
		.processing_system7_0_S_AXI_HP0_AWCACHE_pin	(axi_hp_awcache	),
		.processing_system7_0_S_AXI_HP0_AWLEN_pin	(axi_hp_awlen	),
		.processing_system7_0_S_AXI_HP0_AWQOS_pin	(axi_hp_awqos	),
		.processing_system7_0_S_AXI_HP0_ARID_pin	(axi_hp_arid	),
		.processing_system7_0_S_AXI_HP0_AWID_pin	(axi_hp_awid	),
		.processing_system7_0_S_AXI_HP0_WID_pin		(axi_hp_wid		),
		.processing_system7_0_S_AXI_HP0_WDATA_pin	(axi_hp_wdata	),
		.processing_system7_0_S_AXI_HP0_WSTRB_pin	(axi_hp_wstrb	)
	);

endmodule
//
//**************************************************************************************************

`default_nettype wire

こう見ると長いですが、ほとんど同じ名前の信号をつなぐだけになってます。SystemVerilogのInterface記述やQsys、XPSといったツールが出てきたのもわかりますね。手で書いてたら無駄ですもん。コピペとマクロでやってても面倒くさい。(記述が無駄に冗長なのは半自動的だからです。)

DMA本体やVGAインターフェースもそのうち公開すると思いますが、複数のモジュールに別れてるので結構面倒くさい。どういう公開方法が楽かな?バージョン管理にgit使ってるのでそのままgithubとかに上げるのが良いのかな?ライセンスとかどうするのが良いんでしょ…オープンソースなハードウェアのライセンスってGPLとかCCとかで良いのかな?

モジュールに別れてますが、意外に小さいと思います。
VGA DMA:約270行
AXI Read シーケンサー:約240行
メモリフィル・DMA:約330行
AXI Write シーケンサー:約340行
VGAインターフェース:約280行
その他100~150行ぐらいの細かいファイルが5~6個
という構成。機能削ればこの程度です。

VGAのピン配置をZedBoardのマスターucfから持ってきて、コンパイルします。Sliceの使用率は6%程度。(そのうち約半分はXilinxのAPB関連のIP。しかもその中でまた新たにCritical Warning出てるしw。)
できあがったbitストリームを差し替えてBOOT.BINを作成。他のLinux関連のファイルはそのままです。立ち上げてもなにも変わりません。Linuxにはペリフェラル増えたとか通知してませんし。

PC側でSDKを立ち上げて、Linuxアプリを作成します。
(相変わらずエラーチェック無しのいい加減プログラム…)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

typedef unsigned int uint32;
typedef unsigned short uint16;

const uint32 param[] = {1280, 1360, 1496, 1712, 960, 961, 964, 994}; タイミング

inline void putPixel(uint16 *fb, int x, int y, uint16 c)
{
	fb[y*param[0]+x] = c; 直接書き込みとか
}
…
#define MAP_SIZE 4096UL レジスタ空間のサイズ
#define FB_SIZE 1024UL*1024UL*(512-128) Linuxが取った128MB以外全部
…
main()
/dev/mem開いて直接アドレスでマッピング
    fd = open("/dev/mem", O_RDWR | O_SYNC);
    uint32 *voif = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x72800000); VGA I/F
    uint32 *vdma = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x60A00000); VGA DMA
    uint32 *fill = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x60A20000); Filler
    uint16 *fb   = mmap(0,  FB_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x08000000); フレームバッファー
    close(fd);

    vdma[4] = 0x08000000; ベースアドレス=128MB
    vdma[5] = width*height*2; 転送サイズ=画像サイズ

    voif[0x08] = param[0];
    voif[0x09] = param[1];
    voif[0x0a] = param[2];
    voif[0x0b] = param[3];
    voif[0x0c] = param[4];
    voif[0x0d] = param[5];
    voif[0x0e] = param[6];
    voif[0x0f] = param[7]; パラメータ設定

    vdma[1] = 0x00000001; DMAスタート
    voif[0] = 0x0000000b; VGAスタート

    fill[4] = 0x08000000; 128MB先頭から
    fill[5] = 384*1024*1024; 384MB一気書き込みとか
    fill[1] = 0x00000001;
    fill[1] = 0x00000000;

線引いたり円描いたり
    line(fb, width-1, 0, 0, height-1, 0xffff);
    circle(fb, width/2, height/2,  100, 0xffff);

最後に開放
    munmap(voif, MAP_SIZE);
    munmap(vdma, MAP_SIZE);
    munmap(fill, MAP_SIZE);
    munmap(fb  ,  FB_SIZE);

レジスタ構成とかはまた今度として、こんな感じでプログラム作ってLinuxに転送し実行すると画面に画が出てきます。
R0026628.JPG
Fill DMAがカウンター値を書き込んでるので、格子状のベタ画像になります。Linuxは動作し続けてるので、Fill DMAが書き込んだのはLinux管理外の領域となってるようです。Fill DMAの先頭アドレスを0x0000_0000とかにしてLinuxが管理してるはずのメモリ領域に書き込ませると、ちゃんと暴走します。VGA DMAの先頭アドレスをLinuxの領域にしてなにか操作すると画像が変わるのがわかります。
R0026630.JPGLinuxのどこかの管理領域。
Linuxでも絶対アドレスを指定したポインタによるアクセスって意外と簡単にできるんですね。知らんかったです。デバイスドライバとか書かなくて済むのでデバッグ時は楽です。デバイスドライバ書くとかpcore形式にしてXPSに登録するとか、これがうれしいのは繰り返し使うときで、一回しか使わないときは手間なんですよね。

これでまずはメモリを分けてLinuxの管理領域外のメモリを用意し、FPGAから直接操作する基本的な構成ができました。CPUのキャッシュとの関連とか帯域制御とかまだ色々ありそうですが、必要最低限は用意できたと思います。多分他のプラットフォーム(MBとかNiosIIとか)でも同じ方法で行けるはずです。
Linuxが使えるメモリが減ってしまい、自由度が下がるのが問題ですが、LinuxのページングモデルにFPGAロジックを摺り合わせるよりは楽だと思います。
nice!(0)  トラックバック(0) 

ZedBoard Linux (5) [FPGA]

Linux管理外のメモリ空間がホントに思ったとおりになってるのか、FPGAから読み書きしてみます。

接続方法ですが、諸事情(笑)によりAXI3。
…はじめの頃はAXI4ににしてpcore形式で登録したりもしてたのですが、最近はハードマクロのAXI-HP0~3を直接外に出してそこにつなぐパターンが多くなってます。作る時に毎回XPS立ち上げてうんたらかんたらやるのが面倒に感じてしまい、まずはAXIを外に出してXPSの作業はおしまい、後は外で作成、って感じです。この場合、ハードマクロのインターフェースは、AXI4ではなくAXI3+QoSです。pcore形式でつなぐ場合はAXI4~AXI3変換が自動的に追加されてます。
AlteraのSOPC Builder、Qsysでは面倒に感じず、そのまま作業することが多いんですよね。なにかセンスが違うんでしょう。ARMの付いたSoCシリーズは使ったこと無いのでわかりませんが…VivadoのIPインテグレーターがどうかもまだ試していません。

ということで、FPGA側のAXIマスターはAXI3になります。スレーブはレジスタの読み書きぐらいしかしないので、AXI~APBブリッジのIPを使ってしまいます。手抜き手抜き。
ちなみにAXIの3と4の違いは中の情報(パケット、プロトコル)の違いであって、タイミングは変わりません(依存関係に追加規定はあります)。簡単なAXIマスターモジュールで関係するのはバースト長(AXI3:4bit:最大16回、AXI4:8bit:最大256回)ぐらいじゃないですかね?

XPSの作業。まずはAXI-APBブリッジを追加します。
Image 014.png
APBのスレーブ本数は適当に4本。
自動的にアドレスが割り当てられ、外部にポートが出ます。
Image 011.png
Image 011p.png

PSセッティングの画面からHigh Performance AXIをクリックし、設定画面からS_AXI_HP0を有効に。
Image 018.png
最初はどこにも接続されてないので、Portタブから「S_AXI_HP0」を「Make Ports External」にします。
Image 019.png
「S_AXI_HP0」が直接外部ポートに出てきます。
Image 020.png
※「S_AXI_HP0_ACLK」が入力な点に注意。AXI_HPはFIFOになっていて、クロックを自由に設定できます。他のAXIもクロックブリッジが付いてます。

こうしてできた_stub.vがこちら。
//-----------------------------------------------------------------------------
// ps_module_stub.v
//-----------------------------------------------------------------------------

module ps_module_stub
  (
    processing_system7_0_MIO,
    processing_system7_0_PS_SRSTB_pin,
    processing_system7_0_PS_CLK_pin,
    processing_system7_0_PS_PORB_pin,
    processing_system7_0_DDR_Clk,
    processing_system7_0_DDR_Clk_n,
    processing_system7_0_DDR_CKE,
    processing_system7_0_DDR_CS_n,
    processing_system7_0_DDR_RAS_n,
    processing_system7_0_DDR_CAS_n,
    processing_system7_0_DDR_WEB_pin,
    processing_system7_0_DDR_BankAddr,
    processing_system7_0_DDR_Addr,
    processing_system7_0_DDR_ODT,
    processing_system7_0_DDR_DRSTB,
    processing_system7_0_DDR_DQ,
    processing_system7_0_DDR_DM,
    processing_system7_0_DDR_DQS,
    processing_system7_0_DDR_DQS_n,
    processing_system7_0_DDR_VRN,
    processing_system7_0_DDR_VRP,
    processing_system7_0_GPIO_I_pin,
    processing_system7_0_GPIO_O_pin,
    processing_system7_0_GPIO_T_pin,
    processing_system7_0_FCLK_CLK0_pin,
    processing_system7_0_FCLK_CLK1_pin,
    processing_system7_0_FCLK_CLK2_pin,
    processing_system7_0_FCLK_CLK3_pin,
    axi_apb_bridge_0_M_APB_PCLK_pin,
    axi_apb_bridge_0_M_APB_PRESETN_pin,
    axi_apb_bridge_0_M_APB_PADDR_pin,
    axi_apb_bridge_0_M_APB_PSEL_pin,
    axi_apb_bridge_0_M_APB_PENABLE_pin,
    axi_apb_bridge_0_M_APB_PWRITE_pin,
    axi_apb_bridge_0_M_APB_PWDATA_pin,
    axi_apb_bridge_0_M_APB_PREADY_pin,
    axi_apb_bridge_0_M_APB_PRDATA_pin,
    axi_apb_bridge_0_M_APB_PRDATA2_pin,
    axi_apb_bridge_0_M_APB_PRDATA3_pin,
    axi_apb_bridge_0_M_APB_PRDATA4_pin,
    axi_apb_bridge_0_M_APB_PSLVERR_pin,
    processing_system7_0_S_AXI_HP0_ARREADY_pin,
    processing_system7_0_S_AXI_HP0_AWREADY_pin,
    processing_system7_0_S_AXI_HP0_BVALID_pin,
    processing_system7_0_S_AXI_HP0_RLAST_pin,
    processing_system7_0_S_AXI_HP0_RVALID_pin,
    processing_system7_0_S_AXI_HP0_WREADY_pin,
    processing_system7_0_S_AXI_HP0_BRESP_pin,
    processing_system7_0_S_AXI_HP0_RRESP_pin,
    processing_system7_0_S_AXI_HP0_BID_pin,
    processing_system7_0_S_AXI_HP0_RID_pin,
    processing_system7_0_S_AXI_HP0_RDATA_pin,
    processing_system7_0_S_AXI_HP0_ACLK_pin,
    processing_system7_0_S_AXI_HP0_ARVALID_pin,
    processing_system7_0_S_AXI_HP0_AWVALID_pin,
    processing_system7_0_S_AXI_HP0_BREADY_pin,
    processing_system7_0_S_AXI_HP0_RREADY_pin,
    processing_system7_0_S_AXI_HP0_WLAST_pin,
    processing_system7_0_S_AXI_HP0_WVALID_pin,
    processing_system7_0_S_AXI_HP0_ARBURST_pin,
    processing_system7_0_S_AXI_HP0_ARLOCK_pin,
    processing_system7_0_S_AXI_HP0_ARSIZE_pin,
    processing_system7_0_S_AXI_HP0_AWBURST_pin,
    processing_system7_0_S_AXI_HP0_AWLOCK_pin,
    processing_system7_0_S_AXI_HP0_AWSIZE_pin,
    processing_system7_0_S_AXI_HP0_ARPROT_pin,
    processing_system7_0_S_AXI_HP0_AWPROT_pin,
    processing_system7_0_S_AXI_HP0_ARADDR_pin,
    processing_system7_0_S_AXI_HP0_AWADDR_pin,
    processing_system7_0_S_AXI_HP0_ARCACHE_pin,
    processing_system7_0_S_AXI_HP0_ARLEN_pin,
    processing_system7_0_S_AXI_HP0_ARQOS_pin,
    processing_system7_0_S_AXI_HP0_AWCACHE_pin,
    processing_system7_0_S_AXI_HP0_AWLEN_pin,
    processing_system7_0_S_AXI_HP0_AWQOS_pin,
    processing_system7_0_S_AXI_HP0_ARID_pin,
    processing_system7_0_S_AXI_HP0_AWID_pin,
    processing_system7_0_S_AXI_HP0_WID_pin,
    processing_system7_0_S_AXI_HP0_WDATA_pin,
    processing_system7_0_S_AXI_HP0_WSTRB_pin
  );
  inout [53:0] processing_system7_0_MIO;
  input processing_system7_0_PS_SRSTB_pin;
  input processing_system7_0_PS_CLK_pin;
  input processing_system7_0_PS_PORB_pin;
  inout processing_system7_0_DDR_Clk;
  inout processing_system7_0_DDR_Clk_n;
  inout processing_system7_0_DDR_CKE;
  inout processing_system7_0_DDR_CS_n;
  inout processing_system7_0_DDR_RAS_n;
  inout processing_system7_0_DDR_CAS_n;
  output processing_system7_0_DDR_WEB_pin;
  inout [2:0] processing_system7_0_DDR_BankAddr;
  inout [14:0] processing_system7_0_DDR_Addr;
  inout processing_system7_0_DDR_ODT;
  inout processing_system7_0_DDR_DRSTB;
  inout [31:0] processing_system7_0_DDR_DQ;
  inout [3:0] processing_system7_0_DDR_DM;
  inout [3:0] processing_system7_0_DDR_DQS;
  inout [3:0] processing_system7_0_DDR_DQS_n;
  inout processing_system7_0_DDR_VRN;
  inout processing_system7_0_DDR_VRP;
  input [63:0] processing_system7_0_GPIO_I_pin;
  output [63:0] processing_system7_0_GPIO_O_pin;
  output [63:0] processing_system7_0_GPIO_T_pin;
  output processing_system7_0_FCLK_CLK0_pin;
  output processing_system7_0_FCLK_CLK1_pin;
  output processing_system7_0_FCLK_CLK2_pin;
  output processing_system7_0_FCLK_CLK3_pin;
  output axi_apb_bridge_0_M_APB_PCLK_pin;
  output axi_apb_bridge_0_M_APB_PRESETN_pin;
  output [31:0] axi_apb_bridge_0_M_APB_PADDR_pin;
  output [3:0] axi_apb_bridge_0_M_APB_PSEL_pin;
  output axi_apb_bridge_0_M_APB_PENABLE_pin;
  output axi_apb_bridge_0_M_APB_PWRITE_pin;
  output [31:0] axi_apb_bridge_0_M_APB_PWDATA_pin;
  input [3:0] axi_apb_bridge_0_M_APB_PREADY_pin;
  input [31:0] axi_apb_bridge_0_M_APB_PRDATA_pin;
  input [31:0] axi_apb_bridge_0_M_APB_PRDATA2_pin;
  input [31:0] axi_apb_bridge_0_M_APB_PRDATA3_pin;
  input [31:0] axi_apb_bridge_0_M_APB_PRDATA4_pin;
  input [3:0] axi_apb_bridge_0_M_APB_PSLVERR_pin;
  output processing_system7_0_S_AXI_HP0_ARREADY_pin;
  output processing_system7_0_S_AXI_HP0_AWREADY_pin;
  output processing_system7_0_S_AXI_HP0_BVALID_pin;
  output processing_system7_0_S_AXI_HP0_RLAST_pin;
  output processing_system7_0_S_AXI_HP0_RVALID_pin;
  output processing_system7_0_S_AXI_HP0_WREADY_pin;
  output [1:0] processing_system7_0_S_AXI_HP0_BRESP_pin;
  output [1:0] processing_system7_0_S_AXI_HP0_RRESP_pin;
  output [5:0] processing_system7_0_S_AXI_HP0_BID_pin;
  output [5:0] processing_system7_0_S_AXI_HP0_RID_pin;
  output [63:0] processing_system7_0_S_AXI_HP0_RDATA_pin;
  input processing_system7_0_S_AXI_HP0_ACLK_pin;
  input processing_system7_0_S_AXI_HP0_ARVALID_pin;
  input processing_system7_0_S_AXI_HP0_AWVALID_pin;
  input processing_system7_0_S_AXI_HP0_BREADY_pin;
  input processing_system7_0_S_AXI_HP0_RREADY_pin;
  input processing_system7_0_S_AXI_HP0_WLAST_pin;
  input processing_system7_0_S_AXI_HP0_WVALID_pin;
  input [1:0] processing_system7_0_S_AXI_HP0_ARBURST_pin;
  input [1:0] processing_system7_0_S_AXI_HP0_ARLOCK_pin;
  input [2:0] processing_system7_0_S_AXI_HP0_ARSIZE_pin;
  input [1:0] processing_system7_0_S_AXI_HP0_AWBURST_pin;
  input [1:0] processing_system7_0_S_AXI_HP0_AWLOCK_pin;
  input [2:0] processing_system7_0_S_AXI_HP0_AWSIZE_pin;
  input [2:0] processing_system7_0_S_AXI_HP0_ARPROT_pin;
  input [2:0] processing_system7_0_S_AXI_HP0_AWPROT_pin;
  input [31:0] processing_system7_0_S_AXI_HP0_ARADDR_pin;
  input [31:0] processing_system7_0_S_AXI_HP0_AWADDR_pin;
  input [3:0] processing_system7_0_S_AXI_HP0_ARCACHE_pin;
  input [3:0] processing_system7_0_S_AXI_HP0_ARLEN_pin;
  input [3:0] processing_system7_0_S_AXI_HP0_ARQOS_pin;
  input [3:0] processing_system7_0_S_AXI_HP0_AWCACHE_pin;
  input [3:0] processing_system7_0_S_AXI_HP0_AWLEN_pin;
  input [3:0] processing_system7_0_S_AXI_HP0_AWQOS_pin;
  input [5:0] processing_system7_0_S_AXI_HP0_ARID_pin;
  input [5:0] processing_system7_0_S_AXI_HP0_AWID_pin;
  input [5:0] processing_system7_0_S_AXI_HP0_WID_pin;
  input [63:0] processing_system7_0_S_AXI_HP0_WDATA_pin;
  input [7:0] processing_system7_0_S_AXI_HP0_WSTRB_pin;

  (* BOX_TYPE = "user_black_box" *)
  ps_module
    ps_module_i (
      .processing_system7_0_MIO ( processing_system7_0_MIO ),
      .processing_system7_0_PS_SRSTB_pin ( processing_system7_0_PS_SRSTB_pin ),
      .processing_system7_0_PS_CLK_pin ( processing_system7_0_PS_CLK_pin ),
      .processing_system7_0_PS_PORB_pin ( processing_system7_0_PS_PORB_pin ),
      .processing_system7_0_DDR_Clk ( processing_system7_0_DDR_Clk ),
      .processing_system7_0_DDR_Clk_n ( processing_system7_0_DDR_Clk_n ),
      .processing_system7_0_DDR_CKE ( processing_system7_0_DDR_CKE ),
      .processing_system7_0_DDR_CS_n ( processing_system7_0_DDR_CS_n ),
      .processing_system7_0_DDR_RAS_n ( processing_system7_0_DDR_RAS_n ),
      .processing_system7_0_DDR_CAS_n ( processing_system7_0_DDR_CAS_n ),
      .processing_system7_0_DDR_WEB_pin ( processing_system7_0_DDR_WEB_pin ),
      .processing_system7_0_DDR_BankAddr ( processing_system7_0_DDR_BankAddr ),
      .processing_system7_0_DDR_Addr ( processing_system7_0_DDR_Addr ),
      .processing_system7_0_DDR_ODT ( processing_system7_0_DDR_ODT ),
      .processing_system7_0_DDR_DRSTB ( processing_system7_0_DDR_DRSTB ),
      .processing_system7_0_DDR_DQ ( processing_system7_0_DDR_DQ ),
      .processing_system7_0_DDR_DM ( processing_system7_0_DDR_DM ),
      .processing_system7_0_DDR_DQS ( processing_system7_0_DDR_DQS ),
      .processing_system7_0_DDR_DQS_n ( processing_system7_0_DDR_DQS_n ),
      .processing_system7_0_DDR_VRN ( processing_system7_0_DDR_VRN ),
      .processing_system7_0_DDR_VRP ( processing_system7_0_DDR_VRP ),
      .processing_system7_0_GPIO_I_pin ( processing_system7_0_GPIO_I_pin ),
      .processing_system7_0_GPIO_O_pin ( processing_system7_0_GPIO_O_pin ),
      .processing_system7_0_GPIO_T_pin ( processing_system7_0_GPIO_T_pin ),
      .processing_system7_0_FCLK_CLK0_pin ( processing_system7_0_FCLK_CLK0_pin ),
      .processing_system7_0_FCLK_CLK1_pin ( processing_system7_0_FCLK_CLK1_pin ),
      .processing_system7_0_FCLK_CLK2_pin ( processing_system7_0_FCLK_CLK2_pin ),
      .processing_system7_0_FCLK_CLK3_pin ( processing_system7_0_FCLK_CLK3_pin ),
      .axi_apb_bridge_0_M_APB_PCLK_pin ( axi_apb_bridge_0_M_APB_PCLK_pin ),
      .axi_apb_bridge_0_M_APB_PRESETN_pin ( axi_apb_bridge_0_M_APB_PRESETN_pin ),
      .axi_apb_bridge_0_M_APB_PADDR_pin ( axi_apb_bridge_0_M_APB_PADDR_pin ),
      .axi_apb_bridge_0_M_APB_PSEL_pin ( axi_apb_bridge_0_M_APB_PSEL_pin ),
      .axi_apb_bridge_0_M_APB_PENABLE_pin ( axi_apb_bridge_0_M_APB_PENABLE_pin ),
      .axi_apb_bridge_0_M_APB_PWRITE_pin ( axi_apb_bridge_0_M_APB_PWRITE_pin ),
      .axi_apb_bridge_0_M_APB_PWDATA_pin ( axi_apb_bridge_0_M_APB_PWDATA_pin ),
      .axi_apb_bridge_0_M_APB_PREADY_pin ( axi_apb_bridge_0_M_APB_PREADY_pin ),
      .axi_apb_bridge_0_M_APB_PRDATA_pin ( axi_apb_bridge_0_M_APB_PRDATA_pin ),
      .axi_apb_bridge_0_M_APB_PRDATA2_pin ( axi_apb_bridge_0_M_APB_PRDATA2_pin ),
      .axi_apb_bridge_0_M_APB_PRDATA3_pin ( axi_apb_bridge_0_M_APB_PRDATA3_pin ),
      .axi_apb_bridge_0_M_APB_PRDATA4_pin ( axi_apb_bridge_0_M_APB_PRDATA4_pin ),
      .axi_apb_bridge_0_M_APB_PSLVERR_pin ( axi_apb_bridge_0_M_APB_PSLVERR_pin ),
      .processing_system7_0_S_AXI_HP0_ARREADY_pin ( processing_system7_0_S_AXI_HP0_ARREADY_pin ),
      .processing_system7_0_S_AXI_HP0_AWREADY_pin ( processing_system7_0_S_AXI_HP0_AWREADY_pin ),
      .processing_system7_0_S_AXI_HP0_BVALID_pin ( processing_system7_0_S_AXI_HP0_BVALID_pin ),
      .processing_system7_0_S_AXI_HP0_RLAST_pin ( processing_system7_0_S_AXI_HP0_RLAST_pin ),
      .processing_system7_0_S_AXI_HP0_RVALID_pin ( processing_system7_0_S_AXI_HP0_RVALID_pin ),
      .processing_system7_0_S_AXI_HP0_WREADY_pin ( processing_system7_0_S_AXI_HP0_WREADY_pin ),
      .processing_system7_0_S_AXI_HP0_BRESP_pin ( processing_system7_0_S_AXI_HP0_BRESP_pin ),
      .processing_system7_0_S_AXI_HP0_RRESP_pin ( processing_system7_0_S_AXI_HP0_RRESP_pin ),
      .processing_system7_0_S_AXI_HP0_BID_pin ( processing_system7_0_S_AXI_HP0_BID_pin ),
      .processing_system7_0_S_AXI_HP0_RID_pin ( processing_system7_0_S_AXI_HP0_RID_pin ),
      .processing_system7_0_S_AXI_HP0_RDATA_pin ( processing_system7_0_S_AXI_HP0_RDATA_pin ),
      .processing_system7_0_S_AXI_HP0_ACLK_pin ( processing_system7_0_S_AXI_HP0_ACLK_pin ),
      .processing_system7_0_S_AXI_HP0_ARVALID_pin ( processing_system7_0_S_AXI_HP0_ARVALID_pin ),
      .processing_system7_0_S_AXI_HP0_AWVALID_pin ( processing_system7_0_S_AXI_HP0_AWVALID_pin ),
      .processing_system7_0_S_AXI_HP0_BREADY_pin ( processing_system7_0_S_AXI_HP0_BREADY_pin ),
      .processing_system7_0_S_AXI_HP0_RREADY_pin ( processing_system7_0_S_AXI_HP0_RREADY_pin ),
      .processing_system7_0_S_AXI_HP0_WLAST_pin ( processing_system7_0_S_AXI_HP0_WLAST_pin ),
      .processing_system7_0_S_AXI_HP0_WVALID_pin ( processing_system7_0_S_AXI_HP0_WVALID_pin ),
      .processing_system7_0_S_AXI_HP0_ARBURST_pin ( processing_system7_0_S_AXI_HP0_ARBURST_pin ),
      .processing_system7_0_S_AXI_HP0_ARLOCK_pin ( processing_system7_0_S_AXI_HP0_ARLOCK_pin ),
      .processing_system7_0_S_AXI_HP0_ARSIZE_pin ( processing_system7_0_S_AXI_HP0_ARSIZE_pin ),
      .processing_system7_0_S_AXI_HP0_AWBURST_pin ( processing_system7_0_S_AXI_HP0_AWBURST_pin ),
      .processing_system7_0_S_AXI_HP0_AWLOCK_pin ( processing_system7_0_S_AXI_HP0_AWLOCK_pin ),
      .processing_system7_0_S_AXI_HP0_AWSIZE_pin ( processing_system7_0_S_AXI_HP0_AWSIZE_pin ),
      .processing_system7_0_S_AXI_HP0_ARPROT_pin ( processing_system7_0_S_AXI_HP0_ARPROT_pin ),
      .processing_system7_0_S_AXI_HP0_AWPROT_pin ( processing_system7_0_S_AXI_HP0_AWPROT_pin ),
      .processing_system7_0_S_AXI_HP0_ARADDR_pin ( processing_system7_0_S_AXI_HP0_ARADDR_pin ),
      .processing_system7_0_S_AXI_HP0_AWADDR_pin ( processing_system7_0_S_AXI_HP0_AWADDR_pin ),
      .processing_system7_0_S_AXI_HP0_ARCACHE_pin ( processing_system7_0_S_AXI_HP0_ARCACHE_pin ),
      .processing_system7_0_S_AXI_HP0_ARLEN_pin ( processing_system7_0_S_AXI_HP0_ARLEN_pin ),
      .processing_system7_0_S_AXI_HP0_ARQOS_pin ( processing_system7_0_S_AXI_HP0_ARQOS_pin ),
      .processing_system7_0_S_AXI_HP0_AWCACHE_pin ( processing_system7_0_S_AXI_HP0_AWCACHE_pin ),
      .processing_system7_0_S_AXI_HP0_AWLEN_pin ( processing_system7_0_S_AXI_HP0_AWLEN_pin ),
      .processing_system7_0_S_AXI_HP0_AWQOS_pin ( processing_system7_0_S_AXI_HP0_AWQOS_pin ),
      .processing_system7_0_S_AXI_HP0_ARID_pin ( processing_system7_0_S_AXI_HP0_ARID_pin ),
      .processing_system7_0_S_AXI_HP0_AWID_pin ( processing_system7_0_S_AXI_HP0_AWID_pin ),
      .processing_system7_0_S_AXI_HP0_WID_pin ( processing_system7_0_S_AXI_HP0_WID_pin ),
      .processing_system7_0_S_AXI_HP0_WDATA_pin ( processing_system7_0_S_AXI_HP0_WDATA_pin ),
      .processing_system7_0_S_AXI_HP0_WSTRB_pin ( processing_system7_0_S_AXI_HP0_WSTRB_pin )
    );
endmodule 
一気に信号が増えましたが、「axi_apb_bridge_0_M_APB」がAPB関連、「processing_system7_0_S_AXI_HP0」がAXI_HP関連です。基本一対一でつなぐだけなので、私はエディタのコピペと置換とマクロで半自動的につないでます。ところで、自動的にできるんならツールに任せようよ、ってできたツールがSOPC Builder、Qsys、XPSなどです。

XPSの作業は終了。後は普通にロジック作るだけです。
nice!(0)  トラックバック(0) 

ZedBoard Linux (4) [FPGA]

ちょっと空きましたが、続き。
ZynqのFPGA部分が空っぽになったところで、改めて使い方を考えてみます。

私がZynqを使うときは大体、
・DDRメモリに直接のデータを出し入れするペリフェラルを作る。画像とかパケットとか音声とか色々。
・CPUはその管理。ちょっとデータ処理も行う。
というパターンがほとんどです。

一方、LinuxなどOSを使いたい理由は
・ネットワークアプリが作りやすい
・リモート管理がやりたい
・ファイルシステムが便利
などなどで、実はデータ処理にはあまり関連しません。

FPGA側のメモリの使い方を見てると、いったん確保したら電源切るまで二度と開放しない事もあります。Linuxのダイナミックなメモリ管理の機能はFPGAのロジックには必要なかったりします。逆に複雑なメモリ管理機構は邪魔になりかねません。
※PCのGPGPUでも似た問題が起きますよね。こちらはがんばってGPUがCPUのメモリ空間に合わせようとしています。コヒーレンシーの採れた共通アドレス空間が使えるようなシステムに向かってる感じでしょうか。

そう考えると、DDRメモリはできるだけFPGA側に開放して、Linuxはできるだけ小さくまとまってくれてた方が便利です。物理的に別のメモリになってくれてるとより良いんですけどね。terasicのSoCKitはHPSとFPGA個別にDDRメモリが付いてて良さげです。
解放されたメモリ領域はLinuxの管理外領域として、単なるI/Oとして認識してくれればOKです。FPGAを使うときはLinuxは主役ではありません。※Linuxが主役なら多分FPGA内部のCPUは使いません。
例えば、ZedBoardのZynqが管理している512MBのメモリのうち、384MBを確保してDMAが使える連続空間にマップする、しかも電源切るまで確保しっぱなし、なんて使い方なら、最初からLinuxが使う空間を下位128MBに切っておいて、残りは管理外とした方がスマートだと思います。

それをやるオプションは…devicetreeにあるbootargsだけで良いのかな?
bootargs = "mem=128M console=ttyPS0,115200 root=/dev/ram rw initrd=0x800000,8M earlyprintk rootwait devtmpfs.mount=1";
「mem=128M」が追加オプション。…え?ホント?これだけで良いの?
ps7_ddr_0: memory@0 {
	device_type = "memory";
	reg = < 0x0 0x20000000 >;
};
それともこっち?

とりあえず「mem=128M」だけつけて、なんか騙されてるような気分のままブート。
[    0.000000] Kernel command line: mem=128M console=ttyPS0,115200 root=/dev/ram rw initrd=0x800000,8M earlyprintk rootwait devtmpfs.mount=1
[    0.000000] PID hash table entries: 512 (order: -1, 2048 bytes)
[    0.000000] Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
[    0.000000] Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] Memory: 128MB = 128MB total
[    0.000000] Memory: 116588k/116588k available, 14484k reserved, 0K highmem
…
zynq> cat /proc/meminfo
MemTotal:         124928 kB
MemFree:          105980 kB
Buffers:             284 kB
Cached:             3496 kB
SwapCached:            0 kB
Active:             2720 kB
Inactive:           2388 kB
Active(anon):       1336 kB
Inactive(anon):       56 kB
Active(file):       1384 kB
Inactive(file):     2332 kB
Unevictable:           0 kB
Mlocked:               0 kB
HighTotal:             0 kB
HighFree:              0 kB
LowTotal:         124928 kB
LowFree:          105980 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:          1344 kB
Mapped:             1344 kB
Shmem:                64 kB
Slab:               4236 kB
SReclaimable:       1912 kB
SUnreclaim:         2324 kB
KernelStack:         336 kB
PageTables:          204 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:       62464 kB
Committed_AS:       4812 kB
VmallocTotal:     860160 kB
VmallocUsed:         376 kB
VmallocChunk:     777856 kB
なったっぽい。
…ホントか?これで残りの384MBは管理外のメモリとしてDMAとかで荒らしちゃっても良いのか?

なんかすごく不安なので、確認用のハードウェアをつないでみたいと思います。

ZedBoard Linux (3) [FPGA]

FPGAをカスタマイズしてみます。
…じゃなくて、標準デザインで色々付いてるPLのハードウェアを全部無くして、PSブロックだけで動作させます。自分のロジックを足すときのベースになります。だいたいZynqのチュートリアルに出てる手順です。

標準デザインではProject NavigatorやPlanAheadを使わず、XPSだけでFPGAを作っています。あまり一般的では無いと思います。XPSで扱える形式(pcore)でしか作れず、階層化も困難です。マイコン形式のプロセッサを中心としたシステムがトップデザインになる場合は便利なのでしょう(Suzakuもこの形式だったと記憶してます)。自分としてはあまり便利と思わないのですが…
XPSもプロセッサをただの部品として扱い、接続することをメインに考えたツールになれば良いのになぁと思います。その点AlteraのQsys、SOPC Builderは好みです。

ということで、プロジェクトのトップはPlanAheadで作成します。
テンプレートで入ってるZedBoardをターゲットにして空のプロジェクトを作ります。Add Sources → Add or Create Embedded Sources → Create Sub-Design、「ps_module」とか名前付けてFinishするとXPSが立ち上がります。「PSを追加するか?」というダイアログが出てくるので、ここではYesです。
Image 001.png
ボードやLinuxへのインパクトは少なくしたいので、PSの設定は標準のデザインと同じにしたいところです。標準の設定をImportするのが一番簡単ですかね。色々な設定を忘れずにすみます。
「Import」アイコンを押すとこんな画面が出てきます。
Image 002.png
「User Template」の所に標準デザインのxmlを足します。これを選んでOKすると設定が反映されます。「System Template」の「ZedBoard Development Board Template」もだいたい同じ内容でした。
Image 003.png

ちょっと変更します。EMIO GPIOをFPGA内部で使えるようにします。
Image 004.png
EMIO GPIOを有効にして本数を指定します。
Image 005.png
外部ポートに出します。このときI/Oを出した場合はFPGAのI/Oピンに接続することになります。内部で使う場合は_I、_O、_Tをそれぞれ出します。_Iは入力、_Oは出力、_Tも出力として使えます。
アドレスは標準のまま。
Image 006.png
PLに渡すクロックは適当に設定します。外部の33.333MHzを基準にした周波数が作れます。
Image 007.png

XPSを閉じるとPlanAheadに戻ります。
できた「Design Sources」の「ps_module」を右クリックして「Create Top HDL」を選びます。「ps_module_stub.v(vhd)」ができあがります。これをそのままトップとして使ってもかまいませんし、別途top.vを作ってもかまいません。_stubはPSを変更して「Create Top HDL」を行うたびに上書きされてしまうので、別途トップを作り、コピペすることにします。
module top
    (
        inout    wire    [53:0]    MIO,
        input    wire            PS_SRSTB,
        input    wire            PS_CLK,
        input    wire            PS_PORB,
        inout    wire            DDR_Clk,
        inout    wire            DDR_Clk_n,
        inout    wire            DDR_CKE,
        inout    wire            DDR_CS_n,
        inout    wire            DDR_RAS_n,
        inout    wire            DDR_CAS_n,
        output    wire            DDR_WEB,
        inout    wire    [2:0]    DDR_BankAddr,
        inout    wire    [14:0]    DDR_Addr,
        inout    wire            DDR_ODT,
        inout    wire            DDR_DRSTB,
        inout    wire    [31:0]    DDR_DQ,
        inout    wire    [3:0]    DDR_DM,
        inout    wire    [3:0]    DDR_DQS,
        inout    wire    [3:0]    DDR_DQS_n,
        inout    wire            DDR_VRN,
        inout    wire            DDR_VRP
    );

    wire    [63:0]    EMIO_GPIO_I;
    wire    [63:0]    EMIO_GPIO_O;
    wire    [63:0]    EMIO_GPIO_T;
    wire            FCLK_CLK0;
    wire            FCLK_CLK1;
    wire            FCLK_CLK2;
    wire            FCLK_CLK3;

    (* BOX_TYPE = "user_black_box" *)
    ps_module
    ps_module_i (
        .processing_system7_0_MIO            (MIO            ),
        .processing_system7_0_PS_SRSTB_pin    (PS_SRSTB        ),
        .processing_system7_0_PS_CLK_pin    (PS_CLK            ),
        .processing_system7_0_PS_PORB_pin    (PS_PORB        ),
        .processing_system7_0_DDR_Clk        (DDR_Clk        ),
        .processing_system7_0_DDR_Clk_n        (DDR_Clk_n        ),
        .processing_system7_0_DDR_CKE        (DDR_CKE        ),
        .processing_system7_0_DDR_CS_n        (DDR_CS_n        ),
        .processing_system7_0_DDR_RAS_n        (DDR_RAS_n        ),
        .processing_system7_0_DDR_CAS_n        (DDR_CAS_n        ),
        .processing_system7_0_DDR_WEB_pin    (DDR_WEB        ),
        .processing_system7_0_DDR_BankAddr    (DDR_BankAddr    ),
        .processing_system7_0_DDR_Addr        (DDR_Addr        ),
        .processing_system7_0_DDR_ODT        (DDR_ODT        ),
        .processing_system7_0_DDR_DRSTB        (DDR_DRSTB        ),
        .processing_system7_0_DDR_DQ        (DDR_DQ            ),
        .processing_system7_0_DDR_DM        (DDR_DM            ),
        .processing_system7_0_DDR_DQS        (DDR_DQS        ),
        .processing_system7_0_DDR_DQS_n        (DDR_DQS_n        ),
        .processing_system7_0_DDR_VRN        (DDR_VRN        ),
        .processing_system7_0_DDR_VRP        (DDR_VRP        ),
        .processing_system7_0_GPIO_I_pin    (EMIO_GPIO_I    ),
        .processing_system7_0_GPIO_O_pin    (EMIO_GPIO_O    ),
        .processing_system7_0_GPIO_T_pin    (EMIO_GPIO_T    ),
        .processing_system7_0_FCLK_CLK0_pin    (FCLK_CLK0        ),
        .processing_system7_0_FCLK_CLK1_pin    (FCLK_CLK1        ),
        .processing_system7_0_FCLK_CLK2_pin    (FCLK_CLK2        ),
        .processing_system7_0_FCLK_CLK3_pin    (FCLK_CLK3        )
    );

endmodule
PL内部ではなにもしていません。ハードマクロ側のピン名はどうでも良いみたいですw。

このままインプリします。ハードマクロ側のピンや制約は自動生成されます。というかピンは固定なので動きませんが。
なんとまぁ、これだけでCritical Warningが6個も出ます。PORBとSRSTBとCLKにIBUFが入らないよ~というワーニング。ハードマクロ側のピンなので手が出ません。Xilinxのアンサーでは「無視してくれ」とのこと。昔から似たようなバグがあり続けて一向に直る気配が無いんですが…
こういう、誰もが必ず当たるところにバグがあるから「Xilinxってまともに検証してないでしょ?他の所もバグだらけなんじゃね?」って疑ってしまうんですよ~実際あちらこちらにバグあるし。
CriticalでもWarningなので、そのままインプリは進みます。PLが空なので、実はビットストリームいりません。Zynqはハードマクロだけで動けます。

できあがったら、File → Export → Export Hardware for SDKを選びます。デフォルトでは「プロジェクト名.sdk\SDK\SDK_Export」にSDKのワークスペースができます。後はこれを元に(1)と同じ手順でFSBL~BOOT.BINを作ります。
今度は試しにWindows上のSDKで作ってみます。u-boot.elfはLinuxで作ったのをコピーしておきます。
Image 008.pngImage 009.pngImage 010.png
操作は全く同じ。「.\FSBL\bootimage\u-boot.bin」ができるのでこれをBOOT.BINにします。

DeviceTreeの編集。
やっぱりまだよくわからない点が多いので、標準の「devicetree.dts」を編集します。といってもハードマクロに載ってるペリフェラル以外を削除していくだけです。「ps7_ddr_0」や「ps7_axi_interconnect_0」など、「ps7_」で始まってるのはハードマクロのペリフェラルです。アドレスも決まってるので変更する必要ないです。それ以外のエントリー「axi_vdma_0」「axi_iic_hdmi」などを削除します。
/*
 * digilent-zed.dts - Default Device Tree for ZedBoard
 * 
 * (C) Copyright 2012 Digilent, Inc.
 * 
 * Code based on Device Tree Generator version: 1.1
 *
 * (C) Copyright 2007-2012 Xilinx, Inc.
 * (C) Copyright 2007-2012 Michal Simek
 * (C) Copyright 2007-2012 PetaLogix Qld Pty Ltd
 *
 * Michal SIMEK 
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 *
 * CAUTION: This file is automatically generated by libgen.
 * Version: Xilinx EDK 14.4 EDK_P.49d
 * Today is: Wednesday, the 26 of December, 2012; 15:18:18
 *
 * XPS project directory: device-tree_bsp_0
 */

/dts-v1/;
/ {
	#address-cells = <1>;
	#size-cells = <1>;
	compatible = "xlnx,zynq-zed";
	model = "Xilinx Zynq ZED";

	aliases {
		ethernet0 = &ps7_ethernet_0;
		serial0 = &ps7_uart_1;
	};

	chosen {
		/*bootargs = "console=ttyPS0,115200 root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait devtmpfs.mount=1";*/
		bootargs = "console=ttyPS0,115200 root=/dev/ram rw initrd=0x800000,8M earlyprintk rootwait devtmpfs.mount=1";
		linux,stdout-path = "/axi@0/serial@e0001000";
	};

	cpus {
		#address-cells = <1>;
		#cpus = <0x2>;
		#size-cells = <0>;
		ps7_cortexa9_0: cpu@0 {
			clock-frequency = <666666687>;
			compatible = "xlnx,ps7-cortexa9-1.00.a";
			d-cache-line-size = <0x20>;
			d-cache-size = <0x8000>;
			device_type = "cpu";
			i-cache-line-size = <0x20>;
			i-cache-size = <0x8000>;
			model = "ps7_cortexa9,1.00.a";
			reg = <0>;
			timebase-frequency = <333333343>;
			xlnx,cpu-1x-clk-freq-hz = <0x69f6bcb>;
			xlnx,cpu-clk-freq-hz = <0x27bc86bf>;
		};
		ps7_cortexa9_1: cpu@1 {
			clock-frequency = <666666687>;
			compatible = "xlnx,ps7-cortexa9-1.00.a";
			d-cache-line-size = <0x20>;
			d-cache-size = <0x8000>;
			device_type = "cpu";
			i-cache-line-size = <0x20>;
			i-cache-size = <0x8000>;
			model = "ps7_cortexa9,1.00.a";
			reg = <1>;
			timebase-frequency = <333333343>;
			xlnx,cpu-1x-clk-freq-hz = <0x69f6bcb>;
			xlnx,cpu-clk-freq-hz = <0x27bc86bf>;
		};
	};

	ps7_ddr_0: memory@0 {
		device_type = "memory";
		reg = < 0x0 0x20000000 >;
	};

	ps7_axi_interconnect_0: axi@0 {
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "xlnx,ps7-axi-interconnect-1.00.a", "simple-bus";
		ranges;

		/* PS system internal devices */
		ps7_afi_0: ps7-afi@f8008000 {
			compatible = "xlnx,ps7-afi-1.00.a";
			reg = < 0xf8008000 0x1000 >;
		};
		ps7_afi_1: ps7-afi@f8009000 {
			compatible = "xlnx,ps7-afi-1.00.a";
			reg = < 0xf8009000 0x1000 >;
		};
		ps7_afi_2: ps7-afi@f800a000 {
			compatible = "xlnx,ps7-afi-1.00.a";
			reg = < 0xf800a000 0x1000 >;
		};
		ps7_afi_3: ps7-afi@f800b000 {
			compatible = "xlnx,ps7-afi-1.00.a";
			reg = < 0xf800b000 0x1000 >;
		};

		ps7_ddrc_0: ps7-ddrc@f8006000 {
			compatible = "xlnx,ps7-ddrc-1.00.a";
			reg = < 0xf8006000 0x1000 >;
			xlnx,has-ecc = <0x0>;
		};

		ps7_dev_cfg_0: ps7-dev-cfg@f8007000 {
			compatible = "xlnx,ps7-dev-cfg-1.00.a";
			interrupt-parent = <&ps7_scugic_0>;
			interrupts = < 0 8 4 >;
			reg = < 0xf8007000 0x1000 >;
		};

		ps7_dma_ns: ps7-dma@f8004000 {
			compatible = "xlnx,ps7-dma-1.00.a", "arm,pl330";
			interrupt-parent = <&ps7_scugic_0>;
			interrupts = < 0 13 4 0 14 4 0 15 4 0 16 4 0 17 4 0 40 4 0 41 4 0 42 4 0 43 4 >;
			reg = < 0xf8004000 0x1000 >;
		};

		ps7_dma_s: ps7-dma@f8003000 {
			compatible = "xlnx,ps7-dma-1.00.a", "arm,pl330";
			interrupt-parent = <&ps7_scugic_0>;
			interrupts = < 0 13 4 0 14 4 0 15 4 0 16 4 0 17 4 0 40 4 0 41 4 0 42 4 0 43 4 >;
			reg = < 0xf8003000 0x1000 >;
		};

		ps7_ethernet_0: ps7-ethernet@e000b000 {
			#address-cells = <1>;
			#size-cells = <0>;
			compatible = "xlnx,ps7-ethernet-1.00.a";
			interrupt-parent = <&ps7_scugic_0>;
			interrupts = < 0 22 4 >;
			local-mac-address = [ 00 0a 35 00 00 00 ];
			phy-handle = <&phy0>;
			reg = < 0xe000b000 0x1000 >;
			xlnx,enet-clk-freq-hz = <0x7735940>;
			xlnx,enet-reset = <0xffffffff>;
			xlnx,enet-slcr-1000mbps-div0 = <0x8>;
			xlnx,enet-slcr-1000mbps-div1 = <0x1>;
			xlnx,enet-slcr-100mbps-div0 = <0x8>;
			xlnx,enet-slcr-100mbps-div1 = <0x5>;
			xlnx,enet-slcr-10mbps-div0 = <0x8>;
			xlnx,enet-slcr-10mbps-div1 = <0x32>;
			xlnx,eth-mode = <0x1>;
			xlnx,has-mdio = <0x1>;
			xlnx,ptp-enet-clock = <111111115>;

			mdio {
				#address-cells = <1>;
				#size-cells = <0>;
				phy0: phy@0 {
					compatible = "marvell,88e1510";
					device_type = "ethernet-phy";
					reg = <0>;
					marvell,reg-init = <0x3 0x10 0xff00 0x1e 0x3 0x11 0xfff0 0xa>;
				};
			};
		};

		ps7_gpio_0: ps7-gpio@e000a000 {
			#gpio-cells = <2>;
			compatible = "xlnx,ps7-gpio-1.00.a";
			emio-gpio-width = <60>;
			gpio-controller;
			gpio-mask-high = <0xc0000>;
			gpio-mask-low = <0xfe81>;
			interrupt-parent = <&ps7_scugic_0>;
			interrupts = < 0 20 4 >;
			reg = < 0xe000a000 0x1000 >;
		};

		ps7_iop_bus_config_0: ps7-iop-bus-config@e0200000 {
			compatible = "xlnx,ps7-iop-bus-config-1.00.a";
			reg = < 0xe0200000 0x1000 >;
		};

		ps7_pl310_0: ps7-pl310@f8f02000 {
			arm,data-latency = < 3 2 2 >;
			arm,tag-latency = < 2 2 2 >;
			cache-level = < 2 >;
			cache-unified;
			compatible = "xlnx,ps7-pl310-1.00.a", "arm,pl310-cache";
			reg = < 0xf8f02000 0x1000 >;
		};

		ps7_qspi_0: ps7-qspi@e000d000 {
			bus-num = <0>;
			compatible = "xlnx,ps7-qspi-1.00.a";
			interrupt-parent = <&ps7_scugic_0>;
			interrupts = < 0 19 4 >;
			is-dual = <0>;
			num-chip-select = <1>;
			reg = < 0xe000d000 0x1000 >;
			speed-hz = <200000000>;
			xlnx,fb-clk = <0x1>;
			xlnx,qspi-clk-freq-hz = <0xbebc200>;
			xlnx,qspi-mode = <0x0>;
		};

		ps7_qspi_linear_0: ps7-qspi-linear@fc000000 {
			compatible = "xlnx,ps7-qspi-linear-1.00.a";
			reg = < 0xfc000000 0x1000000 >;
			xlnx,qspi-clk-freq-hz = <0xe4e1c0>;
		};

		ps7_scugic_0: ps7-scugic@f8f01000 {
			#address-cells = < 2 >;
			#interrupt-cells = < 3 >;
			#size-cells = < 1 >;
			compatible = "xlnx,ps7-scugic-1.00.a", "arm,cortex-a9-gic", "arm,gic";
			interrupt-controller;
			linux,phandle = < 0x1 >;
			phandle = < 0x1 >;
			reg = < 0xf8f01000 0x1000 0xf8f00100 0x100 >;
		};

		ps7_scutimer_0: ps7-scutimer@f8f00600 {
			clock-frequency = <333333343>;
			compatible = "xlnx,ps7-scutimer-1.00.a", "arm,cortex-a9-twd-timer";
			interrupt-parent = <&ps7_scugic_0>;
			interrupts = < 1 13 769 >;
			reg = < 0xf8f00600 0x20 >;
		};

		ps7_scuwdt_0: ps7-scuwdt@f8f00620 {
			clock-frequency = <333333343>;
			/* clock-frequency = <111111111>; */
			compatible = "xlnx,ps7-scuwdt-1.00.a";
			device_type = "watchdog";
			interrupt-parent = <&ps7_scugic_0>;
			interrupts = < 1 14 769 >;
			reg = < 0xf8f00620 0xe0 >;
		};

		ps7_sd_0: ps7-sdio@e0100000 {
			clock-frequency = <50000000>;
			compatible = "xlnx,ps7-sdio-1.00.a", "generic-sdhci";
			interrupt-parent = <&ps7_scugic_0>;
			interrupts = < 0 24 4 >;
			reg = < 0xe0100000 0x1000 >;
			xlnx,has-cd = <0x1>;
			xlnx,has-power = <0x0>;
			xlnx,has-wp = <0x1>;
			xlnx,sdio-clk-freq-hz = <0x2faf080>;
			/* clock-frequency = <0x1fc9f08>; */
		};

		ps7_slcr_0: ps7-slcr@f8000000 {
			compatible = "xlnx,ps7-slcr-1.00.a";
			reg = < 0xf8000000 0x1000 >;
		};

		ps7_ttc_0: ps7-ttc@f8001000 {
			clock-frequency = <111111115>;
			clock-frequency-timer0 = <111111115>;
			clock-frequency-timer1 = <111111115>;
			clock-frequency-timer2 = <111111115>;
			compatible = "xlnx,ps7-ttc-1.00.a";
			interrupt-parent = <&ps7_scugic_0>;
			interrupts = < 0 10 4 0 11 4 0 12 4 >;
			reg = < 0xf8001000 0x1000 >;
			xlnx,ttc-clk0-clksrc = <0x0>;
			xlnx,ttc-clk0-freq-hz = <0x69f6bcb>;
			xlnx,ttc-clk1-clksrc = <0x0>;
			xlnx,ttc-clk1-freq-hz = <0x69f6bcb>;
			xlnx,ttc-clk2-clksrc = <0x0>;
			xlnx,ttc-clk2-freq-hz = <0x69f6bcb>;
		};

		ps7_uart_1: serial@e0001000 {
			clock = <50000000>;
			clock-frequency = <50000000>;
			compatible = "xlnx,ps7-uart-1.00.a", "xlnx,xuartps";
			current-speed = <115200>;
			device_type = "serial";
			interrupt-parent = <&ps7_scugic_0>;
			interrupts = < 0 50 4 >;
			port-number = <0>;
			reg = < 0xe0001000 0x1000 >;
			xlnx,has-modem = <0x0>;
			xlnx,uart-clk-freq-hz = <0x2faf080>;
		};

		ps7_usb_0: ps7-usb@e0002000 {
			compatible = "xlnx,ps7-usb-1.00.a";
			dr_mode = "host";
			interrupt-parent = <&ps7_scugic_0>;
			interrupts = < 0 21 4 >;
			phy_type = "ulpi";
			reg = < 0xe0002000 0x1000 >;
			xlnx,usb-reset = <0xffffffff>;
		};

		ps7_xadc: ps7_xadc@f8007100 {
			compatible = "xlnx,ps7-xadc-1.00.a";
			interrupts = < 0 7 4 >;
			reg = < 0xf8007100 0x20 >;
		};

	};
};
以前と同様に
~/linux-digilent/scripts/dtc/dtc -I dts -O dtb -o devicetree.dtb devicetree.dts
でdtbにコンパイル。

これで必要なファイルがそろったので、SDカードにコピーします。zImageとramdiskは前のままです。
U-Boot 2012.04.01 (Sep 25 2013 - 00:19:21)

DRAM:  512 MiB
WARNING: Caches not enabled
MMC:   SDHCI: 0
Using default environment

In:    serial
Out:   serial
Err:   serial
Net:   zynq_gem
Hit any key to stop autoboot:  0
Copying Linux from SD to RAM...
Device: SDHCI
Manufacturer ID: 1d
OEM: 4144
Name: SD
Tran Speed: 25000000
Rd Block Len: 512
SD version 1.10
High Capacity: No
Capacity: 1.9 GiB
Bus Width: 4-bit
reading zImage

2527040 bytes read
reading devicetree.dtb

6481 bytes read
reading ramdisk8M.image.gz

3698068 bytes read
## Starting application at 0x00008000 ...
Uncompressing Linux... done, booting the kernel.
[    0.000000] Booting Linux on physical CPU 0
[    0.000000] Linux version 3.6.0-digilent-13.01-00002-g06b3889 (develop@vm-ubuntu) (gcc version 4.7.2 (Sourcery CodeBench Lite 2012.09-104) ) #1 SMP PREEMPT Wed Sep 25 00:32:40 JST 2013
[    0.000000] CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=18c5387d
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[    0.000000] Machine: Xilinx Zynq Platform, model: Xilinx Zynq ZED
[    0.000000] Memory policy: ECC disabled, Data cache writealloc
[    0.000000] PERCPU: Embedded 7 pages/cpu @c1408000 s6976 r8192 d13504 u32768
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 130048
[    0.000000] Kernel command line: console=ttyPS0,115200 root=/dev/ram rw initrd=0x800000,8M earlyprintk rootwait devtmpfs.mount=1
[    0.000000] PID hash table entries: 2048 (order: 1, 8192 bytes)
[    0.000000] Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)
[    0.000000] Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)
[    0.000000] Memory: 512MB = 512MB total
[    0.000000] Memory: 506432k/506432k available, 17856k reserved, 0K highmem
[    0.000000] Virtual kernel memory layout:
[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.000000]     fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
[    0.000000]     vmalloc : 0xe0800000 - 0xfd000000   ( 456 MB)
[    0.000000]     lowmem  : 0xc0000000 - 0xe0000000   ( 512 MB)
[    0.000000]     pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB)
[    0.000000]     modules : 0xbf000000 - 0xbfe00000   (  14 MB)
[    0.000000]       .text : 0xc0008000 - 0xc0473a60   (4527 kB)
[    0.000000]       .init : 0xc0474000 - 0xc0499b40   ( 151 kB)
[    0.000000]       .data : 0xc049a000 - 0xc04d4ae0   ( 235 kB)
[    0.000000]        .bss : 0xc04d4b04 - 0xc04ee100   ( 102 kB)
[    0.000000] Preemptible hierarchical RCU implementation.
[    0.000000]  Dump stacks of tasks blocking RCU-preempt GP.
[    0.000000]  RCU restricting CPUs from NR_CPUS=4 to nr_cpu_ids=2.
[    0.000000] NR_IRQS:512
[    0.000000] Zynq clock init
[    0.000000] xlnx,ps7-ttc-1.00.a #0 at 0xe0800000, irq=43
[    0.000000] sched_clock: 32 bits at 100 Hz, resolution 10000000ns, wraps every 4294967286ms
[    0.000000] Console: colour dummy device 80x30
[    0.090000] Calibrating delay loop... 1332.01 BogoMIPS (lpj=6660096)
[    0.090000] pid_max: default: 32768 minimum: 301
[    0.090000] Mount-cache hash table entries: 512
[    0.090000] CPU: Testing write buffer coherency: ok
[    0.090000] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
[    0.090000] hw perfevents: enabled with ARMv7 Cortex-A9 PMU driver, 7 counters available
[    0.090000] Setting up static identity map for 0x32be88 - 0x32bebc
[    0.090000] L310 cache controller enabled
[    0.090000] l2x0: 8 ways, CACHE_ID 0x410000c8, AUX_CTRL 0x72360000, Cache size: 524288 B
[    0.130000] Map SLCR registers
[    0.130000] CPU1: Booted secondary processor
[    0.220000] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
[    0.220000] Brought up 2 CPUs
[    0.220000] SMP: Total of 2 processors activated (2664.03 BogoMIPS).
[    0.220000] devtmpfs: initialized
[    0.220000] NET: Registered protocol family 16
[    0.220000] DMA: preallocated 256 KiB pool for atomic coherent allocations
[    0.220000] xgpiops e000a000.ps7-gpio: gpio at 0xe000a000 mapped to 0xe084a000
[    0.230000] registering platform device 'pl330' id 0
[    0.230000] registering platform device 'arm-pmu' id 0
[    0.230000] registering platform device 'zynq-dvfs' id 0
[    0.230000]
[    0.230000] ###############################################
[    0.230000] #                                             #
[    0.230000] #                Board ZED Init               #
[    0.230000] #                                             #
[    0.230000] ###############################################
[    0.230000]
[    0.230000] hw-breakpoint: found 5 (+1 reserved) breakpoint and 1 watchpoint registers.
[    0.230000] hw-breakpoint: maximum watchpoint size is 4 bytes.
[    0.250000] xslcr xslcr.0: at 0xF8000000 mapped to 0xF8000000
[    0.260000] bio: create slab  at 0
[    0.270000] SCSI subsystem initialized
[    0.270000] usbcore: registered new interface driver usbfs
[    0.270000] usbcore: registered new interface driver hub
[    0.270000] usbcore: registered new device driver usb
[    0.270000] Advanced Linux Sound Architecture Driver Version 1.0.25.
[    0.270000] Switching to clocksource xttcpss_timer1
[    0.280000] NET: Registered protocol family 2
[    0.280000] TCP established hash table entries: 16384 (order: 5, 131072 bytes)
[    0.280000] TCP bind hash table entries: 16384 (order: 5, 131072 bytes)
[    0.280000] TCP: Hash tables configured (established 16384 bind 16384)
[    0.280000] TCP: reno registered
[    0.280000] UDP hash table entries: 256 (order: 1, 8192 bytes)
[    0.280000] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes)
[    0.280000] NET: Registered protocol family 1
[    0.280000] RPC: Registered named UNIX socket transport module.
[    0.280000] RPC: Registered udp transport module.
[    0.280000] RPC: Registered tcp transport module.
[    0.280000] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    0.280000] Trying to unpack rootfs image as initramfs...
[    0.280000] rootfs image is not initramfs (no cpio magic); looks like an initrd
[    0.320000] Freeing initrd memory: 8192K
[    0.320000] pl330 dev 0 probe success
[    0.320000] msgmni has been set to 1005
[    0.320000] io scheduler noop registered
[    0.320000] io scheduler deadline registered
[    0.320000] io scheduler cfq registered (default)
[    0.320000] e0001000.serial: ttyPS0 at MMIO 0xe0001000 (irq = 82) is a xuartps
[    0.830000] console [ttyPS0] enabled
[    0.840000] xdevcfg f8007000.ps7-dev-cfg: ioremap f8007000 to e0850000 with size 1000
[    0.840000] [drm] Initialized drm 1.1.0 20060810
[    0.860000] brd: module loaded
[    0.870000] loop: module loaded
[    0.870000] xqspips e000d000.ps7-qspi: master is unqueued, this is deprecated
[    0.880000] xqspips e000d000.ps7-qspi: at 0xE000D000 mapped to 0xE0852000, irq=51
[    0.890000] libphy: XEMACPS mii bus: probed
[    0.900000] xemacps e000b000.ps7-ethernet: pdev->id -1, baseaddr 0xe000b000, irq 54
[    0.900000] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[    0.910000] usb_hcd_xusbps_probe: No OTG assigned!
[    0.910000] usb_hcd_xusbps_probe: OTG now assigned!
[    0.920000] xusbps-ehci xusbps-ehci.0: Xilinx PS USB EHCI Host Controller
[    0.930000] xusbps-ehci xusbps-ehci.0: new USB bus registered, assigned bus number 1
[    0.960000] xusbps-ehci xusbps-ehci.0: irq 53, io mem 0x00000000
[    0.980000] xusbps-ehci xusbps-ehci.0: USB 2.0 started, EHCI 1.00
[    0.980000] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
[    0.990000] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    1.000000] usb usb1: Product: Xilinx PS USB EHCI Host Controller
[    1.000000] usb usb1: Manufacturer: Linux 3.6.0-digilent-13.01-00002-g06b3889 ehci_hcd
[    1.010000] usb usb1: SerialNumber: xusbps-ehci.0
[    1.010000] hub 1-0:1.0: USB hub found
[    1.020000] hub 1-0:1.0: 1 port detected
[    1.020000] Initializing USB Mass Storage driver...
[    1.030000] usbcore: registered new interface driver usb-storage
[    1.030000] USB Mass Storage support registered.
[    1.040000] mousedev: PS/2 mouse device common for all mice
[    1.040000] sdhci: Secure Digital Host Controller Interface driver
[    1.050000] sdhci: Copyright(c) Pierre Ossman
[    1.060000] sdhci-pltfm: SDHCI platform and OF driver helper
[    1.060000] mmc0: Invalid maximum block size, assuming 512 bytes
[    1.110000] mmc0: SDHCI controller on e0100000.ps7-sdio [e0100000.ps7-sdio] using ADMA
[    1.120000] usbcore: registered new interface driver usbhid
[    1.130000] usbhid: USB HID core driver
[    1.140000] TCP: cubic registered
[    1.150000] NET: Registered protocol family 17
[    1.150000] VFP support v0.3: implementor 41 architecture 3 part 30 variant 9 rev 4
[    1.160000] Registering SWP/SWPB emulation handler
[    1.160000] registered taskstats version 1
[    1.170000] drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
[    1.170000] mmc0: SD Status: Invalid Allocation Unit size.
[    1.180000] mmc0: new high speed SD card at address b368
[    1.180000] mmcblk0: mmc0:b368 SD    1.86 GiB
[    1.190000] ALSA device list:
[    1.190000]  mmcblk0: p1
[    1.190000]   No soundcards found.
[    1.200000] RAMDISK: gzip image found at block 0
[    1.510000] EXT4-fs (ram0): couldn't mount as ext3 due to feature incompatibilities
[    1.570000] EXT4-fs (ram0): mounting ext2 file system using the ext4 subsystem
[    1.570000] EXT4-fs (ram0): warning: mounting unchecked fs, running e2fsck is recommended
[    1.580000] EXT4-fs (ram0): mounted filesystem without journal. Opts: (null)
[    1.590000] VFS: Mounted root (ext2 filesystem) on device 1:0.
[    1.590000] devtmpfs: mounted
[    1.600000] Freeing init memory: 148K
Starting rcS...
++ Mounting filesystem
++ Setting up mdev
++ Configure static IP 192.168.1.10
++ Starting telnet daemon
++ Starting http daemon
++ Starting ftp daemon
++ Starting dropbear (ssh) daemon
++ Starting OLED Display
insmod: can't read '/lib/modules/3.6.0-digilent-13.01-00002-g06b3889/pmodoled-gpio.ko': No such file or directory
++ Exporting LEDs & SWs
rcS Complete
zynq> [    6.820000] xemacps e000b000.ps7-ethernet: Set clk to 124999998 Hz
[    6.820000] xemacps e000b000.ps7-ethernet: link up (1000/FULL)
なんか普通に立ち上がっちゃったので、逆に不安ですが…HDMIにペンギンマークも出ませんし、OLEDにロゴも出てこないので、変更後のハードウェアになってるみたいです。
zynq> pwd
/proc/device-tree/axi@0
zynq> ls -l
total 0
-r--r--r--    1 root     0                4 Jan  1 00:07 #address-cells
-r--r--r--    1 root     0                4 Jan  1 00:07 #size-cells
-r--r--r--    1 root     0               44 Jan  1 00:07 compatible
-r--r--r--    1 root     0                4 Jan  1 00:07 name
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-afi@f8008000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-afi@f8009000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-afi@f800a000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-afi@f800b000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-ddrc@f8006000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-dev-cfg@f8007000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-dma@f8003000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-dma@f8004000
dr-xr-xr-x    3 root     0                0 Jan  1 00:07 ps7-ethernet@e000b000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-gpio@e000a000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-iop-bus-config@e0200000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-pl310@f8f02000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-qspi-linear@fc000000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-qspi@e000d000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-scugic@f8f01000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-scutimer@f8f00600
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-scuwdt@f8f00620
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-sdio@e0100000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-slcr@f8000000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-ttc@f8001000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7-usb@e0002000
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 ps7_xadc@f8007100
-r--r--r--    1 root     0                0 Jan  1 00:07 ranges
dr-xr-xr-x    2 root     0                0 Jan  1 00:07 serial@e0001000
こう見るとハードマクロのペリフェラル以外が消えてますし、どうやら効いてるみたいです。

まぁ、色々謎のままですが、これでPLが空っぽのLinux環境ができたので、自分の回路を足していくことになります。

ZedBoard Linux (2) [FPGA]

とりあえず標準状態にはなったので、いじるのに関係しそうな所を眺めてみます。

ramdiskのイメージの中身を変更する方法。ramdisk8M.image.gzを解凍し、作業用の./mntフォルダにマウントさせます。変更後、アンマウントして再圧縮します。
$ gunzip ramdisk8M.image.gz
$ sudo mount -o loop ramdisk8M.image mnt
$ cd mnt
mntの中身を変更
$ sudo umount mnt
$ gzip ramdisk8M.image
IPアドレスの変更は./etc/init.d/rcS、マウントの設定は./etc/fstab、など、この辺はLinux通りですかね。
それほど頻繁に行うわけでは無いですが、ROM化するまでrootfsをNFSにした方が便利そうです。

u-bootの設定。「~/u-boot-digilent/include/configs」下の「zynq_zed.h」に色々設定が見られます。30行目付近を抜粋。
#define CONFIG_ZED /* Community Board */

/* Default environment */
#define CONFIG_IPADDR   192.168.1.10
#define CONFIG_SERVERIP 192.168.1.50

#undef CONFIG_ZYNQ_XIL_LQSPI

/* No NOR Flash available on ZedBoard */
#define CONFIG_SYS_NO_FLASH
#define CONFIG_ENV_IS_NOWHERE

#undef CONFIG_EXTRA_ENV_SETTINGS
#define CONFIG_EXTRA_ENV_SETTINGS 	\
	"ethaddr=00:0a:35:00:01:22\0"	\
	"kernel_size=0x140000\0" 	\
	"ramdisk_size=0x200000\0" 	\
	"qspiboot=sf probe 0 0 0;" \
		"sf read 0x8000 0x100000 0x2c0000;" \
		"sf read 0x1000000 0x3c0000 0x40000;" \
		"sf read 0x800000 0x400000 0x800000;" \
		"go 0x8000\0" \
	"sdboot_linaro=echo Copying Linux from SD to RAM...;" \
		"mmcinfo;" \
		"fatload mmc 0 0x8000 zImage;" \
		"fatload mmc 0 0x1000000 devicetree_linaro.dtb;" \
		"go 0x8000\0" \
	"sdboot=echo Copying Linux from SD to RAM...;" \
		"mmcinfo;" \
		"fatload mmc 0 0x8000 zImage;" \
		"fatload mmc 0 0x1000000 devicetree.dtb;" \
		"fatload mmc 0 0x800000 ramdisk8M.image.gz;" \
		"go 0x8000\0" \
	"jtagboot=echo TFTPing Linux to RAM...;" \
		"tftp 0x8000 zImage;" \
		"tftp 0x1000000 devicetree.dtb;" \
		"tftp 0x800000 ramdisk8M.image.gz;" \
		"go 0x8000\0"
イメージをコピーしてカーネルにジャンプする部分です。IPアドレスとかサーバーのアドレスもここら辺で変えられるようです。
・0x0000_8000:zImage
・0x0100_0000 :devicetree.dtb
・0x0080_0000: ramdisk8M.image.gz
にロードしてるのがわかります。「sdboot」とかがマクロのように定義され、u-bootのコマンドラインから「run sdboot」とすると定義した処理が行われます(手でひとつずつ打っても同じです)。
u-bootが立ち上がり、なにもせず数秒経つと自動的に上のマクロのどれかが実行されます。どれを実行するかを選択しているのは「modeboot」変数で、「\u-boot-digilent\board\xilinx\zynq_common\board.c」で設定されているようです。80行目付近。
int board_late_init (void)
{
	u32 boot_mode;

	boot_mode = (XIo_In32(BOOT_MODE_REG) & BOOT_MODES_MASK);
	switch(boot_mode) {
	case QSPI_MODE:
		setenv("modeboot", "run qspiboot");
		break;
	case NAND_FLASH_MODE:
		setenv("modeboot", "run nandboot");
		break;
	case NOR_FLASH_MODE:
		setenv("modeboot", "run norboot");
		break;
	case SD_MODE:
		setenv("modeboot", "run sdboot");
		break;
	case JTAG_MODE:
		setenv("modeboot", "run jtagboot");
		break;
	default:
		setenv("modeboot", "");
		break;
	}

	return 0;
}
ブートモードジャンパーの値で切り替えてます。通常LinuxはSDからブートしているので、「sdboot」が選ばれるという仕組みです。
これらの設定は「~/u-boot-digilent/include/autoconf.mk」に集められます。このファイルはmake時に自動生成されます。どんな設定がどんな名前で定義されてるのか、このファイルとREADMEから追いかけるようにしています。

一方、devicetree.dts。標準のdtsの48行目付近。
chosen {
	/*bootargs = "console=ttyPS0,115200 root=/dev/mmcblk0p2 rw earlyprintk rootfstype=ext4 rootwait devtmpfs.mount=1";*/
	bootargs = "console=ttyPS0,115200 root=/dev/ram rw initrd=0x800000,8M earlyprintk rootwait devtmpfs.mount=1";
	linux,stdout-path = "/axi@0/serial@e0001000";
};
ここでLinuxカーネルのブート引数を設定してます。シリアルポートの設定や、先にコピーしたramdiskのアドレスなども与えています。コメントアウトされてる設定はSDカードをパーティション分けして、rootにマウントさせてます。この方法は大容量のファイルシステムが使えますし、設定を保存しておくこともできます。けど、いきなりバンと電源を切ってしまうようなシステムだとちょっと怖いです。

SDからu-bootをブートして、nfsかtftpでzImageとdevicetree.dtbをダウンロードして、rootファイルシステムをnfsサーバーに置く、などはこの辺を設定すれば良さそうです。
※標準のカーネルだとnfsが無効になってるようなので、再コンパイルは必要。

……「devicetree.dtbは0x0100_0000にあるぞ」はどこでカーネルに教えてるんでしょう?カーネルは知る必要ない?いやいや、そんなことは…というかdevicetreeの仕組み自体よくわかってないので、もっと勉強が必要ですね。

ZedBoard Linux (1) [FPGA]

ZedBoardでLinuxを実行するまでのメモ。

まずは変更を加えずに、標準の環境ができるまでにします。
Digilentのホームページから「ZedBoard_ELHoT」「ZedBoard_Linux_Design」の2つを落としておきます。手順書やソースファイルなどが入っています。
ISE14.6を使用(元のドキュメントでは14.4)。VMware+Ubuntu 12.04 LTS。ホストはWindows7。

ARMのGCCなどを個別に集めても構築できるらしいですが、Xilinxのツールを入れてしまいます。
XilinxのDownloadページから「Software Development Kit」をダウンロード。約1.7GB。でかい。
$ tar xvf Xilinx_SDK_2013.2_0616_1.tar
$ cd Xilinx_SDK_2013.2_0616_1
$ sudo sh xsetup
デフォルトでは「/opt/Xilinx/SDK/2013.02/」にインストールされます。

毎回忘れる、カーネルコンフィグメニューに必要なncurses-devをインストール。
$ sudo apt-get install ncurses-dev

以下はログインするたびに実行。デフォルトで設定するようにしてもOK。
XilinxのSDK環境変数設定。
$ source /opt/Xilinx/SDK/2013.2/settings32.sh
ついでにARMクロスコンパイル用の環境設定スクリプトも作成&実行。
$ cat armenv.sh
#!/bin/bash 
export CCOMPILER=arm-xilinx-linux-gnueabi-gcc
export ARCH=arm
export CROSS_COMPILE=arm-xilinx-linux-gnueabi-
$ source ./armenv.sh

Linuxのソースを取得、構築。
$ git clone https://github.com/Digilent/linux-digilent
これまた結構でかいので時間かかります。「~/linux-digilent」フォルダができます。
標準のコンフィグは「~/linux-digilent/arch/arm/configs/digilent_zed_defconfig」です。これを「.config」にコピーしても良いです。
$ cd linux-digilent
$ cp ./arch/arm/configs/digilent_zed_defconfig .config
$ make menuconfig
$ make
「~/linux-digilent/arch/arm/boot/zImage」にカーネルイメージができます。

u-bootの作成。
$ git clone https://github.com/Digilent/u-boot-digilent
「~/u-boot-digilent」フォルダができます。
「~/u-boot-digilent/include/configs/zynq_zed.h」がZedBoardの設定ファイルです。必要に応じて編集します。
$ make zynq_zed_config
$ make
makeが終わると「u-boot」ができます。これを「u-boot.elf」とかにリネームしてコピー。

Device Tree Generatorを導入。
SDK上でハードウェアからdtsファイルを作ってくれるツールです。自分でハードウェアをカスタマイズしたときは、このツールでdtsファイルを作ります。
$ git clone git://git.xilinx.com/device-tree.git bsp/device-tree_v0_00_x
$ sudo cp -r bsp/device-tree_v0_00_x/ /opt/Xilinx/SDK/2013.2/sw/lib/bsp/
「~/bsp/device-tree_v0_00_x」フォルダができるので、SDKの標準リポジトリにコピー。
ちなみに、このフォルダをWindowsの「C:\Xilinx\SDK\2013.2\sw\lib\bsp」にコピーすればWindowsのSDKでもDevice Tree Generatorが使えます。

FSBLを作成。SDKを立ち上げます。
$ xsdk
(Xilinx SDK:15612): LIBDBUSMENU-GTK-CRITICAL **: watch_submenu: assertion `GTK_IS_MENU_SHELL(menu)' failed
というエラーが出て、SDKのメニューが表示されない。ググったところ、
$ export UBUNTU_MENUPROXY=0
としてからSDKを立ち上げればば良いらしいです。先の「~/armenv.sh」に追加記述しておいてもOK。

標準の「hw_platform」のフォルダをコピーしておきます。ついでに「system.bit」を「hw_platform」の中にコピーします。本来これらはPlanAheadからExportされます。
このフォルダの中の「system.xml」を元にHardware Platform Specificationを作成します。
New → Others → Xilinx → Hardware Platform Specification を選びます。
Screenshot_1.png
コピーしたフォルダの「system.xml」を指定します。
Screenshot_2.png
Finishで「hw_platform」フォルダができます。

New → Application Projectで新しく「FSBL」というプロジェクトを作ります。テンプレートとしてFSBLを選びます。設定はデフォルトのまま。
Screenshot_3.pngScreenshot_4.png
自動的にBuildが始まりますが、gmakeを呼んでいてBuildに失敗するので、makeにシンボリックリンクさせます。ホントはどう対処するのが正しいんだろ?
$ sudo ln -s /usr/bin/make /usr/bin/gmake
再度Build。「FSBL.elf」ができます。
※ZedBoardではUSBのリセットをFSBLで行うようになっています。手順書に書いてありますがここでは割愛。

ブートイメージを作ります。
SDK上で「FSBL」が選択された状態で、Xilinx Tools → Create Zynq Boot Imageを選択します。
「FSBL.elf」と「system.bit」と「u-boot.elf」を選択し、Createします。
Screenshot_5.png
デフォルトでは「~/workspace/FSBL/bootimage/u-boot.bin」というファイルができます。
これを「BOOT.BIN」にリネームして、SDカードにコピーします。
※多分このSDKの作業はWindows上でも同じように動作するはずです。

Device Tree Blobを作成します。
「devicetree.dts」が標準のソースファイルです。コンパイル済みの「devicetree.dtb」をそのまま使っても同じです。
自分でカスタマイズしたハードウェア用にdtsを作るときは、先に入れたDevice Tree Generatorを使うようです。New → Board Support Packageでdevice-treeを選択します。
Screenshot_6.png
オプション設定。とりあえずコンソールをUARTに割り当てます。
Screenshot_7.png
「ps7_coretex9_0/libsrc/device-tree_xxx/xilinx.dts」が生成されます。「xilinx.dts」と標準の「devicetree.dts」を見比べてみると、生成されたdtsに後で人が色々手を加えてあるようです。dtsの変更はまた今度、今回は標準のdtsを使います。
dtbへのコンパイル。
~/linux-digilent/scripts/dtc/dtc -I dts -O dtb -o devicetree.dtb devicetree.dts


これまで作った
・BOOT.BIN (FSBL+ビットストリーム+u-boot)
・zImage (Linuxカーネル)
・devicetree.dtb
・ramdisk8M.image.gz (これは標準のまま)
の4つをSDカードにコピーします。ファイル名はコード内で決め打ちなのでこのままです。BOOT.BIN以外はソースを書き換えればファイル名の変更はできます。
後はSDカードをZedBoardに挿して、シリアルポートをつないで、電源を入れれば立ち上がる、はず。
U-Boot 2012.04.01 (Sep 25 2013 - 00:19:21)

DRAM:  512 MiB
WARNING: Caches not enabled
MMC:   SDHCI: 0
Using default environment

In:    serial
Out:   serial
Err:   serial
Net:   zynq_gem
Hit any key to stop autoboot:  0
Copying Linux from SD to RAM...
Device: SDHCI
Manufacturer ID: 1d
OEM: 4144
Name: SD
Tran Speed: 25000000
Rd Block Len: 512
SD version 1.10
High Capacity: No
Capacity: 1.9 GiB
Bus Width: 4-bit
reading zImage

2527040 bytes read
reading devicetree.dtb

9648 bytes read
reading ramdisk8M.image.gz

3694324 bytes read
## Starting application at 0x00008000 ...
Uncompressing Linux... done, booting the kernel.
[    0.000000] Booting Linux on physical CPU 0
[    0.000000] Linux version 3.6.0-digilent-13.01-00002-g06b3889 (develop@vm-ubuntu) (gcc version 4.7.2 (Sourcery CodeBench Lite 2012.09-104) ) #1 SMP PREEMPT Wed Sep 25 00:32:40 JST 2013
[    0.000000] CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=18c5387d
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[    0.000000] Machine: Xilinx Zynq Platform, model: Xilinx Zynq ZED
[    0.000000] Memory policy: ECC disabled, Data cache writealloc
[    0.000000] PERCPU: Embedded 7 pages/cpu @c140a000 s6976 r8192 d13504 u32768
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 130048
[    0.000000] Kernel command line: console=ttyPS0,115200 root=/dev/ram rw initrd=0x800000,8M earlyprintk rootwait devtmpfs.mount=1
[    0.000000] PID hash table entries: 2048 (order: 1, 8192 bytes)
[    0.000000] Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)
[    0.000000] Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)
[    0.000000] Memory: 512MB = 512MB total
[    0.000000] Memory: 506424k/506424k available, 17864k reserved, 0K highmem
[    0.000000] Virtual kernel memory layout:
[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.000000]     fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
[    0.000000]     vmalloc : 0xe0800000 - 0xfd000000   ( 456 MB)
[    0.000000]     lowmem  : 0xc0000000 - 0xe0000000   ( 512 MB)
[    0.000000]     pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB)
[    0.000000]     modules : 0xbf000000 - 0xbfe00000   (  14 MB)
[    0.000000]       .text : 0xc0008000 - 0xc0473a60   (4527 kB)
[    0.000000]       .init : 0xc0474000 - 0xc0499b40   ( 151 kB)
[    0.000000]       .data : 0xc049a000 - 0xc04d4ae0   ( 235 kB)
[    0.000000]        .bss : 0xc04d4b04 - 0xc04ee100   ( 102 kB)
[    0.000000] Preemptible hierarchical RCU implementation.
[    0.000000]  Dump stacks of tasks blocking RCU-preempt GP.
[    0.000000]  RCU restricting CPUs from NR_CPUS=4 to nr_cpu_ids=2.
[    0.000000] NR_IRQS:512
[    0.000000] Zynq clock init
[    0.000000] xlnx,ps7-ttc-1.00.a #0 at 0xe0800000, irq=43
[    0.000000] sched_clock: 32 bits at 100 Hz, resolution 10000000ns, wraps every 4294967286ms
[    0.000000] Console: colour dummy device 80x30
[    0.090000] Calibrating delay loop... 1332.01 BogoMIPS (lpj=6660096)
[    0.090000] pid_max: default: 32768 minimum: 301
[    0.090000] Mount-cache hash table entries: 512
[    0.090000] CPU: Testing write buffer coherency: ok
[    0.090000] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
[    0.090000] hw perfevents: enabled with ARMv7 Cortex-A9 PMU driver, 7 counters available
[    0.090000] Setting up static identity map for 0x32be88 - 0x32bebc
[    0.090000] L310 cache controller enabled
[    0.090000] l2x0: 8 ways, CACHE_ID 0x410000c8, AUX_CTRL 0x72360000, Cache size: 524288 B
[    0.130000] Map SLCR registers
[    0.130000] CPU1: Booted secondary processor
[    0.220000] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
[    0.220000] Brought up 2 CPUs
[    0.220000] SMP: Total of 2 processors activated (2664.03 BogoMIPS).
[    0.220000] devtmpfs: initialized
[    0.220000] NET: Registered protocol family 16
[    0.220000] DMA: preallocated 256 KiB pool for atomic coherent allocations
[    0.220000] xgpiops e000a000.ps7-gpio: gpio at 0xe000a000 mapped to 0xe084a000
[    0.230000] registering platform device 'pl330' id 0
[    0.230000] registering platform device 'arm-pmu' id 0
[    0.230000] registering platform device 'zynq-dvfs' id 0
[    0.230000]
[    0.230000] ###############################################
[    0.230000] #                                             #
[    0.230000] #                Board ZED Init               #
[    0.230000] #                                             #
[    0.230000] ###############################################
[    0.230000]
[    0.230000] hw-breakpoint: found 5 (+1 reserved) breakpoint and 1 watchpoint registers.
[    0.230000] hw-breakpoint: maximum watchpoint size is 4 bytes.
[    0.250000] xslcr xslcr.0: at 0xF8000000 mapped to 0xF8000000
[    0.270000] bio: create slab  at 0
[    0.270000] SCSI subsystem initialized
[    0.270000] usbcore: registered new interface driver usbfs
[    0.270000] usbcore: registered new interface driver hub
[    0.270000] usbcore: registered new device driver usb
[    0.270000] Advanced Linux Sound Architecture Driver Version 1.0.25.
[    0.270000] Switching to clocksource xttcpss_timer1
[    0.280000] NET: Registered protocol family 2
[    0.280000] TCP established hash table entries: 16384 (order: 5, 131072 bytes)
[    0.280000] TCP bind hash table entries: 16384 (order: 5, 131072 bytes)
[    0.280000] TCP: Hash tables configured (established 16384 bind 16384)
[    0.280000] TCP: reno registered
[    0.280000] UDP hash table entries: 256 (order: 1, 8192 bytes)
[    0.280000] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes)
[    0.280000] NET: Registered protocol family 1
[    0.280000] RPC: Registered named UNIX socket transport module.
[    0.280000] RPC: Registered udp transport module.
[    0.280000] RPC: Registered tcp transport module.
[    0.280000] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    0.280000] Trying to unpack rootfs image as initramfs...
[    0.280000] rootfs image is not initramfs (no cpio magic); looks like an initrd
[    0.320000] Freeing initrd memory: 8192K
[    0.320000] pl330 dev 0 probe success
[    0.320000] msgmni has been set to 1005
[    0.320000] io scheduler noop registered
[    0.320000] io scheduler deadline registered
[    0.320000] io scheduler cfq registered (default)
[    0.320000] e0001000.serial: ttyPS0 at MMIO 0xe0001000 (irq = 82) is a xuartps
[    0.840000] console [ttyPS0] enabled
[    0.840000] xdevcfg f8007000.ps7-dev-cfg: ioremap f8007000 to e0850000 with size 1000
[    0.850000] [drm] Initialized drm 1.1.0 20060810
[    0.860000] brd: module loaded
[    0.870000] loop: module loaded
[    0.880000] xqspips e000d000.ps7-qspi: master is unqueued, this is deprecated
[    0.880000] xqspips e000d000.ps7-qspi: at 0xE000D000 mapped to 0xE0852000, irq=51
[    0.890000] libphy: XEMACPS mii bus: probed
[    0.900000] xemacps e000b000.ps7-ethernet: pdev->id -1, baseaddr 0xe000b000, irq 54
[    0.910000] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[    0.910000] usb_hcd_xusbps_probe: No OTG assigned!
[    0.920000] usb_hcd_xusbps_probe: OTG now assigned!
[    0.920000] xusbps-ehci xusbps-ehci.0: Xilinx PS USB EHCI Host Controller
[    0.930000] xusbps-ehci xusbps-ehci.0: new USB bus registered, assigned bus number 1
[    0.970000] xusbps-ehci xusbps-ehci.0: irq 53, io mem 0x00000000
[    0.990000] xusbps-ehci xusbps-ehci.0: USB 2.0 started, EHCI 1.00
[    0.990000] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
[    1.000000] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    1.010000] usb usb1: Product: Xilinx PS USB EHCI Host Controller
[    1.010000] usb usb1: Manufacturer: Linux 3.6.0-digilent-13.01-00002-g06b3889 ehci_hcd
[    1.020000] usb usb1: SerialNumber: xusbps-ehci.0
[    1.020000] hub 1-0:1.0: USB hub found
[    1.030000] hub 1-0:1.0: 1 port detected
[    1.030000] Initializing USB Mass Storage driver...
[    1.040000] usbcore: registered new interface driver usb-storage
[    1.040000] USB Mass Storage support registered.
[    1.050000] mousedev: PS/2 mouse device common for all mice
[    1.060000] sdhci: Secure Digital Host Controller Interface driver
[    1.060000] sdhci: Copyright(c) Pierre Ossman
[    1.070000] sdhci-pltfm: SDHCI platform and OF driver helper
[    1.070000] mmc0: Invalid maximum block size, assuming 512 bytes
[    1.080000] No connectors reported connected with modes
[    1.090000] [drm] Cannot find any crtc or sizes - going 1024x768
[    1.110000] Console: switching to colour frame buffer device 128x48
[    1.120000] mmc0: SDHCI controller on e0100000.ps7-sdio [e0100000.ps7-sdio] using ADMA
[    1.130000] usbcore: registered new interface driver usbhid
[    1.130000] usbhid: USB HID core driver
[    1.130000] spi_gpio spi_gpio.2: master is unqueued, this is deprecated
[    1.130000] pmodoled-gpio-spi [zed_oled] SPI Probing
[    1.180000] fb0:  frame buffer device
[    1.180000] drm: registered panic notifier
[    1.190000] [drm] Initialized analog_drm 1.0.0 20110530 on minor 0
[    1.200000] mmc0: SD Status: Invalid Allocation Unit size.
[    1.210000] mmc0: new high speed SD card at address b368
[    1.210000] mmcblk0: mmc0:b368 SD    1.86 GiB
[    1.220000]  mmcblk0: p1
[    1.300000] adv7511 0-0039: Failed to add route DAI IN->TMDS
[    1.310000] adv7511-hdmi-snd adv7511_hdmi_snd.2:  adv7511 <-> 75c00000.axi-spdif-tx mapping ok
[    1.320000] TCP: cubic registered
[    1.320000] NET: Registered protocol family 17
[    1.330000] VFP support v0.3: implementor 41 architecture 3 part 30 variant 9 rev 4
[    1.330000] Registering SWP/SWPB emulation handler
[    1.340000] registered taskstats version 1
[    1.340000] drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
[    1.350000] ALSA device list:
[    1.350000]   #0: HDMI monitor
[    1.360000] RAMDISK: gzip image found at block 0
[    1.680000] EXT4-fs (ram0): couldn't mount as ext3 due to feature incompatibilities
[    1.710000] EXT4-fs (ram0): mounting ext2 file system using the ext4 subsystem
[    1.710000] EXT4-fs (ram0): warning: mounting unchecked fs, running e2fsck is recommended
[    1.720000] EXT4-fs (ram0): mounted filesystem without journal. Opts: (null)
[    1.730000] VFS: Mounted root (ext2 filesystem) on device 1:0.
[    1.730000] devtmpfs: mounted
[    1.740000] Freeing init memory: 148K
Starting rcS...
++ Mounting filesystem
++ Setting up mdev
++ Configure static IP 192.168.1.10
++ Starting telnet daemon
++ Starting http daemon
++ Starting ftp daemon
++ Starting dropbear (ssh) daemon
++ Starting OLED Display
insmod: can't read '/lib/modules/3.6.0-digilent-13.01-00002-g06b3889/pmodoled-gpio.ko': No such file or directory
++ Exporting LEDs & SWs
rcS Complete
zynq> [    6.980000] xemacps e000b000.ps7-ethernet: Set clk to 124999998 Hz
[    6.980000] xemacps e000b000.ps7-ethernet: link up (1000/FULL)
立ち上がりました。なんかinsmodでエラーが出ちゃってますが、これは後でどうにかなるでしょう。
標準ではIPアドレスが192.168.1.10決め打ちです。環境に合わせ、一時的に変更します。
zynq> ifconfig eth0 down
zynq> ifconfig eth0 192.168.0.201
zynq> ifconfig eth0 up
zynq> [  358.170000] xemacps e000b000.ps7-ethernet: Set clk to 124999998 Hz
[  358.170000] xemacps e000b000.ps7-ethernet: link up (1000/FULL)

develop@vm-ubuntu:~$ ssh root@192.168.0.201
root@192.168.0.201's password: root
zynq> 
とかやるとリモートでログインできます。ブラウザでhttp://192.168.0.201/を見るとWelcomeページが表示されます。

とりあえず動いたので、これから自分の目的に合わせてカスタマイズしていくことになります。

Vivado HLS を使ってみた。第一回まとめ [FPGA]

今回のRGB→YCbCr変換、最適化はもっとかけられます。変換に3x3のマトリクス演算を行っていますが、ホントは必要ありません。Yの係数を全部足すと1.0になるという条件と、(B-Y)、(R-Y)の形に式を変えると、乗算器は4つで済みます。実際XilinxのIPなどはそうやって作られてます。IPの資料を見ると詳しく載ってます。C側の計算を変える事になりますが、HDLでがんばるより楽でしょう。
実際に使えるようなIPを作ることを目的にしていないので、一番シンプルな計算式を持ってきています。


ということで、簡単なプログラムを対象に、C to HDLをやってみました。

…やべぇ…前からかかってた「HDLなんかもう一行も書きたくないよ~」病に拍車をかける結果となりました…
実はAlteraのC2Hを使った時も同じ事を思ったんですが(笑)
最近(Qsysになってから)C2Hのアップデートが聞こえてきませんね?どうしたのかな?
今回の例は簡単なのでHDLで書いてもたかがしれてますが、ちょっと複雑な処理が入ったらもうHDLなんかやりたくないです。

本当はもっと色々なディレクティブが必要になります、I/Oにも設定が必要です、使えるCの構文にも制限があります、純粋にソフトウェア的な書き方だけでは最適化は難しいかも、思った通りの回路にはなかなかならない場合もある、などなど考慮する点はたくさんあります。

でもCで記述して、誤差とか精度とか詰めて、ソースの最適化かけたときもCのシミュレーションで確認、シミュレーションでOKだったらディレクティブとかいじって最適化、HDLを全く見ずにハードウェア完成。コンパイルも実行時間もHDLより遙かに速いので効率も良いです。これは癖になります。

HLSの新しいバージョンではAXI関連が有効になってます。今回のもAXI Streamにするとほかとの接続が良くなります。XPSへのエクスポートもあるので、Cで作ったモジュールを自動でZynqのAXIチャンネルに接続することもできます。ここでもHDLを排除できます。
AlteraもQsys、SOPC Builderで同様なことが可能です。というかこの辺昔からAlteraの方が強いです。AXIではなくAvalonという独自の接続形態でしたが、非常に便利です。やっとXilinxも追いついてきたという感じがします。
AXI対応はXilinxの方が先行ですかね。AXIは一種の流行なので、特にこだわる理由は無いと思いますが。

なにも書かずにものができあがる、AlteraもXilinxも、多分ほかのベンダーも、みんな目指してるところでしょう。
今はその中間解として、システム自動作成ツール(Qsys、XPS、+IP群)+C系合成ツール(C2H、HLS)+CPU(ARM、Nios、MB)+モデル設計ツール(DSP Builder、SystGen)というところに落ち着いてる感じでしょうか。バラバラなのが難点ですが適材適所で行くしか無いのが現状でしょう。もちろんHDLで書いた方が効率よい部分もあるので、しばらくはごちゃ混ぜ状態が続きそうです。

それにしてもやばい。結構できが良いので本気でHDL書きたくない気分になってます…ライセンス約50万でしたっけ…?う~む…
まぁそんなこと言いながらHDLは書くんですけどね(笑)
※DigiKeyとかで見てみたら、HLS単体だとFloatingでも25万ぐらいでした…うぅう~むぅ…

Vivado HLS を使ってみた(その6) [FPGA]

リアルタイムでFullHD 1080p60ぐらいは処理して欲しいですよね。
ソースは(その5)のintバージョン。

1080pで148.5MHzなので、ソリューションの周波数を150MHzにしてみます。
Image 019.png
MHzを付けると周波数と認識されるようです。
これで合成すると…(レポートファイル)
================================================================
== Vivado HLS Report for 'rgb2ycbcr'
================================================================
* Date:

* Version:        2013.1
* Project:        rgb2ycbcr
* Solution:       solution1
* Product family: zynq zynq_fpv6 
* Target device:  xc7z020clg484-1


================================================================
== Performance Estimates
================================================================
+ Timing (ns): 
    * Summary: 
    +---------+-------+----------+------------+
    |  Clock  | Target| Estimated| Uncertainty|
    +---------+-------+----------+------------+
    |default  |   6.67|      5.47|        0.83|
    +---------+-------+----------+------------+

+ Latency (clock cycles): 
    * Summary: 
    +-----+-----+-----+-----+---------+
    |  Latency  |  Interval | Pipeline|
    | min | max | min | max |   Type  |
    +-----+-----+-----+-----+---------+
    |    6|    6|    7|    7|   none  |
    +-----+-----+-----+-----+---------+

    + Detail: 
        * Instance: 
        N/A

        * Loop: 
        N/A



================================================================
== Utilization Estimates
================================================================
* Summary: 
+-----------------+---------+-------+--------+-------+
|       Name      | BRAM_18K| DSP48E|   FF   |  LUT  |
+-----------------+---------+-------+--------+-------+
|Expression       |        -|      -|       0|    235|
|FIFO             |        -|      -|       -|      -|
|Instance         |        -|      7|      72|     20|
|Memory           |        -|      -|       -|      -|
|Multiplexer      |        -|      -|       -|      -|
|Register         |        -|      -|     231|      -|
|ShiftMemory      |        -|      -|       -|      -|
+-----------------+---------+-------+--------+-------+
|Total            |        0|      7|     303|    255|
+-----------------+---------+-------+--------+-------+
|Available        |      280|    220|  106400|  53200|
+-----------------+---------+-------+--------+-------+
|Utilization (%)  |        0|      3|   ~0   |   ~0  |
+-----------------+---------+-------+--------+-------+

+ Detail: 
    * Instance: 
    +--------------------------------+-----------------------------+---------+-------+----+----+
    |            Instance            |            Module           | BRAM_18K| DSP48E| FF | LUT|
    +--------------------------------+-----------------------------+---------+-------+----+----+
    |rgb2ycbcr_mul_8ns_10ns_18_3_U1  |rgb2ycbcr_mul_8ns_10ns_18_3  |        0|      1|  18|   5|
    |rgb2ycbcr_mul_8ns_10s_19_3_U5   |rgb2ycbcr_mul_8ns_10s_19_3   |        0|      1|   0|   0|
    |rgb2ycbcr_mul_8ns_12ns_20_3_U7  |rgb2ycbcr_mul_8ns_12ns_20_3  |        0|      1|   0|   0|
    |rgb2ycbcr_mul_8ns_12s_20_3_U3   |rgb2ycbcr_mul_8ns_12s_20_3   |        0|      1|  18|   5|
    |rgb2ycbcr_mul_8ns_12s_20_3_U4   |rgb2ycbcr_mul_8ns_12s_20_3   |        0|      1|  18|   5|
    |rgb2ycbcr_mul_8ns_9ns_17_3_U2   |rgb2ycbcr_mul_8ns_9ns_17_3   |        0|      1|  18|   5|
    |rgb2ycbcr_mul_8ns_9s_18_3_U6    |rgb2ycbcr_mul_8ns_9s_18_3    |        0|      1|   0|   0|
    +--------------------------------+-----------------------------+---------+-------+----+----+
    |Total                           |                             |        0|      7|  72|  20|
    +--------------------------------+-----------------------------+---------+-------+----+----+

    * Memory: 
    N/A

    * FIFO: 
    N/A

    * Shift register: 
    N/A

    * Expression: 
    +--------------------+----------+-------+---+----+------------+------------+
    |    Variable Name   | Operation| DSP48E| FF| LUT| Bitwidth P0| Bitwidth P1|
    +--------------------+----------+-------+---+----+------------+------------+
    |tmp1_fu_171_p2      |     +    |      0|  0|  19|          19|          19|
    |tmp_10_fu_272_p2    |     +    |      0|  0|  21|          21|          21|
    |tmp_5_fu_236_p2     |     +    |      0|  0|  21|          21|          21|
    |p_neg1_fu_320_p2    |     -    |      0|  0|  21|           1|          21|
    |p_neg5_fu_295_p2    |     -    |      0|  0|  21|           1|          21|
    |p_neg_t1_fu_339_p2  |     -    |      0|  0|  10|           1|          10|
    |p_neg_t7_fu_314_p2  |     -    |      0|  0|  10|           1|          10|
    |Cb_fu_373_p3        |  Select  |      0|  0|  10|           1|           1|
    |Cr_fu_396_p3        |  Select  |      0|  0|  10|           1|           1|
    |agg_result_Cb_V     |  Select  |      0|  0|   8|           1|           2|
    |agg_result_Cr_V     |  Select  |      0|  0|   8|           1|           2|
    |tmp_13_fu_367_p3    |  Select  |      0|  0|  10|           1|          10|
    |tmp_s_fu_358_p3     |  Select  |      0|  0|  10|           1|          10|
    |icmp1_fu_413_p2     |   icmp   |      0|  0|   2|           2|           1|
    |icmp_fu_390_p2      |   icmp   |      0|  0|   2|           2|           1|
    |tmp_14_fu_345_p2    |   icmp   |      0|  0|  26|          21|          13|
    |tmp_15_fu_350_p2    |   icmp   |      0|  0|  26|          21|          13|
    +--------------------+----------+-------+---+----+------------+------------+
    |Total               |          |      0|  0| 235|         117|         177|
    +--------------------+----------+-------+---+----+------------+------------+

    * Multiplexer: 
    N/A

    * Register: 
    +---------------------+----+-----+-----------+
    |         Name        | FF | Bits| Const Bits|
    +---------------------+----+-----+-----------+
    |G_cast_reg_462       |   8|   20|         12|
    |ap_CS_fsm            |   3|    3|          0|
    |p_neg_t1_reg_556     |  10|   10|          0|
    |p_neg_t7_reg_551     |  10|   10|          0|
    |tmp1_reg_504         |  19|   19|          0|
    |tmp3_cast_reg_509    |  21|   21|          0|
    |tmp5_cast_reg_514    |  21|   21|          0|
    |tmp_10_reg_535       |  21|   21|          0|
    |tmp_11_cast_reg_499  |  20|   20|          0|
    |tmp_11_reg_530       |   9|    9|          0|
    |tmp_12_reg_541       |   1|    1|          0|
    |tmp_14_reg_561       |   1|    1|          0|
    |tmp_15_reg_566       |   1|    1|          0|
    |tmp_17_reg_546       |   9|    9|          0|
    |tmp_2_reg_489        |  17|   17|          0|
    |tmp_4_reg_525        |   1|    1|          0|
    |tmp_5_reg_519        |  21|   21|          0|
    |tmp_7_cast_reg_494   |  20|   20|          0|
    |tmp_reg_484          |  18|   18|          0|
    +---------------------+----+-----+-----------+
    |Total                | 231|  243|         12|
    +---------------------+----+-----+-----------+



================================================================
== Interface
================================================================
* Summary: 
+------------------------+-----+-----+------------+-----------------+--------------+
|        RTL Ports       | Dir | Bits|  Protocol  |  Source Object  |    C Type    |
+------------------------+-----+-----+------------+-----------------+--------------+
|ap_clk                  |  in |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|ap_rst                  |  in |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|ap_start                |  in |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|ap_done                 | out |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|ap_idle                 | out |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|ap_ready                | out |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|agg_result_Y_V          | out |    8|   ap_vld   |  agg_result_Y_V |    pointer   |
|agg_result_Y_V_ap_vld   | out |    1|   ap_vld   |  agg_result_Y_V |    pointer   |
|agg_result_Cb_V         | out |    8|   ap_vld   | agg_result_Cb_V |    pointer   |
|agg_result_Cb_V_ap_vld  | out |    1|   ap_vld   | agg_result_Cb_V |    pointer   |
|agg_result_Cr_V         | out |    8|   ap_vld   | agg_result_Cr_V |    pointer   |
|agg_result_Cr_V_ap_vld  | out |    1|   ap_vld   | agg_result_Cr_V |    pointer   |
|s_R_V                   |  in |    8|   ap_none  |      s_R_V      |    scalar    |
|s_G_V                   |  in |    8|   ap_none  |      s_G_V      |    scalar    |
|s_B_V                   |  in |    8|   ap_none  |      s_B_V      |    scalar    |
+------------------------+-----+-----+------------+-----------------+--------------+
7クロックに1演算という回路になりました。今回はap_start,ap_doneなどが制御信号として働きます。ap_startで演算開始、ap_doneで計算結果が得られる、という制御になります。

1クロックに1つ答えが得られない困るので、ディレクティブ(指示子)を与えます。おぉ、やっと機種依存するところが出てきた(笑)
「Directive」タブを開き、関数(rgb2ycbcr)を右クリックします。
Image 020.png
ディレクティブの選択画面が出るので「PIPELINE」を選択します。「Source File」を選ぶと「#pragma HLS PIPELINE」がcppソースに埋め込まれます。「Directive File」を選ぶとディレクティブの別のファイルに保存されます。どちらでも効能は同じ。好みの方にします。
Image 021.pngImage 022.png
「Directive File」を選んだ場合。ディレクティブのタブに新しく「HLS_PIPELINE」が追加されます。
Image 023.png

これで合成開始。
================================================================
== Vivado HLS Report for 'rgb2ycbcr'
================================================================
* Date:

* Version:        2013.1
* Project:        rgb2ycbcr
* Solution:       solution1
* Product family: zynq zynq_fpv6 
* Target device:  xc7z020clg484-1


================================================================
== Performance Estimates
================================================================
+ Timing (ns): 
    * Summary: 
    +---------+-------+----------+------------+
    |  Clock  | Target| Estimated| Uncertainty|
    +---------+-------+----------+------------+
    |default  |   6.67|      5.47|        0.83|
    +---------+-------+----------+------------+

+ Latency (clock cycles): 
    * Summary: 
    +-----+-----+-----+-----+----------+
    |  Latency  |  Interval | Pipeline |
    | min | max | min | max |   Type   |
    +-----+-----+-----+-----+----------+
    |    6|    6|    1|    1| function |
    +-----+-----+-----+-----+----------+

    + Detail: 
        * Instance: 
        N/A

        * Loop: 
        N/A



================================================================
== Utilization Estimates
================================================================
* Summary: 
+-----------------+---------+-------+--------+-------+
|       Name      | BRAM_18K| DSP48E|   FF   |  LUT  |
+-----------------+---------+-------+--------+-------+
|Expression       |        -|      -|       0|    235|
|FIFO             |        -|      -|       -|      -|
|Instance         |        -|      7|      72|     20|
|Memory           |        -|      -|       -|      -|
|Multiplexer      |        -|      -|       -|      -|
|Register         |        -|      -|     287|      -|
|ShiftMemory      |        -|      -|       0|     24|
+-----------------+---------+-------+--------+-------+
|Total            |        0|      7|     359|    279|
+-----------------+---------+-------+--------+-------+
|Available        |      280|    220|  106400|  53200|
+-----------------+---------+-------+--------+-------+
|Utilization (%)  |        0|      3|   ~0   |   ~0  |
+-----------------+---------+-------+--------+-------+

+ Detail: 
    * Instance: 
    +--------------------------------+-----------------------------+---------+-------+----+----+
    |            Instance            |            Module           | BRAM_18K| DSP48E| FF | LUT|
    +--------------------------------+-----------------------------+---------+-------+----+----+
    |rgb2ycbcr_mul_8ns_10ns_18_3_U1  |rgb2ycbcr_mul_8ns_10ns_18_3  |        0|      1|  18|   5|
    |rgb2ycbcr_mul_8ns_10s_19_3_U5   |rgb2ycbcr_mul_8ns_10s_19_3   |        0|      1|   0|   0|
    |rgb2ycbcr_mul_8ns_12ns_20_3_U7  |rgb2ycbcr_mul_8ns_12ns_20_3  |        0|      1|   0|   0|
    |rgb2ycbcr_mul_8ns_12s_20_3_U3   |rgb2ycbcr_mul_8ns_12s_20_3   |        0|      1|  18|   5|
    |rgb2ycbcr_mul_8ns_12s_20_3_U4   |rgb2ycbcr_mul_8ns_12s_20_3   |        0|      1|  18|   5|
    |rgb2ycbcr_mul_8ns_9ns_17_3_U2   |rgb2ycbcr_mul_8ns_9ns_17_3   |        0|      1|  18|   5|
    |rgb2ycbcr_mul_8ns_9s_18_3_U6    |rgb2ycbcr_mul_8ns_9s_18_3    |        0|      1|   0|   0|
    +--------------------------------+-----------------------------+---------+-------+----+----+
    |Total                           |                             |        0|      7|  72|  20|
    +--------------------------------+-----------------------------+---------+-------+----+----+

    * Memory: 
    N/A

    * FIFO: 
    N/A

    * Shift register: 
    +--------------------+---+----+-----+-----------+
    |        Name        | FF| LUT| Bits| Const Bits|
    +--------------------+---+----+-----+-----------+
    |G_cast_reg_467      |  0|   8|   20|         12|
    |s_B_V_read_reg_450  |  0|   8|    8|          0|
    |s_R_V_read_reg_456  |  0|   8|    8|          0|
    +--------------------+---+----+-----+-----------+
    |Total               |  0|  24|   36|         12|
    +--------------------+---+----+-----+-----------+

    * Expression: 
    +--------------------+----------+-------+---+----+------------+------------+
    |    Variable Name   | Operation| DSP48E| FF| LUT| Bitwidth P0| Bitwidth P1|
    +--------------------+----------+-------+---+----+------------+------------+
    |tmp1_fu_177_p2      |     +    |      0|  0|  19|          19|          19|
    |tmp_10_fu_277_p2    |     +    |      0|  0|  21|          21|          21|
    |tmp_5_fu_241_p2     |     +    |      0|  0|  21|          21|          21|
    |p_neg1_fu_325_p2    |     -    |      0|  0|  21|           1|          21|
    |p_neg5_fu_300_p2    |     -    |      0|  0|  21|           1|          21|
    |p_neg_t1_fu_344_p2  |     -    |      0|  0|  10|           1|          10|
    |p_neg_t7_fu_319_p2  |     -    |      0|  0|  10|           1|          10|
    |Cb_fu_378_p3        |  Select  |      0|  0|  10|           1|           1|
    |Cr_fu_401_p3        |  Select  |      0|  0|  10|           1|           1|
    |agg_result_Cb_V     |  Select  |      0|  0|   8|           1|           2|
    |agg_result_Cr_V     |  Select  |      0|  0|   8|           1|           2|
    |tmp_13_fu_372_p3    |  Select  |      0|  0|  10|           1|          10|
    |tmp_s_fu_363_p3     |  Select  |      0|  0|  10|           1|          10|
    |icmp1_fu_418_p2     |   icmp   |      0|  0|   2|           2|           1|
    |icmp_fu_395_p2      |   icmp   |      0|  0|   2|           2|           1|
    |tmp_14_fu_350_p2    |   icmp   |      0|  0|  26|          21|          13|
    |tmp_15_fu_355_p2    |   icmp   |      0|  0|  26|          21|          13|
    +--------------------+----------+-------+---+----+------------+------------+
    |Total               |          |      0|  0| 235|         117|         177|
    +--------------------+----------+-------+---+----+------------+------------+

    * Multiplexer: 
    N/A

    * Register: 
    +-------------------------------------+----+-----+-----------+
    |                 Name                | FF | Bits| Const Bits|
    +-------------------------------------+----+-----+-----------+
    |G_cast_reg_467                       |   8|   20|         12|
    |Y_reg_524                            |   8|    8|          0|
    |ap_CS_fsm                            |   1|    1|          0|
    |ap_reg_ppiten_pp0_it1                |   1|    1|          0|
    |ap_reg_ppiten_pp0_it2                |   1|    1|          0|
    |ap_reg_ppiten_pp0_it3                |   1|    1|          0|
    |ap_reg_ppiten_pp0_it4                |   1|    1|          0|
    |ap_reg_ppiten_pp0_it5                |   1|    1|          0|
    |ap_reg_ppiten_pp0_it6                |   1|    1|          0|
    |ap_reg_ppstg_Y_reg_524_pp0_it5       |   8|    8|          0|
    |ap_reg_ppstg_tmp_11_reg_540_pp0_it5  |   9|    9|          0|
    |ap_reg_ppstg_tmp_12_reg_551_pp0_it5  |   1|    1|          0|
    |ap_reg_ppstg_tmp_17_reg_556_pp0_it5  |   9|    9|          0|
    |ap_reg_ppstg_tmp_4_reg_535_pp0_it5   |   1|    1|          0|
    |p_neg_t1_reg_566                     |  10|   10|          0|
    |p_neg_t7_reg_561                     |  10|   10|          0|
    |s_B_V_read_reg_450                   |   8|    8|          0|
    |s_R_V_read_reg_456                   |   8|    8|          0|
    |tmp1_reg_509                         |  19|   19|          0|
    |tmp3_cast_reg_514                    |  21|   21|          0|
    |tmp5_cast_reg_519                    |  21|   21|          0|
    |tmp_10_reg_545                       |  21|   21|          0|
    |tmp_11_cast_reg_504                  |  20|   20|          0|
    |tmp_11_reg_540                       |   9|    9|          0|
    |tmp_12_reg_551                       |   1|    1|          0|
    |tmp_14_reg_571                       |   1|    1|          0|
    |tmp_15_reg_576                       |   1|    1|          0|
    |tmp_17_reg_556                       |   9|    9|          0|
    |tmp_2_reg_494                        |  17|   17|          0|
    |tmp_4_reg_535                        |   1|    1|          0|
    |tmp_5_reg_529                        |  21|   21|          0|
    |tmp_7_cast_reg_499                   |  20|   20|          0|
    |tmp_reg_489                          |  18|   18|          0|
    +-------------------------------------+----+-----+-----------+
    |Total                                | 287|  299|         12|
    +-------------------------------------+----+-----+-----------+



================================================================
== Interface
================================================================
* Summary: 
+------------------------+-----+-----+------------+-----------------+--------------+
|        RTL Ports       | Dir | Bits|  Protocol  |  Source Object  |    C Type    |
+------------------------+-----+-----+------------+-----------------+--------------+
|ap_clk                  |  in |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|ap_rst                  |  in |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|ap_start                |  in |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|ap_done                 | out |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|ap_idle                 | out |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|ap_ready                | out |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|agg_result_Y_V          | out |    8|   ap_vld   |  agg_result_Y_V |    pointer   |
|agg_result_Y_V_ap_vld   | out |    1|   ap_vld   |  agg_result_Y_V |    pointer   |
|agg_result_Cb_V         | out |    8|   ap_vld   | agg_result_Cb_V |    pointer   |
|agg_result_Cb_V_ap_vld  | out |    1|   ap_vld   | agg_result_Cb_V |    pointer   |
|agg_result_Cr_V         | out |    8|   ap_vld   | agg_result_Cr_V |    pointer   |
|agg_result_Cr_V_ap_vld  | out |    1|   ap_vld   | agg_result_Cr_V |    pointer   |
|s_R_V                   |  in |    8|   ap_none  |      s_R_V      |    scalar    |
|s_G_V                   |  in |    8|   ap_none  |      s_G_V      |    scalar    |
|s_B_V                   |  in |    8|   ap_none  |      s_B_V      |    scalar    |
+------------------------+-----+-----+------------+-----------------+--------------+

データの流れとリソース。
Image 024.pngImage 025.png
パイプライン化され、1クロックで1個結果が出てくるようになりました。予想周波数は5.47[ns](約182MHz)。

この辺でいい加減一度ぐらいHDLシミュレーションしておかないと…いままでCのシミュレーションが楽で楽で…改めて思う…HDLのテストベンチってめんどくさい…

中身はほぼ同じで、BMPファイルを流し込んで結果を保存します。ただ、色々書くのが面倒なので、BGRをCbYCrに置き換えたBMPファイルだけ作成します。
ちなみにI/Oピンの情報はレポートファイルの一番下に書かれています。細かい制御方法はXilinxの資料にゆずりますが、今回はI/Oになにも指定していないので、関数の返値(YCbCr)に「ap_ctrl_hs」が、引数(RGB)に「ap_none」が設定されています。Y,Cb,Crそれぞれに「_ap_vld」という信号が付いてますが、この場合「ap_done」と同じ信号になるので見ません。
・「ap_rst」を解除する。
・「ap_start」を'1'にすると動作開始。
・クロック立ち上がり&「ap_ready」が'1'にだったら次のRGBデータをBMPファイルから与える。
・クロック立ち上がり&「ap_done」が'1'だったらYCbCrデータをBMPファイルに書き込む。
という制御だけになります。
`timescale 1ns / 1ps
`default_nettype none

//******************************************
//
module bmp_file;

    integer    bfSize;            //    File Size
    integer    bfOffBits;        //    Image Offset
    integer    biWidth;        //    Width
    integer    biHeight;        //    Height
    integer    biBitCount;        //    bit/pixel
    integer    imgsize;        //    Size

    localparam    headersize    = 14+40;
    reg     [7:0]    tch;
    reg     [7:0]    header    [0:headersize-1];
    integer    ifp, ofp, tx;

    task    init;
        input    [8*20:0]    ifname;
        input    [8*20:0]    ofname;
        integer    i;
    begin
        ifp    = $fopen(ifname, "rb");
        ofp    = $fopen(ofname, "wb");
        $display("open %s", ifname);
        $display("%s created", ofname);

        tx    = $fread(header, ifp);    //, 0, headersize);
        $display("header = %d", tx);

        bfSize        = {header[ 5],header[ 4],header[ 3],header[ 2]};
        bfOffBits    = {header[13],header[12],header[11],header[10]};
        biWidth        = {header[21],header[20],header[19],header[18]};
        biHeight    = {header[25],header[24],header[23],header[22]};
        biBitCount    = {header[29],header[28]};
        imgsize        = bfSize - bfOffBits;
        $display(" = %d,%x :(%d,%d,%d)",bfSize,bfOffBits,biWidth,biHeight,biBitCount);

        for (i = 0; i < headersize; i = i+1) $fwrite(ofp,"%c",header[i]);    //    copy header info

    end
    endtask

    task    done;
    begin
        $fclose(ifp);
        $fclose(ofp);
    end
    endtask

    task    sread;
        output    [7:0]    B;
        output    [7:0]    G;
        output    [7:0]    R;
    begin
        $fread(B, ifp);
        $fread(G, ifp);
        $fread(R, ifp);
    end
    endtask

    task    swrite;
        input    [7:0]    B;
        input    [7:0]    G;
        input    [7:0]    R;
    begin
        $fwrite(ofp,"%c", B);
        $fwrite(ofp,"%c", G);
        $fwrite(ofp,"%c", R);
    end
    endtask

endmodule
//
//******************************************


//******************************************
//
module tb;

    localparam    ifname = "../H-IIA-F13.bmp";
    localparam    ofname = "../out_hdl.bmp";

    integer    bfSize;        //    File Size
    integer    bfOffBits;    //    Image Offset
    integer    biWidth;    //    Width
    integer    biHeight;    //    Height
    integer    biBitCount;    //    bit/pixel

    wire            ap_start;
    wire            ap_done;
    wire            ap_idle;
    wire            ap_ready;
    wire    [7:0]    agg_result_Y_V;
    wire            agg_result_Y_V_ap_vld;
    wire    [7:0]    agg_result_Cb_V;
    wire            agg_result_Cb_V_ap_vld;
    wire    [7:0]    agg_result_Cr_V;
    wire            agg_result_Cr_V_ap_vld;
    wire    [7:0]    s_R_V;
    wire    [7:0]    s_G_V;
    wire    [7:0]    s_B_V;

    reg             clock;
    reg             reset;
    reg             start;
    reg     [7:0]    R,G,B;
    wire    [7:0]    Y,Cb,Cr;

    rgb2ycbcr
    tgt
    (
        .ap_clk                    (clock                    ),    //    ap_clk,
        .ap_rst                    (reset                    ),    //    ap_rst,
        .ap_start                (ap_start                ),    //    ap_start,
        .ap_done                (ap_done                ),    //    ap_done,
        .ap_idle                (ap_idle                ),    //    ap_idle,
        .ap_ready                (ap_ready                ),    //    ap_ready,
        .agg_result_Y_V            (agg_result_Y_V            ),    //    agg_result_Y_V,
        .agg_result_Y_V_ap_vld    (agg_result_Y_V_ap_vld    ),    //    agg_result_Y_V_ap_vld,
        .agg_result_Cb_V        (agg_result_Cb_V        ),    //    agg_result_Cb_V,
        .agg_result_Cb_V_ap_vld    (agg_result_Cb_V_ap_vld    ),    //    agg_result_Cb_V_ap_vld,
        .agg_result_Cr_V        (agg_result_Cr_V        ),    //    agg_result_Cr_V,
        .agg_result_Cr_V_ap_vld    (agg_result_Cr_V_ap_vld    ),    //    agg_result_Cr_V_ap_vld,
        .s_R_V                    (s_R_V                    ),    //    s_R_V,
        .s_G_V                    (s_G_V                    ),    //    s_G_V,
        .s_B_V                    (s_B_V                    )    //    s_B_V,
    );

    bmp_file    bmp();

    assign    ap_start    = start;
    assign    s_R_V        = R;
    assign    s_G_V        = G;
    assign    s_B_V        = B;
    assign    Y            = agg_result_Y_V;
    assign    Cb            = agg_result_Cb_V;
    assign    Cr            = agg_result_Cr_V;

    integer s,d;
    initial
    begin
        reset    <= 1'b1;
        start    <= 1'b0;
        # 100;
        @(posedge clock);
        reset    <= 1'b0;
        @(posedge clock);
        start    <= 1'b1;

        bmp.init(ifname,ofname);

        for (s = 0; s < bmp.imgsize; s = s+3) begin
            wait (ap_ready);
            bmp.sread(B,G,R);
            @(posedge clock);
        end

        start    <= 1'b0;
        # 500;
    end

    initial
    begin
        wait (start);

        for (d = 0; d < bmp.imgsize; d = d+3) begin
            wait (ap_done);
            @(posedge clock);
            bmp.swrite(Cb,Y,Cr);
        end

        bmp.done;
        #300;
        $stop;
    end

    //    Clock
    localparam    period    = (1000.0/148.5);
    initial    clock                <= 1'b0;
    always    #(period/2)    clock    <= ~clock;

endmodule
//
//******************************************
`default_nettype wire
…行間から「HDLめんどくさい」が漏れてる…

シミュレーションの最初と最後だけ出してみます。
Image 026.png
Image 027.png
カラーコードにしたので、シミュレーションの最後の値が動いていませんが、これで正常です。下の方のsとdがそれぞれのピクセルカウンタです。

HDLシミュレーションで生成されたBMPファイルと、Cの整数シミュレーションで生成されたBMPファイルのバイナリ比較は完全一致でした。Cの浮動小数点モデルで生成したBMPファイルとの比較では所々1bitの差が出ます。

PlanAheadでインプリしてみます。
   Number of BUFGs                           1 out of 32      3%
   Number of DSP48E1s                        7 out of 220     3%
   Number of External IOBs                  57 out of 200    28%
      Number of LOCed IOBs                   0 out of 57      0%

   Number of Slices                        102 out of 13300   1%
   Number of Slice Registers               212 out of 106400  1%
      Number used as Flip Flops            212
      Number used as Latches                 0
      Number used as LatchThrus              0

   Number of Slice LUTS                    245 out of 53200   1%
   Number of Slice LUT-Flip Flop pairs     307 out of 53200   1%
HLSの予測値にかなり近い値になりました。レポートされた周波数は150MHz制約に対してSlack 1.63[ns]、約198MHzという結果になってます。

Vivado HLS を使ってみた(その5) [FPGA]

試しに精度の計算をコンパイラ任せにしてみます。ap_fixedではなくintで書き直します。
#define fw    12
#define frc    4096    /*    pow(2, fw)    */
#define dat    256        /*    pow(2, dw)    */

YCbCr rgb2ycbcr(RGB s)
{

    YCbCr    d;

    const int    cY [3] = { 0.2126f*frc,  0.7152f*frc,  0.0722f*frc };
    const int    cCb[3] = {-0.1146f*frc, -0.3854f*frc,  0.5000f*frc };
    const int    cCr[3] = { 0.5000f*frc, -0.4542f*frc, -0.0458f*frc };
    const int    op5    = 0.5f * dat * frc;
    const int    llim   = 0;
    const int    ulim   = dat-1;

    int    R,G,B;
    int    Y,Cb,Cr;

    R = s.R;
    G = s.G;
    B = s.B;

    Y  = (cY [0] * R + cY [1] * G + cY [2] * B      ) /frc;
    Cb = (cCb[0] * R + cCb[1] * G + cCb[2] * B + op5) /frc;
    Cr = (cCr[0] * R + cCr[1] * G + cCr[2] * B + op5) /frc;

    if (Y  < llim) Y  = llim;    if (ulim < Y ) Y  = ulim;
    if (Cb < llim) Cb = llim;    if (ulim < Cb) Cb = ulim;
    if (Cr < llim) Cr = llim;    if (ulim < Cr) Cr = ulim;

    d.Y  = Y ;
    d.Cb = Cb;
    d.Cr = Cr;

    return d;
}
より簡単に。
レポートファイル。
================================================================
== Vivado HLS Report for 'rgb2ycbcr'
================================================================
* Date:

* Version:        2013.1
* Project:        rgb2ycbcr
* Solution:       solution1
* Product family: zynq zynq_fpv6 
* Target device:  xc7z020clg484-1


================================================================
== Performance Estimates
================================================================
+ Timing (ns): 
    * Summary: 
    +---------+--------+----------+------------+
    |  Clock  | Target | Estimated| Uncertainty|
    +---------+--------+----------+------------+
    |default  |  100.00|     23.29|       12.50|
    +---------+--------+----------+------------+

+ Latency (clock cycles): 
    * Summary: 
    +-----+-----+-----+-----+---------+
    |  Latency  |  Interval | Pipeline|
    | min | max | min | max |   Type  |
    +-----+-----+-----+-----+---------+
    |    0|    0|    1|    1|   none  |
    +-----+-----+-----+-----+---------+

    + Detail: 
        * Instance: 
        N/A

        * Loop: 
        N/A



================================================================
== Utilization Estimates
================================================================
* Summary: 
+-----------------+---------+-------+--------+-------+
|       Name      | BRAM_18K| DSP48E|   FF   |  LUT  |
+-----------------+---------+-------+--------+-------+
|Expression       |        -|      7|       0|    235|
|FIFO             |        -|      -|       -|      -|
|Instance         |        -|      -|       -|      -|
|Memory           |        -|      -|       -|      -|
|Multiplexer      |        -|      -|       -|      -|
|Register         |        -|      -|       -|      -|
|ShiftMemory      |        -|      -|       -|      -|
+-----------------+---------+-------+--------+-------+
|Total            |        0|      7|       0|    235|
+-----------------+---------+-------+--------+-------+
|Available        |      280|    220|  106400|  53200|
+-----------------+---------+-------+--------+-------+
|Utilization (%)  |        0|      3|       0|   ~0  |
+-----------------+---------+-------+--------+-------+

+ Detail: 
    * Instance: 
    N/A

    * Memory: 
    N/A

    * FIFO: 
    N/A

    * Shift register: 
    N/A

    * Expression: 
    +-----------------------+----------+-------+---+----+------------+------------+
    |     Variable Name     | Operation| DSP48E| FF| LUT| Bitwidth P0| Bitwidth P1|
    +-----------------------+----------+-------+---+----+------------+------------+
    |tmp_11_cast_fu_281_p2  |     *    |      1|  0|   0|           8|          12|
    |tmp_1_fu_136_p2        |     *    |      1|  0|   0|           8|          12|
    |tmp_2_fu_142_p2        |     *    |      1|  0|   0|           8|           9|
    |tmp_6_fu_179_p2        |     *    |      1|  0|   0|           8|          10|
    |tmp_7_cast_fu_189_p2   |     *    |      1|  0|   0|           8|          12|
    |tmp_7_fu_287_p2        |     *    |      1|  0|   0|           8|           9|
    |tmp_fu_126_p2          |     *    |      1|  0|   0|           8|          10|
    |tmp1_fu_152_p2         |     +    |      0|  0|  19|          19|          19|
    |tmp_10_fu_321_p2       |     +    |      0|  0|  21|          21|          21|
    |tmp_5_fu_219_p2        |     +    |      0|  0|  21|          21|          21|
    |p_neg1_fu_335_p2       |     -    |      0|  0|  21|           1|          21|
    |p_neg5_fu_233_p2       |     -    |      0|  0|  21|           1|          21|
    |p_neg_t1_fu_355_p2     |     -    |      0|  0|  10|           1|          10|
    |p_neg_t7_fu_253_p2     |     -    |      0|  0|  10|           1|          10|
    |Cb_fu_389_p3           |  Select  |      0|  0|  10|           1|           1|
    |Cr_fu_419_p3           |  Select  |      0|  0|  10|           1|           1|
    |agg_result_Cb_V        |  Select  |      0|  0|   8|           1|           2|
    |agg_result_Cr_V        |  Select  |      0|  0|   8|           1|           2|
    |tmp_13_fu_375_p3       |  Select  |      0|  0|  10|           1|          10|
    |tmp_s_fu_273_p3        |  Select  |      0|  0|  10|           1|          10|
    |icmp1_fu_437_p2        |   icmp   |      0|  0|   2|           2|           1|
    |icmp_fu_407_p2         |   icmp   |      0|  0|   2|           2|           1|
    |tmp_14_fu_383_p2       |   icmp   |      0|  0|  26|          21|          13|
    |tmp_15_fu_413_p2       |   icmp   |      0|  0|  26|          21|          13|
    +-----------------------+----------+-------+---+----+------------+------------+
    |Total                  |          |      7|  0| 235|         173|         251|
    +-----------------------+----------+-------+---+----+------------+------------+

    * Multiplexer: 
    N/A

    * Register: 
    N/A



================================================================
== Interface
================================================================
* Summary: 
+------------------------+-----+-----+------------+-----------------+--------------+
|        RTL Ports       | Dir | Bits|  Protocol  |  Source Object  |    C Type    |
+------------------------+-----+-----+------------+-----------------+--------------+
|ap_start                |  in |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|ap_done                 | out |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|ap_idle                 | out |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|ap_ready                | out |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|agg_result_Y_V          | out |    8|   ap_vld   |  agg_result_Y_V |    pointer   |
|agg_result_Y_V_ap_vld   | out |    1|   ap_vld   |  agg_result_Y_V |    pointer   |
|agg_result_Cb_V         | out |    8|   ap_vld   | agg_result_Cb_V |    pointer   |
|agg_result_Cb_V_ap_vld  | out |    1|   ap_vld   | agg_result_Cb_V |    pointer   |
|agg_result_Cr_V         | out |    8|   ap_vld   | agg_result_Cr_V |    pointer   |
|agg_result_Cr_V_ap_vld  | out |    1|   ap_vld   | agg_result_Cr_V |    pointer   |
|s_R_V                   |  in |    8|   ap_none  |      s_R_V      |    scalar    |
|s_G_V                   |  in |    8|   ap_none  |      s_G_V      |    scalar    |
|s_B_V                   |  in |    8|   ap_none  |      s_B_V      |    scalar    |
+------------------------+-----+-----+------------+-----------------+--------------+
こちらの方が若干小さいです。
Image 017.pngImage 018.png
中間値のbit幅が自動計算されてます。ap_fixedの時は18bitだった変数が自動で必要な幅になってます。また、リソースも減ってます。丸めやサチュレーション関連の回路でしょうか。

PlanAheadでインプリしたところ。
   Number of DSP48E1s                        5 out of 220     2%
   Number of External IOBs                  55 out of 200    27%
      Number of LOCed IOBs                   0 out of 55      0%

   Number of Slices                         60 out of 13300   1%
   Number of Slice Registers                 1 out of 106400  1%
      Number used as Flip Flops              1
      Number used as Latches                 0
      Number used as LatchThrus              0

   Number of Slice LUTS                    171 out of 53200   1%
   Number of Slice LUT-Flip Flop pairs     171 out of 53200   1%
こちらだと乗算器が減ってます。詳しくは見てませんが、シフトなどでまかなえる部分は最適化されたんだと思います。速度は約23[ns]。だいたい同じです。


精度をユーザがちゃんと制御したい、自動計算だと中間精度のbit数がふくれあがってしまう、などの場合はfixedなどで精度を制御する必要がありますが、普通はintでコンパイラ任せの方がなんか良さそうです。第一楽ですし。

Vivado HLS を使ってみた(その4) [FPGA]

浮動小数点のままではさすがにでかいし、精度過剰なので固定小数点化します。
#define	fw	12

YCbCr rgb2ycbcr(RGB s)
{
    YCbCr    d;

    const ap_fixed<2+dw+fw, fw, AP_RND_CONV, AP_SAT> cY [3] = { 0.2126f,  0.7152f,  0.0722f };
    const ap_fixed<2+dw+fw, fw, AP_RND_CONV, AP_SAT> cCb[3] = {-0.1146f, -0.3854f,  0.5000f };
    const ap_fixed<2+dw+fw, fw, AP_RND_CONV, AP_SAT> cCr[3] = { 0.5000f, -0.4542f, -0.0458f };
    const ap_fixed<2+dw+fw, fw, AP_RND_CONV, AP_SAT> op5    = 0.5f * dat;
    const ap_fixed<2+dw+fw, fw, AP_RND_CONV, AP_SAT> llim   = 0.0f;
    const ap_fixed<2+dw+fw, fw, AP_RND_CONV, AP_SAT> ulim   = (float)(dat-1);

    ap_fixed<2+dw+fw, fw, AP_RND_CONV, AP_SAT> R,G,B;
    ap_fixed<2+dw+fw, fw, AP_RND_CONV, AP_SAT> Y,Cb,Cr;

    R = s.R;
    G = s.G;
    B = s.B;

    Y  = cY [0] * R + cY [1] * G + cY [2] * B;
    Cb = cCb[0] * R + cCb[1] * G + cCb[2] * B + op5;
    Cr = cCr[0] * R + cCr[1] * G + cCr[2] * B + op5;

    if (Y  < llim) Y  = llim;    if (ulim < Y ) Y  = ulim;
    if (Cb < llim) Cb = llim;    if (ulim < Cb) Cb = ulim;
    if (Cr < llim) Cr = llim;    if (ulim < Cr) Cr = ulim;

    d.Y  = Y;
    d.Cb = Cb;
    d.Cr = Cr;

    return d;
}

「ap_fixed<>」が固定小数点を扱う型です。bit数とか丸めモードとかサチュレーションモードとか設定できるようになってます。今は適当。floatの代わりに置き換えています。
まずはシミュレーション。fw(小数点以下の精度)が8bitぐらいだと明らかにおかしな画になりますが、12bitぐらいだと見た目は大丈夫そうです。出力されたBMPファイルをバイナリ比較すると1bitぐらい違います。

C Synthesisをかけてみます。
レポートファイル。
===============================================================
== Vivado HLS Report for 'rgb2ycbcr'
================================================================
* Date:

* Version:        2013.1
* Project:        rgb2ycbcr
* Solution:       solution1
* Product family: zynq zynq_fpv6 
* Target device:  xc7z020clg484-1


================================================================
== Performance Estimates
================================================================
+ Timing (ns): 
    * Summary: 
    +---------+--------+----------+------------+
    |  Clock  | Target | Estimated| Uncertainty|
    +---------+--------+----------+------------+
    |default  |  100.00|     24.80|       12.50|
    +---------+--------+----------+------------+

+ Latency (clock cycles): 
    * Summary: 
    +-----+-----+-----+-----+---------+
    |  Latency  |  Interval | Pipeline|
    | min | max | min | max |   Type  |
    +-----+-----+-----+-----+---------+
    |    0|    0|    1|    1|   none  |
    +-----+-----+-----+-----+---------+

    + Detail: 
        * Instance: 
        N/A

        * Loop: 
        N/A



================================================================
== Utilization Estimates
================================================================
* Summary: 
+-----------------+---------+-------+--------+-------+
|       Name      | BRAM_18K| DSP48E|   FF   |  LUT  |
+-----------------+---------+-------+--------+-------+
|Expression       |        -|      7|       0|    372|
|FIFO             |        -|      -|       -|      -|
|Instance         |        -|      -|       -|      -|
|Memory           |        -|      -|       -|      -|
|Multiplexer      |        -|      -|       -|      -|
|Register         |        -|      -|       -|      -|
|ShiftMemory      |        -|      -|       -|      -|
+-----------------+---------+-------+--------+-------+
|Total            |        0|      7|       0|    372|
+-----------------+---------+-------+--------+-------+
|Available        |      280|    220|  106400|  53200|
+-----------------+---------+-------+--------+-------+
|Utilization (%)  |        0|      3|       0|   ~0  |
+-----------------+---------+-------+--------+-------+

+ Detail: 
    * Instance: 
    N/A

    * Memory: 
    N/A

    * FIFO: 
    N/A

    * Shift register: 
    N/A

    * Expression: 
    +--------------------------+----------+-------+---+----+------------+------------+
    |       Variable Name      | Operation| DSP48E| FF| LUT| Bitwidth P0| Bitwidth P1|
    +--------------------------+----------+-------+---+----+------------+------------+
    |r_V_13_fu_246_p2          |     *    |      1|  0|   0|          18|           8|
    |r_V_17_fu_342_p2          |     *    |      1|  0|   0|          18|           7|
    |r_V_8_fu_140_p2           |     *    |      1|  0|   0|          18|          10|
    |r_V_9_fu_154_p2           |     *    |      1|  0|   0|          18|           8|
    |r_V_fu_130_p2             |     *    |      1|  0|   0|          18|           7|
    |rhs_V_2_cast_fu_256_p2    |     *    |      1|  0|   0|          18|          10|
    |rhs_V_4_cast_fu_360_p2    |     *    |      1|  0|   0|          18|          10|
    |p_Val2_11_fu_336_p2       |     +    |      0|  0|  18|          18|          18|
    |p_Val2_17_fu_440_p2       |     +    |      0|  0|  18|          18|          18|
    |p_Val2_5_fu_232_p2        |     +    |      0|  0|  18|          18|          18|
    |r_V_10_fu_164_p2          |     +    |      0|  0|  28|          28|          28|
    |r_V_11_fu_174_p2          |     +    |      0|  0|  28|          28|          28|
    |r_V_15_fu_272_p2          |     +    |      0|  0|  28|          28|          28|
    |Cb_V_fu_466_p3            |  Select  |      0|  0|  18|           1|          12|
    |Cr_V_fu_480_p3            |  Select  |      0|  0|  18|           1|          12|
    |Y_V_fu_452_p3             |  Select  |      0|  0|  18|           1|          12|
    |qb_assign_1_fu_222_p2     |    and   |      0|  0|   2|           1|           1|
    |qb_assign_3_fu_326_p2     |    and   |      0|  0|   2|           1|           1|
    |qb_assign_5_fu_430_p2     |    and   |      0|  0|   2|           1|           1|
    |r_1_fu_306_p2             |   icmp   |      0|  0|  10|           9|           1|
    |r_2_fu_410_p2             |   icmp   |      0|  0|  10|           9|           1|
    |r_fu_202_p2               |   icmp   |      0|  0|   2|           1|           1|
    |tmp_2_fu_460_p2           |   icmp   |      0|  0|  22|          18|          12|
    |tmp_4_fu_474_p2           |   icmp   |      0|  0|  22|          18|          12|
    |tmp_9_fu_446_p2           |   icmp   |      0|  0|  22|          18|          12|
    |brmerge_i62_i1_fu_320_p2  |    or    |      0|  0|   2|           1|           1|
    |brmerge_i62_i2_fu_424_p2  |    or    |      0|  0|   2|           1|           1|
    |brmerge_i62_i_fu_216_p2   |    or    |      0|  0|   2|           1|           1|
    |r_V_16_fu_278_p2          |    xor   |      0|  0|  40|          28|          29|
    |r_V_21_fu_382_p2          |    xor   |      0|  0|  40|          28|          29|
    +--------------------------+----------+-------+---+----+------------+------------+
    |Total                     |          |      7|  0| 372|         402|         337|
    +--------------------------+----------+-------+---+----+------------+------------+

    * Multiplexer: 
    N/A

    * Register: 
    N/A



================================================================
== Interface
================================================================
* Summary: 
+------------------------+-----+-----+------------+-----------------+--------------+
|        RTL Ports       | Dir | Bits|  Protocol  |  Source Object  |    C Type    |
+------------------------+-----+-----+------------+-----------------+--------------+
|ap_start                |  in |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|ap_done                 | out |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|ap_idle                 | out |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|ap_ready                | out |    1| ap_ctrl_hs |    rgb2ycbcr    | return value |
|agg_result_Y_V          | out |    8|   ap_vld   |  agg_result_Y_V |    pointer   |
|agg_result_Y_V_ap_vld   | out |    1|   ap_vld   |  agg_result_Y_V |    pointer   |
|agg_result_Cb_V         | out |    8|   ap_vld   | agg_result_Cb_V |    pointer   |
|agg_result_Cb_V_ap_vld  | out |    1|   ap_vld   | agg_result_Cb_V |    pointer   |
|agg_result_Cr_V         | out |    8|   ap_vld   | agg_result_Cr_V |    pointer   |
|agg_result_Cr_V_ap_vld  | out |    1|   ap_vld   | agg_result_Cr_V |    pointer   |
|s_R_V                   |  in |    8|   ap_none  |      s_R_V      |    scalar    |
|s_G_V                   |  in |    8|   ap_none  |      s_G_V      |    scalar    |
|s_B_V                   |  in |    8|   ap_none  |      s_B_V      |    scalar    |
+------------------------+-----+-----+------------+-----------------+--------------+

データフローとリソース。
Image 015.pngImage 016.png
なんとまあ、組み合わせ回路になってしまいました。そりゃそうか。できたHDLを見てみると、ap_startがap_done,ready、各_ap_vldに直結されてます。

実際このままPlanAheadに放り込んでZynqでインプリしたところ、
   Number of DSP48E1s                        9 out of 220     4%
   Number of External IOBs                  55 out of 200    27%
      Number of LOCed IOBs                   0 out of 55      0%

   Number of Slices                         18 out of 13300   1%
   Number of Slice Registers                 0 out of 106400  0%
      Number used as Flip Flops              0
      Number used as Latches                 0
      Number used as LatchThrus              0

   Number of Slice LUTS                     60 out of 53200   1%
   Number of Slice LUT-Flip Flop pairs      60 out of 53200   1%
DSPリソースがHLSの計算より多い。多分0.5倍が最適化されずに乗算器が実装されたんでしょう。速度は約21[ns]と若干速いですがほぼ予想値通りです。

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。