OpenRisc-31-关于在设计具有DMA功能的ipcore时的虚实地址转换问题的分析与解决

引言

之前,我们在讨论基于ORPSoC的ipcore设计时提到过DMA的问题,当时我们实现DMA的功能时,访问的是local memory,并没有使用主存(即外部的SDRAM),使用的是本地的一块存储区域。所以也就不存在虚实地址转换的问题。但是,要想实现一个规范的,通用的,真正意义上的附带有DMA功能的ipcore,虚实地址转换就是必须要解决的问题了。

比如,软件要vga controller通过DMA显示一帧图片,软件必须把这帧图片的物理地址告诉vga controller,但是软件中使用的都是虚拟地址,所以就必须做虚实地址转换操作才行,当然,vga controller模块有local TLB的除外,这里介绍的是外部ipcore共用主TLB。

关于之前带有DMA功能的ipcore的设计,请参考:

http://blog.csdn.net/rill_zhen/article/details/8784510


本小节就解决这个问题。


1,基本思想

1>整体介绍

本小节实现一个ipcore,实现与软件的存储器访问共享。

2>验证步骤

1》软件(驱动)使用virt_adr=kmalloc(4,GFP_DMA);获得一个虚拟地址。

2》将这个虚拟地址转换为物理地址:phy_adr=virt_to_phys(virt_adr);

3》软件向这个虚拟地址写值:*virt_adr=0x6789bcdf;

3》软件将这个物理地址发送给ipcore。

4》ipcore根据这个物理地址进行读取,获得这个地址的值

5》将两个值进行比较,确认虚拟地址和物理地址是否是同一块SDRAM区域。

6》将上述过程反过来,ipcore向物理地址写值(这个值软件事先知道),软件读对应的虚拟地址,然后进行对比。


2,硬件部分

1>硬件组成与操作步骤

基于ORPSoC平台,

1》编写slave模块,接受软件的指令,控制master模块;

2》编写master模块根据slave的控制来访存;

3》编写顶层模块mycore,instanceslave和master两个模块;

4》修改orpsoc_top.v例化mycore。

5》以上步骤在前面的blog中有详细的介绍,请参考,这里不再赘述。

2>代码实现

下面是RTL实现代码:

1》myslave.v


 

/*

*

* rill create 130618

* [email protected]

*/

module myslave

(   

	wb_clk,			

	wb_rst,		

		

	wb_dat_i,			

	wb_adr_i,			

	wb_sel_i,		

	wb_cti_i,	

	wb_bte_i,		

	wb_we_i,		

	wb_cyc_i,		

	wb_stb_i,	

		

	wb_dat_o,		

	wb_ack_o,		

	wb_err_o,                 

	wb_rty_o,

	

	address_o,

	value_o,

	write_o,

	read_o,

	write_ack,

	read_ack,

	value_ack

);



input 			      		    wb_clk;

input 			          		 wb_rst;



input [31:0]      				 wb_adr_i;

input 			    			    wb_stb_i;

input 			    			    wb_cyc_i;

input [2:0] 				       wb_cti_i;

input [1:0] 				       wb_bte_i;

input [31:0] 					    wb_dat_i;

input [3:0] 					    wb_sel_i;

input 								 wb_we_i;

	

output reg [31:0] 		 	    wb_dat_o;

output reg 			      	 	 wb_ack_o;

output 		               	 wb_err_o;

output  					 	       wb_rty_o;



output reg [31:0]					 address_o;

output reg [31:0]					 value_o;

output reg 							 write_o;

output reg							 read_o;

input									 write_ack;

input									 read_ack;

input  		[31:0]				 value_ack;



parameter	address_adr		=8'h04;

parameter   value_adr		=8'h08;

parameter   wr_adr			=8'h18;

parameter   write_done_adr =8'h0c;

parameter   read_done_adr	=8'h10;

parameter   value_ack_adr	=8'h14;

parameter   err_code			=32'habcd_1234;



parameter   read_command	=32'h0000_0002;

parameter	write_command	=32'h0000_0001;



parameter 	s_idle			=9'b000000001;

parameter   s_write_done	=9'b000000010;

parameter   s_read_done 	=9'b000000100;

parameter 	s_read			=9'b000001000;

parameter	s_write			=9'b000010000;

parameter	s_read_pause	=9'b000100000;

parameter	s_write_pause1 =9'b001000000;

parameter   s_write_pause2	=9'b010000000;

parameter 	s_write_pause3	=9'b100000000;



reg [8:0]	state,next_state;

reg [31:0]	value_reg;

reg 			write_done;

reg			read_done;

reg [31:0]	address_reg;

reg [31:0]	value_i_reg;

reg [31:0]	wr_reg;



assign wb_err_o=0;

assign wb_rty_o=0;



always @(posedge wb_clk)

	if(wb_rst)

		state<=s_idle;

	else

		state<=next_state;

		

