⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ceu.v

📁 信道估计Verilog编程
💻 V
字号:
`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company:  
// Engineer:	
//
// Create Date:    10:22:13 06/27/06
// Design Name:    
// Module Name:    CEU
// Project Name:   
// Target Device:  
// Tool versions:  
// Description:	  该模块实现信道估计和频域均衡,采用复数乘法代替复数除法,实数乘法代替复数乘法,可以
//						  用*代替实例化乘法器,使程序简化,通用性增强,更易阅读;输入输出数据均和使能信号线
//                  成对出现,方便调试;当为导频符号时,输出为接收导频序列的模值的平方,当为数据符号时,
//                  输出为接收数据×本地导频×接收导频的共轭。
// Dependencies:
// 
// Revision:	v1.0
// Revision 0.01 - File Created

// Additional Comments:  综合结果显示该算法逻辑资源占用很少。
// 
////////////////////////////////////////////////////////////////////////////////
module CEU(clk_4M, En_in, Sys_rst, Indata_I, Indata_Q, Odata_I, Odata_Q, En_out, En_all, frm_cout);
 //   parameter pilot = 7'b0101101;   // 导频的幅度
    input clk_4M;
    input Sys_rst;
	 input En_in;
    input [9:0] Indata_I;		// 双口ram的输入,同时作为always块的输入
    input [9:0] Indata_Q;
	 output En_out;
	 output En_all;	            // 输出数据使能信号
	 output [5:0] frm_cout;      // 一帧中的第几个OFDM符号,判断是否是数据符号

/////////////////////////////////////////////////////////////////////////////////////////

	 output [15:0] Odata_I;	// 这里输入数据表示为1,2,7,最大值可能有5位符号位,舍弃两位,保留三位备用
    output [15:0] Odata_Q;
	 reg [19:0] Odata_I1;
	 reg [19:0] Odata_Q1;
	 reg [5:0] counterA;
	 reg [8:0] counterB;    // 两个计数器对一帧符号进行计数
//	 reg [5:0] frm_cout;
//  reg [6:0] pilot;
	 reg [8:0] addr;
	 reg [8:0] addra;
	 reg [8:0] addrb;
	 reg signed [9:0] Intemp_I[0:1];     // 将输入延时一个节拍
	 reg signed [9:0] Intemp_Q[0:1];
	 reg En_in1;	     // 输入使能信号的延时1个周期
	 reg En_in2;		  // 输入使能信号的延时2个周期
	 reg En_in3,En_in4;
	 reg En_out;
	 reg enb1,enb2;

	 wire [9:0] Tdata_I;   // 双口ram的输出
	 wire [9:0] Tdata_Q;
	 reg signed [9:0] Ttemp_I;	  // 缓存
	 reg signed [9:0] Ttemp_Q;
	 wire idata;
	 wire qdata;
	 reg signed [10:0] temp_I;	   // 中间结果
	 reg signed [10:0] temp_Q;
	 wire we;
	 wire En_all;

	 assign Odata_I[15:0] = Odata_I1[19:4];
	 assign Odata_Q[15:0] = Odata_Q1[19:4];
  	 assign we = (counterA == 6'h00 || counterA == 6'h09 || counterA == 6'h12 || counterA == 6'h1b) ? En_in : 0;  // 产生一个dram写使能信号
    assign enb = ~(counterA == 6'h00 || counterA == 6'h09 || counterA == 6'h12 || counterA == 6'h1b) ? En_in : 0;  //产生一个dram读有效信号
	 assign frm_cout = counterA;
	 assign En_all = En_in3;

//////////////////////////////////////////////////////////////////////////	 将均衡结果缩放到8位
/*	always@ (posedge clk_4M)	      
	   if(~Sys_rst)
       	Odata_I11 <= 8'h00;
      else if(Odata_I1[19] == 0)
		    begin
			    Odata_I11[7] <= Odata_I1[19];
				 Odata_I11[6] <= Odata_I1[18] || Odata_I1[17] || Odata_I1[16];
				 Odata_I11[5] <= Odata_I1[15] || Odata_I1[14];
				 Odata_I11[4] <= Odata_I1[13] || Odata_I1[12];
				 Odata_I11[3] <= Odata_I1[11] || Odata_I1[10];
			    Odata_I11[2] <= Odata_I1[9] || Odata_I1[8];
				 Odata_I11[1] <= Odata_I1[7] || Odata_I1[6];
				 Odata_I11[0] <= Odata_I1[5] || Odata_I1[4] || Odata_I1[3] || Odata_I1[2] || Odata_I1[1] || Odata_I1[0];
          end
       else
		    begin
			    Odata_I11[7] <= Odata_I1[19];
				 Odata_I11[6] <= Odata_I1[18] && Odata_I1[17] && Odata_I1[16];
				 Odata_I11[5] <= Odata_I1[15] && Odata_I1[14];
				 Odata_I11[4] <= Odata_I1[13] && Odata_I1[12];
				 Odata_I11[3] <= Odata_I1[11] && Odata_I1[10];
			    Odata_I11[2] <= Odata_I1[9] && Odata_I1[8];
				 Odata_I11[1] <= Odata_I1[7] && Odata_I1[6];
				 Odata_I11[0] <= Odata_I1[5] && Odata_I1[4] && Odata_I1[3] && Odata_I1[2] && Odata_I1[1] && Odata_I1[0];
          end 

	always@ (posedge clk_4M)	      
	   if(~Sys_rst)
       	Odata_Q11 <= 8'h00;
      else if(Odata_Q1[19] == 0)
		    begin
			    Odata_Q11[7] <= Odata_Q1[19];
				 Odata_Q11[6] <= Odata_Q1[18] || Odata_Q1[17] || Odata_Q1[16];
				 Odata_Q11[5] <= Odata_Q1[15] || Odata_Q1[14];
				 Odata_Q11[4] <= Odata_Q1[13] || Odata_Q1[12];
				 Odata_Q11[3] <= Odata_Q1[11] || Odata_Q1[10];
			    Odata_Q11[2] <= Odata_Q1[9] || Odata_Q1[8];
				 Odata_Q11[1] <= Odata_Q1[7] || Odata_Q1[6];
				 Odata_Q11[0] <= Odata_Q1[5] || Odata_Q1[4] || Odata_Q1[3] || Odata_Q1[2] || Odata_Q1[1] || Odata_Q1[0];
          end
       else
		    begin
			    Odata_Q11[7] <= Odata_Q1[19];
				 Odata_Q11[6] <= Odata_Q1[18] && Odata_Q1[17] && Odata_Q1[16];
				 Odata_Q11[5] <= Odata_Q1[15] && Odata_Q1[14];
				 Odata_Q11[4] <= Odata_Q1[13] && Odata_Q1[12];
				 Odata_Q11[3] <= Odata_Q1[11] && Odata_Q1[10];
			    Odata_Q11[2] <= Odata_Q1[9] && Odata_Q1[8];
				 Odata_Q11[1] <= Odata_Q1[7] && Odata_Q1[6];
				 Odata_Q11[0] <= Odata_Q1[5] && Odata_Q1[4] && Odata_Q1[3] && Odata_Q1[2] && Odata_Q1[1] && Odata_Q1[0];
          end */
///////////////////////////////////////////////////////////////////////////instance rom

  ceu_irom inst_ceu_irom(
   	.addr(addr),
	   .clk(clk_4M),
	   .dout(idata)
		);
  ceu_qrom inst_ceu_qrom(
   	.addr(addr),
	   .clk(clk_4M),
	   .dout(qdata)
		);

///////////////////////////////////////////////////////////////////////////instance ram, store pilot symbol

  ceu_iram inst_ceu_iram(
	  	.addra(addra),
		.addrb(addrb),
		.clka(clk_4M),
		.clkb(clk_4M),
		.dina(Indata_I),
		.doutb(Tdata_I),
		.enb(enb),
		.wea(we)
		);
  ceu_qram inst_ceu_qram(
	  	.addra(addra),
		.addrb(addrb),
		.clka(clk_4M),
		.clkb(clk_4M),
		.dina(Indata_Q),
		.doutb(Tdata_Q),
		.enb(enb), 
		.wea(we)
		);

/////////////////////////////////////////////////////////////////////////////	产生一个对OFDM符号的计数循环
	       

   always@ (posedge clk_4M)	      
	    if(~Sys_rst)
		    counterB <= 9'h000;
       else if(En_in || En_in4)    // 这里往后延迟一些是为了时序上的匹配,16f -> 172;
		    counterB <= counterB + 9'h001;
       else
			 counterB <= 9'h000;

   always@ (posedge clk_4M)	      
	    if(~Sys_rst)
		    counterA <= 6'h00;
       else if(counterB == 9'h172)	    
		    if(counterA == 6'h23)
		        counterA <= 6'h00;
          else
			     counterA <= counterA + 6'h01;
       else
		     counterA <= counterA;


///////////////////////////////////////////////////////////////////////////generator ram and rom address

   always@ (posedge clk_4M)
	    if(~Sys_rst)
		    addr <= 9'h000;
       else if(counterA == 6'h00 || counterA == 6'h09 || counterA == 6'h12 || counterA == 6'h1b)  //第0、9、18、27个为导频符号
		    addr <= 9'h000;
       else if(En_in)   // 当处理数据符号时rom才有效,此时读出的数据和输入数据错开一个周期,故须将输入延时一个周期
		    begin
			    if(addr == 9'h16f)
		          addr <= 9'h000;
             else  addr <= counterB + 9'h001;
          end
       else
		      addr <= 9'h000;
			   
	always@ (posedge clk_4M)
	    if(~Sys_rst)
		    addrb <= 9'h000;
       else if(counterA == 6'h00 || counterA == 6'h09 || counterA == 6'h12 || counterA == 6'h1b)
		    addrb <= 9'h000;
       else if(En_in)	    // 读地址延时一个周期,此时读出数据延时两个周期
		    begin
			    if(addrb == 9'h16f)	  // 从dram中读数据
		          addrb <= 9'h000;
             else  addrb <= counterB + 9'h001;
          end
       else
		     addrb <= 9'h000;   // 为了保证不对同一地址进行读写,写的时候开启再写使能信号
			   		      
	always@ (posedge clk_4M)
	    if(~Sys_rst)
		    addra <= 9'h000;
       else if(En_in && (counterA == 6'h00 || counterA == 6'h09 || counterA == 6'h12 || counterA == 6'h1b))
		    begin			 				  // 当为导频符号时,向dram中写数据
			   if(addra == 9'h16f)
				   addra <= 9'h000;
            else	addra <= counterB + 9'h001;
          end
       else 
		      addra <= 9'h000;

//////////////////////////////////////////////////////////////////////////////////////

   always@ (posedge clk_4M)				// delay En_in 2cycles when dispose data symbol
	     if(~Sys_rst)
				 En_in1 <= 1'b0;
        else 
				 En_in1 <= En_in; 

   always@ (posedge clk_4M)				
	     if(~Sys_rst)
				 En_in2 <= 1'b0;
        else
				 En_in2 <= En_in1;

   always@ (posedge clk_4M)				
	     if(~Sys_rst)
				 En_in3 <= 1'b0;
        else
				 En_in3 <= En_in2;

	always@ (posedge clk_4M)				
	     if(~Sys_rst)
				 En_in4 <= 1'b0;
        else
				 En_in4 <= En_in3;
   
	always@ (posedge clk_4M)				   // for delay purpose;
	     if(~Sys_rst)
				 enb1 <= 1'b0;
        else
				 enb1 <= enb;

   always@ (posedge clk_4M)				
	     if(~Sys_rst)
				 enb2 <= 1'b0;
        else
				 enb2 <= enb1;

   always@ (posedge clk_4M)				
	     if(~Sys_rst)
				 En_out <= 1'b0;
        else
				 En_out <= enb2;

//////////////////////////////////////////////////////////////////////////////////////
	
  always@ (posedge clk_4M)		    // 将输入数据进行延时,使得在时间轴上能很好的匹配
	     if(~Sys_rst)
		     begin
				 Intemp_I[0] <= 10'h000;		
				 Intemp_Q[0] <= 10'h000;
				 Intemp_I[1] <= 10'h000;		
				 Intemp_Q[1] <= 10'h000;
           end
        else
		     begin
				 Intemp_I[0] <= Indata_I;		
				 Intemp_Q[0] <= Indata_Q;
				 Intemp_I[1] <= Intemp_I[0];		
				 Intemp_Q[1] <= Intemp_Q[0];
           end 

  always@ (posedge clk_4M)		    // 将输入数据进行延时,使得在时间轴上能很好的匹配
	     if(~Sys_rst)
		     begin
			    Ttemp_I <= 10'h000;
				 Ttemp_Q <= 10'h000;
           end
        else
		     begin
			    Ttemp_I <= Tdata_I;
				 Ttemp_Q <= Tdata_Q;
			  end			    

//////////////////////////////////////////////////////////////////////////////////////			      		    

   always@ (posedge clk_4M)
	    if(~Sys_rst)
			  begin
				//	En_out <= 0;
				   Odata_I1 <= 20'h00000;
					Odata_Q1 <= 20'h00000;
					temp_I <= 11'h000;	 // 中间结果
					temp_Q <= 11'h000;    
	        end
       else	if(counterA == 6'h00 || counterA == 6'h09 || counterA == 6'h12 || counterA == 6'h1b)   // write pilot symbol to rom
		     if(En_in2) 
			     begin   
					 Odata_I1 <= Intemp_I[1]*Intemp_I[1] + Intemp_Q[1]*Intemp_Q[1];	  // 选取I路存放导频的模值
					 Odata_Q1 <= 20'h00000;
				    temp_I <= 11'h000;	 
				    temp_Q <= 11'h000; 
              end   	     
			  else 
			     begin        
			       Odata_I1 <= 20'h00000;
				    Odata_Q1 <= 20'h00000;
				    temp_I <= 11'h000;	 
				    temp_Q <= 11'h000;    
              end
       else if(En_in1 || En_in2)       // frequence equalization for data symbol
		     begin
				  case({idata,qdata})    // (1+j)*(Indata_I+j*Indata_Q), (1-j)*..., (-1+j)*..., (-1-j)*...; 
				  	 
				    2'b00:    begin  temp_I <= Intemp_Q[0] - Intemp_I[0];			  // 输入数据乘以本地导频序列
					                  temp_Q <= 0 - (Intemp_I[0] + Intemp_Q[0]);  
								  end
                2'b01:	  begin  temp_I <= 0 - (Intemp_Q[0] + Intemp_I[0]);
					                  temp_Q <= Intemp_I[0] - Intemp_Q[0];  
								  end
                2'b10:	  begin  temp_I <= Intemp_Q[0] + Intemp_I[0];
					                  temp_Q <= Intemp_Q[0] - Intemp_I[0];  
								  end											                                         
				    2'b11:    begin  temp_I <= Intemp_I[0] - Intemp_Q[0];
					                  temp_Q <= Intemp_I[0] + Intemp_Q[0];  
								  end 								     
	           endcase
			     Odata_I1 <= temp_I*Ttemp_I + temp_Q*Ttemp_Q;	  // 这里我们只取21位中的20位,并不需要进行符号位扩展;
				  Odata_Q1 <= temp_Q*Ttemp_I - temp_I*Ttemp_Q;

           end
       else
		     begin
			     Odata_I1 <= 20'h00000;
				  Odata_Q1 <= 20'h00000;
			     temp_I <= 11'h000;
				  temp_Q <= 11'h000;
           end

endmodule

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -