finish test of dl814_k7_cal_coarse

archive dl814_k7_cal_coarse_20230419 and dl814_k7_null_verify_20230420, the function of lcmv nulling algorithm and the data exchange between boards are verified by pre-generated data
This commit is contained in:
2023-04-20 11:39:02 +08:00
parent 3c2cd0ba29
commit 14a5d6e48a
1365 changed files with 494026 additions and 186114 deletions
+92
View File
@@ -0,0 +1,92 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/11/01 11:15:25
// Design Name:
// Module Name: clk_dist
// Project Name:
// Target Devices:
// Tool Versions:
// Description: Clock distribution module
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module clk_dist
(
// input clocks
input clk_25m , // generated by osc, 25mhz
// output clocks & reset
// global reset
output sys_rst , // global reset signal, active high
output ant_rst , // phased-array & rf control reset signal, active high
// pl signal processing clock
output sys_clk , // 41.6667mhz
output sys_clk_2x , // 83.3333mhz
output sys_clk_3x , // 125mhz
output sys_clk_4x , // 166.6667mhz
// phased-array & rf control clocks
output clk_96m ,
output clk_48m ,
output clk_32m ,
output clk_19p2m
);
wire osc_clk_48;
wire sys_clk_ld;
assign sys_rst = ~sys_clk_ld;
sys_clk_gen u_sys_clk_gen_stg1
(
// Clock out ports
.clk_out1 (osc_clk_48 ), // output clk_out1
// Clock in ports
.clk_in1 (clk_25m ) // input clk_in1
);
ad9361_clk_gen u_sys_clk_gen
(
// Clock out ports
.clk_out1 (sys_clk ), // output clk_out1
.clk_out2 (sys_clk_2x ), // output clk_out2
.clk_out3 (sys_clk_3x ), // output clk_out3
.clk_out4 (sys_clk_4x ), // output clk_out4
// Status and control signals
.locked (sys_clk_ld ), // output locked
// Clock in ports
.clk_in1 (osc_clk_48 ) // input clk_in1
);
wire ant_clk_ld;
assign ant_rst = ~ant_clk_ld;
ant_clk_gen u_ant_clk_gen
(
// Clock out ports
.clk_out1 (clk_96m ), // output clk_out1
.clk_out2 (clk_48m ), // output clk_out2
.clk_out3 (clk_32m ), // output clk_out3
.clk_out4 (clk_19p2m ), // output clk_out4
// Status and control signals
.locked (ant_clk_ld ), // output locked
// Clock in ports
.clk_in1 (osc_clk_48 ) // input clk_in1
);
endmodule
@@ -0,0 +1,708 @@
// `timescale 1ns / 1ps
// //////////////////////////////////////////////////////////////////////////////////
// // Company:
// // Engineer:
// // _ _ ____
// // | | ___ ___| |__ / ___| __ _ ___
// // _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// // | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// // \___/ \___/|___/_| |_| \____|\__,_|\___/
// //
// // Create Date: 2022/11/06 15:24:48
// // Design Name:
// // Module Name: accor_mat_formatting
// // Project Name:
// // Target Devices:
// // Tool Versions:
// // Description: Formmat the input complex matrix to 1-bit stream.
// // Parameter:
// // ROW_NUM: Row number of input matrix.
// // COL_NUM: Column number of input matrix.
// // DATA_I_WIDTH: Bit width of input matrix element.
// // FRAME_HEAD: Frame head indicate autocorrelation matrix frame.
// // Data format:
// // din_valid: Indicate [din_real/imag] data are valid.
// // din_real/imag: Suppose the input matrix x = [x11 x12; x21 x22], then
// // din_real = {Re{x22}, Re{x21}, Re{x12}, Re{x11}}
// // din_imag = {Im{x22}, Im{x21}, Im{x12}, Im{x11}}
// // dout_valid: Indicate [dout_data] is valid. The latency is set to 2 clock
// // cycles by default.
// // dout_data:
// // dout_data = {FRAME_HEAD[msb], ..., FRAME_HEAD[lsb], FRAME_LEN[msb],
// // ..., FRAME_LEN[lsb], Re{x11}[msb], ..., Re{x11}[lsb], Im{x11}[msb], ...,
// // Im{x11}[lsb], ..., Re{x12}[msb], ......, Im{x22}[lsb]}
// //
// // Dependencies:
// //
// // Revision:
// // Revision 0.01 - File Created
// // Additional Comments:
// //
// //////////////////////////////////////////////////////////////////////////////////
// module accor_mat_formatting
// #(
// parameter ROW_NUM = 4,
// parameter COL_NUM = 4,
// parameter DATA_I_WIDTH = 32,
// parameter FRAME_HEAD = 32'h7E7E7E7E
// )
// (
// // clock & reset
// input clk,
// input rst,
// // input data
// input din_valid,
// input [ROW_NUM*COL_NUM*DATA_I_WIDTH-1 : 0] din_real,
// input [ROW_NUM*COL_NUM*DATA_I_WIDTH-1 : 0] din_imag,
// // output data
// output dout_valid,
// output dout_data
// );
// localparam CMPLX_DIM = 2;
// localparam FRAME_LEN = ROW_NUM*COL_NUM*CMPLX_DIM; // 32-bit data number per frame
// localparam BYTE_LEN = 4 * (ROW_NUM*COL_NUM*CMPLX_DIM + 2); // byte number per frame, plus frame head and frame length
// // available state
// localparam STATE_NUM = 4;
// localparam STATE_IDLE = 0;
// localparam STATE_HEAD = 1;
// localparam STATE_LEN = 2;
// localparam STATE_DATA = 3;
// genvar i;
// // format input data to array
// wire [DATA_I_WIDTH-1 : 0] din_array [0 : ROW_NUM*COL_NUM*CMPLX_DIM-1];
// generate
// for (i = 0; i < ROW_NUM*COL_NUM; i = i + 1) begin: input_mat_reshape
// assign din_array[i*2] = din_real[i*DATA_I_WIDTH +: DATA_I_WIDTH];
// assign din_array[i*2+1] = din_imag[i*DATA_I_WIDTH +: DATA_I_WIDTH];
// end
// endgenerate
// // center state machine & counter
// reg [$clog2(STATE_NUM)-1 : 0] state = STATE_IDLE;
// reg [$clog2(DATA_I_WIDTH)-1 : 0] bit_cnt = 'b0; // bit counter within one frame
// reg [$clog2(FRAME_LEN)-1 : 0] frame_cnt = 'b0; // frame counter
// always @(posedge clk) begin
// if (rst) begin
// state <= STATE_IDLE;
// end
// else begin
// case (state)
// STATE_IDLE: state <= din_valid ? STATE_HEAD : STATE_IDLE;
// STATE_HEAD: state <= (bit_cnt == DATA_I_WIDTH-1) ? STATE_LEN : STATE_HEAD;
// STATE_LEN : state <= (bit_cnt == DATA_I_WIDTH-1) ? STATE_DATA : STATE_LEN;
// STATE_DATA: state <= (frame_cnt == FRAME_LEN-1 && bit_cnt == DATA_I_WIDTH-1) ? STATE_IDLE : STATE_DATA;
// default: state <= STATE_IDLE;
// endcase
// end
// end
// always @(posedge clk) begin
// if (rst) begin
// bit_cnt <= 'b0;
// end
// else if (state == STATE_IDLE) begin
// bit_cnt <= 'b0;
// end
// else begin
// bit_cnt <= (bit_cnt == DATA_I_WIDTH-1) ? 'b0 : bit_cnt + 1'b1;
// end
// end
// always @(posedge clk) begin
// if (rst) begin
// frame_cnt <= 'b0;
// end
// else if (state == STATE_IDLE) begin
// frame_cnt <= 'b0;
// end
// else if (state == STATE_DATA && bit_cnt == DATA_I_WIDTH-1) begin
// frame_cnt <= frame_cnt + 1'b1;
// end
// else begin
// frame_cnt <= frame_cnt;
// end
// end
// // output data
// reg dout_valid_buf = 'b0;
// reg dout_data_buf = 'b0;
// assign dout_valid = dout_valid_buf;
// assign dout_data = dout_data_buf;
// always @(posedge clk) begin
// if (rst) begin
// dout_valid_buf <= 'b0;
// dout_data_buf <= 'b0;
// end
// else case (state)
// STATE_IDLE: begin dout_valid_buf <= 'b0 ; dout_data_buf <= 'b0; end
// STATE_HEAD: begin dout_valid_buf <= 1'b1; dout_data_buf <= FRAME_HEAD[DATA_I_WIDTH-1 - bit_cnt]; end
// STATE_LEN : begin dout_valid_buf <= 1'b1; dout_data_buf <= BYTE_LEN[DATA_I_WIDTH-1 - bit_cnt]; end
// STATE_DATA: begin dout_valid_buf <= 1'b1; dout_data_buf <= din_array[frame_cnt][DATA_I_WIDTH-1 - bit_cnt]; end
// default: begin dout_valid_buf <= 'b0 ; dout_data_buf <= 'b0; end
// endcase
// end
// endmodule
// //////////////////////////////////////////////////////////////////////////////////
// // Company:
// // Engineer:
// // _ _ ____
// // | | ___ ___| |__ / ___| __ _ ___
// // _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// // | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// // \___/ \___/|___/_| |_| \____|\__,_|\___/
// //
// // Create Date: 2022/10/30 20:46:26
// // Design Name:
// // Module Name: tb_accum
// // Project Name:
// // Target Devices:
// // Tool Versions:
// // Description: Testbench for [accor_mat_formatting]
// //
// // Dependencies:
// //
// // Revision:
// // Revision 0.01 - File Created
// // Additional Comments:
// //
// //////////////////////////////////////////////////////////////////////////////////
// // -------------------------------
// // MATLAB Code for data generation
// // -------------------------------
// // COLUMN_NUM = 4;
// // DATA_I_WIDTH = 12;
// // ACC_NUM = 10;
// // rng(0);
// // data = rand(4,2)*2-1;
// // d_12b = round(data.*(2^(DATA_I_WIDTH-1)-1));
// // d_12b_cmplx = d_12b(:,1) + 1i*d_12b(:,2);
// // d_12b_cmplx = d_12b_cmplx(end:-1:1,:);
// // d_12b_acorr = d_12b_cmplx*d_12b_cmplx';
// // d_12b_acorr_real_sim = reshape(flip(reshape(real(d_12b_acorr)',1,16)),4,4);
// // d_12b_acorr_imag_sim = reshape(flip(reshape(imag(d_12b_acorr)',1,16)),4,4);
// // d_12b_acorr_real_sim_sum = ACC_NUM*d_12b_acorr_real_sim;
// // d_12b_acorr_imag_sim_sum = ACC_NUM*d_12b_acorr_imag_sim;
// // module tb_accor_format;
// // localparam DATA_I_WIDTH = 32;
// // localparam ROW_NUM = 4;
// // localparam COL_NUM = 4;
// // reg clk = 1'b1;
// // reg rst = 1'b1;
// // reg din_valid = 'b0;
// // reg [ROW_NUM*COL_NUM*DATA_I_WIDTH-1:0] din_real, din_imag = 'b0;
// // wire dout_valid;
// // wire dout_data;
// // accor_mat_formatting #(
// // .ROW_NUM (ROW_NUM),
// // .COL_NUM (COL_NUM),
// // .DATA_I_WIDTH (DATA_I_WIDTH)
// // ) u_accor_mat_formatting
// // (
// // // clock & reset
// // .clk (clk ),
// // .rst (rst ),
// // // input data
// // .din_valid (din_valid ),
// // .din_real (din_real ),
// // .din_imag (din_imag ),
// // // output data
// // .dout_valid (dout_valid ),
// // .dout_data (dout_data )
// // );
// // initial begin
// // #102 rst = 1'b0;
// // #222;
// // @(posedge clk)
// // din_valid = 1'b1;
// // din_real = {
// // 32'd1952708, 32'd1246152, -32'd2458370, 32'd2283360,
// // 32'd1246152, 32'd5474825, -32'd1041611, 32'd2493996,
// // -32'd2458370, -32'd1041611, 32'd3154378, -32'd2757828,
// // 32'd2283360, 32'd2493996, -32'd2757828, 32'd2899728
// // };
// // din_imag = {
// // 32'd0, -32'd3022886, -32'd340582, -32'd669768,
// // 32'd3022886, 32'd0, -32'd4023023, 32'd3107328,
// // 32'd340582, 32'd4023023, 32'd0, 32'd1241460,
// // 32'd669768, -32'd3107328, -32'd1241460, 32'd0
// // };
// // @(posedge clk)
// // din_valid = 1'b0;
// // end
// // always #10 clk = ~clk;
// // endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/11/06 15:24:48
// Design Name:
// Module Name: accor_mat_formatting
// Project Name:
// Target Devices:
// Tool Versions:
// Description: Formmat the input complex matrix to 1-bit stream.
// Parameter:
// ROW_NUM: Row number of input matrix.
// COL_NUM: Column number of input matrix.
// DATA_I_WIDTH: Bit width of input matrix element.
// FRAME_HEAD: Frame head indicate autocorrelation matrix frame.
// Data format:
// din_valid: Indicate [din_real/imag] data are valid.
// din_real/imag: Suppose the input matrix x = [x11 x12; x21 x22], then
// din_real = {Re{x22}, Re{x21}, Re{x12}, Re{x11}}
// din_imag = {Im{x22}, Im{x21}, Im{x12}, Im{x11}}
// dout_valid: Indicate [dout_data] is valid. The latency is set to 2 clock
// cycles by default.
// dout_data:
// dout_data = {FRAME_HEAD[msb], ..., FRAME_HEAD[lsb], FRAME_LEN[msb],
// ..., FRAME_LEN[lsb], Re{x11}[msb], ..., Re{x11}[lsb], Im{x11}[msb], ...,
// Im{x11}[lsb], ..., Re{x12}[msb], ......, Im{x22}[lsb]}
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module accor_mat_formatting
#(
parameter ROW_NUM = 4,
parameter COL_NUM = 4,
parameter DATA_I_WIDTH = 32,
parameter FRAME_HEAD = 32'h7E7E7E7E
)
(
// clock & reset
input sys_clk,
input sys_rst,
input clk_96m,
input ant_rst,
// input data
input din_valid,
input [ROW_NUM*COL_NUM*DATA_I_WIDTH-1 : 0] din_real,
input [ROW_NUM*COL_NUM*DATA_I_WIDTH-1 : 0] din_imag,
// output data
output dout_valid,
output dout_data
);
localparam CMPLX_DIM = 2;
localparam FRAME_LEN = ROW_NUM*COL_NUM*CMPLX_DIM; // 32-bit data number per frame
localparam BYTE_LEN = 4 * (ROW_NUM*COL_NUM*CMPLX_DIM + 2); // byte number per frame, plus frame head and frame length
// available state
localparam STATE_NUM = 4;
localparam STATE_IDLE = 0;
localparam STATE_HEAD = 1;
localparam STATE_LEN = 2;
localparam STATE_DATA = 3;
genvar i;
integer m;
// format input data to array
wire [DATA_I_WIDTH-1 : 0] din_array [0 : ROW_NUM*COL_NUM*CMPLX_DIM-1];
reg [DATA_I_WIDTH-1 : 0] din_array_cdc [0 : ROW_NUM*COL_NUM*CMPLX_DIM-1];
generate
for (i = 0; i < ROW_NUM*COL_NUM; i = i + 1) begin: input_mat_reshape
assign din_array[i*2] = din_real[i*DATA_I_WIDTH +: DATA_I_WIDTH];
assign din_array[i*2+1] = din_imag[i*DATA_I_WIDTH +: DATA_I_WIDTH];
end
endgenerate
// input clock domain crossing buffer
reg fifo_wr_en = 'b0;
reg fifo_wr_en_d1 = 'b0; // buffer input data for 1 clock cycle
reg [$clog2(ROW_NUM*COL_NUM*CMPLX_DIM)-1 : 0] fifo_wr_cnt = 'b0;
reg [DATA_I_WIDTH-1 : 0] fifo_din = 'b0;
always @(posedge sys_clk) begin
if (sys_rst) begin
fifo_wr_en <= 'b0;
end
else if (din_valid) begin
fifo_wr_en <= 1'b1;
end
else if (fifo_wr_cnt == ROW_NUM*COL_NUM*CMPLX_DIM-1) begin
fifo_wr_en <= 1'b0;
end
else begin
fifo_wr_en <= fifo_wr_en;
end
end
always @(posedge sys_clk) begin
if (sys_rst) begin
fifo_wr_en_d1 <= 'b0;
end
else begin
fifo_wr_en_d1 <= fifo_wr_en;
end
end
always @(posedge sys_clk) begin
if (sys_rst) begin
fifo_wr_cnt <= 'b0;
end
else if (fifo_wr_en) begin
fifo_wr_cnt <= fifo_wr_cnt + 1'b1;
end
else begin
fifo_wr_cnt <= 'b0;
end
end
always @(posedge sys_clk) begin
if (sys_rst) begin
fifo_din <= 'b0;
end
else if (fifo_wr_en) begin
fifo_din <= din_array[fifo_wr_cnt];
end
else begin
fifo_din <= 'b0;
end
end
reg fifo_rd_en = 'b0;
reg fifo_rd_en_d1 = 'b0; // read data latency
reg [$clog2(ROW_NUM*COL_NUM*CMPLX_DIM)-1 : 0] fifo_rd_cnt = 'b0;
reg [$clog2(ROW_NUM*COL_NUM*CMPLX_DIM)-1 : 0] fifo_rd_cnt_d1 = 'b0; // read data latency
reg fifo_rd_valid = 'b0;
wire [DATA_I_WIDTH-1 : 0] fifo_dout;
wire [$clog2(ROW_NUM*COL_NUM*CMPLX_DIM)-1 : 0] fifo_rd_num;
always @(posedge clk_96m) begin
if (ant_rst) begin
fifo_rd_en <= 'b0;
end
else if (fifo_rd_num == ROW_NUM*COL_NUM) begin
fifo_rd_en <= 1'b1;
end
else if (fifo_rd_cnt == ROW_NUM*COL_NUM*CMPLX_DIM-1) begin
fifo_rd_en <= 'b0;
end
else begin
fifo_rd_en <= fifo_rd_en;
end
end
always @(posedge clk_96m) begin
if (ant_rst) begin
fifo_rd_en_d1 <= 'b0;
end
else begin
fifo_rd_en_d1 <= fifo_rd_en;
end
end
always @(posedge clk_96m) begin
if (ant_rst) begin
fifo_rd_cnt <= 'b0;
end
else if (fifo_rd_en) begin
fifo_rd_cnt <= fifo_rd_cnt + 1'b1;
end
else begin
fifo_rd_cnt <= 'b0;
end
end
always @(posedge clk_96m) begin
if (ant_rst) begin
fifo_rd_cnt_d1 <= 'b0;
end
else begin
fifo_rd_cnt_d1 <= fifo_rd_cnt;
end
end
always @(posedge clk_96m) begin
if (ant_rst) begin
fifo_rd_valid <= 'b0;
end
else if (fifo_rd_cnt_d1 == ROW_NUM*COL_NUM*CMPLX_DIM-1) begin
fifo_rd_valid <= 1'b1;
end
else begin
fifo_rd_valid <= 'b0;
end
end
always @(posedge clk_96m) begin
if (ant_rst) begin
for (m = 0; m < ROW_NUM*COL_NUM*CMPLX_DIM; m = m + 1) begin
din_array_cdc[m] <= 'b0;
end
end
else if (fifo_rd_en_d1) begin
din_array_cdc[fifo_rd_cnt_d1] <= fifo_dout;
end
else begin
for (m = 0; m < ROW_NUM*COL_NUM*CMPLX_DIM; m = m + 1) begin
din_array_cdc[m] <= din_array_cdc[m];
end
end
end
fifo_accor_cdc u_fifo_accor_cdc
(
.wr_clk (sys_clk ), // input wire wr_clk
.wr_rst (sys_rst ), // input wire wr_rst
.rd_clk (clk_96m ), // input wire rd_clk
.rd_rst (ant_rst ), // input wire rd_rst
.din (fifo_din ), // input wire [31 : 0] din
.wr_en (fifo_wr_en_d1 ), // input wire wr_en
.rd_en (fifo_rd_en ), // input wire rd_en
.dout (fifo_dout ), // output wire [31 : 0] dout
.full ( ), // output wire full
.empty ( ), // output wire empty
.rd_data_count (fifo_rd_num ) // output wire [4 : 0] rd_data_count
);
// center state machine & counter
reg [$clog2(STATE_NUM)-1 : 0] state = STATE_IDLE;
reg [$clog2(DATA_I_WIDTH)-1 : 0] bit_cnt = 'b0; // bit counter within one frame
reg [$clog2(FRAME_LEN)-1 : 0] frame_cnt = 'b0; // frame counter
always @(posedge clk_96m) begin
if (ant_rst) begin
state <= STATE_IDLE;
end
else begin
case (state)
STATE_IDLE: state <= fifo_rd_valid ? STATE_HEAD : STATE_IDLE;
STATE_HEAD: state <= (bit_cnt == DATA_I_WIDTH-1) ? STATE_LEN : STATE_HEAD;
STATE_LEN : state <= (bit_cnt == DATA_I_WIDTH-1) ? STATE_DATA : STATE_LEN;
STATE_DATA: state <= (frame_cnt == FRAME_LEN-1 && bit_cnt == DATA_I_WIDTH-1) ? STATE_IDLE : STATE_DATA;
default: state <= STATE_IDLE;
endcase
end
end
always @(posedge clk_96m) begin
if (ant_rst) begin
bit_cnt <= 'b0;
end
else if (state == STATE_IDLE) begin
bit_cnt <= 'b0;
end
else begin
bit_cnt <= (bit_cnt == DATA_I_WIDTH-1) ? 'b0 : bit_cnt + 1'b1;
end
end
always @(posedge clk_96m) begin
if (ant_rst) begin
frame_cnt <= 'b0;
end
else if (state == STATE_IDLE) begin
frame_cnt <= 'b0;
end
else if (state == STATE_DATA && bit_cnt == DATA_I_WIDTH-1) begin
frame_cnt <= frame_cnt + 1'b1;
end
else begin
frame_cnt <= frame_cnt;
end
end
// output data
reg dout_valid_buf = 'b0;
reg dout_data_buf = 'b0;
assign dout_valid = dout_valid_buf;
assign dout_data = dout_data_buf;
always @(posedge clk_96m) begin
if (ant_rst) begin
dout_valid_buf <= 'b0;
dout_data_buf <= 'b0;
end
else case (state)
STATE_IDLE: begin dout_valid_buf <= 'b0 ; dout_data_buf <= 'b0; end
STATE_HEAD: begin dout_valid_buf <= 1'b1; dout_data_buf <= FRAME_HEAD[DATA_I_WIDTH-1 - bit_cnt]; end
STATE_LEN : begin dout_valid_buf <= 1'b1; dout_data_buf <= BYTE_LEN[DATA_I_WIDTH-1 - bit_cnt]; end
STATE_DATA: begin dout_valid_buf <= 1'b1; dout_data_buf <= din_array_cdc[frame_cnt][DATA_I_WIDTH-1 - bit_cnt]; end
default: begin dout_valid_buf <= 'b0 ; dout_data_buf <= 'b0; end
endcase
end
endmodule
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/10/30 20:46:26
// Design Name:
// Module Name: tb_accum
// Project Name:
// Target Devices:
// Tool Versions:
// Description: Testbench for [accor_mat_formatting]
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
// -------------------------------
// MATLAB Code for data generation
// -------------------------------
// COLUMN_NUM = 4;
// DATA_I_WIDTH = 12;
// ACC_NUM = 10;
// rng(0);
// data = rand(4,2)*2-1;
// d_12b = round(data.*(2^(DATA_I_WIDTH-1)-1));
// d_12b_cmplx = d_12b(:,1) + 1i*d_12b(:,2);
// d_12b_cmplx = d_12b_cmplx(end:-1:1,:);
// d_12b_acorr = d_12b_cmplx*d_12b_cmplx';
// d_12b_acorr_real_sim = reshape(flip(reshape(real(d_12b_acorr)',1,16)),4,4);
// d_12b_acorr_imag_sim = reshape(flip(reshape(imag(d_12b_acorr)',1,16)),4,4);
// d_12b_acorr_real_sim_sum = ACC_NUM*d_12b_acorr_real_sim;
// d_12b_acorr_imag_sim_sum = ACC_NUM*d_12b_acorr_imag_sim;
// module tb_accor_format;
// localparam DATA_I_WIDTH = 32;
// localparam ROW_NUM = 4;
// localparam COL_NUM = 4;
// reg sys_clk = 1'b1;
// reg sys_rst = 1'b1;
// reg clk_96m = 1'b1;
// reg ant_rst = 1'b1;
// reg din_valid = 'b0;
// reg [ROW_NUM*COL_NUM*DATA_I_WIDTH-1:0] din_real = 'b0, din_imag = 'b0;
// wire dout_valid;
// wire dout_data;
// accor_mat_formatting #(
// .ROW_NUM (ROW_NUM),
// .COL_NUM (COL_NUM),
// .DATA_I_WIDTH (DATA_I_WIDTH)
// ) u_accor_mat_formatting
// (
// // clock & reset
// .sys_clk (sys_clk ), // input sys_clk
// .sys_rst (sys_rst ), // input sys_rst
// .clk_96m (clk_96m ), // input clk_96m
// .ant_rst (ant_rst ), // input ant_rst
// // input data
// .din_valid (din_valid ),
// .din_real (din_real ),
// .din_imag (din_imag ),
// // output data
// .dout_valid (dout_valid ),
// .dout_data (dout_data )
// );
// initial begin
// #102
// sys_rst = 1'b0;
// ant_rst = 1'b0;
// #222;
// @(posedge sys_clk)
// din_valid = 1'b1;
// din_real = {
// 32'd1952708, 32'd1246152, -32'd2458370, 32'd2283360,
// 32'd1246152, 32'd5474825, -32'd1041611, 32'd2493996,
// -32'd2458370, -32'd1041611, 32'd3154378, -32'd2757828,
// 32'd2283360, 32'd2493996, -32'd2757828, 32'd2899728
// };
// din_imag = {
// 32'd1, -32'd3022886, -32'd340582, -32'd669768,
// 32'd3022886, 32'd2, -32'd4023023, 32'd3107328,
// 32'd340582, 32'd4023023, 32'd3, 32'd1241460,
// 32'd669768, -32'd3107328, -32'd1241460, 32'd4
// };
// @(posedge sys_clk)
// din_valid = 1'b0;
// end
// always begin
// #20 sys_clk = ~sys_clk;
// end
// always begin
// #7;
// clk_96m = ~clk_96m;
// #3;
// end
// endmodule
@@ -0,0 +1,332 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/11/02 11:06:43
// Design Name:
// Module Name: accum_cmplx_mat
// Project Name:
// Target Devices:
// Tool Versions: 2019.1.3
// Description: Compute the accumulation of complex matrices. The row number
// [ROW_NUM] and column number [ROW_NUM] are flexible parameters. The
// accumulation number [ACC_NUM], input data width [DATA_I_WIDTH] and output
// data width [DATA_ACC_WIDTH] are related to each other and should match the
// Adder/Subtracter LogiCORE IP configuration.
// Parameter:
// ROW_NUM: Row number of input matrix.
// COL_NUM: Column number of input matrix.
// ACC_NUM: Accumulation number of input matrix.
// DATA_I_WIDTH: Bit width of input matrix element.
// DATA_ACC_WIDTH: !!!Caution!!! Accumulation adder output data width. It is
// determined by [DATA_I_WIDTH] and [ACC_NUM], and is calculated as
// log2(ACC_NUM*(2^DATA_I_WIDTH-1)), and should match the Adder/Subtracter
// LogiCORE IP configuration.
// DATA_O_WIDTH: Bit width of output matrix element. If [DATA_O_WIDTH] <
// [DATA_ACC_WIDTH], MSB of accumulation result will be truncated. If
// [DATA_O_WIDTH] > [DATA_ACC_WIDTH], the sign bit of accumulation result
// will be extended.
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module accum_cmplx_mat
#(
parameter ROW_NUM = 4,
parameter COL_NUM = 4,
parameter ACC_NUM = 256,
parameter DATA_I_WIDTH = 24,
parameter DATA_ACC_WIDTH = $clog2(ACC_NUM*(2^DATA_I_WIDTH-1)),
parameter DATA_O_WIDTH = 32
)
(
// clock & reset
input clk,
input rst,
input acc_rst, // [acc_rst] should assert before accumulation starts
// input data
input din_valid,
input [ROW_NUM*COL_NUM*DATA_I_WIDTH-1:0] din_real,
input [ROW_NUM*COL_NUM*DATA_I_WIDTH-1:0] din_imag,
// output data
output dout_valid,
output [ROW_NUM*COL_NUM*DATA_O_WIDTH-1:0] dout_real,
output [ROW_NUM*COL_NUM*DATA_O_WIDTH-1:0] dout_imag
);
genvar i;
// prepare adder input & output data
wire [DATA_I_WIDTH-1:0] add_real_a_array [0:ROW_NUM*COL_NUM-1];
wire [DATA_I_WIDTH-1:0] add_imag_a_array [0:ROW_NUM*COL_NUM-1];
wire [DATA_ACC_WIDTH-1:0] add_real_b_array [0:ROW_NUM*COL_NUM-1];
wire [DATA_ACC_WIDTH-1:0] add_imag_b_array [0:ROW_NUM*COL_NUM-1];
wire [DATA_ACC_WIDTH-1:0] add_real_s_array [0:ROW_NUM*COL_NUM-1];
wire [DATA_ACC_WIDTH-1:0] add_imag_s_array [0:ROW_NUM*COL_NUM-1];
generate
for (i = 0; i < ROW_NUM*COL_NUM; i = i + 1) begin: cmplx_mat_accum
assign add_real_a_array[i] = din_real[i*DATA_I_WIDTH +: DATA_I_WIDTH];
assign add_imag_a_array[i] = din_imag[i*DATA_I_WIDTH +: DATA_I_WIDTH];
assign add_real_b_array[i] = add_real_s_array[i];
assign add_imag_b_array[i] = add_imag_s_array[i];
if (ACC_NUM > 1) begin
add_s24_s32_s32 u_accum_real
(
.A (add_real_a_array[i]), // input wire [23 : 0] A
.B (add_real_b_array[i]), // input wire [31 : 0] B
.CLK (clk ), // input wire CLK
.CE (din_valid ), // input wire CE
.SCLR (rst || acc_rst ), // input wire SCLR
.S (add_real_s_array[i]) // output wire [31 : 0] S
);
add_s24_s32_s32 u_accum_imag
(
.A (add_imag_a_array[i]), // input wire [23 : 0] A
.B (add_imag_b_array[i]), // input wire [31 : 0] B
.CLK (clk ), // input wire CLK
.CE (din_valid ), // input wire CE
.SCLR (rst || acc_rst ), // input wire SCLR
.S (add_imag_s_array[i]) // output wire [31 : 0] S
);
end
end
endgenerate
// input data counter & full flag
reg [$clog2(ACC_NUM)-1:0] accum_cnt = 'b0;
reg accum_full_flag = 'b0;
reg accum_full_flag_d = 'b0; // delay of [accum_full_flag]
if (ACC_NUM > 1) begin
always @(posedge clk) begin
if (rst || acc_rst) begin
accum_cnt <= 'b0;
end
else if (din_valid) begin
accum_cnt <= accum_cnt + 1'b1;
end
else begin
accum_cnt <= accum_cnt;
end
end
always @(posedge clk) begin
if (rst || acc_rst) begin
accum_full_flag <= 'b0;
end
else begin
accum_full_flag <= (accum_cnt == ACC_NUM - 1) ? 1'b1 : accum_full_flag;
end
accum_full_flag_d <= accum_full_flag;
end
end
// output control
reg dout_valid_buf;
reg [DATA_O_WIDTH-1:0] dout_real_array [0:ROW_NUM*COL_NUM-1];
reg [DATA_O_WIDTH-1:0] dout_imag_array [0:ROW_NUM*COL_NUM-1];
assign dout_valid = dout_valid_buf;
always @(posedge clk) begin
if (rst || acc_rst) begin
dout_valid_buf <= 'b0;
end
else begin
if (ACC_NUM > 1) begin
dout_valid_buf <= ~accum_full_flag_d & accum_full_flag;
end
else begin
dout_valid_buf <= din_valid;
end
end
end
generate
for (i = 0; i < ROW_NUM*COL_NUM; i = i + 1) begin: output_buf
assign dout_real[i*DATA_O_WIDTH +: DATA_O_WIDTH] = dout_real_array[i];
assign dout_imag[i*DATA_O_WIDTH +: DATA_O_WIDTH] = dout_imag_array[i];
always @(posedge clk) begin
if (rst || acc_rst) begin
dout_real_array[i] <= 'b0;
dout_imag_array[i] <= 'b0;
end
else begin
if (ACC_NUM > 1) begin
if (~accum_full_flag_d & accum_full_flag) begin
if (DATA_O_WIDTH <= DATA_ACC_WIDTH) begin
// truncate msb
dout_real_array[i] <= add_real_s_array[i][DATA_ACC_WIDTH-1 -: DATA_O_WIDTH];
dout_imag_array[i] <= add_imag_s_array[i][DATA_ACC_WIDTH-1 -: DATA_O_WIDTH];
end
else begin // if (ACC_NUM <= 1)
// Sign extension to fit output data width
dout_real_array[i] <= {{(DATA_O_WIDTH-DATA_ACC_WIDTH){add_real_s_array[i][DATA_ACC_WIDTH-1]}},add_real_s_array[i]};
dout_imag_array[i] <= {{(DATA_O_WIDTH-DATA_ACC_WIDTH){add_imag_s_array[i][DATA_ACC_WIDTH-1]}},add_real_s_array[i]};
end
end
else begin
dout_real_array[i] <= dout_real_array[i];
dout_imag_array[i] <= dout_imag_array[i];
end
end // if (ACC_NUM > 1)
else begin // if (ACC_NUM <= 1)
if (DATA_O_WIDTH <= DATA_I_WIDTH) begin
// truncate msb
dout_real_array[i] <= add_real_a_array[i][DATA_I_WIDTH-1 -: DATA_O_WIDTH];
dout_imag_array[i] <= add_imag_a_array[i][DATA_I_WIDTH-1 -: DATA_O_WIDTH];
end
else begin // if (DATA_O_WIDTH > DATA_I_WIDTH)
// Sign extension to fit output data width
dout_real_array[i] <= {{(DATA_O_WIDTH-DATA_I_WIDTH){add_real_a_array[i][DATA_I_WIDTH-1]}},add_real_a_array[i]};
dout_imag_array[i] <= {{(DATA_O_WIDTH-DATA_I_WIDTH){add_imag_a_array[i][DATA_I_WIDTH-1]}},add_imag_a_array[i]};
end
end // if (ACC_NUM <= 1)
end
end
end
endgenerate
endmodule
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/10/30 20:46:26
// Design Name:
// Module Name: tb_accum
// Project Name:
// Target Devices:
// Tool Versions:
// Description: Testbench for [accum_cmplx_mat]
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
// -------------------------------
// MATLAB Code for data generation
// -------------------------------
// COLUMN_NUM = 4;
// DATA_I_WIDTH = 12;
// ACC_NUM = 10;
// rng(0);
// data = rand(4,2)*2-1;
// d_12b = round(data.*(2^(DATA_I_WIDTH-1)-1));
// d_12b_cmplx = d_12b(:,1) + 1i*d_12b(:,2);
// d_12b_cmplx = d_12b_cmplx(end:-1:1,:);
// d_12b_acorr = d_12b_cmplx*d_12b_cmplx';
// d_12b_acorr_real_sim = reshape(flip(reshape(real(d_12b_acorr)',1,16)),4,4);
// d_12b_acorr_imag_sim = reshape(flip(reshape(imag(d_12b_acorr)',1,16)),4,4);
// d_12b_acorr_real_sim_sum = ACC_NUM*d_12b_acorr_real_sim;
// d_12b_acorr_imag_sim_sum = ACC_NUM*d_12b_acorr_imag_sim;
// module tb_accum;
// localparam DATA_I_WIDTH = 24;
// localparam DATA_ACC_WIDTH = 32;
// localparam DATA_O_WIDTH = 35;
// localparam ROW_NUM = 4;
// localparam COL_NUM = 4;
// reg acc_rst = 1'b0;
// reg clk = 1'b1;
// reg rst = 1'b1;
// reg din_valid = 'b0;
// reg [ROW_NUM*COL_NUM*DATA_I_WIDTH-1:0] din_real = 'b0, din_imag = 'b0;
// wire dout_valid;
// wire [ROW_NUM*COL_NUM*DATA_O_WIDTH-1:0] dout_real, dout_imag;
// accum_cmplx_mat #(
// .ROW_NUM (ROW_NUM),
// .COL_NUM (COL_NUM),
// .DATA_I_WIDTH (DATA_I_WIDTH),
// .DATA_ACC_WIDTH (DATA_ACC_WIDTH),
// .DATA_O_WIDTH (DATA_O_WIDTH),
// .ACC_NUM (1)
// ) u_accum_cmplx_mat
// (
// // clock & reset
// .clk (clk ),
// .rst (rst ),
// .acc_rst (acc_rst ), // [acc_rst] should assert before accumulation starts
// // input data
// .din_valid (din_valid ),
// .din_real (din_real ),
// .din_imag (din_imag ),
// // output data
// .dout_valid (dout_valid ),
// .dout_real (dout_real ),
// .dout_imag (dout_imag )
// );
// initial begin
// #102 rst = 1'b0;
// #222;
// @(posedge clk)
// din_valid = 1'b1;
// din_real = {
// 24'd1952708, 24'd1246152, -24'd2458370, 24'd2283360,
// 24'd1246152, 24'd5474825, -24'd1041611, 24'd2493996,
// -24'd2458370, -24'd1041611, 24'd3154378, -24'd2757828,
// 24'd2283360, 24'd2493996, -24'd2757828, 24'd2899728
// };
// din_imag = {
// 24'd0, -24'd3022886, -24'd340582, -24'd669768,
// 24'd3022886, 24'd0, -24'd4023023, 24'd3107328,
// 24'd340582, 24'd4023023, 24'd0, 24'd1241460,
// 24'd669768, -24'd3107328, -24'd1241460, 24'd0
// };
// #1002
// acc_rst = 1'b1;
// #20
// acc_rst = 1'b0;
// end
// always #10 clk = ~clk;
// endmodule
@@ -0,0 +1,266 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/10/30 19:27:01
// Design Name:
// Module Name: acorr_cmplx_col_vec
// Project Name:
// Target Devices:
// Tool Versions:
// Description: Compute the autocorrelation of a complex column vector. The
// computation is conducted in fully parallel style.
// Parameter:
// DATA_I_WIDTH: Bit width of input vector element, the same as of complex
// multiplication input data.
// DATA_MULT_FULL_WIDTH (local): Bit width of unsigned complex multiplication
// output data (The cmpy LogiCore IP does not care whether the input data
// are signed or unsigned). It equals to (2*[DATA_MULT_WIDTH]+1).
// DATA_MULT_VALID_WIDTH (local): Bit width of signed complex multiplication.acc_rst
// It equals to 2*[DATA_MULT_WIDTH].
// DATA_O_WIDTH: Bit width of output matrix element. If [DATA_O_WIDTH] <
// [DATA_MULT_WIDTH], MSB of valid complex mutiplication output will be
// truncated. If [DATA_O_WIDTH] > [DATA_MULT_WIDTH], the sign bit of valid
// complex mutiplication output will be extended.
// Data format:
// din_valid: Indicate [din_real/imag] data are valid.
// din_real/imag: Suppose the input column vector x = [x1 x2 x3 x4]^T, then
// din_real = {Re{x4}, Re{x3}, Re{x2}, Re{x1}}
// din_imag = {Im{x4}, Im{x3}, Im{x2}, Im{x1}}
// dout_valid: Indicate [dout_real/imag] data are valid. The latency is
// determined by the configuration of the cmpy ip core, which is set to 6
// clock cycles by default.
// dout_real/imag:
// dout_real = {Re{x4*x4^H}, Re{x4*x3^H}, ..., Re{x1*x2^H}, Re{x1*x1^H}}
// dout_imag = {Im{x4*x4^H}, Im{x4*x3^H}, ..., Im{x1*x2^H}, Im{x1*x1^H}}
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module acorr_cmplx_col_vec
#(
parameter DATA_I_WIDTH = 12,
parameter DATA_O_WIDTH = 24,
parameter COL_NUM = 4
)
(
// clock & reset
input clk,
input rst,
// input data
input din_valid,
input [COL_NUM*DATA_I_WIDTH-1:0] din_real,
input [COL_NUM*DATA_I_WIDTH-1:0] din_imag,
// output data
output dout_valid,
output [COL_NUM*COL_NUM*DATA_O_WIDTH-1:0] dout_real,
output [COL_NUM*COL_NUM*DATA_O_WIDTH-1:0] dout_imag
);
localparam DATA_MULT_FULL_WIDTH = 2*DATA_I_WIDTH+1;
localparam DATA_MULT_VALID_WIDTH = 2*DATA_I_WIDTH;
localparam AXIS_DATA_I_WIDTH = 8*((DATA_I_WIDTH-1)/8+1) ; // axis data width of input real/image data
localparam AXIS_DATA_P_WIDTH = 8*((DATA_MULT_FULL_WIDTH-1)/8+1) ; // axis data width of cmpy output real/image data
genvar i,j;
// prepare cmpy input data
wire [AXIS_DATA_I_WIDTH-1:0] din_real_array [0:COL_NUM-1];
wire [AXIS_DATA_I_WIDTH-1:0] din_imag_array [0:COL_NUM-1];
generate
for(i = 0; i < COL_NUM; i = i + 1) begin: array_convert
// Sign extension to fit 8-bit axis data format
assign din_real_array[i] = {{(AXIS_DATA_I_WIDTH-DATA_I_WIDTH){din_real[(i+1)*DATA_I_WIDTH-1]}},din_real[i*DATA_I_WIDTH +: DATA_I_WIDTH]};
assign din_imag_array[i] = {{(AXIS_DATA_I_WIDTH-DATA_I_WIDTH){din_imag[(i+1)*DATA_I_WIDTH-1]}},din_imag[i*DATA_I_WIDTH +: DATA_I_WIDTH]};
end
endgenerate
// complex multiplication
wire [AXIS_DATA_P_WIDTH-1:0] cmpy_real_array [0:COL_NUM*COL_NUM-1];
wire [AXIS_DATA_P_WIDTH-1:0] cmpy_imag_array [0:COL_NUM*COL_NUM-1];
wire [DATA_O_WIDTH-1:0] dout_real_array [0:COL_NUM*COL_NUM-1];
wire [DATA_O_WIDTH-1:0] dout_imag_array [0:COL_NUM*COL_NUM-1];
generate
for(i = 0; i < COL_NUM; i = i + 1) begin: acorr_cmpy_col
for(j = 0; j < COL_NUM; j = j + 1) begin: acorr_cmpy_row
wire [2*AXIS_DATA_I_WIDTH-1:0] cmpy_a;
wire [2*AXIS_DATA_I_WIDTH-1:0] cmpy_b;
wire [2*AXIS_DATA_P_WIDTH-1:0] cmpy_p;
wire cmpy_p_vld;
assign cmpy_a = {din_imag_array[i],din_real_array[i]};
assign cmpy_b = {-din_imag_array[j],din_real_array[j]};
assign {cmpy_imag_array[i*COL_NUM+j],cmpy_real_array[i*COL_NUM+j]} = cmpy_p;
if (DATA_O_WIDTH <= DATA_MULT_VALID_WIDTH) begin
// truncate msb of the valid part
assign dout_real_array[i*COL_NUM+j] = cmpy_real_array[i*COL_NUM+j][DATA_MULT_VALID_WIDTH-1 -: DATA_O_WIDTH];
assign dout_imag_array[i*COL_NUM+j] = cmpy_imag_array[i*COL_NUM+j][DATA_MULT_VALID_WIDTH-1 -: DATA_O_WIDTH];
end
else begin
// sign extension to fit output data width
assign dout_real_array[i*COL_NUM+j] = {{(DATA_O_WIDTH-DATA_MULT_VALID_WIDTH){cmpy_real_array[i*COL_NUM+j][DATA_MULT_VALID_WIDTH-1]}},cmpy_real_array[i*COL_NUM+j][0 +: DATA_MULT_VALID_WIDTH]};
assign dout_imag_array[i*COL_NUM+j] = {{(DATA_O_WIDTH-DATA_MULT_VALID_WIDTH){cmpy_imag_array[i*COL_NUM+j][DATA_MULT_VALID_WIDTH-1]}},cmpy_imag_array[i*COL_NUM+j][0 +: DATA_MULT_VALID_WIDTH]};
end
assign dout_real[(i*COL_NUM+j)*DATA_O_WIDTH +: DATA_O_WIDTH] = dout_real_array[i*COL_NUM+j];
assign dout_imag[(i*COL_NUM+j)*DATA_O_WIDTH +: DATA_O_WIDTH] = dout_imag_array[i*COL_NUM+j];
cmpy_12x12 u_cmpy_12x12
(
.aclk (clk ), // input wire aclk
.s_axis_a_tvalid (din_valid ), // input wire s_axis_a_tvalid
.s_axis_a_tdata (cmpy_a ), // input wire [31 : 0] s_axis_a_tdata
.s_axis_b_tvalid (din_valid ), // input wire s_axis_b_tvalid
.s_axis_b_tdata (cmpy_b ), // input wire [31 : 0] s_axis_b_tdata
.m_axis_dout_tvalid (cmpy_p_vld ), // output wire m_axis_dout_tvalid
.m_axis_dout_tdata (cmpy_p ) // output wire [63 : 0] m_axis_dout_tdata
);
end
end
endgenerate
// output mapping
assign dout_valid = acorr_cmpy_col[0].acorr_cmpy_row[0].cmpy_p_vld;
endmodule
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/10/30 20:46:26
// Design Name:
// Module Name: acorr_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description: Testbench for [acorr_cmplx_col_vec]
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
// -------------------------------
// MATLAB Code for data generation
// -------------------------------
// COLUMN_NUM = 4;
// DATA_I_WIDTH = 12;
// rng(0);
// data = (rand(4,2)*2-1) + 1i*(rand(4,2)*2-1);
// d_12b = round(data/max(max(abs(data)))*(2^11-1));
// d_12b_real = real(d_12b(end:-1:1,:));
// d_12b_imag = imag(d_12b(end:-1:1,:));
// d_12b_acorr(:,:,1) = d_12b(:,1)*d_12b(:,1)';
// d_12b_acorr(:,:,2) = d_12b(:,2)*d_12b(:,2)';
// module tb_acorr;
// localparam ROW_NUM = 1;
// localparam COL_NUM = 4;
// localparam DATA_I_WIDTH = 12;
// localparam DATA_O_WIDTH = 23;
// reg acc_rst = 1'b0;
// reg clk = 1'b1;
// reg rst = 1'b1;
// reg din_valid = 'b0;
// reg [COL_NUM*DATA_I_WIDTH-1:0] din_real = 'b0, din_imag = 'b0;
// wire dout_valid;
// wire [COL_NUM*COL_NUM*DATA_O_WIDTH-1:0] dout_real, dout_imag;
// acorr_cmplx_col_vec #(
// .COL_NUM (COL_NUM),
// .DATA_I_WIDTH (DATA_I_WIDTH),
// .DATA_O_WIDTH (DATA_O_WIDTH)
// ) u_acorr_cmplx_col_vec
// (
// // clock & reset
// .clk (clk ),
// .rst (rst ),
// // input data
// .din_valid (din_valid ),
// .din_real (din_real ),
// .din_imag (din_imag ),
// // output data
// .dout_valid (dout_valid ),
// .dout_real (dout_real ),
// .dout_imag (dout_imag )
// );
// initial begin
// #102 rst = 1'b0;
// #222;
// @(posedge clk)
// din_valid = 1'b1;
// din_real = {
// 12'd1351,
// -12'd1219,
// 12'd1326,
// 12'd1029};
// din_imag = {
// 12'd1538,
// -12'd1119,
// 12'd1519,
// 12'd1495};
// @(posedge clk)
// din_valid = 1'b0;
// @(posedge clk)
// din_valid = 1'b1;
// din_real = {
// 12'd153 ,
// -12'd724 ,
// -12'd1315,
// 12'd433 };
// din_imag = {
// -12'd1170,
// 12'd981 ,
// -12'd48 ,
// 12'd1494};
// end
// always #10 clk = ~clk;
// endmodule
@@ -0,0 +1,440 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/09/14 16:45:10
// Design Name:
// Module Name: ad9361_phase_cal
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module ad9361_phase_cal
#(
parameter COUNTER_MOD = 48,
parameter PEAK_POS = 12
)
(
// clock & reset
input clk ,
input rst ,
// control interface
input ad9361_1_cal_start ,
output ad9361_1_cal_done ,
input ad9361_2_cal_start ,
output ad9361_2_cal_done ,
output ad9361_cal_result ,
output ad9361_cal_valid ,
input ad9361_recal ,
// input data interface
input [11:0] rx_ch1_i ,
input [11:0] rx_ch1_q ,
input [11:0] rx_ch2_i ,
input [11:0] rx_ch2_q ,
input [11:0] rx_ch3_i ,
input [11:0] rx_ch3_q ,
input [11:0] rx_ch4_i ,
input [11:0] rx_ch4_q ,
// output data interface
output [11:0] rx_cal_ch1_i ,
output [11:0] rx_cal_ch1_q ,
output [11:0] rx_cal_ch2_i ,
output [11:0] rx_cal_ch2_q ,
output [11:0] rx_cal_ch3_i ,
output [11:0] rx_cal_ch3_q ,
output [11:0] rx_cal_ch4_i ,
output [11:0] rx_cal_ch4_q
);
localparam STATE_IDLE = 2'd0;
localparam STATE_CAL_1 = 2'd1;
localparam STATE_CAL_2 = 2'd2;
localparam STATE_DONE = 2'd3;
// buffer input control signals
reg ad9361_1_cal_start_d1 = 'b0;
reg ad9361_1_cal_start_d2 = 'b0;
reg ad9361_2_cal_start_d1 = 'b0;
reg ad9361_2_cal_start_d2 = 'b0;
reg ad9361_recal_d1 = 'b0;
reg ad9361_recal_d2 = 'b0;
always @(posedge clk) begin
ad9361_1_cal_start_d1 <= ad9361_1_cal_start;
ad9361_1_cal_start_d2 <= ad9361_1_cal_start_d1;
ad9361_2_cal_start_d1 <= ad9361_2_cal_start;
ad9361_2_cal_start_d2 <= ad9361_2_cal_start_d1;
ad9361_recal_d1 <= ad9361_recal;
ad9361_recal_d2 <= ad9361_recal_d1;
end
// center state machine
reg [ 1:0] curr_state = STATE_IDLE;
always @(posedge clk) begin
if (rst) begin
curr_state <= STATE_IDLE;
end
else begin
case (curr_state)
STATE_IDLE: begin
// move to next state when [ad9361_1_cal_start] asserts
curr_state <= ad9361_1_cal_start_d2 ? STATE_CAL_1 : STATE_IDLE;
end
STATE_CAL_1: begin
// move to next state when 1st cal finishes [ad9361_2_cal_start] asserts
curr_state <= (ad9361_1_cal_done && ad9361_2_cal_start_d2) ? STATE_CAL_2 : STATE_CAL_1;
end
STATE_CAL_2: begin
// move to next state when 2nd cal finishes
curr_state <= ad9361_2_cal_done ? STATE_DONE : STATE_CAL_2;
end
STATE_DONE: begin
// move to ILDA state when it needs to recal
curr_state <= (ad9361_recal_d2) ? STATE_IDLE : STATE_DONE;
end
default: begin
curr_state <= STATE_IDLE;
end
endcase
end
end
//
reg rx_ch2_i_msb_d1 = 'b0;
reg cnt_start = 'b0;
reg cnt_start_flag = 'b0;
reg [$clog2(COUNTER_MOD)-1:0] cnt = 'b0;
reg [11:0] rx_ch2_i_rec = 'b0;
reg rx_ch2_i_rec_flag = 'b0;
assign ad9361_1_cal_done = rx_ch2_i_rec_flag;
always @(posedge clk) begin
if (rst) begin
rx_ch2_i_msb_d1 <= 'b0;
end
else if (curr_state == STATE_IDLE) begin
// reset at IDLE state
rx_ch2_i_msb_d1 <= 'b0;
end
else if (curr_state == STATE_CAL_1) begin
rx_ch2_i_msb_d1 <= rx_ch2_i[11];
end
else begin
rx_ch2_i_msb_d1 <= rx_ch2_i_msb_d1;
end
end
always @(posedge clk) begin
if (rst) begin
cnt_start <= 'b0;
end
else if (curr_state == STATE_IDLE) begin
// reset at IDLE state
cnt_start <= 'b0;
end
else if (curr_state == STATE_CAL_1 && ~cnt_start) begin
// assert when the 1st falling edge of msb of rx_ch2_i is detected
cnt_start <= (rx_ch2_i_msb_d1 & ~rx_ch2_i[11]) ? 1'b1 : 1'b0;
end
else begin
cnt_start <= cnt_start;
end
end
always @(posedge clk) begin
if (rst) begin
cnt <= 'b0;
end
else if (curr_state == STATE_IDLE) begin
// reset at IDLE state
cnt <= 'b0;
end
else if (cnt_start) begin
cnt <= (cnt == COUNTER_MOD - 1) ? 'b0 : cnt + 1'b1;
end
else begin
cnt <= cnt;
end
end
always @(posedge clk) begin
if (rst) begin
rx_ch2_i_rec <= 'b0;
rx_ch2_i_rec_flag <= 'b0;
end
else if (curr_state == STATE_IDLE) begin
// reset at IDLE state
rx_ch2_i_rec <= 'b0;
rx_ch2_i_rec_flag <= 'b0;
end
else if (curr_state == STATE_CAL_1 && cnt == PEAK_POS && ~rx_ch2_i_rec_flag) begin
rx_ch2_i_rec <= rx_ch2_i;
rx_ch2_i_rec_flag <= 1'b1;
end
else begin
rx_ch2_i_rec <= rx_ch2_i_rec;
rx_ch2_i_rec_flag <= rx_ch2_i_rec_flag;
end
end
//
reg [11:0] rx_ch4_i_rec = 'b0;
reg rx_ch4_i_rec_flag = 'b0;
assign ad9361_2_cal_done = rx_ch4_i_rec_flag;
always @(posedge clk) begin
if (rst) begin
rx_ch4_i_rec <= 'b0;
rx_ch4_i_rec_flag <= 'b0;
end
else if (curr_state == STATE_IDLE) begin
// reset at IDLE state
rx_ch4_i_rec <= 'b0;
rx_ch4_i_rec_flag <= 'b0;
end
else if (curr_state == STATE_CAL_2 && cnt == COUNTER_MOD/4 && ~rx_ch4_i_rec_flag) begin
rx_ch4_i_rec <= rx_ch4_i;
rx_ch4_i_rec_flag <= 1'b1;
end
else begin
rx_ch4_i_rec <= rx_ch4_i_rec;
rx_ch4_i_rec_flag <= rx_ch4_i_rec_flag;
end
end
reg ad9361_cal_valid_buf = 'b0;
reg ad9361_cal_result_buf = 'b0;
reg [11:0] rx_cal_ch1_i_buf = 'b0;
reg [11:0] rx_cal_ch2_i_buf = 'b0;
reg [11:0] rx_cal_ch3_i_buf = 'b0;
reg [11:0] rx_cal_ch4_i_buf = 'b0;
reg [11:0] rx_cal_ch1_q_buf = 'b0;
reg [11:0] rx_cal_ch2_q_buf = 'b0;
reg [11:0] rx_cal_ch3_q_buf = 'b0;
reg [11:0] rx_cal_ch4_q_buf = 'b0;
assign ad9361_cal_valid = ad9361_cal_valid_buf;
assign ad9361_cal_result = ad9361_cal_result_buf;
assign rx_cal_ch1_i = rx_cal_ch1_i_buf;
assign rx_cal_ch2_i = rx_cal_ch2_i_buf;
assign rx_cal_ch3_i = rx_cal_ch3_i_buf;
assign rx_cal_ch4_i = rx_cal_ch4_i_buf;
assign rx_cal_ch1_q = rx_cal_ch1_q_buf;
assign rx_cal_ch2_q = rx_cal_ch2_q_buf;
assign rx_cal_ch3_q = rx_cal_ch3_q_buf;
assign rx_cal_ch4_q = rx_cal_ch4_q_buf;
always @(posedge clk) begin
if (rst) begin
ad9361_cal_valid_buf <= 'b0;
ad9361_cal_result_buf <= 'b0;
rx_cal_ch1_i_buf <= 'b0;
rx_cal_ch2_i_buf <= 'b0;
rx_cal_ch3_i_buf <= 'b0;
rx_cal_ch4_i_buf <= 'b0;
rx_cal_ch1_q_buf <= 'b0;
rx_cal_ch2_q_buf <= 'b0;
rx_cal_ch3_q_buf <= 'b0;
rx_cal_ch4_q_buf <= 'b0;
end
else if (curr_state == STATE_DONE) begin
ad9361_cal_valid_buf <= 1'b1;
if (rx_ch2_i_rec[11] == rx_ch4_i_rec[11]) begin
ad9361_cal_result_buf <= 'b0;
rx_cal_ch1_i_buf <= rx_ch1_i;
rx_cal_ch2_i_buf <= -rx_ch2_i;
rx_cal_ch3_i_buf <= rx_ch3_i;
rx_cal_ch4_i_buf <= -rx_ch4_i;
rx_cal_ch1_q_buf <= rx_ch1_q;
rx_cal_ch2_q_buf <= -rx_ch2_q;
rx_cal_ch3_q_buf <= rx_ch3_q;
rx_cal_ch4_q_buf <= -rx_ch4_q;
end
else begin
ad9361_cal_result_buf <= 'b1;
rx_cal_ch1_i_buf <= rx_ch1_i;
rx_cal_ch2_i_buf <= -rx_ch2_i;
rx_cal_ch3_i_buf <= -rx_ch3_i;
rx_cal_ch4_i_buf <= rx_ch4_i;
rx_cal_ch1_q_buf <= rx_ch1_q;
rx_cal_ch2_q_buf <= -rx_ch2_q;
rx_cal_ch3_q_buf <= -rx_ch3_q;
rx_cal_ch4_q_buf <= rx_ch4_q;
end
end
else begin
ad9361_cal_valid_buf <= 1'b0;
ad9361_cal_result_buf <= ad9361_cal_result_buf;
rx_cal_ch1_i_buf <= rx_cal_ch1_i_buf;
rx_cal_ch2_i_buf <= rx_cal_ch2_i_buf;
rx_cal_ch3_i_buf <= rx_cal_ch3_i_buf;
rx_cal_ch4_i_buf <= rx_cal_ch4_i_buf;
rx_cal_ch1_q_buf <= rx_cal_ch1_q_buf;
rx_cal_ch2_q_buf <= rx_cal_ch2_q_buf;
rx_cal_ch3_q_buf <= rx_cal_ch3_q_buf;
rx_cal_ch4_q_buf <= rx_cal_ch4_q_buf;
end
end
endmodule
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/09/15 11:12:45
// Last Modified Data: 2022/11/02
// Design Name:
// Module Name: tb_ad9361_cal
// Project Name:
// Target Devices:
// Tool Versions:
// Description: testbench for [ad9361_phase_cal]
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
// module tb_ad9361_cal;
// reg clk = 'b0;
// reg rst = 1'b1;
// reg ad9361_1_cal_start = 'b0;
// wire ad9361_1_cal_done ;
// reg ad9361_2_cal_start = 'b0;
// wire ad9361_2_cal_done ;
// wire ad9361_cal_result ;
// wire ad9361_cal_valid;
// reg ad9361_recal = 'b0;
// // phase difference of 180 degree
// reg [11:0] rx_ch1_i = 12'd2047;
// reg [11:0] rx_ch1_q = 12'd2047;
// reg [11:0] rx_ch2_i = -12'd2047;
// reg [11:0] rx_ch2_q = -12'd2047;
// reg [11:0] rx_ch3_q = -12'd2047;
// reg [11:0] rx_ch3_i = -12'd2047;
// reg [11:0] rx_ch4_i = 12'd2047;
// reg [11:0] rx_ch4_q = 12'd2047;
// wire [11:0] rx_cal_ch1_i;
// wire [11:0] rx_cal_ch2_i;
// wire [11:0] rx_cal_ch3_i;
// wire [11:0] rx_cal_ch4_i;
// wire [11:0] rx_cal_ch1_q;
// wire [11:0] rx_cal_ch2_q;
// wire [11:0] rx_cal_ch3_q;
// wire [11:0] rx_cal_ch4_q;
// ad9361_phase_cal #(
// .COUNTER_MOD (48),
// .PEAK_POS (12)
// ) u_ad9361_phase_cal
// (
// // clock & reset
// .clk (clk ), // input clk
// .rst (rst ), // input rst
// // control interface
// .ad9361_1_cal_start (ad9361_1_cal_start ), // input ad9361_1_cal_start
// .ad9361_1_cal_done (ad9361_1_cal_done ), // output ad9361_1_cal_done
// .ad9361_2_cal_start (ad9361_2_cal_start ), // input ad9361_2_cal_start
// .ad9361_2_cal_done (ad9361_2_cal_done ), // output ad9361_2_cal_done
// .ad9361_cal_result (ad9361_cal_result ), // output ad9361_cal_result
// .ad9361_cal_valid (ad9361_cal_valid ), // output ad9361_cal_valid
// .ad9361_recal (ad9361_recal ), // input ad9361_recal
// // input data interface
// .rx_ch1_i (rx_ch1_i ), // input [11:0] rx_ch1_i
// .rx_ch2_i (rx_ch2_i ), // input [11:0] rx_ch2_i
// .rx_ch3_i (rx_ch3_i ), // input [11:0] rx_ch3_i
// .rx_ch4_i (rx_ch4_i ), // input [11:0] rx_ch4_i
// .rx_ch1_q (rx_ch1_q ), // input [11:0] rx_ch1_q
// .rx_ch2_q (rx_ch2_q ), // input [11:0] rx_ch2_q
// .rx_ch3_q (rx_ch3_q ), // input [11:0] rx_ch3_q
// .rx_ch4_q (rx_ch4_q ), // input [11:0] rx_ch4_q
// // output data interface
// .rx_cal_ch1_i (rx_cal_ch1_i ), // output [11:0] rx_cal_ch1_i
// .rx_cal_ch2_i (rx_cal_ch2_i ), // output [11:0] rx_cal_ch2_i
// .rx_cal_ch3_i (rx_cal_ch3_i ), // output [11:0] rx_cal_ch3_i
// .rx_cal_ch4_i (rx_cal_ch4_i ), // output [11:0] rx_cal_ch4_i
// .rx_cal_ch1_q (rx_cal_ch1_q ), // output [11:0] rx_cal_ch1_q
// .rx_cal_ch2_q (rx_cal_ch2_q ), // output [11:0] rx_cal_ch2_q
// .rx_cal_ch3_q (rx_cal_ch3_q ), // output [11:0] rx_cal_ch3_q
// .rx_cal_ch4_q (rx_cal_ch4_q ) // output [11:0] rx_cal_ch4_q
// );
// initial begin
// #102
// rst = 1'b0;
// #100
// ad9361_1_cal_start = 1'b1;
// end
// initial begin
// #10000
// ad9361_recal = 1'b1;
// #20
// ad9361_recal = 1'b0;
// end
// always begin
// #2 clk = ~clk;
// end
// always begin
// #72
// rx_ch1_i = ~rx_ch1_i;
// rx_ch2_i = ~rx_ch2_i;
// rx_ch3_i = ~rx_ch3_i;
// rx_ch4_i = ~rx_ch4_i;
// #24
// rx_ch1_q = ~rx_ch1_q;
// rx_ch2_q = ~rx_ch2_q;
// rx_ch3_q = ~rx_ch3_q;
// rx_ch4_q = ~rx_ch4_q;
// end
// always @(posedge clk) begin
// if (ad9361_1_cal_done) begin
// ad9361_2_cal_start <= 1'b1;
// end
// else begin
// ad9361_2_cal_start <= 1'b0;
// end
// end
// endmodule
@@ -0,0 +1,865 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/10/30 18:09:20
// Design Name:
// Module Name: rx_pre_process
// Project Name:
// Target Devices:
// Tool Versions:
// Description: Pre-process rx data, including ad9361 mcs & implementing nulling
// algorithm on rx data. The latency of autocorrelation is consisted of 2
// parts: 1. [STABLE_CNT_MOD] + [SNAPSHOT_NUM] + several intermediate delay
// of [sys_clk] clock cycles; 2. ([CHANNEL_NUM]*[CHANNEL_NUM]*[CMPLX_DIM] +
// 1 frame head + 1 frame length)*[ACCUM_WIDTH] of [clk_96m] clock cycles.
// The simulation result shows delay of about 30us when [sys_clk] is 48m.
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
/*******************************************************************************
* Contents
* 01. AD9361 Rx Multi-Channel Calibration
* 02. Autocorrelation of Snapshot Vector
* 03. Accumulation of Snapshot Autocorrelation Matrices
* 04. 32-bit Matrix Element to 1-bit Stream Conversion
* 05. 1-bit Stream to 32-bit Vector Element Conversion
* 06. RF Synthesizer Control
* 07. Debug IO
* 08. DDR and Fixed-io (Do NOT Modify)
*******************************************************************************/
module rx_pre_process
#(
parameter BYPASS_CAL = 0 ,
parameter CAL_CNT_MOD = 48 ,
parameter CAL_PEAK_POS = 12 ,
parameter STABLE_CNT_MOD = 48 ,
parameter ADC_DATA_WIDTH = 12 ,
parameter CHANNEL_NUM = 4 ,
parameter SNAPSHOT_NUM = 256,
parameter PS_PL_WIDTH = 32 ,
parameter WEIGHT_TRUNC_WIDTH = 16 ,
parameter CMPLX_DIM = 2 ,
parameter OUTPUT_DATA_WIDTH = ADC_DATA_WIDTH,
parameter ACCOR_FRAME_HEAD = 32'h7E7E7E7E,
parameter WEIGHT_FRAME_HEAD = ACCOR_FRAME_HEAD // Same head is required by [c2c_bridge] module
)
(
// clock & reset
input sys_clk , // sync to adc data
input sys_clk_4x , // sync to adc data
input sys_rst , // sync to [sys_clk]
input clk_96m , // sync to c2c data
input ant_rst , // sync to [clk_96m]
// input un-calibrated data
input [ADC_DATA_WIDTH-1:0] rx_ch1_i ,
input [ADC_DATA_WIDTH-1:0] rx_ch1_q ,
input [ADC_DATA_WIDTH-1:0] rx_ch2_i ,
input [ADC_DATA_WIDTH-1:0] rx_ch2_q ,
input [ADC_DATA_WIDTH-1:0] rx_ch3_i ,
input [ADC_DATA_WIDTH-1:0] rx_ch3_q ,
input [ADC_DATA_WIDTH-1:0] rx_ch4_i ,
input [ADC_DATA_WIDTH-1:0] rx_ch4_q ,
// ad9361 calibration interface
input ad9361_1_cal_start ,
output ad9361_1_cal_done ,
input ad9361_2_cal_start ,
output ad9361_2_cal_done ,
output ad9361_cal_result ,
output ad9361_cal_valid ,
input ad9361_recal ,
// nulling algotithm interface
input hop_start_flag , // sync to [sys_clk_4x]
output accor_stream_valid , // sync to [clk_96m]
output accor_stream_data , // sync to [clk_96m]
input weight_stream_data , // sync to [clk_96m]
output rx_data_valid , // sync to [sys_clk]
output [OUTPUT_DATA_WIDTH-1:0] rx_data_i, // sync to [sys_clk]
output [OUTPUT_DATA_WIDTH-1:0] rx_data_q // sync to [sys_clk]
);
localparam ACORR_WIDTH = 2*ADC_DATA_WIDTH;
localparam ACCUM_WIDTH = $clog2(SNAPSHOT_NUM)+ACORR_WIDTH; // = 32
// autocorrelation state machine
localparam ACORR_STATE_NUM = 3;
localparam ACORR_STATE_IDLE = 0;
localparam ACORR_STATE_STABLE = 1; // wait until rf is stable
localparam ACORR_STATE_CALC = 2; // autocorrelation calculation and formatting
////////////////////////////////////////////////////////////////////////////////
///////////////////// AD9361 Rx Multi-Channel Calibration //////////////////////
////////////////////////////////////////////////////////////////////////////////
wire [11:0] rx_cal_ch1_i, rx_cal_ch1_q;
wire [11:0] rx_cal_ch2_i, rx_cal_ch2_q;
wire [11:0] rx_cal_ch3_i, rx_cal_ch3_q;
wire [11:0] rx_cal_ch4_i, rx_cal_ch4_q;
if (BYPASS_CAL) begin
assign ad9361_1_cal_done = 1'b1;
assign ad9361_2_cal_done = 1'b1;
assign ad9361_cal_result = 1'b0;
assign ad9361_cal_valid = 1'b1;
assign rx_cal_ch1_i = rx_ch1_i;
assign rx_cal_ch1_q = rx_ch1_q;
assign rx_cal_ch2_i = rx_ch2_i;
assign rx_cal_ch2_q = rx_ch2_q;
assign rx_cal_ch3_i = rx_ch3_i;
assign rx_cal_ch3_q = rx_ch3_q;
assign rx_cal_ch4_i = rx_ch4_i;
assign rx_cal_ch4_q = rx_ch4_q;
end
else begin
ad9361_phase_cal #(
.COUNTER_MOD (CAL_CNT_MOD ),
.PEAK_POS (CAL_PEAK_POS ) // 48M 时钟下计数 48 次 = 1M 正弦波的 1 个周期,因此峰值出现在 48/4 的地方
) u_ad9361_phase_cal
(
// clock & reset
.clk (sys_clk ), // input clk
.rst (sys_rst ), // input rst
// control interface
.ad9361_1_cal_start (ad9361_1_cal_start ), // input ad9361_1_cal_start
.ad9361_1_cal_done (ad9361_1_cal_done ), // output ad9361_1_cal_done
.ad9361_2_cal_start (ad9361_2_cal_start ), // input ad9361_2_cal_start
.ad9361_2_cal_done (ad9361_2_cal_done ), // output ad9361_2_cal_done
.ad9361_cal_result (ad9361_cal_result ), // output ad9361_cal_result
.ad9361_cal_valid (ad9361_cal_valid ), // output ad9361_cal_valid
.ad9361_recal (ad9361_recal ), // input ad9361_recal
// input data interface
.rx_ch1_i (rx_ch1_i ), // input [11:0] rx_ch1_i
.rx_ch1_q (rx_ch1_q ), // input [11:0] rx_ch1_q
.rx_ch2_i (rx_ch2_i ), // input [11:0] rx_ch2_i
.rx_ch2_q (rx_ch2_q ), // input [11:0] rx_ch2_q
.rx_ch3_i (rx_ch3_i ), // input [11:0] rx_ch3_i
.rx_ch3_q (rx_ch3_q ), // input [11:0] rx_ch3_q
.rx_ch4_i (rx_ch4_i ), // input [11:0] rx_ch4_i
.rx_ch4_q (rx_ch4_q ), // input [11:0] rx_ch4_q
// output data interface
.rx_cal_ch1_i (rx_cal_ch1_i ), // output [11:0] rx_cal_ch1_i
.rx_cal_ch1_q (rx_cal_ch1_q ), // output [11:0] rx_cal_ch1_q
.rx_cal_ch2_i (rx_cal_ch2_i ), // output [11:0] rx_cal_ch2_i
.rx_cal_ch2_q (rx_cal_ch2_q ), // output [11:0] rx_cal_ch2_q
.rx_cal_ch3_i (rx_cal_ch3_i ), // output [11:0] rx_cal_ch3_i
.rx_cal_ch3_q (rx_cal_ch3_q ), // output [11:0] rx_cal_ch3_q
.rx_cal_ch4_i (rx_cal_ch4_i ), // output [11:0] rx_cal_ch4_i
.rx_cal_ch4_q (rx_cal_ch4_q ) // output [11:0] rx_cal_ch4_q
);
end
////////////////////////////////////////////////////////////////////////////////
//////////////////////// Autocorrelation State Machine /////////////////////////
////////////////////////////////////////////////////////////////////////////////
reg [$clog2(ACORR_STATE_NUM)-1 : 0] acorr_state = ACORR_STATE_IDLE;
reg [$clog2(STABLE_CNT_MOD)-1 : 0] stable_cnt = 'b0;
reg [$clog2(SNAPSHOT_NUM)-1 : 0] snapshot_cnt = 'b0;
reg snapshot_valid = 'b0;
wire hop_start_flag_cdc;
xpm_cdc_pulse #(
.DEST_SYNC_FF (4), // DECIMAL; range: 2-10
.INIT_SYNC_FF (1), // DECIMAL; 0=disable simulation init values, 1=enable simulation init values
.REG_OUTPUT (1), // DECIMAL; 0=disable registered output, 1=enable registered output
.RST_USED (0), // DECIMAL; 0=no reset, 1=implement reset
.SIM_ASSERT_CHK (1) // DECIMAL; 0=disable simulation messages, 1=enable simulation messages
) u_hop_start_flag_cdc
(
.dest_pulse (hop_start_flag_cdc ), // 1-bit output: Outputs a pulse the size of one dest_clk period when a pulse
// transfer is correctly initiated on src_pulse input. This output is
// combinatorial unless REG_OUTPUT is set to 1.
.dest_clk (sys_clk ), // 1-bit input: Destination clock.
.dest_rst (1'b1 ), // 1-bit input: optional; required when RST_USED = 1
.src_clk (sys_clk_4x ), // 1-bit input: Source clock.
.src_pulse (hop_start_flag ), // 1-bit input: Rising edge of this signal initiates a pulse transfer to the
// destination clock domain. The minimum gap between each pulse transfer must be
// at the minimum 2*(larger(src_clk period, dest_clk period)). This is measured
// between the falling edge of a src_pulse to the rising edge of the next
// src_pulse. This minimum gap will guarantee that each rising edge of src_pulse
// will generate a pulse the size of one dest_clk period in the destination
// clock domain. When RST_USED = 1, pulse transfers will not be guaranteed while
// src_rst and/or dest_rst are asserted.
.src_rst (1'b1 ) // 1-bit input: optional; required when RST_USED = 1
);
always @(posedge sys_clk) begin
if (sys_rst) begin
acorr_state <= ACORR_STATE_IDLE;
end
else begin
case (acorr_state)
ACORR_STATE_IDLE : acorr_state <= (hop_start_flag_cdc & ad9361_cal_valid) ? ACORR_STATE_STABLE : ACORR_STATE_IDLE;
ACORR_STATE_STABLE: acorr_state <= (stable_cnt == STABLE_CNT_MOD-1) ? ACORR_STATE_CALC : ACORR_STATE_STABLE;
ACORR_STATE_CALC : acorr_state <= (snapshot_cnt == SNAPSHOT_NUM-1) ? ACORR_STATE_IDLE : ACORR_STATE_CALC;
default: acorr_state <= ACORR_STATE_IDLE;
endcase
end
end
always @(posedge sys_clk) begin
if (sys_rst) begin
stable_cnt <= 'b0;
end
else begin
case (acorr_state)
ACORR_STATE_IDLE : stable_cnt <= 'b0;
ACORR_STATE_STABLE: stable_cnt <= (stable_cnt == STABLE_CNT_MOD-1) ? 'b0 : stable_cnt + 1'b1;
ACORR_STATE_CALC : stable_cnt <= 'b0;
default: stable_cnt <= 'b0;
endcase
end
end
always @(posedge sys_clk) begin
if (sys_rst) begin
snapshot_cnt <= 'b0;
end
else begin
case (acorr_state)
ACORR_STATE_IDLE : snapshot_cnt <= 'b0;
ACORR_STATE_STABLE: snapshot_cnt <= 'b0;
ACORR_STATE_CALC : snapshot_cnt <= (snapshot_cnt == SNAPSHOT_NUM-1) ? 'b0 : snapshot_cnt + 1'b1;
default: snapshot_cnt <= 'b0;
endcase
end
end
always @(posedge sys_clk) begin
if (sys_rst) begin
snapshot_valid <= 'b0;
end
else begin
case (acorr_state)
ACORR_STATE_IDLE : snapshot_valid <= 'b0;
ACORR_STATE_STABLE: snapshot_valid <= 'b0;
ACORR_STATE_CALC : snapshot_valid <= 1'b1;
default: snapshot_valid <= 'b0;
endcase
end
end
////////////////////////////////////////////////////////////////////////////////
////////////////////// Autocorrelation of Snapshot Vector //////////////////////
////////////////////////////////////////////////////////////////////////////////
// input data
wire acorr_din_valid;
wire [CHANNEL_NUM*ADC_DATA_WIDTH-1 : 0] acorr_din_real;
wire [CHANNEL_NUM*ADC_DATA_WIDTH-1 : 0] acorr_din_imag;
assign acorr_din_valid = snapshot_valid;
assign acorr_din_real = {rx_cal_ch4_i, rx_cal_ch3_i, rx_cal_ch2_i, rx_cal_ch1_i};
assign acorr_din_imag = {rx_cal_ch4_q, rx_cal_ch3_q, rx_cal_ch2_q, rx_cal_ch1_q};
// output data
wire acorr_dout_valid;
wire [CHANNEL_NUM*CHANNEL_NUM*ACORR_WIDTH-1:0] acorr_dout_real;
wire [CHANNEL_NUM*CHANNEL_NUM*ACORR_WIDTH-1:0] acorr_dout_imag;
acorr_cmplx_col_vec #(
.DATA_I_WIDTH (ADC_DATA_WIDTH ),
.DATA_O_WIDTH (ACORR_WIDTH ),
.COL_NUM (CHANNEL_NUM )
) u_acorr (
// clock & reset
.clk (sys_clk ),
.rst (sys_rst ),
// input data
.din_valid (acorr_din_valid ),
.din_real (acorr_din_real ),
.din_imag (acorr_din_imag ),
// output data
.dout_valid (acorr_dout_valid ),
.dout_real (acorr_dout_real ),
.dout_imag (acorr_dout_imag )
);
////////////////////////////////////////////////////////////////////////////////
////////////// Accumulation of Snapshot Autocorrelation Matrices ///////////////
////////////////////////////////////////////////////////////////////////////////
// accumulation reset
wire acc_rst; // [acc_rst] should assert before accumulation starts
assign acc_rst = hop_start_flag_cdc;
// input data
wire accum_din_valid;
wire [CHANNEL_NUM*CHANNEL_NUM*ACORR_WIDTH-1:0] accum_din_real;
wire [CHANNEL_NUM*CHANNEL_NUM*ACORR_WIDTH-1:0] accum_din_imag;
assign accum_din_valid = acorr_dout_valid;
assign accum_din_real = acorr_dout_real;
assign accum_din_imag = acorr_dout_imag;
// output data
wire accum_dout_valid;
wire [CHANNEL_NUM*CHANNEL_NUM*PS_PL_WIDTH-1:0] accum_dout_real;
wire [CHANNEL_NUM*CHANNEL_NUM*PS_PL_WIDTH-1:0] accum_dout_imag;
accum_cmplx_mat #(
.ROW_NUM (CHANNEL_NUM ),
.COL_NUM (CHANNEL_NUM ),
.DATA_I_WIDTH (ACORR_WIDTH ),
.DATA_ACC_WIDTH (ACCUM_WIDTH ),
.DATA_O_WIDTH (PS_PL_WIDTH ),
.ACC_NUM (SNAPSHOT_NUM )
) u_accum_cmplx_mat
(
// clock & reset
.clk (sys_clk ),
.rst (sys_rst ),
.acc_rst (acc_rst ), // [acc_rst] should assert before accumulation starts
// input data
.din_valid (accum_din_valid ),
.din_real (accum_din_real ),
.din_imag (accum_din_imag ),
// output data
.dout_valid (accum_dout_valid ),
.dout_real (accum_dout_real ),
.dout_imag (accum_dout_imag )
);
////////////////////////////////////////////////////////////////////////////////
/////////////// 32-bit Matrix Element to 1-bit Stream Conversion ///////////////
////////////////////////////////////////////////////////////////////////////////
// input data
wire stream_din_valid;
wire [CHANNEL_NUM*CHANNEL_NUM*PS_PL_WIDTH-1 : 0] stream_din_real;
wire [CHANNEL_NUM*CHANNEL_NUM*PS_PL_WIDTH-1 : 0] stream_din_imag;
assign stream_din_valid = accum_dout_valid;
assign stream_din_real = accum_dout_real;
assign stream_din_imag = accum_dout_imag;
// output data
wire stream_dout_valid;
wire stream_dout_data;
assign accor_stream_valid = stream_dout_valid; // to module port
assign accor_stream_data = stream_dout_data; // to module port
accor_mat_formatting #(
.ROW_NUM (CHANNEL_NUM ),
.COL_NUM (CHANNEL_NUM ),
.DATA_I_WIDTH (PS_PL_WIDTH ),
.FRAME_HEAD (ACCOR_FRAME_HEAD )
) u_accor_mat_stream
(
// clock & reset
.sys_clk (sys_clk ),
.sys_rst (sys_rst ),
.clk_96m (clk_96m ),
.ant_rst (ant_rst ),
// input data, sync to [sys_clk]
.din_valid (stream_din_valid ),
.din_real (stream_din_real ),
.din_imag (stream_din_imag ),
// output data, sync to [clk_96m]
.dout_valid (stream_dout_valid ),
.dout_data (stream_dout_data )
);
////////////////////////////////////////////////////////////////////////////////
/////////////// 1-bit Stream to 32-bit Vector Element Conversion ///////////////
////////////////////////////////////////////////////////////////////////////////
// input data
wire weight_din_data;
assign weight_din_data = weight_stream_data;
assign stream_din_real = accum_dout_real;
assign stream_din_imag = accum_dout_imag;
// output data
wire weight_dout_valid;
wire [CHANNEL_NUM*WEIGHT_TRUNC_WIDTH-1 : 0] weight_dout_real;
wire [CHANNEL_NUM*WEIGHT_TRUNC_WIDTH-1 : 0] weight_dout_imag;
weight_vec_formatting #(
.COL_NUM (CHANNEL_NUM ),
.WEIGHT_WIDTH (PS_PL_WIDTH ),
.DATA_O_WIDTH (WEIGHT_TRUNC_WIDTH ),
.FRAME_HEAD (WEIGHT_FRAME_HEAD )
) u_weight_vec_formatting
(
// clock & reset
.sys_clk (sys_clk ),
.sys_rst (sys_rst ),
.clk_96m (clk_96m ),
.ant_rst (ant_rst ),
// input data, sync to [clk_96m]
.din_data (weight_din_data ),
// output data, sync to [sys_clk]
.dout_valid (weight_dout_valid ),
.dout_real (weight_dout_real ),
.dout_imag (weight_dout_imag )
);
////////////////////////////////////////////////////////////////////////////////
//////////////////////////////// Spatial Filter ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// input weight vector
wire filter_weight_valid;
wire [CHANNEL_NUM*WEIGHT_TRUNC_WIDTH-1 : 0] filter_weight_real;
wire [CHANNEL_NUM*WEIGHT_TRUNC_WIDTH-1 : 0] filter_weight_imag;
assign filter_weight_valid = weight_dout_valid;
assign filter_weight_real = weight_dout_real;
assign filter_weight_imag = weight_dout_imag;
// input adc data
wire filter_adc_valid;
wire [CHANNEL_NUM*ADC_DATA_WIDTH-1 : 0] filter_adc_real;
wire [CHANNEL_NUM*ADC_DATA_WIDTH-1 : 0] filter_adc_imag;
assign filter_adc_valid = ad9361_cal_valid;
assign filter_adc_real = {rx_cal_ch4_i, rx_cal_ch3_i, rx_cal_ch2_i, rx_cal_ch1_i};
assign filter_adc_imag = {rx_cal_ch4_q, rx_cal_ch3_q, rx_cal_ch2_q, rx_cal_ch1_q};
// output data
wire filter_dout_valid;
wire [OUTPUT_DATA_WIDTH-1 : 0] filter_dout_real;
wire [OUTPUT_DATA_WIDTH-1 : 0] filter_dout_imag;
assign rx_data_valid = filter_dout_valid;
assign rx_data_i = filter_dout_real;
assign rx_data_q = filter_dout_imag;
spatial_filter #(
.CHANNEL_NUM (CHANNEL_NUM ),
.WEIGHT_WIDTH (WEIGHT_TRUNC_WIDTH ),
.ADC_WIDTH (ADC_DATA_WIDTH ),
.FILTER_O_WIDTH (OUTPUT_DATA_WIDTH )
) u_spatial_filter
(
// clock & reset
.clk (sys_clk ),
.rst (sys_rst ),
// input weight vector
.din_weight_valid (filter_weight_valid),
.din_weight_real (filter_weight_real ),
.din_weight_imag (filter_weight_imag ),
// input adc data
.hop_start_flag (hop_start_flag_cdc ),
.din_adc_valid (filter_adc_valid ),
.din_adc_real (filter_adc_real ),
.din_adc_imag (filter_adc_imag ),
// output data
.dout_valid (filter_dout_valid ),
.dout_real (filter_dout_real ),
.dout_imag (filter_dout_imag )
);
endmodule
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/09/15 11:12:45
// Last Modified Data: 2022/11/02
// Design Name:
// Module Name: tb_ad9361_cal
// Project Name:
// Target Devices:
// Tool Versions:
// Description: testbench for [rx_pre_process]
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
// -------------------------------
// MATLAB Code for data generation
// -------------------------------
// %%%%%%%%%%%%%%%%%%%%%%%%%%
// %本仿真基于以下环境,64元矩形方阵,每若干个阵元通过TR通道和合路器,合成一路子阵信号,然后AD采样进入阵列信号处理单元;
// % - 子阵分割均匀,(16,16,16,16),共有4个子阵
// % - 1个已知方向的期望来波,3个未知方向的干扰信号;
// % - 信干比60dB;
// %θ表示俯仰角(来波与Z轴正向夹角);φ表示方位角(来波在XOY平面投影与X轴正向夹角);X轴与阵列每列平行,Y轴与阵列每行平行
// %通过空域滤波得到抑制干扰后的信号
// %%%%%%%%%%%%%%%%%%%%%%%%
// clc;
// clear all;
// Tt=256;%快拍数,用于阵列信号处理的采样点数
// Tmax = 32768;
// t=1:Tmax;
// %%%%%%%%%此处假设来波均为单频信号,可按自身定义修改
// f1=0.1*pi;
// f2=0.1*pi;
// f3=0.1*pi;
// f4=0.1*pi;
// %% 通信基带信号
// %% 窄带白噪声干扰信号
// filter_name = 'lpf_fs100_fpass5_fstop6.mat';
// %%
// snr=0;%信噪比可根据应用场景确定
// sjr=(60+snr);%干信比
// s1=sqrt(2*10^(snr/10))*exp(1i*f1*t);
// s2=sqrt(2*10^(sjr/10))*exp(1i*f2*t);
// s3=sqrt(2*10^(sjr/10))*exp(1i*f3*t);
// s4=sqrt(2*10^(sjr/10))*exp(1i*f4*t);
// %%%%%%%由信噪比和干信比计算出信号的幅度
// lamuda=1;%当前载频的波长,可根据载频输入实际值d
// d=0.5;%阵元间距,需小于最高工作频率半波长,可根据实际情况输入实际值
// theta1=20;%期望来波俯仰角
// phi1=30;%期望来波方位角
// theta2=-20;%干扰1俯仰角
// phi2=50;%干扰1方位角
// theta3=-40;%干扰2俯仰角
// phi3=80;%干扰2方位角
// theta4=-60;%干扰3俯仰角
// phi4=120;%干扰3方位角
// %%%%%%%%
// m=8;%列
// n=8;%行
// L=m*n;
// a1=exp(1i*2*pi*d/lamuda*(-(m/2-1/2):1:(m/2-1/2)).'*sin(theta1/180*pi)*sin(phi1/180*pi));
// b1=exp(1i*2*pi*d/lamuda*(-(n/2-1/2):1:(n/2-1/2)).'*sin(theta1/180*pi)*cos(phi1/180*pi));
// A1=kron(b1,a1);
// a2=exp(1i*2*pi*d/lamuda*(-(m/2-1/2):1:(m/2-1/2)).'*sin(theta2/180*pi)*sin(phi2/180*pi));
// b2=exp(1i*2*pi*d/lamuda*(-(n/2-1/2):1:(n/2-1/2)).'*sin(theta2/180*pi)*cos(phi2/180*pi));
// A2=kron(b2,a2);
// a3=exp(1i*2*pi*d/lamuda*(-(m/2-1/2):1:(m/2-1/2)).'*sin(theta3/180*pi)*sin(phi3/180*pi));
// b3=exp(1i*2*pi*d/lamuda*(-(n/2-1/2):1:(n/2-1/2)).'*sin(theta3/180*pi)*cos(phi3/180*pi));
// A3=kron(b3,a3);
// a4=exp(1i*2*pi*d/lamuda*(-(m/2-1/2):1:(m/2-1/2)).'*sin(theta4/180*pi)*sin(phi4/180*pi));
// b4=exp(1i*2*pi*d/lamuda*(-(n/2-1/2):1:(n/2-1/2)).'*sin(theta4/180*pi)*cos(phi4/180*pi));
// A4=kron(b4,a4);
// As=[A1,A2,A3,A4];%阵列流型
// rng(0);
// x=As*[s1;s2;s3;s4]+randn(L,Tmax);
// %%%%%%%%%%%%%%%4元子阵
// %
// N1=4;
// C1=zeros(N1,64);
// D1=zeros(N1,64);
// for kk=0:3
// C1(1,(kk*8+1):(kk*8+4))=ones(1,4);
// C1(2,(kk*8+5):(kk*8+8))=ones(1,4);
// C1(3,(kk*8+33):(kk*8+36))=ones(1,4);
// C1(4,(kk*8+37):(kk*8+40))=ones(1,4);
// end
// %}
// %%%%%%%%%%%%%%%%%%%%%%
// D1=C1*diag(A1');%4元 阵元通道移相后,每16路合路为一个子阵
// % D2=C2*diag(A1');%6元 阵元通道移相后,每(16,8)路合路为一个子阵
// % D3=C3*diag(A1');%8元 阵元通道移相后,每8路合路为一个子阵
// % %%%%%%%%%%%%%%%%%
// xs1=D1*x(:,1:Tt);
// Rx1=xs1*xs1';%4元子阵协方差矩阵
// Ax1=D1*A1;%期望来波方向的子阵导向矢量
// wx1=inv(Rx1)*Ax1/(Ax1'*inv(Rx1)*Ax1);%4子阵的LCMV权值
// s_new1=wx1'*(D1*x);%4子阵情况下的空域滤波后的信号
// % s_new1=[1,1,1,1]*xs1;
// %% 方向图
// [theta,phi] = meshgrid(-180:180);
// wx = zeros(length(theta),length(phi));
// for i = 1:length(theta)
// for j = 1:length(phi)
// a = exp(1i*2*pi*d/lamuda*(-(m/2-1/2):1:(m/2-1/2)).'*sin(theta(i,j)/180*pi)*sin(phi(i,j)/180*pi));
// b = exp(1i*2*pi*d/lamuda*(-(n/2-1/2):1:(n/2-1/2)).'*sin(theta(i,j)/180*pi)*cos(phi(i,j)/180*pi));
// A = kron(b,a);
// Ax = D1*A;
// wx(i,j) = wx1'*Ax;
// end
// end
// wx_abs = abs(wx)/max(max(abs(wx)));
// m = mesh(theta,phi,20*log(wx_abs));
// xlabel('俯仰角');
// ylabel('方位角');
// datatip(m,'DataIndex',(theta1+180)*361+(phi1+180)+1);
// datatip(m,'DataIndex',(theta2+180)*361+(phi2+180)+1);
// datatip(m,'DataIndex',(theta3+180)*361+(phi3+180)+1);
// datatip(m,'DataIndex',(theta4+180)*361+(phi4+180)+1);
// zlim([-150 0]);
// %% 数据导出
// xs1_long = (D1*x)';
// xs1_real = real(xs1_long);
// xs1_imag = imag(xs1_long);
// xs1_real_12b = round(xs1_real/max(max(abs(xs1_long)))*(2^11-1));
// xs1_imag_12b = round(xs1_imag/max(max(abs(xs1_long)))*(2^11-1));
// writematrix(xs1_real_12b,'D:\xs1_real.csv');
// writematrix(xs1_imag_12b,'D:\xs1_imag.csv');
// xs1_12b = xs1_real_12b' + 1i*xs1_imag_12b';
// wx1_32b = round(wx1/max(abs(wx1))*(2^31-1));
// wx1_16b = floor(wx1_32b/2^16);
// s_new1_30b = (wx1_16b'*xs1_12b).';
// s_new1_12b = floor(s_new1_30b/2^18);
// -----------------------------------------------------------------------------
// module tb_rx_pre;
// localparam COL_NUM = 4;
// localparam PS_PL_WIDTH = 32;
// localparam FRAME_HEAD = 32'b10110011100011110000111000110010;
// localparam FRAME_BITS = (2+COL_NUM*2)*PS_PL_WIDTH;
// reg [FRAME_BITS-1 : 0] weight_stream_buf =
// {
// FRAME_HEAD, 32'd8,
// 32'd1708831055, 32'd1022099874,
// 32'd1470077321, 32'd1478611174,
// 32'd1521211943, -32'd1515783705,
// 32'd1625618723, -32'd984927344
// };
// reg sys_clk = 1'b1;
// reg sys_clk_4x = 1'b1;
// reg sys_rst = 1'b1;
// reg clk_96m = 1'b1;
// reg ant_rst = 1'b1;
// reg ad9361_1_cal_start = 'b0;
// wire ad9361_1_cal_done ;
// reg ad9361_2_cal_start = 'b0;
// wire ad9361_2_cal_done ;
// wire ad9361_cal_result ;
// wire ad9361_cal_valid ;
// reg ad9361_recal = 'b0;
// // phase difference of 0 degree
// wire [11:0] rx_ch1_i;
// wire [11:0] rx_ch1_q;
// wire [11:0] rx_ch2_i;
// wire [11:0] rx_ch2_q;
// wire [11:0] rx_ch3_q;
// wire [11:0] rx_ch3_i;
// wire [11:0] rx_ch4_i;
// wire [11:0] rx_ch4_q;
// reg hop_start_flag = 1'b0;
// wire accor_stream_valid;
// wire accor_stream_data;
// wire weight_stream_data;
// wire rx_data_valid;
// wire [11:0] rx_data_i, rx_data_q;
// rx_pre_process u_rx_pre_process
// (
// // clock & reset
// .sys_clk (sys_clk ), // input sys_clk
// .sys_clk_4x (sys_clk_4x ), // input sys_clk_4x
// .sys_rst (sys_rst ), // input sys_rst
// .clk_96m (clk_96m ), // input clk_96m
// .ant_rst (ant_rst ), // input ant_rst
// // input data interface
// .rx_ch1_i (rx_ch1_i ), // input [11:0] rx_ch1_i
// .rx_ch1_q (rx_ch1_q ), // input [11:0] rx_ch1_q
// .rx_ch2_i (-rx_ch2_i ), // input [11:0] rx_ch2_i
// .rx_ch2_q (-rx_ch2_q ), // input [11:0] rx_ch2_q
// .rx_ch3_i (rx_ch3_i ), // input [11:0] rx_ch3_i
// .rx_ch3_q (rx_ch3_q ), // input [11:0] rx_ch3_q
// .rx_ch4_i (-rx_ch4_i ), // input [11:0] rx_ch4_i
// .rx_ch4_q (-rx_ch4_q ), // input [11:0] rx_ch4_q
// // ad9361 calibration interface
// .ad9361_1_cal_start (ad9361_1_cal_start ), // input ad9361_1_cal_start
// .ad9361_1_cal_done (ad9361_1_cal_done ), // output ad9361_1_cal_done
// .ad9361_2_cal_start (ad9361_2_cal_start ), // input ad9361_2_cal_start
// .ad9361_2_cal_done (ad9361_2_cal_done ), // output ad9361_2_cal_done
// .ad9361_cal_result (ad9361_cal_result ), // output ad9361_cal_result
// .ad9361_cal_valid (ad9361_cal_valid ), // output ad9361_cal_valid
// .ad9361_recal (ad9361_recal ), // input ad9361_recal
// // nulling algotithm interface
// .hop_start_flag (hop_start_flag ), // input hop_start_flag
// .accor_stream_valid (accor_stream_valid ), // output accor_stream_valid
// .accor_stream_data (accor_stream_data ), // output accor_stream_data
// .weight_stream_data (weight_stream_data ), // input weight_stream_data
// .rx_data_valid (rx_data_valid ),
// .rx_data_i (rx_data_i ),
// .rx_data_q (rx_data_q )
// );
// // system clock generation
// always begin
// #20 sys_clk = ~sys_clk;
// end
// always begin
// #5 sys_clk_4x = ~sys_clk_4x;
// end
// always begin
// #7;
// clk_96m = ~clk_96m;
// #3;
// end
// initial begin
// #102
// sys_rst = 1'b0;
// ant_rst = 1'b0;
// #100
// ad9361_1_cal_start = 1'b1;
// end
// always @(posedge sys_clk) begin
// if (ad9361_1_cal_done) begin
// ad9361_2_cal_start <= 1'b1;
// end
// else begin
// ad9361_2_cal_start <= 1'b0;
// end
// end
// integer r_file_real;
// integer r_file_imag;
// reg signed [11:0] rx_ch1_i_data = 'b0, rx_ch1_q_data = 'b0;
// reg signed [11:0] rx_ch2_i_data = 'b0, rx_ch2_q_data = 'b0;
// reg signed [11:0] rx_ch3_i_data = 'b0, rx_ch3_q_data = 'b0;
// reg signed [11:0] rx_ch4_i_data = 'b0, rx_ch4_q_data = 'b0;
// reg [11:0] rx_ch1_i_cal = 12'd2047;
// reg [11:0] rx_ch1_q_cal = 12'd2047;
// reg [11:0] rx_ch2_i_cal = -12'd2047;
// reg [11:0] rx_ch2_q_cal = -12'd2047;
// reg [11:0] rx_ch3_q_cal = 12'd2047;
// reg [11:0] rx_ch3_i_cal = 12'd2047;
// reg [11:0] rx_ch4_i_cal = -12'd2047;
// reg [11:0] rx_ch4_q_cal = -12'd2047;
// assign rx_ch1_i = ad9361_cal_valid ? rx_ch1_i_data : rx_ch1_i_cal;
// assign rx_ch1_q = ad9361_cal_valid ? rx_ch1_q_data : rx_ch1_q_cal;
// assign rx_ch2_i = ad9361_cal_valid ? rx_ch2_i_data : rx_ch2_i_cal;
// assign rx_ch2_q = ad9361_cal_valid ? rx_ch2_q_data : rx_ch2_q_cal;
// assign rx_ch3_i = ad9361_cal_valid ? rx_ch3_i_data : rx_ch3_i_cal;
// assign rx_ch3_q = ad9361_cal_valid ? rx_ch3_q_data : rx_ch3_q_cal;
// assign rx_ch4_i = ad9361_cal_valid ? rx_ch4_i_data : rx_ch4_i_cal;
// assign rx_ch4_q = ad9361_cal_valid ? rx_ch4_q_data : rx_ch4_q_cal;
// initial begin
// forever begin
// @(posedge sys_clk)
// // 校准数据
// #720
// rx_ch1_i_cal = ~rx_ch1_i_cal;
// rx_ch2_i_cal = ~rx_ch2_i_cal;
// rx_ch3_i_cal = ~rx_ch3_i_cal;
// rx_ch4_i_cal = ~rx_ch4_i_cal;
// #240
// rx_ch1_q_cal = ~rx_ch1_q_cal;
// rx_ch2_q_cal = ~rx_ch2_q_cal;
// rx_ch3_q_cal = ~rx_ch3_q_cal;
// rx_ch4_q_cal = ~rx_ch4_q_cal;
// end
// end
// initial begin
// r_file_real = $fopen("D:\\xs1_real.csv","r");
// r_file_imag = $fopen("D:\\xs1_imag.csv","r");
// @(posedge ad9361_cal_valid)
// #200;
// #160; // [hop_start_flag_cdc]
// forever begin
// @(posedge sys_clk)
// $fscanf(r_file_real,"%d,%d,%d,%d",
// rx_ch1_i_data,
// rx_ch2_i_data,
// rx_ch3_i_data,
// rx_ch4_i_data);
// $fscanf(r_file_imag,"%d,%d,%d,%d",
// rx_ch1_q_data,
// rx_ch2_q_data,
// rx_ch3_q_data,
// rx_ch4_q_data);
// end
// end
// initial begin
// @(posedge ad9361_cal_valid)
// #200;
// forever begin
// @(posedge sys_clk_4x)
// hop_start_flag = 1'b1;
// @(posedge sys_clk_4x)
// hop_start_flag = 1'b0;
// #((192*200-1)*10); // 200us of 192M clock
// end
// end
// reg weight_stream_valid = 'b0;
// always @(negedge accor_stream_valid) begin
// #((48*50)*40+18); // 50us of 48M clock
// weight_stream_valid = 'b1;
// #(FRAME_BITS*20);
// weight_stream_valid = 'b0;
// end
// reg [$clog2(FRAME_BITS)-1 : 0] weight_stream_cnt;
// always @(posedge clk_96m) begin
// if (sys_rst) begin
// weight_stream_cnt <= 'b0;
// end
// else begin
// weight_stream_cnt <= (weight_stream_valid & ~(weight_stream_cnt == FRAME_BITS - 1)) ? weight_stream_cnt + 1'b1 : 'b0;
// end
// end
// assign weight_stream_data = weight_stream_buf[FRAME_BITS-1-weight_stream_cnt];
// endmodule
@@ -0,0 +1,472 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/11/16 11:18:28
// Design Name:
// Module Name: rx_pre_test
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module rx_pre_test
#(
parameter ADC_DATA_WIDTH = 12,
parameter BYPASS_CAL = 0
)
(
// clock & reset
input sys_clk ,
input sys_clk_4x ,
input sys_rst ,
// calc result
input ad9361_cal_result , // sync to [sys_clk]
input ad9361_cal_valid ,
// output test data
output [ADC_DATA_WIDTH-1:0] rx_ch1_i , // sync to [sys_clk]
output [ADC_DATA_WIDTH-1:0] rx_ch1_q , // sync to [sys_clk]
output [ADC_DATA_WIDTH-1:0] rx_ch2_i , // sync to [sys_clk]
output [ADC_DATA_WIDTH-1:0] rx_ch2_q , // sync to [sys_clk]
output [ADC_DATA_WIDTH-1:0] rx_ch3_i , // sync to [sys_clk]
output [ADC_DATA_WIDTH-1:0] rx_ch3_q , // sync to [sys_clk]
output [ADC_DATA_WIDTH-1:0] rx_ch4_i , // sync to [sys_clk]
output [ADC_DATA_WIDTH-1:0] rx_ch4_q , // sync to [sys_clk]
output hop_start_flag // sync to [sys_clk_4x]
);
localparam HOP_CNT_MOD_192M = 192*200;
localparam HOP_CNT_MOD_48M = 48*200;
// [hop_start_flag] generation
wire ad9361_cal_valid_cdc;
xpm_cdc_single #(
.DEST_SYNC_FF (4), // DECIMAL; range: 2-10
.INIT_SYNC_FF (0), // DECIMAL; 0=disable simulation init values, 1=enable simulation init values
.SIM_ASSERT_CHK (0), // DECIMAL; 0=disable simulation messages, 1=enable simulation messages
.SRC_INPUT_REG (1) // DECIMAL; 0=do not register input, 1=register input
) u_ad9361_cal_valid_cdc
(
.dest_out (ad9361_cal_valid_cdc ), // 1-bit output: src_in synchronized to the destination clock domain. This output is
// registered.
.dest_clk (sys_clk_4x ), // 1-bit input: Clock signal for the destination clock domain.
.src_clk (sys_clk ), // 1-bit input: optional; required when SRC_INPUT_REG = 1
.src_in (ad9361_cal_valid ) // 1-bit input: Input signal to be synchronized to dest_clk domain.
);
reg [$clog2(HOP_CNT_MOD_192M)-1 : 0] hop_cnt_192m = 'b0;
reg hop_flag = 'b0;
assign hop_start_flag = hop_flag;
always @(posedge sys_clk_4x) begin
if (sys_rst) begin
hop_cnt_192m = 'b0;
hop_flag = 'b0;
end
else if (ad9361_cal_valid_cdc) begin
hop_cnt_192m <= (hop_cnt_192m == HOP_CNT_MOD_192M-1) ? 'b0 : hop_cnt_192m + 1'b1;
hop_flag <= (hop_cnt_192m == 20) ? 1'b1 : 1'b0;
end
else begin
hop_cnt_192m <= 'b0;
hop_flag = 'b0;
end
end
// read rx data
wire hop_flag_cdc;
xpm_cdc_pulse #(
.DEST_SYNC_FF (4), // DECIMAL; range: 2-10
.INIT_SYNC_FF (0), // DECIMAL; 0=disable simulation init values, 1=enable simulation init values
.REG_OUTPUT (0), // DECIMAL; 0=disable registered output, 1=enable registered output
.RST_USED (1), // DECIMAL; 0=no reset, 1=implement reset
.SIM_ASSERT_CHK (0) // DECIMAL; 0=disable simulation messages, 1=enable simulation messages
) u_hop_flag_cdc
(
.dest_pulse (hop_flag_cdc ), // 1-bit output: Outputs a pulse the size of one dest_clk period when a pulse
// transfer is correctly initiated on src_pulse input. This output is
// combinatorial unless REG_OUTPUT is set to 1.
.dest_clk (sys_clk ), // 1-bit input: Destination clock.
.dest_rst (sys_rst ), // 1-bit input: optional; required when RST_USED = 1
.src_clk (sys_clk_4x ), // 1-bit input: Source clock.
.src_pulse (hop_flag ), // 1-bit input: Rising edge of this signal initiates a pulse transfer to the
// destination clock domain. The minimum gap between each pulse transfer must be
// at the minimum 2*(larger(src_clk period, dest_clk period)). This is measured
// between the falling edge of a src_pulse to the rising edge of the next
// src_pulse. This minimum gap will guarantee that each rising edge of src_pulse
// will generate a pulse the size of one dest_clk period in the destination
// clock domain. When RST_USED = 1, pulse transfers will not be guaranteed while
// src_rst and/or dest_rst are asserted.
.src_rst (sys_rst ) // 1-bit input: optional; required when RST_USED = 1
);
reg [$clog2(HOP_CNT_MOD_48M)-1 : 0] hop_cnt_48m = 'b0;
always @(posedge sys_clk) begin
if (sys_rst) begin
hop_cnt_48m <= 2'd2;
end
else if (ad9361_cal_valid) begin
if (hop_flag_cdc) begin
hop_cnt_48m = 2'd2;
end
else begin
hop_cnt_48m <= (hop_cnt_48m == HOP_CNT_MOD_48M-1 || hop_flag_cdc) ? 'b0 : hop_cnt_48m + 1'b1;
end
end
else begin
hop_cnt_48m <= 2'd2;
end
end
wire [95:0] hop_data;
wire [11:0] rom_ch1_i,rom_ch2_i,rom_ch3_i,rom_ch4_i;
wire [11:0] rom_ch1_q,rom_ch2_q,rom_ch3_q,rom_ch4_q;
assign {rom_ch1_i,rom_ch2_i,rom_ch3_i,rom_ch4_i,
rom_ch1_q,rom_ch2_q,rom_ch3_q,rom_ch4_q} = hop_data;
rom_hop_data u_rom_hop_data
(
.clka (sys_clk ), // input wire clka
.addra (hop_cnt_48m), // input wire [13 : 0] addra
.douta (hop_data ) // output wire [95 : 0] douta
);
reg [11:0] rom_ch1_i_buf,rom_ch2_i_buf,rom_ch3_i_buf,rom_ch4_i_buf;
reg [11:0] rom_ch1_q_buf,rom_ch2_q_buf,rom_ch3_q_buf,rom_ch4_q_buf;
assign rx_ch1_i = rom_ch1_i_buf;
assign rx_ch1_q = rom_ch1_q_buf;
assign rx_ch2_i = rom_ch2_i_buf;
assign rx_ch2_q = rom_ch2_q_buf;
assign rx_ch3_i = rom_ch3_i_buf;
assign rx_ch3_q = rom_ch3_q_buf;
assign rx_ch4_i = rom_ch4_i_buf;
assign rx_ch4_q = rom_ch4_q_buf;
always @(posedge sys_clk) begin
if (BYPASS_CAL) begin
rom_ch1_i_buf <= rom_ch1_i;
rom_ch1_q_buf <= rom_ch1_q;
rom_ch2_i_buf <= rom_ch2_i;
rom_ch2_q_buf <= rom_ch2_q;
rom_ch3_i_buf <= rom_ch3_i;
rom_ch3_q_buf <= rom_ch3_q;
rom_ch4_i_buf <= rom_ch4_i;
rom_ch4_q_buf <= rom_ch4_q;
end
else begin
if (ad9361_cal_result) begin
rom_ch1_i_buf <= rom_ch1_i;
rom_ch1_q_buf <= rom_ch1_q;
rom_ch2_i_buf <= -rom_ch2_i;
rom_ch2_q_buf <= -rom_ch2_q;
rom_ch3_i_buf <= -rom_ch3_i;
rom_ch3_q_buf <= -rom_ch3_q;
rom_ch4_i_buf <= rom_ch4_i;
rom_ch4_q_buf <= rom_ch4_q;
end
else begin
rom_ch1_i_buf <= rom_ch1_i;
rom_ch1_q_buf <= rom_ch1_q;
rom_ch2_i_buf <= -rom_ch2_i;
rom_ch2_q_buf <= -rom_ch2_q;
rom_ch3_i_buf <= rom_ch3_i;
rom_ch3_q_buf <= rom_ch3_q;
rom_ch4_i_buf <= -rom_ch4_i;
rom_ch4_q_buf <= -rom_ch4_q;
end
end
end
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/11/16 15:08:02
// Design Name:
// Module Name: tb_re_pre_test
// Project Name:
// Target Devices:
// Tool Versions:
// Description: testbench for [rx_pre_test]
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
// module tb_re_pre_test;
// reg sys_clk = 1'b1;
// reg sys_clk_4x = 1'b1;
// reg sys_rst = 1'b1;
// reg ad9361_cal_result = 1'b0;
// reg ad9361_cal_valid = 1'b0;
// wire [11:0] rx_ch1_i;
// wire [11:0] rx_ch1_q;
// wire [11:0] rx_ch2_i;
// wire [11:0] rx_ch2_q;
// wire [11:0] rx_ch3_i;
// wire [11:0] rx_ch3_q;
// wire [11:0] rx_ch4_i;
// wire [11:0] rx_ch4_q;
// wire hop_start_flag;
// rx_pre_test u_rx_pre_test
// (
// // clock & reset
// .sys_clk (sys_clk ),
// .sys_clk_4x (sys_clk_4x ),
// .sys_rst (sys_rst ),
// // calc result
// .ad9361_cal_result (ad9361_cal_result ),
// .ad9361_cal_valid (ad9361_cal_valid ),
// // output test data
// .rx_ch1_i (rx_ch1_i ),
// .rx_ch1_q (rx_ch1_q ),
// .rx_ch2_i (rx_ch2_i ),
// .rx_ch2_q (rx_ch2_q ),
// .rx_ch3_i (rx_ch3_i ),
// .rx_ch3_q (rx_ch3_q ),
// .rx_ch4_i (rx_ch4_i ),
// .rx_ch4_q (rx_ch4_q ),
// .hop_start_flag (hop_start_flag )
// );
// // system clock generation
// always begin
// #20 sys_clk = ~sys_clk;
// end
// always begin
// #5 sys_clk_4x = ~sys_clk_4x;
// end
// initial begin
// #102
// sys_rst = 1'b0;
// #100
// ad9361_cal_valid = 1'b1;
// end
// endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/11/16 15:58:28
// Design Name:
// Module Name: tb_rx_pre_test
// Project Name:
// Target Devices:
// Tool Versions:
// Description: Co-simulation testbench for [rx_pre_process] and [rx_pre_test]
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
// module tb_rx_pre_test;
// localparam COL_NUM = 4;
// localparam PS_PL_WIDTH = 32;
// localparam FRAME_HEAD = 32'b01001100011100001111000111001101;
// localparam FRAME_BITS = (2+COL_NUM*2)*PS_PL_WIDTH;
// reg [FRAME_BITS-1 : 0] weight_stream_buf =
// {
// FRAME_HEAD, 32'd40,
// 32'd1681399168, -32'd984290880,
// 32'd1494147072, -32'd1542469120,
// 32'd1531326976, 32'd1443639808,
// 32'd1665626240, 32'd1083120000
// };
// reg sys_clk = 1'b1;
// reg sys_clk_4x = 1'b1;
// reg sys_rst = 1'b1;
// reg clk_96m = 1'b1;
// reg ant_rst = 1'b1;
// reg ad9361_1_cal_start = 'b0;
// wire ad9361_1_cal_done ;
// reg ad9361_2_cal_start = 'b0;
// wire ad9361_2_cal_done ;
// wire ad9361_cal_result ;
// wire ad9361_cal_valid ;
// reg ad9361_recal = 'b0;
// // phase difference of 0 degree
// wire [11:0] rx_ch1_i;
// wire [11:0] rx_ch1_q;
// wire [11:0] rx_ch2_i;
// wire [11:0] rx_ch2_q;
// wire [11:0] rx_ch3_q;
// wire [11:0] rx_ch3_i;
// wire [11:0] rx_ch4_i;
// wire [11:0] rx_ch4_q;
// wire hop_start_flag;
// wire accor_stream_valid;
// wire accor_stream_data;
// wire weight_stream_data;
// wire rx_data_valid;
// wire [11:0] rx_data_i, rx_data_q;
// rx_pre_process #(
// .BYPASS_CAL (1)
// ) u_rx_pre_process
// (
// // clock & reset
// .sys_clk (sys_clk ), // sync to adc data
// .sys_clk_4x (sys_clk_4x ), // sync to physical layer
// .sys_rst (sys_rst ), // sync to [sys_clk]
// .clk_96m (clk_96m ), // sync to c2c data
// .ant_rst (ant_rst ), // sync to [clk_96m]
// // input data interface
// .rx_ch1_i (rx_ch1_i ),
// .rx_ch1_q (rx_ch1_q ),
// .rx_ch2_i (rx_ch2_i ),
// .rx_ch2_q (rx_ch2_q ),
// .rx_ch3_i (rx_ch3_i ),
// .rx_ch3_q (rx_ch3_q ),
// .rx_ch4_i (rx_ch4_i ),
// .rx_ch4_q (rx_ch4_q ),
// // ad9361 calibration interface
// .ad9361_1_cal_start (ad9361_1_cal_start ),
// .ad9361_1_cal_done (ad9361_1_cal_done ),
// .ad9361_2_cal_start (ad9361_2_cal_start ),
// .ad9361_2_cal_done (ad9361_2_cal_done ),
// .ad9361_cal_result (ad9361_cal_result ),
// .ad9361_cal_valid (ad9361_cal_valid ),
// .ad9361_recal (ad9361_recal ),
// // nulling algotithm interface
// .hop_start_flag (hop_start_flag ), // sync to [sys_clk_4x]
// .accor_stream_valid (accor_stream_valid ), // sync to [clk_96m]
// .accor_stream_data (accor_stream_data ), // sync to [clk_96m]
// .weight_stream_data (weight_stream_data ), // sync to [clk_96m]
// .rx_data_valid (rx_data_valid ), // sync to [sys_clk]
// .rx_data_i (rx_data_i ), // sync to [sys_clk]
// .rx_data_q (rx_data_q ) // sync to [sys_clk]
// );
// // temporary test cases
// rx_pre_test #(
// .BYPASS_CAL (1)
// ) u_rx_pre_test
// (
// // clock & reset
// .sys_clk (sys_clk ),
// .sys_clk_4x (sys_clk_4x ),
// .sys_rst (sys_rst ),
// // calc result
// .ad9361_cal_result (ad9361_cal_result ),
// .ad9361_cal_valid (ad9361_cal_valid ),
// // output test data
// .rx_ch1_i (rx_ch1_i ),
// .rx_ch1_q (rx_ch1_q ),
// .rx_ch2_i (rx_ch2_i ),
// .rx_ch2_q (rx_ch2_q ),
// .rx_ch3_i (rx_ch3_i ),
// .rx_ch3_q (rx_ch3_q ),
// .rx_ch4_i (rx_ch4_i ),
// .rx_ch4_q (rx_ch4_q ),
// .hop_start_flag (hop_start_flag )
// );
// // system clock generation
// always begin
// #20 sys_clk = ~sys_clk;
// end
// always begin
// #5 sys_clk_4x = ~sys_clk_4x;
// end
// always begin
// #7;
// clk_96m = ~clk_96m;
// #3;
// end
// initial begin
// #102
// sys_rst = 1'b0;
// ant_rst = 1'b0;
// end
// reg weight_stream_valid = 'b0;
// always @(negedge accor_stream_valid) begin
// #((48*50)*40+18); // 50us of 48M clock
// weight_stream_valid = 'b1;
// #(FRAME_BITS*20);
// weight_stream_valid = 'b0;
// end
// reg [$clog2(FRAME_BITS)-1 : 0] weight_stream_cnt;
// always @(posedge clk_96m) begin
// if (sys_rst) begin
// weight_stream_cnt <= 'b0;
// end
// else begin
// weight_stream_cnt <= (weight_stream_valid & ~(weight_stream_cnt == FRAME_BITS - 1)) ? weight_stream_cnt + 1'b1 : 'b0;
// end
// end
// assign weight_stream_data = weight_stream_buf[FRAME_BITS-1-weight_stream_cnt];
// endmodule
@@ -0,0 +1,516 @@
// `timescale 1ns / 1ps
// //////////////////////////////////////////////////////////////////////////////////
// // Company:
// // Engineer:
// //
// // Create Date: 2022/11/11 17:05:31
// // Design Name:
// // Module Name: spatial_filter
// // Project Name:
// // Target Devices:
// // Tool Versions:
// // Description:
// //
// // Dependencies:
// //
// // Revision:
// // Revision 0.01 - File Created
// // Additional Comments:
// //
// //////////////////////////////////////////////////////////////////////////////////
// module spatial_filter
// #(
// parameter CHANNEL_NUM = 4,
// parameter WEIGHT_WIDTH = 16,
// parameter ADC_WIDTH = 12,
// parameter FILTER_O_WIDTH = ADC_WIDTH
// )
// (
// // clock & reset
// input clk,
// input rst,
// // input weight vector
// input din_weight_valid,
// input [CHANNEL_NUM*WEIGHT_WIDTH-1 : 0] din_weight_real,
// input [CHANNEL_NUM*WEIGHT_WIDTH-1 : 0] din_weight_imag,
// // input adc data
// input hop_start_flag,
// input din_adc_valid,
// input [CHANNEL_NUM*ADC_WIDTH-1 : 0] din_adc_real,
// input [CHANNEL_NUM*ADC_WIDTH-1 : 0] din_adc_imag,
// // output data
// output dout_valid,
// output [FILTER_O_WIDTH-1 : 0] dout_real,
// output [FILTER_O_WIDTH-1 : 0] dout_imag
// );
// localparam RAM_HOP_DEPTH = 9600;
// localparam CMPLX_DIM = 2;
// localparam FILTER_MULT_FULL_WIDTH = WEIGHT_WIDTH+ADC_WIDTH+1;
// localparam FILTER_MULT_VALID_WIDTH = WEIGHT_WIDTH+ADC_WIDTH;
// localparam FILTER_SUM_WIDTH = FILTER_MULT_VALID_WIDTH+$clog2(CHANNEL_NUM);
// localparam AXIS_WEIGHT_WIDTH = 8*((WEIGHT_WIDTH-1)/8+1); // axis data width of input weight vector real/image data
// localparam AXIS_ADC_I_WIDTH = 8*((ADC_WIDTH-1)/8+1) ; // axis data width of input adc real/image data
// localparam AXIS_FILTER_WIDTH = 8*((FILTER_MULT_FULL_WIDTH-1)/8+1) ; // axis data width of cmpy output real/image data
// genvar i;
// // store current hop & restore last hop weight
// reg [CMPLX_DIM*CHANNEL_NUM*WEIGHT_WIDTH-1 : 0] current_hop_weight = 'b0;
// reg [CMPLX_DIM*CHANNEL_NUM*WEIGHT_WIDTH-1 : 0] last_hop_weight = 'b0;
// wire [CHANNEL_NUM*WEIGHT_WIDTH-1 : 0] last_weight_real;
// wire [CHANNEL_NUM*WEIGHT_WIDTH-1 : 0] last_weight_imag;
// assign {last_weight_imag,last_weight_real} = last_hop_weight;
// always @(posedge clk) begin
// if (rst) begin
// current_hop_weight <= 'b0;
// end
// else begin
// current_hop_weight <= (din_weight_valid) ? {din_weight_imag,din_weight_real} : current_hop_weight;
// end
// end
// always @(posedge clk) begin
// if (rst) begin
// last_hop_weight <= 'b0;
// end
// else begin
// last_hop_weight <= (hop_start_flag) ? current_hop_weight : last_hop_weight;
// end
// end
// // store current hop & restore last hop data
// wire [CMPLX_DIM*CHANNEL_NUM*ADC_WIDTH-1 : 0] current_hop_data;
// reg last_hop_valid = 'b0;
// wire [CMPLX_DIM*CHANNEL_NUM*ADC_WIDTH-1 : 0] last_hop_data;
// wire [CHANNEL_NUM*ADC_WIDTH-1 : 0] last_data_real;
// wire [CHANNEL_NUM*ADC_WIDTH-1 : 0] last_data_imag;
// reg [$clog2(RAM_HOP_DEPTH)-1 : 0] hop_data_cnt = 'b0;
// assign current_hop_data = {din_adc_imag,din_adc_real};
// assign {last_data_imag,last_data_real} = last_hop_data;
// always @(posedge clk) begin
// last_hop_valid <= din_adc_valid;
// end
// always @(posedge clk) begin
// if (rst) begin
// hop_data_cnt <= 'b0;
// end
// else if (hop_start_flag) begin
// hop_data_cnt <= 'b0;
// end
// else begin
// hop_data_cnt <= din_adc_valid ? (hop_data_cnt + 1'b1) : hop_data_cnt;
// end
// end
// ram_hop_data u_ram_hop_data
// (
// .clka (clk ), // input wire clka
// .wea (din_adc_valid ), // input wire [0 : 0] wea
// .addra(hop_data_cnt ), // input wire [13 : 0] addra
// .dina (current_hop_data ), // input wire [95 : 0] dina
// .douta(last_hop_data ) // output wire [95 : 0] douta
// );
// // prepare cmpy input data
// wire [AXIS_WEIGHT_WIDTH-1:0] din_weight_real_array [0:CHANNEL_NUM-1];
// wire [AXIS_WEIGHT_WIDTH-1:0] din_weight_imag_array [0:CHANNEL_NUM-1];
// wire [AXIS_ADC_I_WIDTH-1:0] din_adc_real_array [0:CHANNEL_NUM-1];
// wire [AXIS_ADC_I_WIDTH-1:0] din_adc_imag_array [0:CHANNEL_NUM-1];
// generate
// for(i = 0; i < CHANNEL_NUM; i = i + 1) begin: weight_array_convert
// // Sign extension to fit 8-bit axis data format
// assign din_weight_real_array[i] = {{(AXIS_WEIGHT_WIDTH-WEIGHT_WIDTH){last_weight_real[(i+1)*WEIGHT_WIDTH-1]}},last_weight_real[i*WEIGHT_WIDTH +: WEIGHT_WIDTH]};
// assign din_weight_imag_array[i] = {{(AXIS_WEIGHT_WIDTH-WEIGHT_WIDTH){last_weight_imag[(i+1)*WEIGHT_WIDTH-1]}},last_weight_imag[i*WEIGHT_WIDTH +: WEIGHT_WIDTH]};
// assign din_adc_real_array[i] = {{(AXIS_ADC_I_WIDTH-ADC_WIDTH){last_data_real[(i+1)*ADC_WIDTH-1]}},last_data_real[i*ADC_WIDTH +: ADC_WIDTH]};
// assign din_adc_imag_array[i] = {{(AXIS_ADC_I_WIDTH-ADC_WIDTH){last_data_imag[(i+1)*ADC_WIDTH-1]}},last_data_imag[i*ADC_WIDTH +: ADC_WIDTH]};
// end
// endgenerate
// // complex multiplication, spatial filtering
// wire [AXIS_FILTER_WIDTH-1:0] cmpy_real_array [0:CHANNEL_NUM-1];
// wire [AXIS_FILTER_WIDTH-1:0] cmpy_imag_array [0:CHANNEL_NUM-1];
// wire [FILTER_MULT_VALID_WIDTH-1:0] weight_adc_real_array [0:CHANNEL_NUM-1];
// wire [FILTER_MULT_VALID_WIDTH-1:0] weight_adc_imag_array [0:CHANNEL_NUM-1];
// wire weight_adc_valid;
// wire [CHANNEL_NUM*FILTER_MULT_VALID_WIDTH-1:0] weight_adc_real;
// wire [CHANNEL_NUM*FILTER_MULT_VALID_WIDTH-1:0] weight_adc_imag;
// generate
// for(i = 0; i < CHANNEL_NUM; i = i + 1) begin: spatial_filter_cmpy
// wire [2*AXIS_WEIGHT_WIDTH-1:0] cmpy_a;
// wire [2*AXIS_ADC_I_WIDTH-1:0] cmpy_b;
// wire [2*AXIS_FILTER_WIDTH-1:0] cmpy_p;
// wire cmpy_p_vld;
// assign cmpy_a = {-din_weight_imag_array[i],din_weight_real_array[i]};
// assign cmpy_b = {din_adc_imag_array[i],din_adc_real_array[i]};
// assign {cmpy_imag_array[i],cmpy_real_array[i]} = cmpy_p;
// assign weight_adc_real_array[i] = cmpy_real_array[i][0 +: FILTER_MULT_VALID_WIDTH];
// assign weight_adc_imag_array[i] = cmpy_imag_array[i][0 +: FILTER_MULT_VALID_WIDTH];
// assign weight_adc_real[i*FILTER_MULT_VALID_WIDTH +: FILTER_MULT_VALID_WIDTH] = weight_adc_real_array[i];
// assign weight_adc_imag[i*FILTER_MULT_VALID_WIDTH +: FILTER_MULT_VALID_WIDTH] = weight_adc_imag_array[i];
// cmpy_16x12 u_cmpy_16x12
// (
// .aclk (clk ), // input wire aclk
// .s_axis_a_tvalid (last_hop_valid ), // input wire s_axis_a_tvalid
// .s_axis_a_tdata (cmpy_a ), // input wire [31 : 0] s_axis_a_tdata
// .s_axis_b_tvalid (last_hop_valid ), // input wire s_axis_b_tvalid
// .s_axis_b_tdata (cmpy_b ), // input wire [31 : 0] s_axis_b_tdata
// .m_axis_dout_tvalid (cmpy_p_vld ), // output wire m_axis_dout_tvalid
// .m_axis_dout_tdata (cmpy_p ) // output wire [63 : 0] m_axis_dout_tdata
// );
// end
// endgenerate
// assign weight_adc_valid = spatial_filter_cmpy[0].cmpy_p_vld;
// // multi-channel sum
// wire weight_adc_sum_valid;
// wire [FILTER_SUM_WIDTH-1 : 0] weight_adc_sum_real;
// wire [FILTER_SUM_WIDTH-1 : 0] weight_adc_sum_imag;
// adder_tree_ppl #(
// .DATA_I_WIDTH (FILTER_MULT_VALID_WIDTH),
// .DATA_NUM (CHANNEL_NUM )
// ) u_multi_ch_add_ppl_i (
// // clock & reset
// .clk (clk ),
// .rst (rst ),
// // input data
// .din_valid (weight_adc_valid ),
// .din_data (weight_adc_real ),
// // output data
// .dout_valid (weight_adc_sum_valid ),
// .dout_data (weight_adc_sum_real )
// );
// adder_tree_ppl #(
// .DATA_I_WIDTH (FILTER_MULT_VALID_WIDTH),
// .DATA_NUM (CHANNEL_NUM )
// ) u_multi_ch_add_ppl_q (
// // clock & reset
// .clk (clk ),
// .rst (rst ),
// // input data
// .din_valid (weight_adc_valid ),
// .din_data (weight_adc_imag ),
// // output data
// .dout_valid ( ),
// .dout_data (weight_adc_sum_imag )
// );
// // output filtered signal
// assign dout_valid = weight_adc_sum_valid;
// if (FILTER_O_WIDTH <= FILTER_SUM_WIDTH) begin
// assign dout_real = weight_adc_sum_real[FILTER_SUM_WIDTH-1 -: FILTER_O_WIDTH];
// assign dout_imag = weight_adc_sum_imag[FILTER_SUM_WIDTH-1 -: FILTER_O_WIDTH];
// end
// else begin
// assign dout_real = {{(FILTER_O_WIDTH-FILTER_SUM_WIDTH){weight_adc_sum_real[FILTER_SUM_WIDTH-1]}},weight_adc_sum_real};
// assign dout_imag = {{(FILTER_O_WIDTH-FILTER_SUM_WIDTH){weight_adc_sum_imag[FILTER_SUM_WIDTH-1]}},weight_adc_sum_imag};
// end
// endmodule
// // This module has been tested during the simulation of [rx_pre_process]
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/11/11 17:05:31
// Design Name:
// Module Name: spatial_filter
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// 20230404-1037 - 将权矢量和数据对齐,增加 [last_hop_weight_d1] 补偿 RAM 读数
// 的延迟。
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module spatial_filter
#(
parameter CHANNEL_NUM = 4,
parameter WEIGHT_WIDTH = 16,
parameter ADC_WIDTH = 12,
parameter FILTER_O_WIDTH = ADC_WIDTH
)
(
// clock & reset
input clk,
input rst,
// input weight vector
input din_weight_valid,
input [CHANNEL_NUM*WEIGHT_WIDTH-1 : 0] din_weight_real,
input [CHANNEL_NUM*WEIGHT_WIDTH-1 : 0] din_weight_imag,
// input adc data
input hop_start_flag,
input din_adc_valid,
input [CHANNEL_NUM*ADC_WIDTH-1 : 0] din_adc_real,
input [CHANNEL_NUM*ADC_WIDTH-1 : 0] din_adc_imag,
// output data
output dout_valid,
output [FILTER_O_WIDTH-1 : 0] dout_real,
output [FILTER_O_WIDTH-1 : 0] dout_imag
);
localparam RAM_HOP_DEPTH = 9728;
localparam CMPLX_DIM = 2;
localparam FILTER_MULT_FULL_WIDTH = WEIGHT_WIDTH+ADC_WIDTH+1;
localparam FILTER_MULT_VALID_WIDTH = WEIGHT_WIDTH+ADC_WIDTH;
localparam FILTER_SUM_WIDTH = FILTER_MULT_VALID_WIDTH+$clog2(CHANNEL_NUM);
localparam AXIS_WEIGHT_WIDTH = 8*((WEIGHT_WIDTH-1)/8+1); // axis data width of input weight vector real/image data
localparam AXIS_ADC_I_WIDTH = 8*((ADC_WIDTH-1)/8+1) ; // axis data width of input adc real/image data
localparam AXIS_FILTER_WIDTH = 8*((FILTER_MULT_FULL_WIDTH-1)/8+1) ; // axis data width of cmpy output real/image data
genvar i;
// store current hop & restore last hop weight
reg [CMPLX_DIM*CHANNEL_NUM*WEIGHT_WIDTH-1 : 0] current_hop_weight = 'b0;
reg [CMPLX_DIM*CHANNEL_NUM*WEIGHT_WIDTH-1 : 0] last_hop_weight = 'b0;
reg [CMPLX_DIM*CHANNEL_NUM*WEIGHT_WIDTH-1 : 0] last_hop_weight_d1 = 'b0; // wait for ram data
wire [CHANNEL_NUM*WEIGHT_WIDTH-1 : 0] last_weight_real;
wire [CHANNEL_NUM*WEIGHT_WIDTH-1 : 0] last_weight_imag;
assign {last_weight_imag,last_weight_real} = last_hop_weight_d1;
always @(posedge clk) begin
if (rst) begin
current_hop_weight <= 'b0;
end
else begin
current_hop_weight <= (din_weight_valid) ? {din_weight_imag,din_weight_real} : current_hop_weight;
end
end
always @(posedge clk) begin
if (rst) begin
last_hop_weight <= 'b0;
end
else begin
last_hop_weight <= (hop_start_flag) ? current_hop_weight : last_hop_weight;
end
end
always @(posedge clk) begin
if (rst) begin
last_hop_weight_d1 <= 'b0;
end
else begin
last_hop_weight_d1 <= last_hop_weight;
end
end
// store current hop & restore last hop data
wire [CMPLX_DIM*CHANNEL_NUM*ADC_WIDTH-1 : 0] current_hop_data;
reg last_hop_valid = 'b0;
wire [CMPLX_DIM*CHANNEL_NUM*ADC_WIDTH-1 : 0] last_hop_data;
wire [CHANNEL_NUM*ADC_WIDTH-1 : 0] last_data_real;
wire [CHANNEL_NUM*ADC_WIDTH-1 : 0] last_data_imag;
reg [$clog2(RAM_HOP_DEPTH)-1 : 0] hop_data_cnt = 'b0;
assign current_hop_data = {din_adc_imag,din_adc_real};
assign {last_data_imag,last_data_real} = last_hop_data;
always @(posedge clk) begin
last_hop_valid <= din_adc_valid;
end
always @(posedge clk) begin
if (rst) begin
hop_data_cnt <= 'b0;
end
else if(din_adc_valid) begin
if (hop_start_flag) begin
hop_data_cnt <= 'b0;
end
else if (hop_data_cnt == RAM_HOP_DEPTH-1) begin
hop_data_cnt <= 'b0;
end
else begin
hop_data_cnt <= hop_data_cnt + 1'b1;
end
end
else begin
hop_data_cnt <= hop_data_cnt;
end
end
ram_hop_data u_ram_hop_data
(
.clka (clk ), // input wire clka
.wea (din_adc_valid ), // input wire [0 : 0] wea
.addra(hop_data_cnt ), // input wire [13 : 0] addra
.dina (current_hop_data ), // input wire [95 : 0] dina
.douta(last_hop_data ) // output wire [95 : 0] douta
);
// prepare cmpy input data
wire [AXIS_WEIGHT_WIDTH-1:0] din_weight_real_array [0:CHANNEL_NUM-1];
wire [AXIS_WEIGHT_WIDTH-1:0] din_weight_imag_array [0:CHANNEL_NUM-1];
wire [AXIS_ADC_I_WIDTH-1:0] din_adc_real_array [0:CHANNEL_NUM-1];
wire [AXIS_ADC_I_WIDTH-1:0] din_adc_imag_array [0:CHANNEL_NUM-1];
generate
for(i = 0; i < CHANNEL_NUM; i = i + 1) begin: weight_array_convert
// Sign extension to fit 8-bit axis data format
assign din_weight_real_array[i] = {{(AXIS_WEIGHT_WIDTH-WEIGHT_WIDTH){last_weight_real[(i+1)*WEIGHT_WIDTH-1]}},last_weight_real[i*WEIGHT_WIDTH +: WEIGHT_WIDTH]};
assign din_weight_imag_array[i] = {{(AXIS_WEIGHT_WIDTH-WEIGHT_WIDTH){last_weight_imag[(i+1)*WEIGHT_WIDTH-1]}},last_weight_imag[i*WEIGHT_WIDTH +: WEIGHT_WIDTH]};
assign din_adc_real_array[i] = {{(AXIS_ADC_I_WIDTH-ADC_WIDTH){last_data_real[(i+1)*ADC_WIDTH-1]}},last_data_real[i*ADC_WIDTH +: ADC_WIDTH]};
assign din_adc_imag_array[i] = {{(AXIS_ADC_I_WIDTH-ADC_WIDTH){last_data_imag[(i+1)*ADC_WIDTH-1]}},last_data_imag[i*ADC_WIDTH +: ADC_WIDTH]};
end
endgenerate
// complex multiplication, spatial filtering
wire [AXIS_FILTER_WIDTH-1:0] cmpy_real_array [0:CHANNEL_NUM-1];
wire [AXIS_FILTER_WIDTH-1:0] cmpy_imag_array [0:CHANNEL_NUM-1];
wire [FILTER_MULT_VALID_WIDTH-1:0] weight_adc_real_array [0:CHANNEL_NUM-1];
wire [FILTER_MULT_VALID_WIDTH-1:0] weight_adc_imag_array [0:CHANNEL_NUM-1];
wire weight_adc_valid;
wire [CHANNEL_NUM*FILTER_MULT_VALID_WIDTH-1:0] weight_adc_real;
wire [CHANNEL_NUM*FILTER_MULT_VALID_WIDTH-1:0] weight_adc_imag;
generate
for(i = 0; i < CHANNEL_NUM; i = i + 1) begin: spatial_filter_cmpy
wire [2*AXIS_WEIGHT_WIDTH-1:0] cmpy_a;
wire [2*AXIS_ADC_I_WIDTH-1:0] cmpy_b;
wire [2*AXIS_FILTER_WIDTH-1:0] cmpy_p;
wire cmpy_p_vld;
assign cmpy_a = {-din_weight_imag_array[i],din_weight_real_array[i]};
assign cmpy_b = {din_adc_imag_array[i],din_adc_real_array[i]};
assign {cmpy_imag_array[i],cmpy_real_array[i]} = cmpy_p;
assign weight_adc_real_array[i] = cmpy_real_array[i][0 +: FILTER_MULT_VALID_WIDTH];
assign weight_adc_imag_array[i] = cmpy_imag_array[i][0 +: FILTER_MULT_VALID_WIDTH];
assign weight_adc_real[i*FILTER_MULT_VALID_WIDTH +: FILTER_MULT_VALID_WIDTH] = weight_adc_real_array[i];
assign weight_adc_imag[i*FILTER_MULT_VALID_WIDTH +: FILTER_MULT_VALID_WIDTH] = weight_adc_imag_array[i];
cmpy_16x12 u_cmpy_16x12
(
.aclk (clk ), // input wire aclk
.s_axis_a_tvalid (last_hop_valid ), // input wire s_axis_a_tvalid
.s_axis_a_tdata (cmpy_a ), // input wire [31 : 0] s_axis_a_tdata
.s_axis_b_tvalid (last_hop_valid ), // input wire s_axis_b_tvalid
.s_axis_b_tdata (cmpy_b ), // input wire [31 : 0] s_axis_b_tdata
.m_axis_dout_tvalid (cmpy_p_vld ), // output wire m_axis_dout_tvalid
.m_axis_dout_tdata (cmpy_p ) // output wire [63 : 0] m_axis_dout_tdata
);
end
endgenerate
assign weight_adc_valid = spatial_filter_cmpy[0].cmpy_p_vld;
// multi-channel sum
wire weight_adc_sum_valid;
wire [FILTER_SUM_WIDTH-1 : 0] weight_adc_sum_real;
wire [FILTER_SUM_WIDTH-1 : 0] weight_adc_sum_imag;
adder_tree_ppl #(
.DATA_I_WIDTH (FILTER_MULT_VALID_WIDTH),
.DATA_NUM (CHANNEL_NUM )
) u_multi_ch_add_ppl_i (
// clock & reset
.clk (clk ),
.rst (rst ),
// input data
.din_valid (weight_adc_valid ),
.din_data (weight_adc_real ),
// output data
.dout_valid (weight_adc_sum_valid ),
.dout_data (weight_adc_sum_real )
);
adder_tree_ppl #(
.DATA_I_WIDTH (FILTER_MULT_VALID_WIDTH),
.DATA_NUM (CHANNEL_NUM )
) u_multi_ch_add_ppl_q (
// clock & reset
.clk (clk ),
.rst (rst ),
// input data
.din_valid (weight_adc_valid ),
.din_data (weight_adc_imag ),
// output data
.dout_valid ( ),
.dout_data (weight_adc_sum_imag )
);
// output filtered signal
assign dout_valid = weight_adc_sum_valid;
if (FILTER_O_WIDTH <= FILTER_SUM_WIDTH) begin
assign dout_real = weight_adc_sum_real[FILTER_SUM_WIDTH-1 -: FILTER_O_WIDTH];
assign dout_imag = weight_adc_sum_imag[FILTER_SUM_WIDTH-1 -: FILTER_O_WIDTH];
end
else begin
assign dout_real = {{(FILTER_O_WIDTH-FILTER_SUM_WIDTH){weight_adc_sum_real[FILTER_SUM_WIDTH-1]}},weight_adc_sum_real};
assign dout_imag = {{(FILTER_O_WIDTH-FILTER_SUM_WIDTH){weight_adc_sum_imag[FILTER_SUM_WIDTH-1]}},weight_adc_sum_imag};
end
endmodule
// This module has been tested during the simulation of [rx_pre_process]
@@ -0,0 +1,378 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/11/10 11:48:23
// Design Name:
// Module Name: weight_vec_formatting
// Project Name:
// Target Devices:
// Tool Versions:
// Description: Format the input 1-bit stream to weight vector.
// Parameter:
// COL_NUM: Column number of output vector.
// WEIGHT_WIDTH: Bit width of input weight vector element (retrieve from
// stream data).
// DATA_O_WIDTH: Bit width of output vector element, and bit width of
// FRAME_HEAD: Frame head indicate weight vector frame.
// FIFO_CDC_DEPTH: Depth of [clk_96m] to [sys_clk] cdc fifo.
// Data format:
// din_data: Suppose the output vector x = [x11 x21 x31 x41]^T, then
// din_data = {FRAME_HEAD[msb], ..., FRAME_HEAD[lsb], FRAME_LEN[msb],
// ..., FRAME_LEN[lsb], Re{x11}[msb], ..., Re{x11}[lsb], Im{x11}[msb], ...,
// Im{x11}[lsb], ..., Re{x41}[msb], ......, Im{x41}[lsb]}
// dout_valid: Indicate [dout_data] is valid.
// dout_real/imag:
// dout_real = {Re{x41}, Re{x31}, Re{x21}, Re{x11}}
// dout_imag = {Im{x41}, Im{x31}, Im{x21}, Im{x11}}
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module weight_vec_formatting
#(
parameter COL_NUM = 4,
parameter WEIGHT_WIDTH = 32,
parameter DATA_O_WIDTH = 16,
parameter FRAME_HEAD = 32'h7E7E7E7E,
parameter FIFO_CDC_DEPTH = 32
)
(
// clock & reset
input sys_clk,
input sys_rst,
input clk_96m,
input ant_rst,
// input data
input din_data,
// output data
output dout_valid,
output [COL_NUM*DATA_O_WIDTH-1 : 0] dout_real,
output [COL_NUM*DATA_O_WIDTH-1 : 0] dout_imag
);
localparam CMPLX_DIM = 2;
localparam FRAME_LEN = COL_NUM*CMPLX_DIM;
localparam BYTE_LEN = 4 * (COL_NUM*CMPLX_DIM + 2);
// available state
localparam STATE_NUM_DIN = 3;
localparam STATE_IDLE_DIN = 0;
localparam STATE_LEN_DIN = 1;
localparam STATE_DATA_DIN = 2;
localparam STATE_NUM_DOUT = 2;
localparam STATE_IDLE_DOUT = 0;
localparam STATE_READ_DOUT = 1;
genvar i;
integer m;
// input data shift register
reg [WEIGHT_WIDTH-1 : 0] din_shift = 'b0;
always @(posedge clk_96m) begin
if (ant_rst) begin
din_shift <= 'b0;
end
else begin
din_shift <= {din_shift[WEIGHT_WIDTH-2 : 0],din_data};
end
end
// input data center state machine & counter
reg [$clog2(STATE_NUM_DIN)-1 : 0] state_din = STATE_IDLE_DIN;
reg [$clog2(WEIGHT_WIDTH)-1 : 0] bit_cnt = 'b0; // bit counter within one frame
reg [$clog2(FRAME_LEN)-1 : 0] frame_cnt = 'b0; // frame counter
always @(posedge clk_96m) begin
if (ant_rst) begin
state_din <= STATE_IDLE_DIN;
end
else begin
case (state_din)
STATE_IDLE_DIN: state_din <= (din_shift == FRAME_HEAD) ? STATE_LEN_DIN : STATE_IDLE_DIN;
STATE_LEN_DIN : begin
if (bit_cnt == WEIGHT_WIDTH-1) begin
state_din <= (din_shift == BYTE_LEN) ? STATE_DATA_DIN : STATE_IDLE_DIN;
end
else begin
state_din <= STATE_LEN_DIN;
end
end
STATE_DATA_DIN: state_din <= (frame_cnt == FRAME_LEN-1 && bit_cnt == WEIGHT_WIDTH-1) ? STATE_IDLE_DIN : STATE_DATA_DIN;
default: state_din <= STATE_IDLE_DIN;
endcase
end
end
always @(posedge clk_96m) begin
if (ant_rst) begin
bit_cnt <= 'b0;
end
else if (state_din == STATE_IDLE_DIN) begin
bit_cnt <= 'b0;
end
else begin
bit_cnt <= (bit_cnt == WEIGHT_WIDTH-1) ? 'b0 : bit_cnt + 1'b1;
end
end
always @(posedge clk_96m) begin
if (ant_rst) begin
frame_cnt <= 'b0;
end
else if (state_din == STATE_IDLE_DIN) begin
frame_cnt <= 'b0;
end
else if (state_din == STATE_DATA_DIN && bit_cnt == WEIGHT_WIDTH-1) begin
frame_cnt <= frame_cnt + 1'b1;
end
else begin
frame_cnt <= frame_cnt;
end
end
// output data center state machine & counter
reg [$clog2(STATE_NUM_DOUT)-1 : 0] state_dout = STATE_IDLE_DOUT;
wire [$clog2(FIFO_CDC_DEPTH)-1 : 0] fifo_rd_cnt;
always @(posedge sys_clk) begin
if (sys_rst) begin
state_dout <= STATE_IDLE_DOUT;
end
else begin
case (state_dout)
STATE_IDLE_DOUT: state_dout <= (fifo_rd_cnt == FRAME_LEN) ? STATE_READ_DOUT : STATE_IDLE_DOUT;
STATE_READ_DOUT: state_dout <= (fifo_rd_cnt == 0) ? STATE_IDLE_DOUT : STATE_READ_DOUT;
default: state_dout <= STATE_IDLE_DOUT;
endcase
end
end
// clock domain crossing fifo
reg [DATA_O_WIDTH-1 : 0] fifo_din = 'b0;
reg fifo_wr_en = 'b0;
wire [DATA_O_WIDTH-1 : 0] fifo_dout;
reg fifo_rd_en = 'b0;
always @(posedge clk_96m) begin
if (ant_rst) begin
fifo_din <= 'b0;
fifo_wr_en <= 'b0;
end
else if (state_din == STATE_DATA_DIN && bit_cnt == DATA_O_WIDTH-1) begin
fifo_din <= din_shift[DATA_O_WIDTH-1 -: DATA_O_WIDTH];
fifo_wr_en <= 1'b1;
end
else begin
fifo_din <= fifo_din;
fifo_wr_en <= 'b0;
end
end
always @(posedge sys_clk) begin
if (sys_rst) begin
fifo_rd_en <= 'b0;
end
else if (state_dout == STATE_READ_DOUT) begin
fifo_rd_en <= 1'b1;
end
else begin
fifo_rd_en <= 'b0;
end
end
fifo_weight_cdc u_fifo_weight_cdc
(
.wr_clk (clk_96m ), // input wire wr_clk
.wr_rst (ant_rst ), // input wire wr_rst
.rd_clk (sys_clk ), // input wire rd_clk
.rd_rst (sys_rst ), // input wire rd_rst
.din (fifo_din ), // input wire [15 : 0] din
.wr_en (fifo_wr_en ), // input wire wr_en
.rd_en (fifo_rd_en ), // input wire rd_en
.dout (fifo_dout ), // output wire [15 : 0] dout
.full ( ), // output wire full
.empty ( ), // output wire empty
.rd_data_count (fifo_rd_cnt) // output wire [3 : 0] rd_data_count
);
// format output data array
reg [DATA_O_WIDTH-1 : 0] dout_real_array [0 : COL_NUM-1];
reg [DATA_O_WIDTH-1 : 0] dout_imag_array [0 : COL_NUM-1];
reg dout_valid_buf = 'b0;
generate
for(i = 0; i < COL_NUM; i = i + 1) begin: array_convert
assign dout_real[i*DATA_O_WIDTH +: DATA_O_WIDTH] = dout_real_array[i];
assign dout_imag[i*DATA_O_WIDTH +: DATA_O_WIDTH] = dout_imag_array[i];
end
endgenerate
assign dout_valid = dout_valid_buf;
always @(posedge sys_clk) begin
if (sys_rst) begin
for (m = 0; m < COL_NUM; m = m + 1) begin: dout_data_array_reset
dout_real_array[m] <= 'b0;
dout_imag_array[m] <= 'b0;
end
end
else if (fifo_rd_en) begin
if (fifo_rd_cnt[0]) begin
dout_imag_array[COL_NUM-1-fifo_rd_cnt[$clog2(FIFO_CDC_DEPTH)-1 : 1]] <= fifo_dout;
end
else begin
dout_real_array[COL_NUM-fifo_rd_cnt[$clog2(FIFO_CDC_DEPTH)-1 : 1]] <= fifo_dout;
end
end
end
always @(posedge sys_clk) begin
if (sys_rst) begin
dout_valid_buf <= 'b0;
end
else if (state_dout == STATE_READ_DOUT && fifo_rd_cnt == 0) begin
dout_valid_buf <= 1'b1;
end
else begin
dout_valid_buf <= 'b0;
end
end
endmodule
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2022/10/30 20:46:26
// Design Name:
// Module Name: tb_wvec_format
// Project Name:
// Target Devices:
// Tool Versions:
// Description: Testbench for [weight_vec_formatting]
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
// -------------------------------
// MATLAB Code for data generation
// -------------------------------
// COLUMN_NUM = 4;
// DATA_O_WIDTH = 32;
// rng(0);
// data = rand(4,2)*2-1;
// d_32b = round(data.*(2^(DATA_O_WIDTH-1)-1));
// d_32b_cmplx = d_32b(:,1) + 1i*d_32b(:,2);
// module tb_wvec_format;
// localparam ROW_NUM = 1;
// localparam COL_NUM = 4;
// localparam WEIGHT_WIDTH = 32;
// localparam DATA_O_WIDTH = 16;
// localparam FRAME_HEAD = 32'b10110011100011110000111000110010;
// localparam FRAME_BITS = (2+COL_NUM*2)*WEIGHT_WIDTH + 1024;
// reg sys_clk = 1'b1;
// reg sys_rst = 1'b1;
// reg clk_96m = 1'b1;
// reg ant_rst = 1'b1;
// wire din_data;
// reg [FRAME_BITS-1 : 0] din_buf =
// {
// FRAME_HEAD, 32'd40,
// 32'd1351727940, 32'd568478634,
// 32'd1742863098, -32'd1728550798,
// -32'd1602079424, -32'd951342906,
// 32'd1775435782, 32'd201354592,
// 1024'd0
// };
// wire dout_valid;
// wire [COL_NUM*DATA_O_WIDTH-1:0] dout_real, dout_imag;
// weight_vec_formatting #(
// .COL_NUM (COL_NUM),
// .DATA_O_WIDTH (DATA_O_WIDTH),
// .WEIGHT_WIDTH (WEIGHT_WIDTH),
// .FRAME_HEAD (FRAME_HEAD )
// ) u_weight_vec_formatting
// (
// // clock & reset
// .sys_clk (sys_clk ), // input sys_clk
// .sys_rst (sys_rst ), // input sys_rst
// .clk_96m (clk_96m ), // input clk_96m
// .ant_rst (ant_rst ), // input ant_rst
// // input data
// .din_data (din_data ),
// // output data
// .dout_valid (dout_valid ),
// .dout_real (dout_real ),
// .dout_imag (dout_imag )
// );
// always begin
// #20 sys_clk = ~sys_clk;
// end
// always begin
// #7;
// clk_96m = ~clk_96m;
// #3;
// end
// initial begin
// #102
// sys_rst = 1'b0;
// ant_rst = 1'b0;
// end
// reg [$clog2(FRAME_BITS)-1 : 0] din_cnt;
// always @(posedge clk_96m) begin
// if (sys_rst) begin
// din_cnt <= 'b0;
// end
// else begin
// din_cnt <= (din_cnt == FRAME_BITS-1) ? 'b0 : din_cnt + 1'b1;
// end
// end
// assign din_data = din_buf[FRAME_BITS-1-din_cnt];
// endmodule
+428
View File
@@ -0,0 +1,428 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// _ _ ____
// | | ___ ___| |__ / ___| __ _ ___
// _ | |/ _ \/ __| '_ \ | | _ / _` |/ _ \
// | |_| | (_) \__ \ | | | | |_| | (_| | (_) |
// \___/ \___/|___/_| |_| \____|\__,_|\___/
//
// Create Date: 2021/12/14 15:54:11
// Design Name:
// Module Name: system_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module system_top
(
/***************************************************************************
* Contents
* 01. Clocks
* 02. AD9516 Interface
* 03. AD9361-1 Interface
* 04. AD9361-2 Interface
* 05. Phased-Array Control
* 06. RF Synthesizer Control
* 07. LVDS for Time Synchronization
* 08. Debug IO
**************************************************************************/
// *************************************************************************
// ******************************** Clocks *********************************
// *************************************************************************
// power-up configure clock
input clk_25m ,
// 250mhz backup clock
input clk_250m_p , // generated by ad9516, 250mhz
input clk_250m_n ,
// ad9361 buffered clock
input ad9361_1_buffer_clk , // derived from ad9361 input clock
input ad9361_2_buffer_clk , // derived from ad9361 input clock
// *************************************************************************
// *************************** AD9516 Interface ****************************
// *************************************************************************
// spi interface
output ad9516_spi_clk ,
output ad9516_spi_csn ,
inout ad9516_spi_mosi ,
input ad9516_spi_miso ,
// control signals
input ad9516_refmon , // ad9516 reference clock monitor
input ad9516_ld , // ad9516 lock detect
input ad9516_status , // ad9516 multiple selectable status output
output ad9516_pd_b , // ad9516 active-low power down control
output ad9516_reset_b , // ad9516 active-low reset control
output ad9516_sync_b , // ad9516 active-low manual synchronization control
// *************************************************************************
// ************************** AD9361-1 Interface ***************************
// *************************************************************************
// rx data (rx channels are tied to ground physically)
input ad9361_1_rx_data_clk, // ad9361 rx data clock, 83.3333mhz
input ad9361_1_rx_frame ,
input [11:0] ad9361_1_rx_data ,
// tx data
output ad9361_1_tx_fb_clk ,
output ad9361_1_tx_frame ,
output [11:0] ad9361_1_tx_data ,
// spi interface
output ad9361_1_spi_clk ,
output ad9361_1_spi_csn ,
inout ad9361_1_spi_mosi ,
input ad9361_1_spi_miso ,
// control signals
output ad9361_1_reset_b , // ad9361 active-low reset control
output ad9361_1_en_agc , // ad9361 manual agc control
output ad9361_1_enable , // ad9361 enable state machine pin control (spi control is also allowed)
output ad9361_1_txnrx , // ad9361 enable state machine pin control (spi control is also allowed)
output [ 3:0] ad9361_1_ctrl_in ,
input [ 7:0] ad9361_1_ctrl_out ,
output ad9361_sync ,
// *************************************************************************
// ************************** AD9361-2 Interface ***************************
// *************************************************************************
// rx data (rx channels are tied to ground physically)
input ad9361_2_rx_data_clk, // ad9361 rx data clock, 83.3333mhz
input ad9361_2_rx_frame ,
input [11:0] ad9361_2_rx_data ,
// tx data
output ad9361_2_tx_fb_clk ,
output ad9361_2_tx_frame ,
output [11:0] ad9361_2_tx_data ,
// spi interface
output ad9361_2_spi_clk ,
output ad9361_2_spi_csn ,
inout ad9361_2_spi_mosi ,
input ad9361_2_spi_miso ,
// control signals
output ad9361_2_reset_b , // ad9361 active-low reset control
output ad9361_2_en_agc , // ad9361 manual agc control
output ad9361_2_enable , // ad9361 enable state machine pin control (spi control is also allowed)
output ad9361_2_txnrx , // ad9361 enable state machine pin control (spi control is also allowed)
output [ 3:0] ad9361_2_ctrl_in ,
input [ 7:0] ad9361_2_ctrl_out ,
// *************************************************************************
// ************************* Phased-Array Control **************************
// *************************************************************************
output ant_cin ,
output ant_din0 ,
output ant_din1 ,
input ant_cout ,
input ant_dout0 ,
input ant_dout1 ,
output ant_tr ,
output ant_dary ,
// *************************************************************************
// ************************ RF Synthesizer Control *************************
// *************************************************************************
output rf_standby ,
output rf_sw_pll ,
output rf_t ,
output rf_r ,
output rf_sw_bpf ,
output rf_sclk1 ,
output rf_sdio1 ,
output rf_cs1 ,
input rf_ld1 ,
output rf_sclk2 ,
output rf_sdio2 ,
output rf_cs2 ,
input rf_ld2 ,
output rf_sclk3 ,
output rf_sdio3 ,
output rf_cs3 ,
input rf_ld3 ,
output rf_tmgc_16 ,
output rf_tmgc_8 ,
output rf_tmgc_4 ,
output rf_tmgc_2 ,
output rf_tmgc_1 ,
output rf_rmgc_16 ,
output rf_rmgc_8 ,
output rf_rmgc_4 ,
output rf_rmgc_2 ,
output rf_rmgc_1 ,
output rf_enable ,
output rf_sc ,
output rf_sd ,
output rf_endsyn ,
input rf_sdout ,
inout rf_dq_wd ,
output rf_sw_rx ,
// *************************************************************************
// ********************* LVDS for Time Synchronization *********************
// *************************************************************************
// 1st group
input lvds_in_1 ,
output lvds_out_1 ,
// 2nd group (these pins can be disconnected physically)
input lvds_in_2 ,
output lvds_out_2 ,
// *************************************************************************
// ******************************* Debug IO ********************************
// *************************************************************************
// 3.3v ports
output uart1_txd ,
input uart1_rxd ,
output uart2_txd ,
input uart2_rxd ,
output uart3_txd ,
input uart3_rxd ,
inout debug_io_1 ,
inout debug_io_2 ,
inout debug_io_3 ,
inout debug_io_4 ,
inout debug_io_5 ,
inout debug_io_6 ,
inout debug_io_7 ,
inout debug_io_8 ,
// 1.8v ports
inout debug_io_00_p ,
inout debug_io_01_p ,
inout debug_io_02_p ,
inout debug_io_03_p ,
inout debug_io_04_p ,
inout debug_io_05_p ,
inout debug_io_06_p ,
inout debug_io_07_p ,
inout debug_io_08_p
);
/*******************************************************************************
* Contents
* 01. Input/Output Buffer
* 02. System Clock Generation
* 03. Block Design Interface
* 04. Phased-Array Control
* 05. RF Synthesizer Control
* 06. LVDS for Time Synchronization
* 07. Tx Signals
* 08. Rx Signals
* 09. ILAs and VIOs
******************************************************************************/
////////////////////////////////////////////////////////////////////////////////
/////////////////////////// System Clock Generation ////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// global reset
wire sys_rst ; // global reset signal, active high
wire ant_rst ; // phased-array & rf control reset signal, active high
// pl signal processing clock
wire sys_clk ; // 41.6667mhz
wire sys_clk_2x ; // 83.3333mhz
wire sys_clk_3x ; // 125mhz
wire sys_clk_4x ; // 166.6667mhz
wire sys_clk_ld ; // system main clock locked indicator
// phased-array & rf control clocks
wire clk_96m ;
wire clk_48m ;
wire clk_32m ;
wire clk_19p2m ;
clk_dist u_clk_dist
(
// input clocks
.clk_25m (clk_25m ), // generated by osc, 25mhz
// output clocks & reset
// global reset
.sys_rst (sys_rst ), // global reset signal, active high
.ant_rst (ant_rst ), // phased-array & rf control reset signal, active high
// pl signal processing clock
.sys_clk (sys_clk ), // 41.6667mhz
.sys_clk_2x (sys_clk_2x ), // 83.3333mhz
.sys_clk_3x (sys_clk_3x ), // 125mhz
.sys_clk_4x (sys_clk_4x ), // 166.6667mhz
// phased-array & rf control clocks
.clk_96m (clk_96m ),
.clk_48m (clk_48m ),
.clk_32m (clk_32m ),
.clk_19p2m (clk_19p2m )
);
////////////////////////////////////////////////////////////////////////////////
//////////////////////////// Block Design Interface ////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///////////////////////////// Phased-Array Control /////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//////////////////////////// RF Synthesizer Control ////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//////////////////////// LVDS for Time Synchronization /////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////// Tx Signals //////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////// Rx Signals //////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
wire [11:0] rx_ch1_i, rx_ch1_q;
wire [11:0] rx_ch2_i, rx_ch2_q;
wire [11:0] rx_ch3_i, rx_ch3_q;
wire [11:0] rx_ch4_i, rx_ch4_q;
wire rx_data_valid;
wire [29:0] rx_data_i, rx_data_q;
wire hop_start_flag ;
wire accor_stream_valid ;
wire accor_stream_data ;
reg ant_dout1_d1 = 'b0;
reg ant_dout1_d2 = 'b0;
reg weight_stream_data = 'b0 ;
assign ant_cin = clk_96m;
assign ant_din1 = accor_stream_data;
always @(posedge clk_96m) begin
if (ant_rst) begin
ant_dout1_d1 <= 'b0;
ant_dout1_d2 <= 'b0;
weight_stream_data <= 'b0;
end
else begin
ant_dout1_d1 <= ant_dout1;
ant_dout1_d2 <= ant_dout1_d1;
weight_stream_data <= ant_dout1_d2;
end
end
rx_pre_process #(
.BYPASS_CAL (1 ),
.OUTPUT_DATA_WIDTH (30 )
) u_rx_pre_process
(
// clock & reset
.sys_clk (sys_clk ), // sync to adc data
.sys_clk_4x (sys_clk_4x ), // sync to physical layer
.sys_rst (sys_rst ), // sync to [sys_clk]
.clk_96m (clk_96m ), // sync to c2c data
.ant_rst (ant_rst ), // sync to [clk_96m]
// input data interface
.rx_ch1_i (rx_ch1_i ),
.rx_ch1_q (rx_ch1_q ),
.rx_ch2_i (rx_ch2_i ),
.rx_ch2_q (rx_ch2_q ),
.rx_ch3_i (rx_ch3_i ),
.rx_ch3_q (rx_ch3_q ),
.rx_ch4_i (rx_ch4_i ),
.rx_ch4_q (rx_ch4_q ),
// ad9361 calibration interface
.ad9361_1_cal_start (ad9361_1_cal_start ),
.ad9361_1_cal_done (ad9361_1_cal_done ),
.ad9361_2_cal_start (ad9361_2_cal_start ),
.ad9361_2_cal_done (ad9361_2_cal_done ),
.ad9361_cal_result (ad9361_cal_result ),
.ad9361_cal_valid (ad9361_cal_valid ),
.ad9361_recal (ad9361_recal ),
// nulling algotithm interface
.hop_start_flag (hop_start_flag ), // sync to [sys_clk_4x]
.accor_stream_valid (accor_stream_valid ), // sync to [clk_96m]
.accor_stream_data (accor_stream_data ), // sync to [clk_96m]
.weight_stream_data (weight_stream_data ), // sync to [clk_96m]
.rx_data_valid (rx_data_valid ), // sync to [sys_clk]
.rx_data_i (rx_data_i ), // sync to [sys_clk]
.rx_data_q (rx_data_q ) // sync to [sys_clk]
);
// temporary test cases
rx_pre_test #(
.BYPASS_CAL (1)
) u_rx_pre_test
(
// clock & reset
.sys_clk (sys_clk ),
.sys_clk_4x (sys_clk_4x ),
.sys_rst (sys_rst ),
// calc result
.ad9361_cal_result (ad9361_cal_result ),
.ad9361_cal_valid (ad9361_cal_valid ),
// output test data
.rx_ch1_i (rx_ch1_i ),
.rx_ch1_q (rx_ch1_q ),
.rx_ch2_i (rx_ch2_i ),
.rx_ch2_q (rx_ch2_q ),
.rx_ch3_i (rx_ch3_i ),
.rx_ch3_q (rx_ch3_q ),
.rx_ch4_i (rx_ch4_i ),
.rx_ch4_q (rx_ch4_q ),
.hop_start_flag (hop_start_flag )
);
// <--------------------------------------------------------------------------->
// <----------------------- insert receiver logic below ----------------------->
// <--------------------------------------------------------------------------->
////////////////////////////////////////////////////////////////////////////////
//////////////////////////////// ILAs and VIOs /////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
ila_8x12_2x30_8192 u_ila_rx
(
.clk (sys_clk ), // input wire clk
.probe0 (u_rx_pre_process.rx_cal_ch1_i ), // input wire [11:0] probe0
.probe1 (u_rx_pre_process.rx_cal_ch1_q ), // input wire [11:0] probe1
.probe2 (u_rx_pre_process.rx_cal_ch2_i ), // input wire [11:0] probe2
.probe3 (u_rx_pre_process.rx_cal_ch2_q ), // input wire [11:0] probe3
.probe4 (u_rx_pre_process.rx_cal_ch3_i ), // input wire [11:0] probe4
.probe5 (u_rx_pre_process.rx_cal_ch3_q ), // input wire [11:0] probe5
.probe6 (u_rx_pre_process.rx_cal_ch4_i ), // input wire [11:0] probe6
.probe7 (u_rx_pre_process.rx_cal_ch4_q ), // input wire [11:0] probe7
.probe8 (rx_data_i ), // input wire [11:0] probe8
.probe9 (rx_data_q ) // input wire [11:0] probe9
);
ila_rx_pre u_ila_rx_pre
(
.clk (sys_clk_4x ), // input wire clk
.probe0 (hop_start_flag ), // input wire [0:0] probe0
.probe1 (accor_stream_valid ), // input wire [0:0] probe1
.probe2 (accor_stream_data ), // input wire [0:0] probe2
.probe3 (weight_stream_data ) // input wire [0:0] probe3
);
ila_ant_interface u_ila_ant_interface
(
.clk (clk_96m ), // input wire clk
.probe0 (ant_din1 ), // input wire [0:0] probe0
.probe1 (ant_dout1 ), // input wire [0:0] probe1
.probe2 (ant_dout1_d1 ), // input wire [0:0] probe2
.probe3 (ant_dout1_d2 ), // input wire [0:0] probe3
.probe4 (weight_stream_data ) // input wire [0:0] probe4
);
endmodule