always @(*)

	begin

	case(state)

		s_idle:

			begin

				if(write_ack)

					next_state=s_write_done;

				else if(read_ack)

					next_state=s_read_done;

				else if(wb_stb_i && wb_cyc_i && wb_we_i)

					next_state=s_write;

				else if(wb_stb_i && wb_cyc_i && !wb_we_i)

					next_state=s_read;

				else

					next_state=s_idle;

			end

		s_write_done:

			begin

				next_state=s_idle;

			end

		s_read_done:

			begin

				next_state=s_idle;

			end

		s_write:

			begin

				next_state=s_write_pause1;

			end

		s_write_pause1:

			begin

				next_state=s_write_pause2;

			end

		s_read:

			begin

				next_state=s_read_pause;

			end

		s_read_pause:

			begin

				next_state=s_idle;

			end

		s_write_pause2:

			begin

				next_state=s_write_pause3;

			end

		s_write_pause3:

			begin

				next_state=s_idle;

			end

		default:

			begin

				next_state=s_idle;

			end

	endcase

 end



 always @(posedge wb_clk)

 if(wb_rst)

	begin

		address_o<=0;

		value_o	<=0;

		write_o	<=0;

		read_o	<=0;

		

		value_reg<=0;

		read_done<=0;

		write_done<=0;

		address_reg<=0;

		value_i_reg<=0;

		wr_reg	<=0;

		

		wb_dat_o<=0;

		wb_ack_o<=0;

	end

else

	begin

	case(next_state)

		s_idle:

			begin

				address_o<=0;

				value_o	<=0;

				write_o	<=0;

				read_o	<=0;

		

				wb_dat_o<=0;

				wb_ack_o<=0;

			 end

		s_read_done:

			begin

				address_o<=0;

				value_o	<=0;

				write_o	<=0;

				read_o	<=0;

		

				wb_dat_o<=0;

				wb_ack_o<=0;  

				

				read_done<=1'b1;

				value_reg<=value_ack;

				

			end

		s_write_done:

			begin

				address_o<=0;

				value_o	<=0;

				write_o	<=0;

				read_o	<=0;

		

				wb_dat_o<=0;

				wb_ack_o<=0;  

				

				write_done<=1'b1;	



			end

		s_read:

			begin

				if(wb_adr_i[7:0] == value_ack_adr)

					wb_dat_o<={value_reg[7:0],value_reg[15:8],value_reg[23:16],value_reg[31:24]};

				else if(wb_adr_i[7:0] == write_done_adr)

					wb_dat_o<=write_done;

				else if(wb_adr_i[7:0] == read_done_adr)

					wb_dat_o<=read_done;

				else if(wb_adr_i[7:0] == address_adr)

					wb_dat_o<={address_reg[7:0],address_reg[15:8],address_reg[23:16],address_reg[31:24]};

				else if(wb_adr_i[7:0] == wr_adr)

					wb_dat_o<=wr_reg;

				else if(wb_adr_i[7:0] == value_adr)

					wb_dat_o<=value_i_reg;

				else

					wb_dat_o<=wb_adr_i;

				   

					wb_ack_o<=0;

					

					address_o<=0;

					value_o	<=0;

					write_o	<=0;

					read_o	<=0;

			end

		s_read_pause:

			begin

					wb_dat_o<=wb_dat_o;

					wb_ack_o<=1'b1;

					

					address_o<=0;

					value_o	<=0;

					write_o	<=0;

					read_o	<=0;		

			end

		s_write:

			begin

				if(wb_adr_i[7:0]== address_adr)

					address_reg<={wb_dat_i[7:0],wb_dat_i[15:8],wb_dat_i[23:16],wb_dat_i[31:24]};

				else if(wb_adr_i[7:0] == value_adr)

					value_i_reg<=wb_dat_i;

				else if(wb_adr_i[7:0] == wr_adr) 

					wr_reg	<= wb_dat_i;

					

					wb_ack_o <=0;

					wb_dat_o	<=0;

					

					address_o<=0;

					value_o	<=0;

					write_o	<=0;

					read_o	<=0;		

			end

		s_write_pause1:

			begin

				if(wr_reg == read_command)

					begin

						read_o<=1'b1;

						address_o<=address_reg;

//						wb_ack_o<=1'b1;

//						wb_dat_o<=0;

//						address_reg<=0;

//						wr_reg<=0;

//						value_reg<=0;

//						read_done<=0;

					end

				else if(wr_reg == write_command)

					begin

						write_o<=1'b1;

//						address_o<={address_reg[7:0],address_reg[15:8],address_reg[23:16],address_reg[31:24]};

						address_o<=address_reg;

						value_o<=value_i_reg;

//						wb_ack_o<=1'b1;

//						wb_dat_o<=0;

//						value_i_reg<=0;

//						address_reg<=0;

//						wr_reg	<=0;

//						write_done<=0;

					end

				else

					begin

						write_o<=0;

						read_o<=0;

					//	wb_ack_o<=1'b1;

					//	wb_dat_o<=0;

						address_o<=0;

						value_o<=0;

					end

				end

			s_write_pause2:

			begin

				if(wr_reg == read_command)

					begin

						read_o<=1'b1;

						address_o<=address_reg;

