openofdm/verilog/equalizer.v
2017-04-03 12:52:03 -04:00

541 lines
14 KiB
Verilog

`include "common_defs.v"
module equalizer
(
input clock,
input enable,
input reset,
input [31:0] sample_in,
input sample_in_strobe,
input ht_next,
output [31:0] phase_in_i,
output [31:0] phase_in_q,
output reg phase_in_stb,
input [31:0] phase_out,
input phase_out_stb,
output [`ROTATE_LUT_LEN_SHIFT-1:0] rot_addr,
input [31:0] rot_data,
output reg [31:0] sample_out,
output reg sample_out_strobe,
output reg [2:0] state
);
// mask[0] is DC, mask[1:26] -> 1,..., 26
// mask[38:63] -> -26,..., -1
localparam SUBCARRIER_MASK =
64'b1111111111111111111111111100000000000111111111111111111111111110;
localparam HT_SUBCARRIER_MASK =
64'b1111111111111111111111111111000000011111111111111111111111111110;
// -7, -21, 21, 7
localparam PILOT_MASK =
64'b0000001000000000000010000000000000000000001000000000000010000000;
localparam DATA_SUBCARRIER_MASK =
SUBCARRIER_MASK ^ PILOT_MASK;
localparam HT_DATA_SUBCARRIER_MASK =
HT_SUBCARRIER_MASK ^ PILOT_MASK;
// -1,..,-26, 26,..,1
localparam LTS_REF =
64'b0000101001100000010100110000000000000000010101100111110101001100;
localparam HT_LTS_REF =
64'b0000101001100000010100110000000000011000010101100111110101001100;
localparam POLARITY =
128'b1111111000111011000101001011111010101000010110111100111001010110011000001101101011101000110010001000000100100110100111101110000;
// 21, 7, -7, -21
localparam HT_POLARITY = 4'b1000;
localparam IN_BUF_LEN_SHIFT = 6;
reg ht;
reg [5:0] num_data_carrier;
// bit masks
reg [63:0] lts_ref;
reg [63:0] ht_lts_ref;
reg [63:0] subcarrier_mask;
reg [63:0] data_subcarrier_mask;
reg [63:0] pilot_mask;
reg [127:0] polarity;
reg [3:0] ht_polarity;
reg [3:0] current_polarity;
reg [3:0] pilot_count;
reg signed [15:0] input_i;
reg signed [15:0] input_q;
reg current_sign;
wire signed [15:0] new_lts_i;
wire signed [15:0] new_lts_q;
wire new_lts_stb;
reg calc_mean_strobe;
reg [5:0] lts_waddr;
reg [6:0] lts_raddr; // one bit wider to detect overflow
reg [15:0] lts_i_in;
reg [15:0] lts_q_in;
reg lts_in_stb;
wire signed [15:0] lts_i_out;
wire signed [15:0] lts_q_out;
wire signed [15:0] lts_q_out_neg = ~lts_q_out + 1;
reg [5:0] in_waddr;
reg [6:0] in_raddr;
wire [15:0] buf_i_out;
wire [15:0] buf_q_out;
reg pilot_in_stb;
wire signed [31:0] pilot_i;
wire signed [31:0] pilot_q;
reg signed [31:0] pilot_sum_i;
reg signed [31:0] pilot_sum_q;
assign phase_in_i = pilot_sum_i;
assign phase_in_q = pilot_sum_q;
reg signed [31:0] pilot_phase;
reg rot_in_stb;
wire signed [15:0] rot_i;
wire signed [15:0] rot_q;
wire [31:0] mag_sq;
wire [31:0] prod_i;
wire [31:0] prod_q;
wire [31:0] prod_i_scaled = prod_i<<`CONS_SCALE_SHIFT;
wire [31:0] prod_q_scaled = prod_q<<`CONS_SCALE_SHIFT;
wire prod_stb;
reg [15:0] num_output;
wire [31:0] norm_i;
wire [31:0] norm_q;
wire norm_out_stb;
reg prod_in_strobe;
wire prod_out_strobe;
ram_2port #(.DWIDTH(32), .AWIDTH(6)) lts_inst (
.clka(clock),
.ena(1),
.wea(lts_in_stb),
.addra(lts_waddr),
.dia({lts_i_in, lts_q_in}),
.doa(),
.clkb(clock),
.enb(1),
.web(1'b0),
.addrb(lts_raddr[5:0]),
.dib(32'hFFFF),
.dob({lts_i_out, lts_q_out})
);
calc_mean lts_i_inst (
.clock(clock),
.enable(enable),
.reset(reset),
.a(lts_i_out),
.b(input_i),
.sign(current_sign),
.input_strobe(calc_mean_strobe),
.c(new_lts_i),
.output_strobe(new_lts_stb)
);
calc_mean lts_q_inst (
.clock(clock),
.enable(enable),
.reset(reset),
.a(lts_q_out),
.b(input_q),
.sign(current_sign),
.input_strobe(calc_mean_strobe),
.c(new_lts_q)
);
ram_2port #(.DWIDTH(32), .AWIDTH(6)) in_buf_inst (
.clka(clock),
.ena(1),
.wea(sample_in_strobe),
.addra(in_waddr),
.dia(sample_in),
.doa(),
.clkb(clock),
.enb(1),
.web(1'b0),
.addrb(in_raddr[5:0]),
.dib(32'hFFFF),
.dob({buf_i_out, buf_q_out})
);
complex_mult pilot_inst (
.clock(clock),
.enable(enable),
.reset(reset),
.a_i(input_i),
.a_q(input_q),
.b_i(lts_i_out),
.b_q(lts_q_out),
.input_strobe(pilot_in_stb),
.p_i(pilot_i),
.p_q(pilot_q),
.output_strobe(pilot_out_stb)
);
rotate rotate_inst (
.clock(clock),
.enable(enable),
.reset(reset),
.in_i(buf_i_out),
.in_q(buf_q_out),
.phase(pilot_phase),
.input_strobe(rot_in_stb),
.rot_addr(rot_addr),
.rot_data(rot_data),
.out_i(rot_i),
.out_q(rot_q),
.output_strobe(rot_out_stb)
);
complex_mult input_lts_prod_inst (
.clock(clock),
.enable(enable),
.reset(reset),
.a_i(rot_i),
.a_q(rot_q),
.b_i(lts_i_out),
.b_q(lts_q_out_neg),
.input_strobe(rot_out_stb),
.p_i(prod_i),
.p_q(prod_q),
.output_strobe(prod_out_strobe)
);
complex_mult lts_lts_prod_inst (
.clock(clock),
.enable(enable),
.reset(reset),
.a_i(lts_i_out),
.a_q(lts_q_out),
.b_i(lts_i_out),
.b_q(lts_q_out_neg),
.input_strobe(rot_out_stb),
.p_i(mag_sq)
);
divider norm_i_inst (
.clock(clock),
.enable(enable),
.reset(reset),
.dividend(prod_i_scaled),
.divisor(mag_sq[23:0]),
.input_strobe(prod_out_strobe),
.quotient(norm_i),
.output_strobe(norm_out_stb)
);
divider norm_q_inst (
.clock(clock),
.enable(enable),
.reset(reset),
.dividend(prod_q_scaled),
.divisor(mag_sq[23:0]),
.input_strobe(prod_out_strobe),
.quotient(norm_q)
);
localparam S_FIRST_LTS = 0;
localparam S_SECOND_LTS = 1;
localparam S_GET_POLARITY = 2;
localparam S_CALC_FREQ_OFFSET = 3;
localparam S_ADJUST_FREQ_OFFSET = 4;
localparam S_HT_LTS = 5;
always @(posedge clock) begin
if (reset) begin
sample_out_strobe <= 0;
lts_raddr <= 0;
lts_waddr <= 0;
sample_out <= 0;
lts_in_stb <= 0;
lts_i_in <= 0;
lts_q_in <= 0;
ht <= 0;
num_data_carrier <= 48;
subcarrier_mask <= SUBCARRIER_MASK;
data_subcarrier_mask <= DATA_SUBCARRIER_MASK;
pilot_mask <= PILOT_MASK;
lts_ref <= LTS_REF;
ht_lts_ref <= HT_LTS_REF;
polarity <= POLARITY;
ht_polarity <= HT_POLARITY;
current_polarity <= 0;
pilot_count <= 0;
in_waddr <= 0;
in_raddr <= 0;
phase_in_stb <= 0;
pilot_sum_i <= 0;
pilot_sum_q <= 0;
pilot_phase <= 0;
pilot_in_stb <= 0;
prod_in_strobe <= 0;
rot_in_stb <= 0;
current_sign <= 0;
input_i <= 0;
input_q <= 0;
calc_mean_strobe <= 0;
num_output <= 0;
state <= S_FIRST_LTS;
end else if (enable) begin
case(state)
S_FIRST_LTS: begin
// store first LTS as is
lts_in_stb <= sample_in_strobe;
{lts_i_in, lts_q_in} <= sample_in;
if (lts_in_stb) begin
if (lts_waddr == 63) begin
lts_waddr <= 0;
lts_raddr <= 0;
state <= S_SECOND_LTS;
end else begin
lts_waddr <= lts_waddr + 1;
end
end
end
S_SECOND_LTS: begin
// calculate and store the mean of the two LTS
if (sample_in_strobe) begin
calc_mean_strobe <= sample_in_strobe;
{input_i, input_q} <= sample_in;
current_sign <= lts_ref[0];
lts_ref <= {lts_ref[0], lts_ref[63:1]};
lts_raddr <= lts_raddr + 1;
end else begin
calc_mean_strobe <= 0;
end
lts_in_stb <= new_lts_stb;
{lts_i_in, lts_q_in} <= {new_lts_i, new_lts_q};
if (lts_in_stb) begin
if (lts_waddr == 63) begin
lts_waddr <= 0;
state <= S_GET_POLARITY;
end else begin
lts_waddr <= lts_waddr + 1;
end
end
end
S_GET_POLARITY: begin
// obtain the polarity of pilot sub-carriers for next OFDM symbol
if (ht) begin
current_polarity <= {
ht_polarity[1]^polarity[0], // -7
ht_polarity[0]^polarity[0], // -21
ht_polarity[3]^polarity[0], // 21
ht_polarity[2]^polarity[0] // 7
};
ht_polarity <= {ht_polarity[0], ht_polarity[3:1]};
end else begin
current_polarity <= {
polarity[0], // -7
polarity[0], // -21
~polarity[0], // 21
polarity[0] // 7
};
end
polarity <= {polarity[0], polarity[127:1]};
pilot_sum_i <= 0;
pilot_sum_q <= 0;
pilot_count <= 0;
in_waddr <= 0;
in_raddr <= 0;
input_i <= 0;
input_q <= 0;
lts_raddr <= 0;
state <= S_CALC_FREQ_OFFSET;
end
S_CALC_FREQ_OFFSET: begin
if (~ht & ht_next) begin
ht <= 1;
num_data_carrier <= 52;
lts_waddr <= 0;
lts_ref <= HT_LTS_REF;
subcarrier_mask <= HT_SUBCARRIER_MASK;
data_subcarrier_mask <= HT_DATA_SUBCARRIER_MASK;
pilot_mask <= PILOT_MASK;
// reverse this extra shift
polarity <= {polarity[126:0], polarity[127]};
state <= S_HT_LTS;
end
// calculate residue freq offset using pilot sub carriers
if (sample_in_strobe) begin
in_waddr <= in_waddr + 1;
lts_raddr <= lts_raddr + 1;
pilot_mask <= {pilot_mask[0], pilot_mask[63:1]};
if (pilot_mask[0]) begin
pilot_count <= pilot_count + 1;
current_polarity <= {current_polarity[0],
current_polarity[3:1]};
// obtain the conjugate of current pilot sub carrier
if (current_polarity[0] == 0) begin
input_i <= sample_in[31:16];
input_q <= ~sample_in[15:0] + 1;
end else begin
input_i <= ~sample_in[31:16] + 1;
input_q <= sample_in[15:0];
end
pilot_in_stb <= 1;
end else begin
pilot_in_stb <= 0;
end
end else begin
pilot_in_stb <= 0;
end
if (pilot_out_stb) begin
pilot_sum_i <= pilot_sum_i + pilot_i;
pilot_sum_q <= pilot_sum_q + pilot_q;
if (pilot_count == 4) begin
phase_in_stb <= 1;
end else begin
phase_in_stb <= 0;
end
end else begin
phase_in_stb <= 0;
end
if (phase_out_stb) begin
`ifdef DEBUG_PRINT
$display("[PILOT OFFSET] %d", phase_out);
`endif
pilot_phase <= phase_out;
in_raddr <= 0;
// compensate for RAM read delay
lts_raddr <= 1;
rot_in_stb <= 0;
num_output <= 0;
state <= S_ADJUST_FREQ_OFFSET;
end
end
S_ADJUST_FREQ_OFFSET: begin
// first rotate, then normalize by avg LTS
if (in_raddr < 64) begin
in_raddr <= in_raddr + 1;
rot_in_stb <= 1;
end else begin
rot_in_stb <= 0;
end
if (rot_out_stb) begin
lts_raddr <= lts_raddr + 1;
end
if (norm_out_stb) begin
data_subcarrier_mask <= {data_subcarrier_mask[0],
data_subcarrier_mask[63:1]};
if (data_subcarrier_mask[0]) begin
sample_out_strobe <= 1;
sample_out <= {norm_i[31], norm_i[14:0],
norm_q[31], norm_q[14:0]};
num_output <= num_output + 1;
end else begin
sample_out_strobe <= 0;
end
end else begin
sample_out_strobe <= 0;
end
if (num_output == num_data_carrier) begin
state <= S_GET_POLARITY;
end
end
S_HT_LTS: begin
if (sample_in_strobe) begin
lts_in_stb <= 1;
ht_lts_ref <= {ht_lts_ref[0], ht_lts_ref[63:1]};
if (ht_lts_ref[0] == 0) begin
{lts_i_in, lts_q_in} <= sample_in;
end else begin
lts_i_in <= ~sample_in[31:16]+1;
lts_q_in <= ~sample_in[15:0]+1;
end
end else begin
lts_in_stb <= 0;
end
if (lts_in_stb) begin
if (lts_waddr == 63) begin
lts_waddr <= 0;
lts_raddr <= 0;
state <= S_GET_POLARITY;
end else begin
lts_waddr <= lts_waddr + 1;
end
end
end
default: begin
state <= S_FIRST_LTS;
end
endcase
end else begin
sample_out_strobe <= 0;
end
end
endmodule