zoukankan      html  css  js  c++  java
  • 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
    * rillzhen@gmail.com
    */
    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
    * rillzhen@gmail.com
    */
    
    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
    * rillzhen@gmail.com
    */
    
    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!
    ");
    		return -1;
    	}
    	else
    	{
    		printk("mkg mem ioremap addr:%d!
    ",(int)g_mkg_mem_base);
    	} 
    		if(NULL == g_mkg_core_base)
    	{
    		printk(KERN_ERR "mkg core open ioremap error!
    ");
    		return -1;
    	}
    	else
    	{
    		printk("mkg core ioremap addr:%d!
    ",(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
    ",);*/
    	
    	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======
    ");
    
       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.
    ");
    				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.
    ");
    			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 !
    ");
         
        phy_adr=virt_to_phys(virt_adr);
        printk("virtual address !0x%x 
     ",virt_adr);		
         printk("original physical address !0x%x 
    ",phy_adr); 
    
        *virt_adr=0x6789bcdf;
        final_phy_adr=phy_adr;
     //   final_phy_adr=0x98000040;
        printk("final physical address !0x%x 
     ",final_phy_adr); 
    //  test begin
    //  write first number : final_phy_adr
        printk("test begin 
     write first number : final_phy_adr
    ");
        iowrite32(final_phy_adr,g_mkg_core_base+0x4);
        printk("write address done !
    ");
        read=ioread32(g_mkg_core_base+0x4);
        printk("write address : 0x%x 
    ",read);
        iowrite32(0x3956abcd,g_mkg_core_base+0x8);
        printk("write value done !
    ");
        read=ioread32(g_mkg_core_base+0x8);
        printk("write value : 0x%x 
    ",read);
        iowrite32(0x01000000,g_mkg_core_base+0x18);
        printk("write command done !
    ");
        printk("write two number:  final_phy_adr+4 
    ");
    //  write two number:  final_phy_adr+4
    iowrite32(final_phy_adr+4,g_mkg_core_base+0x4);
        printk("write address done !
    ");
        read=ioread32(g_mkg_core_base+0x4);
        printk("write address : 0x%x 
    ",read);
        iowrite32(0x3956abcd,g_mkg_core_base+0x8);
        printk("write value done !
    ");
        read=ioread32(g_mkg_core_base+0x8);
        printk("write value : 0x%x 
    ",read);
        iowrite32(0x01000000,g_mkg_core_base+0x18);
        printk("write command done !
    ");
    //  write third number: final_phy_adr-4
        printk("write third number: final_phy_adr-4 
    ");
        iowrite32(final_phy_adr-4,g_mkg_core_base+0x4);
        printk("write address done !
    ");
        read=ioread32(g_mkg_core_base+0x4);
        printk("write address : 0x%x 
    ",read);
        iowrite32(0x3956abcd,g_mkg_core_base+0x8);
        printk("write value done !
    ");
        read=ioread32(g_mkg_core_base+0x8);
        printk("write value : 0x%x 
    ",read);
        iowrite32(0x01000000,g_mkg_core_base+0x18);
        printk("write command done !
    ");
    //  write forth number:	0x98000040
        printk("write forth number: 98000040 
    ");
       iowrite32(0x98000040,g_mkg_core_base+0x4);
        printk("write address done !
    ");
        read=ioread32(g_mkg_core_base+0x4);
        printk("write address : 0x%x 
    ",read);
        iowrite32(0x3956abcd,g_mkg_core_base+0x8);
        printk("write value done !
    ");
        read=ioread32(g_mkg_core_base+0x8);
        printk("write value : 0x%x 
    ",read);
        iowrite32(0x01000000,g_mkg_core_base+0x18);
        printk("write command done !
    ");
        read=ioread32(g_mkg_core_base+0x18);
        printk("write command : 0x%x 
    ",read);
         write_done=ioread32(g_mkg_core_base+0x0c);
    //   read first number : final_phy_adr
      printk("read first number : final_phy_adr
    ");
         iowrite32(final_phy_adr,g_mkg_core_base+0x4);
        printk("read address done !
    ");
        read=ioread32(g_mkg_core_base+0x4);
        printk("read address : 0x%x 
    ",read);
        iowrite32(0x02000000,g_mkg_core_base+0x18);
        printk("read commnad done !
    ");
        read=ioread32(g_mkg_core_base+0x18);
        printk("read command : 0x%x 
    ",read);
        read_done=ioread32(g_mkg_core_base+0x10);
        read_value=ioread32(g_mkg_core_base+0x14);
        printk("<write_done flag: 0x%x   >
    ",write_done);
        printk("<read from or1200: 0x%x  >
    ",*virt_adr); 
        printk("<read_done  flag: 0x%x   >
    ",read_done);
        printk("<read_value flag: 0x%x   >
    ",read_value); 
    printk(" read second number	: final_phy_adr+4
    ");
    //  read second number	: final_phy_adr+4
        iowrite32(final_phy_adr+4,g_mkg_core_base+0x4);
        printk("read address done !
    ");
        read=ioread32(g_mkg_core_base+0x4);
        printk("read address : 0x%x 
    ",read);
        iowrite32(0x02000000,g_mkg_core_base+0x18);
        printk("read commnad done !
    ");
        read=ioread32(g_mkg_core_base+0x18);
        printk("read command : 0x%x 
    ",read);
        read_done=ioread32(g_mkg_core_base+0x10);
        read_value=ioread32(g_mkg_core_base+0x14);
        printk("<read_done  flag: 0x%x   >
    ",read_done);
        printk("<read_value flag: 0x%x   >
    ",read_value);
    printk("  read third number 	: final_phy_adr-4
    ");
    //  read third number 	: final_phy_adr-4
        iowrite32(final_phy_adr-4,g_mkg_core_base+0x4);
        printk("read address done !
    ");
        read=ioread32(g_mkg_core_base+0x4);
        printk("read address : 0x%x 
    ",read);
        iowrite32(0x02000000,g_mkg_core_base+0x18);
        printk("read commnad done !
    ");
        read=ioread32(g_mkg_core_base+0x18);
        printk("read command : 0x%x 
    ",read);
        read_done=ioread32(g_mkg_core_base+0x10);
        read_value=ioread32(g_mkg_core_base+0x14);
        printk("<read_done  flag: 0x%x   >
    ",read_done);
        printk("<read_value flag: 0x%x   >
    ",read_value);
     	printk(" read forth number	: 0x98000040
    ");
    // read forth number	: 0x98000040
        iowrite32(0x98000040,g_mkg_core_base+0x4);
        printk("read address done !
    ");
        read=ioread32(g_mkg_core_base+0x4);
        printk("read address : 0x%x 
    ",read);
        iowrite32(0x02000000,g_mkg_core_base+0x18);
        printk("read commnad done !
    ");
        read=ioread32(g_mkg_core_base+0x18);
        printk("read command : 0x%x 
    ",read);
        read_done=ioread32(g_mkg_core_base+0x10);
        read_value=ioread32(g_mkg_core_base+0x14);
        printk("<read_done  flag: 0x%x   >
    ",read_done);
        printk("<read_value flag: 0x%x   >
    ",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)
    ", 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!
    ");
    		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!
    ");
    		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!
    ");
    		return -1;
    	}
    	else
    	{
    		;//printk("mkg ioremap addr:%d!
    ",(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!
    ");
    		return -1;
    	}
    	else
    	{
    		;//printk("mkg ioremap addr:%d!
    ",(unsigned int)g_mkg_mem_base);
    	}
    
    	
      
    	printk("mkg module init done!
    ");
    
    
    	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:rill_zhen@126.com");
    
    
    



    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,问题就不大了。




  • 相关阅读:
    [排序算法] 选择排序(2种)
    [排序算法] 交换排序(2种)
    针对Oracle表 列字段的增加、删除、修改以及重命名操作sql
    myelcipse中SVN进行代码更新和提交
    SVN服务器的搭建
    无法变更启动序列号
    mybatis入门学习记录(一)
    java中判断两个字符串是否相等的问题
    xshell如何同时打开多个标签
    设计模式(六) xml方式实现AOP
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3143229.html
Copyright © 2011-2022 走看看