//						wb_ack_o<=1'b1;

//						wb_dat_o<=0;

//						address_reg<=0;

//						wr_reg<=0;

//						value_reg<=0;

//						read_done<=0;

					end

				else if(wr_reg == write_command)

					begin

						write_o<=1'b1;

					//	address_o<={address_reg[7:0],address_reg[15:8],address_reg[23:16],address_reg[31:24]};

						address_o<=address_reg;

						value_o<=value_i_reg;

//						wb_ack_o<=1'b1;

//						wb_dat_o<=0;

//						value_i_reg<=0;

//						address_reg<=0;

//						wr_reg	<=0;

//						write_done<=0;

					end

				else

					begin

						write_o<=0;

						read_o<=0;

					//	wb_ack_o<=1'b1;

					//	wb_dat_o<=0;

						address_o<=0;

						value_o<=0;

					end

				end	

		s_write_pause3:

				begin

				  if(wr_reg == read_command)

				  begin

						read_o<=0;

						address_o<=0;

						

						

					

						wb_ack_o<=1'b1;

						wb_dat_o<=0;

					

						address_reg<=0;

						wr_reg<=0;

						value_reg<=0;

						read_done<=0;

				  end

				  else if(wr_reg  == write_command)

				  begin

						write_o<=0;

						address_o<=0;

						value_o<=0;

						

					

						wb_ack_o<=1'b1;

						wb_dat_o<=0;

						

						address_reg<=0;

						wr_reg<=0;

						value_i_reg<=0;

						write_done<=0;

					end	

					else

					begin

						write_o<=0;

						read_o<=0;

						

						wb_ack_o<=1'b1;

						wb_dat_o<=0;

						

						address_o<=0;

						value_o<=0;

					end



				end

		

		default:

			begin

				address_o<=0;

				value_o	<=0;

				write_o	<=0;

				read_o	<=0;

		

				value_reg<=0;

				read_done<=0;

				write_done<=0;

				address_reg<=0;

				value_i_reg<=0;

				wr_reg	<=0;

		

				wb_dat_o<=0;

				wb_ack_o<=0;			

			end

		endcase

	end

endmodule

				

				   

	 

	


  
 

 


2》mymaster.v


 

/*

*

* rill create 130618

* [email protected]

*/



module mymaster

(   

	wb_clk,			

	wb_rst,		



	wb_adr_o,

	wb_dat_o,

	wb_sel_o,

	wb_we_o,

	wb_cyc_o,

	wb_stb_o,

	wb_cti_o,

	wb_bte_o,

  

	wb_dat_i,

	wb_ack_i,

	wb_err_i,

	wb_rty_i,

	

	

	write_i ,

	read_i ,

	address_i,

	value_i ,

	write_ack ,

	read_ack,

	value_o 

	

);



//wishbone interface

input							wb_clk;			

input							wb_rst;



input							wb_ack_i; 

input							wb_err_i; 

input							wb_rty_i;

input	[31:0]				wb_dat_i;



output	reg [31:0]		wb_adr_o;

output	reg [31:0]		wb_dat_o;

output	reg 				wb_cyc_o; 

output	reg				wb_stb_o;

output	reg [3:0]		wb_sel_o;

output	reg 				wb_we_o;

output	reg [2:0]		wb_cti_o;

output	reg [1:0]		wb_bte_o;

input							write_i;

input							read_i;

input		 [31:0]		address_i;

input		 [31:0]		value_i;

output	reg [31:0]	value_o;

output 	reg 			write_ack;

output	reg 			read_ack;



parameter	m_idle			=	9'b000000001;

parameter   m_write_ready	=  9'b010000000;

parameter	m_read_ready	=	9'b100000000;

parameter	m_write_begin	=	9'b000000010;

parameter	m_write_wait	=	9'b000000100;

parameter	m_write_done	=	9'b000001000;

parameter	m_read_begin	=	9'b000010000;

parameter	m_read_wait		=	9'b000100000;

parameter 	m_read_done		=	9'b001000000;

parameter cti_default	= 3'b000;

parameter bte_default	= 2'b00;

parameter sel_default	= 4'b1111;

		

reg [8:0] 	state,next_state;



always @(posedge wb_clk)

	if(wb_rst)

		state<=m_idle;

	else

		state<=next_state;



always @(*)

	case(state)

		m_idle:

			begin

				if(write_i)

					next_state=m_write_ready;

				else if(read_i)

					next_state=m_read_ready;

				else 

					next_state=m_idle;

			end

		m_write_ready:

			begin

			next_state=m_write_begin;

			end

		m_read_ready:

			begin

			next_state=m_read_begin;

			end

		m_write_begin:

			begin

				next_state=m_write_wait;

			end

		m_write_wait:

			begin

				if(wb_ack_i)

				next_state=m_write_done;

				else

				next_state=m_write_wait;

			end

		m_write_done:

			begin

			next_state=m_idle;

			end

		m_read_begin:

			begin

			next_state=m_read_wait;

			end

		m_read_wait:

			begin

			if(wb_ack_i)

				next_state=m_read_done;

			else

				next_state=m_read_wait;

			end

		m_read_done:

			begin

				next_state=m_idle;

			end

		default:

			begin

				next_state=m_idle;

			end

	endcase



