📄 ceu.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 + -