File: backend_iface.v

package info (click to toggle)
uhd 4.9.0.0%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 184,180 kB
  • sloc: cpp: 262,887; python: 112,011; ansic: 102,670; vhdl: 57,031; tcl: 19,924; xml: 8,581; makefile: 3,028; sh: 2,812; pascal: 230; javascript: 120; csh: 94; asm: 20; perl: 11
file content (197 lines) | stat: -rw-r--r-- 8,175 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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
//
// Copyright 2019 Ettus Research, A National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: backend_iface
// Description:
//   A noc_shell interface to the backend infrastructure
//
// Parameters:
// - CTRL_CLK_IDX: The index of the clock that is used for the control interface.
//                 UHD will query this to generate a clock interface object for
//                 the register interface. Set to 0 to let UHD figure this out
//                 itself.
// - TB_CLK_IDX: The index of the clock that is used as the timebase for this
//               block. UHD will query this to generate a clock interface object
//               for the register interface. This allows converting real-valued
//               timestamps into tick counts.

module backend_iface #(
  parameter [31:0] NOC_ID              = 32'h0,
  parameter  [5:0] NUM_DATA_I          = 0,
  parameter  [5:0] NUM_DATA_O          = 0,
  parameter  [5:0] CTRL_FIFOSIZE       = 0,
  parameter  [7:0] CTRL_MAX_ASYNC_MSGS = 0,
  parameter  [5:0] CTRL_CLK_IDX        = 6'h3F,
  parameter  [5:0] TB_CLK_IDX          = 6'h3F,
  parameter  [5:0] MTU                 = 0
)(
  // Input clock
  input  wire         rfnoc_chdr_clk,
  input  wire         rfnoc_ctrl_clk,
  // Output reset
  output wire         rfnoc_chdr_rst,
  output wire         rfnoc_ctrl_rst,
  // Flush interface (sync. to rfnoc_chdr_clk)
  output wire         data_i_flush_en,
  output wire [31:0]  data_i_flush_timeout,
  input  wire [63:0]  data_i_flush_active,
  input  wire [63:0]  data_i_flush_done,
  output wire         data_o_flush_en,
  output wire [31:0]  data_o_flush_timeout,
  input  wire [63:0]  data_o_flush_active,
  input  wire [63:0]  data_o_flush_done,
  // Backend interface (sync. to rfnoc_ctrl_clk)
  input  wire [511:0] rfnoc_core_config,
  output wire [511:0] rfnoc_core_status
);
  localparam RESET_LENGTH = 32;

  `include "rfnoc_backend_iface.vh"

  // -----------------------------------
  // CONFIG: Infrastructure => Block
  // -----------------------------------
  wire [BEC_TOTAL_WIDTH-1:0] rfnoc_core_config_trim = rfnoc_core_config[BEC_TOTAL_WIDTH-1:0];
  // Synchronize flush signals to the CHDR clock domain. Note this is only
  // necessary if we have data ports.
  generate
    if (NUM_DATA_I > 0 || NUM_DATA_O > 0) begin


      reg  [31:0] flush_timeout_ctclk = 32'd0;
      reg         flush_en_ctclk      = 1'b0;

      // Register logic before synchronizer
      always @(posedge rfnoc_ctrl_clk) begin
        flush_timeout_ctclk <= rfnoc_core_config_trim[BEC_FLUSH_TIMEOUT_OFFSET +: BEC_FLUSH_TIMEOUT_WIDTH];
        flush_en_ctclk      <= rfnoc_core_config_trim[BEC_FLUSH_EN_OFFSET      +: BEC_FLUSH_EN_WIDTH     ];
      end

      // Synchronizer
      wire [31:0] flush_timeout_chclk;
      wire        flush_en_chclk;

      // Note: We are using a synchronizer to cross the 32-bit timeout bus
      // into a different clock domain. Typically we would use a 2clk FIFO
      // but it's OK to have the bits unsynchronized here because the value
      // is static and is set from SW long before it is actually used.

      synchronizer #(.WIDTH(33), .INITIAL_VAL(33'd0)) sync_ctrl_i (
        .clk(rfnoc_chdr_clk), .rst(1'b0),
        .in({flush_en_ctclk, flush_timeout_ctclk}),
        .out({flush_en_chclk, flush_timeout_chclk})
      );

      assign data_i_flush_timeout = flush_timeout_chclk;
      assign data_o_flush_timeout = flush_timeout_chclk;
      assign data_i_flush_en      = flush_en_chclk;
      assign data_o_flush_en      = flush_en_chclk;

    end else begin
      assign data_i_flush_timeout = 32'h0;
      assign data_o_flush_timeout = 32'h0;
      assign data_i_flush_en      = 1'b0;
      assign data_o_flush_en      = 1'b0;
    end
  endgenerate

  // Synchronize the reset to the CHDR and CTRL clock domains, and extend the
  // reset pulse to make it long enough for most IP to reset correctly.

  reg soft_ctrl_rst_ctclk = 1'b0;
  reg soft_chdr_rst_ctclk = 1'b0;

  wire rfnoc_ctrl_rst_pulse;
  wire rfnoc_chdr_rst_pulse;

  // Register logic before synchronizer
  always @(posedge rfnoc_ctrl_clk) begin
    soft_ctrl_rst_ctclk <= rfnoc_core_config_trim[BEC_SOFT_CTRL_RST_OFFSET +: BEC_SOFT_CTRL_RST_WIDTH];
    soft_chdr_rst_ctclk <= rfnoc_core_config_trim[BEC_SOFT_CHDR_RST_OFFSET +: BEC_SOFT_CHDR_RST_WIDTH];
  end

  pulse_synchronizer #(.MODE("POSEDGE")) soft_ctrl_rst_sync_i (
    .clk_a(rfnoc_ctrl_clk), .rst_a(1'b0), .pulse_a(soft_ctrl_rst_ctclk), .busy_a(),
    .clk_b(rfnoc_ctrl_clk), .pulse_b(rfnoc_ctrl_rst_pulse)
  );

  pulse_synchronizer #(.MODE("POSEDGE")) soft_chdr_rst_sync_i (
    .clk_a(rfnoc_ctrl_clk), .rst_a(1'b0), .pulse_a(soft_chdr_rst_ctclk), .busy_a(),
    .clk_b(rfnoc_chdr_clk), .pulse_b(rfnoc_chdr_rst_pulse)
  );

  pulse_stretch_min #(.LENGTH(RESET_LENGTH)) soft_ctrl_rst_stretch_i (
    .clk(rfnoc_ctrl_clk), .rst(1'b0),
    .pulse_in(rfnoc_ctrl_rst_pulse), .pulse_out(rfnoc_ctrl_rst)
  );

  pulse_stretch_min #(.LENGTH(RESET_LENGTH)) soft_chdr_rst_stretch_i (
    .clk(rfnoc_chdr_clk), .rst(1'b0),
    .pulse_in(rfnoc_chdr_rst_pulse), .pulse_out(rfnoc_chdr_rst)
  );

  // -----------------------------------
  // STATUS: Block => Infrastructure
  // -----------------------------------

  generate
    if (NUM_DATA_I > 0 || NUM_DATA_O > 0) begin

      reg  flush_active_chclk  = 1'b0;
      reg  flush_done_chclk    = 1'b0;

      // Register logic before synchronizer
      wire flush_active_ctclk;
      wire flush_done_ctclk;

      if (NUM_DATA_I > 0 && NUM_DATA_O > 0) begin
        always @(posedge rfnoc_chdr_clk) begin
          flush_active_chclk <= (|data_i_flush_active[NUM_DATA_I-1:0]) | (|data_o_flush_active[NUM_DATA_O-1:0]);
          flush_done_chclk   <= (&data_i_flush_done  [NUM_DATA_I-1:0]) & (&data_o_flush_done  [NUM_DATA_O-1:0]);
        end
      end else if (NUM_DATA_I > 0 && NUM_DATA_O == 0) begin
        always @(posedge rfnoc_chdr_clk) begin
          flush_active_chclk <= (|data_i_flush_active[NUM_DATA_I-1:0]);
          flush_done_chclk   <= (&data_i_flush_done  [NUM_DATA_I-1:0]);
        end
      end else if (NUM_DATA_I == 0 && NUM_DATA_O > 0) begin
        always @(posedge rfnoc_chdr_clk) begin
          flush_active_chclk <= (|data_o_flush_active[NUM_DATA_O-1:0]);
          flush_done_chclk   <= (&data_o_flush_done  [NUM_DATA_O-1:0]);
        end
      end

      // Synchronizer
      synchronizer #(.WIDTH(2), .INITIAL_VAL(2'd0)) sync_status_i (
        .clk(rfnoc_ctrl_clk), .rst(1'b0),
        .in({flush_active_chclk, flush_done_chclk}),
        .out({flush_active_ctclk, flush_done_ctclk})
      );

  assign rfnoc_core_status[BES_FLUSH_ACTIVE_OFFSET+:BES_FLUSH_ACTIVE_WIDTH] = flush_active_ctclk;
  assign rfnoc_core_status[BES_FLUSH_DONE_OFFSET  +:BES_FLUSH_DONE_WIDTH  ] = flush_done_ctclk;

end else begin
  assign rfnoc_core_status[BES_FLUSH_ACTIVE_OFFSET+:BES_FLUSH_ACTIVE_WIDTH] = {BES_FLUSH_ACTIVE_WIDTH{1'b0}};
  assign rfnoc_core_status[BES_FLUSH_DONE_OFFSET  +:BES_FLUSH_DONE_WIDTH  ] = {BES_FLUSH_DONE_WIDTH{1'b1}};

    end

  endgenerate

  assign rfnoc_core_status[BES_PROTO_VER_OFFSET          +:BES_PROTO_VER_WIDTH          ] = BACKEND_PROTO_VER;
  assign rfnoc_core_status[BES_NUM_DATA_I_OFFSET         +:BES_NUM_DATA_I_WIDTH         ] = NUM_DATA_I;
  assign rfnoc_core_status[BES_NUM_DATA_O_OFFSET         +:BES_NUM_DATA_O_WIDTH         ] = NUM_DATA_O;
  assign rfnoc_core_status[BES_CTRL_FIFOSIZE_OFFSET      +:BES_CTRL_FIFOSIZE_WIDTH      ] = CTRL_FIFOSIZE;
  assign rfnoc_core_status[BES_CTRL_MAX_ASYNC_MSGS_OFFSET+:BES_CTRL_MAX_ASYNC_MSGS_WIDTH] = CTRL_MAX_ASYNC_MSGS;
  assign rfnoc_core_status[BES_NOC_ID_OFFSET             +:BES_NOC_ID_WIDTH             ] = NOC_ID;
  assign rfnoc_core_status[BES_DATA_MTU_OFFSET           +:BES_DATA_MTU_WIDTH           ] = MTU;
  assign rfnoc_core_status[BES_CTRL_CLK_IDX_OFFSET       +:BES_CTRL_CLK_IDX_WIDTH       ] = CTRL_CLK_IDX;
  assign rfnoc_core_status[BES_TB_CLK_IDX_OFFSET         +:BES_TB_CLK_IDX_WIDTH         ] = TB_CLK_IDX;
  // Assign the rest to 0
  assign rfnoc_core_status[511:BES_TOTAL_WIDTH] = {(512-BES_TOTAL_WIDTH){1'b0}};

endmodule // backend_iface