always @ (posedge wb_clk)

if(wb_rst)

	begin

	wb_adr_o<=0;

	wb_dat_o<=0;

	wb_sel_o<=sel_default;

	wb_we_o<=0;

	wb_cyc_o<=0;

	wb_stb_o<=0;

	wb_cti_o<=cti_default;

	wb_bte_o<=bte_default;

	write_ack<=0;

	read_ack<=0;

	value_o <=0;

	end

else

	begin

		case(next_state)

			m_idle:

				begin

				wb_adr_o<=0;

				wb_dat_o<=0;

				wb_sel_o<=sel_default;

				wb_we_o<=0;

				wb_cyc_o<=0;

				wb_stb_o<=0;

				wb_cti_o<=cti_default;

				wb_bte_o<=bte_default;

				write_ack<=0;

				read_ack<=0;

				value_o <=0;

				end

			m_write_ready:

				begin

				wb_adr_o<=0;

				wb_dat_o<=0;

				wb_cyc_o<=0;

				wb_stb_o<=0;

				wb_we_o<=0;

				end

			m_read_ready:

				begin

				wb_adr_o<=0;

				wb_dat_o<=0;

				wb_cyc_o<=0;

				wb_stb_o<=0;

				wb_we_o<=0;

				 end

			m_write_begin:

				begin

				wb_adr_o<=address_i;

				wb_dat_o<=value_i;

				wb_cyc_o<=1'b1;

				wb_stb_o<=1'b1;

				wb_we_o<=1'b1;

				end

			m_write_wait:

				begin

				wb_adr_o<=wb_adr_o;

				wb_dat_o<=wb_dat_o;

				wb_cyc_o<=wb_cyc_o;

				wb_stb_o<=wb_stb_o;

				wb_we_o<=wb_we_o;

				end

			m_write_done:

				begin

				wb_adr_o<=0;

				wb_dat_o<=0;

				wb_cyc_o<=0;

				wb_stb_o<=0;

				wb_we_o<=0;

				write_ack<=1'b1;

				end

			m_read_begin:

				begin

				wb_adr_o<=address_i;

				wb_dat_o<=0;

				wb_cyc_o<=1'b1;

				wb_stb_o<=1'b1;

				wb_we_o<=0;

				end

			m_read_wait:

				begin

				wb_adr_o<=wb_adr_o;

				wb_dat_o<=wb_dat_o;

				wb_cyc_o<=wb_cyc_o;

				wb_stb_o<=wb_stb_o;

				wb_we_o <=0;

				end

			m_read_done:

				begin

				wb_adr_o<=0;

				wb_dat_o<=0;

				wb_cyc_o<=0;

				wb_stb_o<=0;

				wb_we_o<=0;

				read_ack<=1'b1;

				value_o<=wb_dat_i;

				end

			default:

				begin

				wb_adr_o<=0;

				wb_dat_o<=0;

				wb_sel_o<=sel_default;

				wb_we_o<=0;

				wb_cyc_o<=0;

				wb_stb_o<=0;

				wb_cti_o<=cti_default;

				wb_bte_o<=bte_default;

				write_ack<=0;

				read_ack<=0;

				value_o <=0;

				end

			endcase

	end

endmodule

				


 



3》mycore.v


 

/*

*

* rill create 130618

* [email protected]

*/



module mycore

