1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
//
// Copyright 2018 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// mixer with 90 degree angles, i.e., multiplying the input signal with 1, i, -1, -i:
// Let S(t) = I(t) + i*Q(t) be the input signal based on inputs i_in and q_in
// Multiplying with (1,i,-1,-i) then becomes:
// S(t) * 1 = I(t) + i*Q(t)
// S(t) * i = -Q(t) + i*I(t)
// S(t) * -1 = -I(t) - i*Q(t)
// S(t) * -i = Q(t) - i*I(t)
// To control the direction of rotation, the dirctn input is used
// When set to 0, the phase is increased with pi/2 every sample, i.e., rotating counter clock wise
// When set to 1, the phase is increased with -pi/2 every sample, i.e., rotating clock wise
// the input is the concatenation of the i and q signal: {i_in, q_in}
module quarter_rate_downconverter #(
parameter WIDTH=24
)(
input clk,
input reset,
input [2*WIDTH-1:0] i_tdata,
input i_tlast,
input i_tvalid,
output i_tready,
output [2*WIDTH-1:0] o_tdata,
output o_tlast,
output o_tvalid,
input o_tready,
input dirctn
);
// temporary signals for i and q after rotation
reg [WIDTH-1:0] tmp_i = {WIDTH{1'b0}};
reg [WIDTH-1:0] tmp_q = {WIDTH{1'b0}};
// State machine types and reg
localparam S0=0, S1=1, S2=2, S3=3;
reg[1:0] cur_state;
// split input into i and q signal
wire[WIDTH-1:0] i_in, q_in;
assign i_in = i_tdata[2*WIDTH-1:WIDTH];
assign q_in = i_tdata[WIDTH-1:0];
// The state machine doing the rotations among states
always @(posedge clk) begin
if(reset) begin
cur_state <= S0;
end else begin
case (cur_state)
S0: begin
if(i_tvalid == 1'b1 && i_tready == 1'b1)
if(dirctn == 1'b0)
cur_state <= S1;
else
cur_state <= S3;
else
cur_state <= S0;
end
S1: begin
if(i_tvalid == 1'b1 && i_tready == 1'b1)
if(dirctn == 1'b0)
cur_state <= S2;
else
cur_state <= S0;
else
cur_state <= S1;
end
S2: begin
if(i_tvalid == 1'b1 && i_tready == 1'b1)
if(dirctn == 1'b0)
cur_state <= S3;
else
cur_state <= S1;
else
cur_state <= S2;
end
S3: begin
if(i_tvalid == 1'b1 && i_tready == 1'b1)
if(dirctn == 1'b0)
cur_state <= S0;
else
cur_state <= S2;
else
cur_state <= S3;
end
endcase
end
end
// Multiplication of input IQ signal with (1,i,-1,-i):
always @(*) begin
case (cur_state)
S0: begin
// S(t) * 1 = I(t) + iQ(t):
tmp_i = i_in;
tmp_q = q_in;
end
S1: begin
// S(t) * i = -Q(t) + iI(t):
tmp_i = -q_in;
tmp_q = i_in;
end
S2: begin
// S(t) * -1 = -I(t) - iQ(t):
tmp_i = -i_in;
tmp_q = -q_in;
end
S3: begin
// S(t) * -i = Q(t) - iI(t):
tmp_i = q_in;
tmp_q = -i_in;
end
default: begin
tmp_i = i_in;
tmp_q = q_in;
end
endcase
end
// Flop for valid and ready signals and shortening of comb. paths.
axi_fifo #(.WIDTH(2*WIDTH + 1), .SIZE(1)) flop (
.clk(clk), .reset(reset), .clear(1'b0),
.i_tdata({i_tlast, tmp_i, tmp_q}), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata({o_tlast, o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
.occupied(), .space());
endmodule // quarter_rate_downconverter
|