File: quarter_rate_downconverter.v

package info (click to toggle)
uhd 3.13.1.0-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 207,120 kB
  • sloc: cpp: 167,245; ansic: 86,841; vhdl: 53,420; python: 40,839; xml: 13,167; tcl: 5,688; makefile: 2,167; sh: 1,719; pascal: 230; csh: 94; asm: 20; perl: 11
file content (137 lines) | stat: -rw-r--r-- 3,692 bytes parent folder | download | duplicates (2)
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