(   

	//===slave interface signals

	wb_clk,			

	wb_rst,		



	wbs_d_mycore_dat_o,

	wbs_d_mycore_ack_o,

	wbs_d_mycore_err_o,

	wbs_d_mycore_rty_o,



	wbs_d_mycore_adr_i,

	wbs_d_mycore_dat_i,

	wbs_d_mycore_sel_i,

	wbs_d_mycore_we_i,

	wbs_d_mycore_cyc_i,

	wbs_d_mycore_stb_i,

	wbs_d_mycore_cti_i,

	wbs_d_mycore_bte_i,	



	

	

	

	//===master interface signals



	wbm_d_mycore_dat_i,

	wbm_d_mycore_ack_i,

	wbm_d_mycore_err_i,

	wbm_d_mycore_rty_i,



	wbm_d_mycore_adr_o,

	wbm_d_mycore_dat_o,

	wbm_d_mycore_sel_o,

	wbm_d_mycore_we_o,

	wbm_d_mycore_cyc_o,

	wbm_d_mycore_stb_o,

	wbm_d_mycore_cti_o,

	wbm_d_mycore_bte_o

);

	input 				 wb_clk;

	input				   wb_rst;

	output	[31:0]	wbs_d_mycore_dat_o;

	output				wbs_d_mycore_ack_o;

	output				wbs_d_mycore_err_o;

	output				wbs_d_mycore_rty_o;



	input	[31:0]	wbs_d_mycore_adr_i;

	input	[31:0]	wbs_d_mycore_dat_i;

	input	[3:0]		wbs_d_mycore_sel_i;

	input				wbs_d_mycore_we_i;

	input				wbs_d_mycore_cyc_i;

	input				wbs_d_mycore_stb_i;

	input	[2:0]		wbs_d_mycore_cti_i;

	input	[1:0]		wbs_d_mycore_bte_i;

	

	input	[31:0]	wbm_d_mycore_dat_i;

	input				wbm_d_mycore_ack_i;

	input				wbm_d_mycore_err_i;

	input				wbm_d_mycore_rty_i;



	output	[31:0]	wbm_d_mycore_adr_o;

	output	[31:0]	wbm_d_mycore_dat_o;

	output	[3:0]		wbm_d_mycore_sel_o;

	output				wbm_d_mycore_we_o;

	output				wbm_d_mycore_cyc_o;

	output				wbm_d_mycore_stb_o;

	output	[2:0]		wbm_d_mycore_cti_o;

	output	[1:0]		wbm_d_mycore_bte_o;

	

	wire 		[31:0]	address;

	wire		[31:0]	value;

	wire					write;

	wire					read;

	wire					read_ack;

	wire					write_ack;

	wire		[31:0]	value_ack;

	myslave myslave0

	(

	.wb_clk(wb_clk),

	.wb_rst(wb_rst),

	.wb_adr_i(wbs_d_mycore_adr_i),

	.wb_dat_i(wbs_d_mycore_dat_i),

	.wb_sel_i(wbs_d_mycore_sel_i),

	.wb_we_i(wbs_d_mycore_we_i),

	.wb_cyc_i(wbs_d_mycore_cyc_i),

	.wb_stb_i(wbs_d_mycore_stb_i),

	.wb_cti_i(wbs_d_mycore_cti_i),

	.wb_bte_i(wbs_d_mycore_bte_i),

   

	.wb_dat_o(wbs_d_mycore_dat_o),   

	.wb_ack_o(wbs_d_mycore_ack_o),

	.wb_err_o(wbs_d_mycore_err_o),

	.wb_rty_o(wbs_d_mycore_rty_o),

	.address_o(address),

	.value_o(value),

	.write_o(write),

	.read_o(read),

	.write_ack(write_ack),

	.read_ack(read_ack),

	.value_ack(value_ack)

	); 

	mymaster mymaster0

	(

	.wb_clk (wb_clk),			

	.wb_rst (wb_rst),



	.wb_adr_o (wbm_d_mycore_adr_o),

	.wb_dat_o (wbm_d_mycore_dat_o),

	.wb_sel_o (wbm_d_mycore_sel_o),

	.wb_we_o (wbm_d_mycore_we_o),

	.wb_cyc_o (wbm_d_mycore_cyc_o),

	.wb_stb_o (wbm_d_mycore_stb_o),

	.wb_cti_o (wbm_d_mycore_cti_o),

	.wb_bte_o (wbm_d_mycore_bte_o),

  

	.wb_dat_i (wbm_d_mycore_dat_i),

	.wb_ack_i (wbm_d_mycore_ack_i),

	.wb_err_i (wbm_d_mycore_err_i),

	.wb_rty_i (wbm_d_mycore_rty_i),

	

//internal signals

	.write_i (write),

	.read_i (read),

	.address_i (address),

	.value_i (value),

	.write_ack (write_ack),

	.read_ack (read_ack),

	.value_o (value_ack)

	);

endmodule





/************** EOF ****************/


 


3,软件部分

1>介绍

为了测试虚实转换的正确性,编写ipcore的linux驱动是必须的,以实现之前介绍的验证步骤,软件部分的操作流程,前面已经介绍了。这里直接将代码贴在这里,一目了然。

细心的读者可能会发现,在给ipcore传数据的时候并没有做byteorder的转换(大小端的问题,之前反复提到过),这是因为之前对字节序的转换是驱动做的,这次是硬件做的(RTL里面增加了相应的逻辑,请仔细看硬件部分的代码便知),道理一样,不必疑惑。

2>代码实现

还跟之前的驱动一样,共三部分组成。

1》ip_mkg.c


 

/*

*

* rill mkg driver

*

*/

#include <linux/vmalloc.h>

#include <linux/slab.h>

#include <linux/gfp.h>

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/fs.h>

#include <asm/uaccess.h> /* get_user and put_user */

//#include <linux/clk.h>

//#include <linux/ioport.h>

#include <asm/io.h> /*ioremap*/

#include <linux/platform_device.h> /*cleanup_module*/

#include <linux/delay.h>

#include <asm-generic/io.h>



#include "ip_mkg.h"







void	__iomem 	*g_mkg_mem_base = NULL;

void  __iomem   *g_mkg_core_base = NULL;



static int device_open(struct inode *inode, struct file *file)

{

	g_mkg_mem_base = ioremap(MKG_MEM_BASE,MKG_MEM_LEN);

	g_mkg_core_base = ioremap (MKG_CORE_BASE, MKG_CORE_LEN);

	

	if(NULL == g_mkg_mem_base)

	{

		printk(KERN_ERR "mkg mem open ioremap error!\n");

		return -1;

	}

	else

	{

		printk("mkg mem ioremap addr:%d!\n",(int)g_mkg_mem_base);

	} 

		if(NULL == g_mkg_core_base)

	{

		printk(KERN_ERR "mkg core open ioremap error!\n");

		return -1;

	}

	else

	{

		printk("mkg core ioremap addr:%d!\n",(int)g_mkg_core_base);

	}

 

	return 0;

}



static int device_release(struct inode *inode, struct file *file)

{

	return 0;

}





static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset)

{

	/*int ret_val = 0;



	char * data = NULL;

	

	data = (char*)kmalloc(4, GFP_KERNEL);

	if((ret_val = copy_from_user(new_regs, (struct reg_data*)ioctl_param, sizeof(struct reg_data))) != 0) 



	ioread32(g_mkg_mem_base+length);

	printk("============read:%d\n",);*/

	

	return 1;

}



static ssize_t device_write(struct file *filp, const char *buffer, size_t count, loff_t *offset)

{

	//iowrite32(2,g_mkg_mem_base);

	return 1;

}



long device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)

{

#if 0



   int ret_val = 0;

   unsigned int ret = 0;

   struct reg_data *new_regs;

   printk("ioctl======\n");



   switch(ioctl_num)

   {

      case IOCTL_REG_SET:

	  {

		 new_regs = (struct reg_data*)kmalloc(sizeof(struct reg_data), GFP_KERNEL);

		 if((ret_val = copy_from_user(new_regs, (struct reg_data*)ioctl_param, sizeof(struct reg_data))) != 0) 

		 	{

			    kfree(new_regs);

			    printk(KERN_ERR " error copy line_datafrom user.\n");

				return -1;

		 	}



			//iowrite16(new_regs->value,g_mkg_mem_base+new_regs->addr);

		 kfree(new_regs);

     }

	 break;



	case IOCTL_REG_GET:

	{

	 new_regs = (struct reg_data*)kmalloc(sizeof(struct reg_data), GFP_KERNEL);

	 if((ret_val = copy_from_user(new_regs, (struct reg_data*)ioctl_param, sizeof(struct reg_data))) != 0) 

	 	{

		    kfree(new_regs);

		    printk(KERN_ERR " error copy line_datafrom user.\n");

			return -1;

	 	}



		//ret = ioread16(g_mkg_mem_base+new_regs->addr);

	 	kfree(new_regs);

		return ret;

	}

	break;

      

   }

#endif



  return -1;

}



struct file_operations our_file_ops = {

  .unlocked_ioctl = device_ioctl,

  .read = device_read,

  .write = device_write,

  .open = device_open,

  .release = device_release,

  .owner = THIS_MODULE,

};





int ToBigEndian(int lit_End)

{

   char * p=(char *)&lit_End;

   

   return (int)(p[0]<<24)+(int)(p[1]<<16)+(int)(p[2]<<8)+(int)(p[3]);

}

void test(void)

{  

 

    unsigned int  * virt_adr;

    unsigned int phy_adr;

    int write_done=0,read_done=0,read_value=0;

    unsigned int final_phy_adr;

    char *p;

    int read=0;

    virt_adr=kmalloc(4,GFP_DMA);

    if(!virt_adr)

    printk("apply for kernel memory fails !\n");

     

    phy_adr=virt_to_phys(virt_adr);

    printk("virtual address !0x%x \n ",virt_adr);		

     printk("original physical address !0x%x \n",phy_adr); 



    *virt_adr=0x6789bcdf;

    final_phy_adr=phy_adr;

 //   final_phy_adr=0x98000040;

    printk("final physical address !0x%x \n ",final_phy_adr); 

//  test begin

//  write first number : final_phy_adr

    printk("test begin \n write first number : final_phy_adr\n");

    iowrite32(final_phy_adr,g_mkg_core_base+0x4);

    printk("write address done !\n");

    read=ioread32(g_mkg_core_base+0x4);

    printk("write address : 0x%x \n",read);

    iowrite32(0x3956abcd,g_mkg_core_base+0x8);

    printk("write value done !\n");

    read=ioread32(g_mkg_core_base+0x8);

    printk("write value : 0x%x \n",read);

    iowrite32(0x01000000,g_mkg_core_base+0x18);

    printk("write command done !\n");

    printk("write two number:  final_phy_adr+4 \n");

//  write two number:  final_phy_adr+4

iowrite32(final_phy_adr+4,g_mkg_core_base+0x4);

    printk("write address done !\n");

    read=ioread32(g_mkg_core_base+0x4);

    printk("write address : 0x%x \n",read);

    iowrite32(0x3956abcd,g_mkg_core_base+0x8);

    printk("write value done !\n");

    read=ioread32(g_mkg_core_base+0x8);

    printk("write value : 0x%x \n",read);

    iowrite32(0x01000000,g_mkg_core_base+0x18);

    printk("write command done !\n");

//  write third number: final_phy_adr-4

    printk("write third number: final_phy_adr-4 \n");

    iowrite32(final_phy_adr-4,g_mkg_core_base+0x4);

    printk("write address done !\n");

    read=ioread32(g_mkg_core_base+0x4);

    printk("write address : 0x%x \n",read);

    iowrite32(0x3956abcd,g_mkg_core_base+0x8);

    printk("write value done !\n");

    read=ioread32(g_mkg_core_base+0x8);

    printk("write value : 0x%x \n",read);

    iowrite32(0x01000000,g_mkg_core_base+0x18);

    printk("write command done !\n");

//  write forth number:	0x98000040

    printk("write forth number: 98000040 \n");

   iowrite32(0x98000040,g_mkg_core_base+0x4);

    printk("write address done !\n");

    read=ioread32(g_mkg_core_base+0x4);

    printk("write address : 0x%x \n",read);

    iowrite32(0x3956abcd,g_mkg_core_base+0x8);

    printk("write value done !\n");

    read=ioread32(g_mkg_core_base+0x8);

    printk("write value : 0x%x \n",read);

    iowrite32(0x01000000,g_mkg_core_base+0x18);

    printk("write command done !\n");

    read=ioread32(g_mkg_core_base+0x18);

    printk("write command : 0x%x \n",read);

     write_done=ioread32(g_mkg_core_base+0x0c);

//   read first number : final_phy_adr

  printk("read first number : final_phy_adr\n");

     iowrite32(final_phy_adr,g_mkg_core_base+0x4);

    printk("read address done !\n");

    read=ioread32(g_mkg_core_base+0x4);

    printk("read address : 0x%x \n",read);

    iowrite32(0x02000000,g_mkg_core_base+0x18);

    printk("read commnad done !\n");

    read=ioread32(g_mkg_core_base+0x18);

    printk("read command : 0x%x \n",read);

    read_done=ioread32(g_mkg_core_base+0x10);

    read_value=ioread32(g_mkg_core_base+0x14);

    printk("<write_done flag: 0x%x   >\n",write_done);

    printk("<read from or1200: 0x%x  >\n",*virt_adr); 

    printk("<read_done  flag: 0x%x   >\n",read_done);

    printk("<read_value flag: 0x%x   >\n",read_value); 

printk(" read second number	: final_phy_adr+4\n");

//  read second number	: final_phy_adr+4

    iowrite32(final_phy_adr+4,g_mkg_core_base+0x4);

    printk("read address done !\n");

    read=ioread32(g_mkg_core_base+0x4);

    printk("read address : 0x%x \n",read);

    iowrite32(0x02000000,g_mkg_core_base+0x18);

    printk("read commnad done !\n");

    read=ioread32(g_mkg_core_base+0x18);

    printk("read command : 0x%x \n",read);

    read_done=ioread32(g_mkg_core_base+0x10);

    read_value=ioread32(g_mkg_core_base+0x14);

    printk("<read_done  flag: 0x%x   >\n",read_done);

    printk("<read_value flag: 0x%x   >\n",read_value);

printk("  read third number 	: final_phy_adr-4\n");

//  read third number 	: final_phy_adr-4

    iowrite32(final_phy_adr-4,g_mkg_core_base+0x4);

    printk("read address done !\n");

    read=ioread32(g_mkg_core_base+0x4);

    printk("read address : 0x%x \n",read);

    iowrite32(0x02000000,g_mkg_core_base+0x18);

    printk("read commnad done !\n");

    read=ioread32(g_mkg_core_base+0x18);

    printk("read command : 0x%x \n",read);

    read_done=ioread32(g_mkg_core_base+0x10);

    read_value=ioread32(g_mkg_core_base+0x14);

    printk("<read_done  flag: 0x%x   >\n",read_done);

    printk("<read_value flag: 0x%x   >\n",read_value);

 	printk(" read forth number	: 0x98000040\n");

// read forth number	: 0x98000040

    iowrite32(0x98000040,g_mkg_core_base+0x4);

    printk("read address done !\n");

    read=ioread32(g_mkg_core_base+0x4);

    printk("read address : 0x%x \n",read);

    iowrite32(0x02000000,g_mkg_core_base+0x18);

    printk("read commnad done !\n");

    read=ioread32(g_mkg_core_base+0x18);

    printk("read command : 0x%x \n",read);

    read_done=ioread32(g_mkg_core_base+0x10);

    read_value=ioread32(g_mkg_core_base+0x14);

    printk("<read_done  flag: 0x%x   >\n",read_done);

    printk("<read_value flag: 0x%x   >\n",read_value);

   

  



}













int init_module()

{

	int ret_val;

	int ret;

	int ret2;

	void __iomem *ret_from_request;

	void __iomem *ret_from_request2;





	//=== Allocate character device 

	ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &our_file_ops);

	if (ret_val < 0)

	{

		printk(KERN_ALERT " device %s failed(%d)\n", DEVICE_NAME, ret_val);

		return ret_val;

	}



	ret = check_mem_region(MKG_MEM_BASE, MKG_MEM_LEN);

	if (ret < 0) 

	{

		printk(KERN_ERR "mkg check_mem_region bussy error!\n");

		return -1;

	}



	ret_from_request = request_mem_region(MKG_MEM_BASE, MKG_MEM_LEN, "ip_mkg");

	

	ret2 = check_mem_region(MKG_CORE_BASE, MKG_CORE_LEN);

	if (ret2 < 0) 

	{

		printk(KERN_ERR "mkg check_mem_region bussy error!\n");

		return -1;

	}



	ret_from_request2 = request_mem_region(MKG_CORE_BASE, MKG_CORE_LEN, "ip_mkg");



	//===ioremap mkg registers



	g_mkg_mem_base = ioremap(MKG_MEM_BASE,MKG_MEM_LEN);

	if(NULL == g_mkg_mem_base)

	{

		printk(KERN_ERR "mkg mem ioremap error!\n");

		return -1;

	}

	else

	{

		;//printk("mkg ioremap addr:%d!\n",(unsigned int)g_mkg_mem_base);

	}

	

	g_mkg_core_base = ioremap(MKG_CORE_BASE,MKG_CORE_LEN);

	if(NULL == g_mkg_core_base)

	{

		printk(KERN_ERR "mkg core ioremap error!\n");

		return -1;

	}

	else

	{

		;//printk("mkg ioremap addr:%d!\n",(unsigned int)g_mkg_mem_base);

	}



	

  

	printk("mkg module init done!\n");





	test();



	return 0;

}



void cleanup_module()

{

	release_mem_region(MKG_MEM_BASE, MKG_MEM_LEN);

  release_mem_region(MKG_CORE_BASE,MKG_CORE_LEN);

	unregister_chrdev(MAJOR_NUM, DEVICE_NAME);

}



MODULE_LICENSE("GPL");

MODULE_AUTHOR("Rill zhen:[email protected]");






 


2》ip_mkg.h


 

#ifndef __IP_MKG_H__

#define __IP_MKG_H__



#define MAJOR_NUM	102

#define DEVICE_NAME	"ip_mkg"

#define MKG_MEM_BASE 0x98000000

#define MKG_MEM_LEN	3072

#define MKG_CORE_BASE 0x97000000

#define MKG_CORE_LEN 128

#define IOCTL_REG_SET 0

#define IOCTL_REG_GET 1







struct reg_data 

{

	unsigned short addr;

	int value;

};



#endif


 


3》makefile

请参考之前的写法,要编译的文件不同而已。


4,验证

1>将修改后的ORPSoC的工程进行综合

2>编译驱动生成ko文件,在板子上进行测试验证

3>具体操作步骤,前面的blog中有详细介绍,请参考:

http://blog.csdn.net/rill_zhen/article/details/8849149

http://blog.csdn.net/rill_zhen/article/details/8700937


4>结果

因为截屏的话,一屏显示不完整,故只将打印输出信息保存,如下:

可以看出,软件(使用虚拟地址)和硬件(使用物理地址)的访存操作为同一地址。


 

Please press Enter to activate this console. 

# mkdir nfs

# mount -t nfs -o nolock 192.168.1.101:/home/openrisc/nfs nfs

# cd nfs

# insmod ip_mkg.ko 

mkg module init done!

virtual address !0xc1526010 

 original physical address !0x1526010 

final physical address !0x1526010 

 test begin 

 write first number : final_phy_adr

write address done !

write address : 0x1526010 

write value done !

write value : 0x3956abcd 

write command done !

write two number:  final_phy_adr+4 

write address done !

write address : 0x1526014 

write value done !

write value : 0x3956abcd 

write command done !

write third number: final_phy_adr-4 

write address done !

write address : 0x152600c 

write value done !

write value : 0x3956abcd 

write command done !

write forth number: 98000040 

write address done !

write address : 0x98000040 

write value done !

write value : 0x3956abcd 

write command done !

write command : 0x0 

read first number : final_phy_adr

read address done !

read address : 0x1526010 

read commnad done !

read command : 0x0 

<write_done flag: 0x0   >

<read from or1200: 0xcdab5639  >

<read_done  flag: 0x1000000   >

<read_value flag: 0xcdab5639   >

 read second number	: final_phy_adr+4

read address done !

read address : 0x1526014 

read commnad done !

read command : 0x0 

<read_done  flag: 0x1000000   >

<read_value flag: 0xcdab5639   >

  read third number 	: final_phy_adr-4

read address done !

read address : 0x152600c 

read commnad done !

read command : 0x0 

<read_done  flag: 0x1000000   >

<read_value flag: 0xcdab5639   >

 read forth number	: 0x98000040

read address done !

read address : 0x98000040 

read commnad done !

read command : 0x0 

<read_done  flag: 0x1000000   >

<read_value flag: 0xcdab5639   >

# 


 


5,小结

虚实地址转换的问题解决了,中断的问题也解决了(请参考http://blog.csdn.net/rill_zhen/article/details/8894856),那么设计一个完整的具有DMA功能的ipcore,问题就不大了。




 

你可能感兴趣的:(open)