1/////////////////////////////////////////////////////////////////////
2//
3// Copyright 2018 Ettus Research, A National Instruments Company
4// Copyright 2019 Ettus Research, A National Instruments Brand
5//
6// SPDX-License-Identifier: LGPL-3.0
7//
8// Module: e31x_core
9// Description:
10//  - Motherboard Registers
11//  - RFNoC Image Core + Blocks
12//  - Radio Front End control
13//
14/////////////////////////////////////////////////////////////////////
15
16`default_nettype none
17module e31x_core #(
18  parameter REG_DWIDTH   = 32,        // Width of the AXI4-Lite data bus (must be 32 or 64)
19  parameter REG_AWIDTH   = 32,        // Width of the address bus
20  parameter BUS_CLK_RATE = 200000000, // bus_clk rate
21  parameter NUM_SFP_PORTS = 0,        // Number of SFP Ports
22  parameter NUM_RADIOS = 1,
23  parameter NUM_CHANNELS_PER_RADIO = 2,
24  parameter NUM_CHANNELS = 2,
25  parameter NUM_DBOARDS = 1,
26  parameter NUM_CHANNELS_PER_DBOARD = 2,
27  parameter FP_GPIO_WIDTH = 8,  // Front panel GPIO width
28  parameter DB_GPIO_WIDTH = 16,  // Daughterboard GPIO width
29  parameter CHDR_WIDTH  = 16'd64 ,
30  parameter RFNOC_PROTOVER  = {8'd1, 8'd0}
31)(
32  // Clocks and resets
33  input wire radio_clk,
34  input wire radio_rst,
35  input wire bus_clk,
36  input wire bus_rst,
37  input wire clk40,
38
39  // Motherboard Registers: AXI lite interface
40  input wire                    s_axi_aclk,
41  input wire                    s_axi_aresetn,
42  input wire [REG_AWIDTH-1:0]   s_axi_awaddr,
43  input wire                    s_axi_awvalid,
44  output wire                   s_axi_awready,
45
46  input wire [REG_DWIDTH-1:0]   s_axi_wdata,
47  input wire [REG_DWIDTH/8-1:0] s_axi_wstrb,
48  input wire                    s_axi_wvalid,
49  output wire                   s_axi_wready,
50
51  output wire [1:0]             s_axi_bresp,
52  output wire                   s_axi_bvalid,
53  input wire                    s_axi_bready,
54
55  input wire [REG_AWIDTH-1:0]   s_axi_araddr,
56  input wire                    s_axi_arvalid,
57  output wire                   s_axi_arready,
58
59  output wire [REG_DWIDTH-1:0]  s_axi_rdata,
60  output wire [1:0]             s_axi_rresp,
61  output wire                   s_axi_rvalid,
62  input wire                    s_axi_rready,
63
64  // PPS and Clock Control
65  input wire            pps_refclk,
66  input wire            refclk_locked,
67  output reg [1:0]      pps_select,
68
69  // PS GPIO source
70  input wire  [FP_GPIO_WIDTH-1:0]  ps_gpio_out,
71  input wire  [FP_GPIO_WIDTH-1:0]  ps_gpio_tri,
72  output wire [FP_GPIO_WIDTH-1:0]  ps_gpio_in,
73
74  // Front Panel GPIO
75  input wire  [FP_GPIO_WIDTH-1:0] fp_gpio_in,
76  output wire [FP_GPIO_WIDTH-1:0] fp_gpio_tri,
77  output wire [FP_GPIO_WIDTH-1:0] fp_gpio_out,
78
79  // Radio GPIO control
80  output wire [DB_GPIO_WIDTH*NUM_CHANNELS-1:0] db_gpio_out_flat,
81  output wire [DB_GPIO_WIDTH*NUM_CHANNELS-1:0] db_gpio_ddr_flat,
82  input wire  [DB_GPIO_WIDTH*NUM_CHANNELS-1:0] db_gpio_in_flat,
83  input wire  [DB_GPIO_WIDTH*NUM_CHANNELS-1:0] db_gpio_fab_flat,
84
85  // TX/RX LEDs
86  output wire [32*NUM_CHANNELS-1:0] leds_flat,
87
88  // Radio ATR
89  output wire [NUM_CHANNELS-1:0] rx_atr,
90  output wire [NUM_CHANNELS-1:0] tx_atr,
91
92  // Radio Data
93  input wire  [NUM_CHANNELS-1:0]    rx_stb,
94  input wire  [NUM_CHANNELS-1:0]    tx_stb,
95  input wire  [32*NUM_CHANNELS-1:0] rx,
96  output wire [32*NUM_CHANNELS-1:0] tx,
97
98  // DMA xport adapter to PS
99  input wire  [63:0] s_dma_tdata,
100  input wire         s_dma_tlast,
101  output wire        s_dma_tready,
102  input wire         s_dma_tvalid,
103
104  output wire [63:0] m_dma_tdata,
105  output wire        m_dma_tlast,
106  input wire         m_dma_tready,
107  output wire        m_dma_tvalid,
108
109  // Misc
110  input wire [31:0] build_datestamp,
111  input wire [31:0] sfp_ports_info,
112  input wire [31:0] dboard_status,
113  input wire [31:0] xadc_readback,
114  output reg [31:0] fp_gpio_ctrl,
115  output reg [31:0] dboard_ctrl,
116  output reg [15:0] device_id
117);
118  `include "../../lib/rfnoc/core/ctrlport.vh"
119
120  /////////////////////////////////////////////////////////////////////////////////
121  //
122  // FPGA Compatibility Number
123  //   Rules for modifying compat number:
124  //   - Major is updated when the FPGA is changed and requires a software
125  //     change as a result.
126  //   - Minor is updated when a new feature is added to the FPGA that does not
127  //     break software compatibility.
128  //
129  /////////////////////////////////////////////////////////////////////////////////
130
131  localparam [15:0] COMPAT_MAJOR = 16'd6;
132  localparam [15:0] COMPAT_MINOR = 16'd0;
133
134  /////////////////////////////////////////////////////////////////////////////////
135
136  /////////////////////////////////////////////////////////////////////////////////
137  //
138  // Motherboard Registers
139  //
140  /////////////////////////////////////////////////////////////////////////////////
141
142  // Register base
143  localparam [CTRLPORT_ADDR_W-1:0] REG_BASE_MISC       = 20'h0;
144  localparam [CTRLPORT_ADDR_W-1:0] REG_BASE_TIMEKEEPER = 20'h1000;
145
146  // Register region sizes. Give each register region a 256-byte window.
147  localparam REG_GLOB_ADDR_W       = 8;
148  localparam REG_TIMEKEEPER_ADDR_W = 8;
149
150  // Misc Registers
151  localparam REG_COMPAT_NUM        = REG_BASE_MISC + 14'h00;
152  localparam REG_DATESTAMP         = REG_BASE_MISC + 14'h04;
153  localparam REG_GIT_HASH          = REG_BASE_MISC + 14'h08;
154  localparam REG_SCRATCH           = REG_BASE_MISC + 14'h0C;
155  localparam REG_DEVICE_ID         = REG_BASE_MISC + 14'h10;
156  localparam REG_RFNOC_INFO        = REG_BASE_MISC + 14'h14;
157  localparam REG_CLOCK_CTRL        = REG_BASE_MISC + 14'h18;
158  localparam REG_XADC_READBACK     = REG_BASE_MISC + 14'h1C;
159  localparam REG_BUS_CLK_RATE      = REG_BASE_MISC + 14'h20;
160  localparam REG_BUS_CLK_COUNT     = REG_BASE_MISC + 14'h24;
161  localparam REG_SFP_PORT_INFO     = REG_BASE_MISC + 14'h28;
162  localparam REG_FP_GPIO_CTRL      = REG_BASE_MISC + 14'h2C;
163  localparam REG_FP_GPIO_MASTER    = REG_BASE_MISC + 14'h30;
164  localparam REG_FP_GPIO_RADIO_SRC = REG_BASE_MISC + 14'h34;
165  localparam REG_DBOARD_CTRL       = REG_BASE_MISC + 14'h40;
166  localparam REG_DBOARD_STATUS     = REG_BASE_MISC + 14'h44;
167  localparam REG_NUM_TIMEKEEPERS   = REG_BASE_MISC + 14'h48;
168
169  localparam NUM_TIMEKEEPERS = 1;
170
171  wire                  m_ctrlport_req_wr;
172  wire                  m_ctrlport_req_rd;
173  wire [19:0]           m_ctrlport_req_addr;
174  wire [31:0]           m_ctrlport_req_data;
175  wire                  m_ctrlport_req_has_time;
176  wire [63:0]           m_ctrlport_req_time;
177  wire                  m_ctrlport_resp_ack;
178  wire [31:0]           m_ctrlport_resp_data;
179
180  reg  [31:0]           fp_gpio_master_reg = 32'h0;
181  reg  [31:0]           fp_gpio_src_reg    = 32'h0;
182
183  reg [31:0] scratch_reg = 32'h0;
184  reg [31:0] bus_counter = 32'h0;
185
186  always @(posedge bus_clk) begin
187    if (bus_rst)
188      bus_counter <= 32'd0;
189    else
190      bus_counter <= bus_counter + 32'd1;
191  end
192
193  /////////////////////////////////////////////////////////////////////////////
194  //
195  // Bus Bridge
196  //
197  /////////////////////////////////////////////////////////////////////////////
198
199  // We need a really long timeout for CtrlPort transactions, since the
200  // radio_clk for the timekeeper might be really slow compared to s_axi_aclk.
201  localparam CTRLPORT_TIMEOUT = 20;
202
203  wire                       cp_req_wr_aclk;
204  wire                       cp_req_rd_aclk;
205  wire [CTRLPORT_ADDR_W-1:0] cp_req_addr_aclk;
206  wire [CTRLPORT_DATA_W-1:0] cp_req_data_aclk;
207  wire                       cp_resp_ack_aclk;
208  wire [ CTRLPORT_STS_W-1:0] cp_resp_status_aclk;
209  wire [CTRLPORT_DATA_W-1:0] cp_resp_data_aclk;
210
211  // Convert the AXI4-Lite transactions to CtrlPort
212  axil_ctrlport_master #(
213    .TIMEOUT         (CTRLPORT_TIMEOUT),
214    .AXI_AWIDTH      (REG_AWIDTH),
215    .CTRLPORT_AWIDTH (CTRLPORT_ADDR_W)
216  ) axil_ctrlport_master_i (
217    .s_axi_aclk                (s_axi_aclk),
218    .s_axi_aresetn             (s_axi_aresetn),
219    .s_axi_awaddr              (s_axi_awaddr),
220    .s_axi_awvalid             (s_axi_awvalid),
221    .s_axi_awready             (s_axi_awready),
222    .s_axi_wdata               (s_axi_wdata),
223    .s_axi_wstrb               (s_axi_wstrb),
224    .s_axi_wvalid              (s_axi_wvalid),
225    .s_axi_wready              (s_axi_wready),
226    .s_axi_bresp               (s_axi_bresp),
227    .s_axi_bvalid              (s_axi_bvalid),
228    .s_axi_bready              (s_axi_bready),
229    .s_axi_araddr              (s_axi_araddr),
230    .s_axi_arvalid             (s_axi_arvalid),
231    .s_axi_arready             (s_axi_arready),
232    .s_axi_rdata               (s_axi_rdata),
233    .s_axi_rresp               (s_axi_rresp),
234    .s_axi_rvalid              (s_axi_rvalid),
235    .s_axi_rready              (s_axi_rready),
236    .m_ctrlport_req_wr         (cp_req_wr_aclk),
237    .m_ctrlport_req_rd         (cp_req_rd_aclk),
238    .m_ctrlport_req_addr       (cp_req_addr_aclk),
239    .m_ctrlport_req_portid     (),
240    .m_ctrlport_req_rem_epid   (),
241    .m_ctrlport_req_rem_portid (),
242    .m_ctrlport_req_data       (cp_req_data_aclk),
243    .m_ctrlport_req_byte_en    (),
244    .m_ctrlport_req_has_time   (),
245    .m_ctrlport_req_time       (),
246    .m_ctrlport_resp_ack       (cp_resp_ack_aclk),
247    .m_ctrlport_resp_status    (cp_resp_status_aclk),
248    .m_ctrlport_resp_data      (cp_resp_data_aclk)
249  );
250
251  wire                       cp_req_wr;
252  wire                       cp_req_rd;
253  wire [CTRLPORT_ADDR_W-1:0] cp_req_addr;
254  wire [CTRLPORT_DATA_W-1:0] cp_req_data;
255  wire                       cp_resp_ack;
256  wire [ CTRLPORT_STS_W-1:0] cp_resp_status;
257  wire [CTRLPORT_DATA_W-1:0] cp_resp_data;
258
259  // Cross transactions from s_axi_clk to bus_clk domain
260  ctrlport_clk_cross ctrlport_clk_cross_i (
261    .rst                       (~s_axi_aresetn),
262    .s_ctrlport_clk            (s_axi_aclk),
263    .s_ctrlport_req_wr         (cp_req_wr_aclk),
264    .s_ctrlport_req_rd         (cp_req_rd_aclk),
265    .s_ctrlport_req_addr       (cp_req_addr_aclk),
266    .s_ctrlport_req_portid     ({CTRLPORT_PORTID_W{1'b0}}),
267    .s_ctrlport_req_rem_epid   ({CTRLPORT_REM_EPID_W{1'b0}}),
268    .s_ctrlport_req_rem_portid ({CTRLPORT_PORTID_W{1'b0}}),
269    .s_ctrlport_req_data       (cp_req_data_aclk),
270    .s_ctrlport_req_byte_en    ({CTRLPORT_BYTE_EN_W{1'b1}}),
271    .s_ctrlport_req_has_time   (1'b0),
272    .s_ctrlport_req_time       ({CTRLPORT_TIME_W{1'b0}}),
273    .s_ctrlport_resp_ack       (cp_resp_ack_aclk),
274    .s_ctrlport_resp_status    (cp_resp_status_aclk),
275    .s_ctrlport_resp_data      (cp_resp_data_aclk),
276    .m_ctrlport_clk            (bus_clk),
277    .m_ctrlport_req_wr         (cp_req_wr),
278    .m_ctrlport_req_rd         (cp_req_rd),
279    .m_ctrlport_req_addr       (cp_req_addr),
280    .m_ctrlport_req_portid     (),
281    .m_ctrlport_req_rem_epid   (),
282    .m_ctrlport_req_rem_portid (),
283    .m_ctrlport_req_data       (cp_req_data),
284    .m_ctrlport_req_byte_en    (),
285    .m_ctrlport_req_has_time   (),
286    .m_ctrlport_req_time       (),
287    .m_ctrlport_resp_ack       (cp_resp_ack),
288    .m_ctrlport_resp_status    (cp_resp_status),
289    .m_ctrlport_resp_data      (cp_resp_data)
290  );
291
292  wire                       cp_glob_req_wr;
293  wire                       cp_glob_req_rd;
294  wire [CTRLPORT_ADDR_W-1:0] cp_glob_req_addr;
295  wire [CTRLPORT_DATA_W-1:0] cp_glob_req_data;
296  reg                        cp_glob_resp_ack  = 1'b0;
297  reg  [CTRLPORT_DATA_W-1:0] cp_glob_resp_data = 1'bX;
298
299  wire                       cp_tk_req_wr;
300  wire                       cp_tk_req_rd;
301  wire [CTRLPORT_ADDR_W-1:0] cp_tk_req_addr;
302  wire [CTRLPORT_DATA_W-1:0] cp_tk_req_data;
303  wire                       cp_tk_resp_ack;
304  wire [CTRLPORT_DATA_W-1:0] cp_tk_resp_data;
305
306  // Split the CtrlPort for the global registers and the timekeeper registers
307  ctrlport_decoder_param #(
308    .NUM_SLAVES  (2),
309    .PORT_BASE   ({   REG_BASE_TIMEKEEPER,   REG_BASE_MISC }),
310    .PORT_ADDR_W ({ REG_TIMEKEEPER_ADDR_W, REG_GLOB_ADDR_W })
311  ) ctrlport_decoder_param_i (
312    .ctrlport_clk            (bus_clk),
313    .ctrlport_rst            (bus_rst),
314    .s_ctrlport_req_wr       (cp_req_wr),
315    .s_ctrlport_req_rd       (cp_req_rd),
316    .s_ctrlport_req_addr     (cp_req_addr),
317    .s_ctrlport_req_data     (cp_req_data),
318    .s_ctrlport_req_byte_en  ({CTRLPORT_BYTE_EN_W{1'b1}}),
319    .s_ctrlport_req_has_time (1'b0),
320    .s_ctrlport_req_time     ({CTRLPORT_TIME_W{1'b0}}),
321    .s_ctrlport_resp_ack     (cp_resp_ack),
322    .s_ctrlport_resp_status  (cp_resp_status),
323    .s_ctrlport_resp_data    (cp_resp_data),
324    .m_ctrlport_req_wr       ({    cp_tk_req_wr,    cp_glob_req_wr }),
325    .m_ctrlport_req_rd       ({    cp_tk_req_rd,    cp_glob_req_rd }),
326    .m_ctrlport_req_addr     ({  cp_tk_req_addr,  cp_glob_req_addr }),
327    .m_ctrlport_req_data     ({  cp_tk_req_data,  cp_glob_req_data }),
328    .m_ctrlport_req_byte_en  (),
329    .m_ctrlport_req_has_time (),
330    .m_ctrlport_req_time     (),
331    .m_ctrlport_resp_ack     ({  cp_tk_resp_ack,  cp_glob_resp_ack }),
332    .m_ctrlport_resp_status  ({2{CTRL_STS_OKAY}}),
333    .m_ctrlport_resp_data    ({ cp_tk_resp_data, cp_glob_resp_data })
334  );
335
336
337  /////////////////////////////////////////////////////////////////////////////
338  //
339  // Global Registers
340  //
341  /////////////////////////////////////////////////////////////////////////////
342
343  // Write Registers
344  always @ (posedge bus_clk) begin
345    if (bus_rst) begin
346      scratch_reg       <= 32'h0;
347      pps_select        <= 2'b01; // Default to internal
348      fp_gpio_ctrl      <= 32'h9; // Default to OFF - 4'b1001
349      dboard_ctrl       <= 32'h1; // Default to mimo
350      device_id         <= 16'h0;
351      cp_glob_resp_ack  <= 1'b0;
352      cp_glob_resp_data <= 'bX;
353    end else begin
354      cp_glob_resp_ack <= 1'b0;
355
356      if (cp_glob_req_wr) begin
357        cp_glob_resp_ack <= 1'b1;
358
359        case (cp_glob_req_addr[REG_GLOB_ADDR_W-1:0])
360          REG_DEVICE_ID:
361            device_id <= cp_glob_req_data[15:0];
362
363          REG_FP_GPIO_MASTER:
364            fp_gpio_master_reg <= cp_glob_req_data;
365
366          REG_FP_GPIO_RADIO_SRC:
367            fp_gpio_src_reg  <= cp_glob_req_data;
368
369          REG_SCRATCH:
370            scratch_reg <= cp_glob_req_data;
371
372          REG_CLOCK_CTRL:
373            pps_select <= cp_glob_req_data[1:0];
374
375          REG_FP_GPIO_CTRL:
376            fp_gpio_ctrl <= cp_glob_req_data;
377
378          REG_DBOARD_CTRL:
379            dboard_ctrl <= cp_glob_req_data;
380
381          default : begin
382            // Don't acknowledge if the address doesn't match
383            cp_glob_resp_ack <= 1'b0;
384          end
385        endcase
386      end
387
388      if (cp_glob_req_rd) begin
389        cp_glob_resp_data <= 0;  // Unused bits will read 0
390        cp_glob_resp_ack  <= 1'b1;
391
392        case (cp_glob_req_addr[REG_GLOB_ADDR_W-1:0])
393          REG_DEVICE_ID:
394            cp_glob_resp_data <= {16'd0, device_id};
395
396          REG_RFNOC_INFO:
397            cp_glob_resp_data <= {CHDR_WIDTH[15:0], RFNOC_PROTOVER[15:0]};
398
399          REG_COMPAT_NUM:
400            cp_glob_resp_data <= {COMPAT_MAJOR[15:0], COMPAT_MINOR[15:0]};
401
402          REG_FP_GPIO_CTRL:
403            cp_glob_resp_data <= fp_gpio_ctrl;
404
405          REG_FP_GPIO_MASTER:
406            cp_glob_resp_data <= fp_gpio_master_reg;
407
408          REG_FP_GPIO_RADIO_SRC:
409            cp_glob_resp_data <= fp_gpio_src_reg;
410
411          REG_DATESTAMP:
412            cp_glob_resp_data <= build_datestamp;
413
414          REG_GIT_HASH: begin
415            `ifndef GIT_HASH
416            `define GIT_HASH 32'h0BADC0DE
417            `endif
418            cp_glob_resp_data <= `GIT_HASH;
419          end
420
421          REG_SCRATCH:
422            cp_glob_resp_data <= scratch_reg;
423
424          REG_CLOCK_CTRL: begin
425            cp_glob_resp_data      <= 32'b0;
426            cp_glob_resp_data[1:0] <= pps_select;
427            cp_glob_resp_data[3]   <= refclk_locked;
428          end
429
430          REG_XADC_READBACK:
431            cp_glob_resp_data <= xadc_readback;
432
433          REG_BUS_CLK_RATE:
434            cp_glob_resp_data <= BUS_CLK_RATE;
435
436          REG_BUS_CLK_COUNT:
437            cp_glob_resp_data <= bus_counter;
438
439          REG_SFP_PORT_INFO:
440            cp_glob_resp_data <= sfp_ports_info;
441
442          REG_DBOARD_CTRL:
443            cp_glob_resp_data <= dboard_ctrl;
444
445          REG_DBOARD_STATUS:
446            cp_glob_resp_data <= dboard_status;
447
448          REG_NUM_TIMEKEEPERS:
449            cp_glob_resp_data <= NUM_TIMEKEEPERS;
450
451          default: begin
452            // Don't acknowledge if the address doesn't match
453            cp_glob_resp_ack <= 1'b0;
454          end
455        endcase
456      end
457    end
458  end
459
460  wire pps_radioclk;
461
462  // Synchronize the PPS signal to the radio clock domain
463  synchronizer pps_radio_sync (
464    .clk(radio_clk), .rst(1'b0), .in(pps_refclk), .out(pps_radioclk)
465  );
466
467  /////////////////////////////////////////////////////////////////////////////
468  //
469  // Radio Daughter board and Front End Control
470  //
471  /////////////////////////////////////////////////////////////////////////////
472
473  // Radio Daughter board GPIO
474  wire [DB_GPIO_WIDTH-1:0] db_gpio_in[0:NUM_CHANNELS-1];
475  wire [DB_GPIO_WIDTH-1:0] db_gpio_out[0:NUM_CHANNELS-1];
476  wire [DB_GPIO_WIDTH-1:0] db_gpio_ddr[0:NUM_CHANNELS-1];
477  wire [DB_GPIO_WIDTH-1:0] db_gpio_fab[0:NUM_CHANNELS-1];
478  wire [31:0] radio_gpio_out[0:NUM_CHANNELS-1];
479  wire [31:0] radio_gpio_ddr[0:NUM_CHANNELS-1];
480  wire [31:0] radio_gpio_in[0:NUM_CHANNELS-1];
481  wire [31:0] leds[0:NUM_CHANNELS-1];
482
483  // Daughter board I/O
484  wire        rx_running[0:NUM_CHANNELS-1], tx_running[0:NUM_CHANNELS-1];
485  wire [31:0] rx_int[0:NUM_CHANNELS-1], rx_data[0:NUM_CHANNELS-1], tx_int[0:NUM_CHANNELS-1], tx_data[0:NUM_CHANNELS-1];
486  //wire        rx_stb[0:NUM_CHANNELS-1], tx_stb[0:NUM_CHANNELS-1];
487  wire        db_fe_set_stb[0:NUM_CHANNELS-1];
488  wire [7:0]  db_fe_set_addr[0:NUM_CHANNELS-1];
489  wire [31:0] db_fe_set_data[0:NUM_CHANNELS-1];
490  wire        db_fe_rb_stb[0:NUM_CHANNELS-1];
491  wire [7:0]  db_fe_rb_addr[0:NUM_CHANNELS-1];
492  wire [63:0] db_fe_rb_data[0:NUM_CHANNELS-1];
493
494  wire [NUM_RADIOS-1:0] sync_out;
495
496  genvar i;
497  generate
498    for (i = 0; i < NUM_CHANNELS; i = i + 1) begin
499      assign rx_atr[i] = rx_running[i];
500      assign tx_atr[i] = tx_running[i];
501    end
502  endgenerate
503
504
505  //------------------------------------
506  // Daughterboard Control
507  // -----------------------------------
508
509  localparam [7:0] SR_DB_BASE = 8'd160;
510  localparam [7:0] RB_DB_BASE = 8'd16;
511
512  generate
513    for (i = 0; i < NUM_CHANNELS; i = i + 1) begin: gen_db_control
514      db_control #(
515        .USE_SPI_CLK(0),
516        .SR_BASE(SR_DB_BASE),
517        .RB_BASE(RB_DB_BASE)
518      ) db_control_i (
519        .clk(radio_clk), .reset(radio_rst),
520        .set_stb(db_fe_set_stb[i]), .set_addr(db_fe_set_addr[i]), .set_data(db_fe_set_data[i]),
521        .rb_stb(db_fe_rb_stb[i]), .rb_addr(db_fe_rb_addr[i]), .rb_data(db_fe_rb_data[i]),
522        .run_rx(rx_running[i]), .run_tx(tx_running[i]),
523        .misc_ins(32'h0), .misc_outs(),
524        .fp_gpio_in(radio_gpio_in[i]), .fp_gpio_out(radio_gpio_out[i]), .fp_gpio_ddr(radio_gpio_ddr[i]), .fp_gpio_fab(32'h0),
525        .db_gpio_in(db_gpio_in[i]), .db_gpio_out(db_gpio_out[i]), .db_gpio_ddr(db_gpio_ddr[i]), .db_gpio_fab(),
526        .leds(leds[i]),
527        .spi_clk(1'b0), .spi_rst(1'b0), .sen(), .sclk(), .mosi(), .miso(1'b0)
528      );
529    end
530  endgenerate
531
532  generate
533    for (i = 0; i < NUM_CHANNELS; i = i + 1) begin: gen_gpio_control
534      // Radio Data
535      assign rx_data[i] = rx[32*i+31:32*i];
536      assign tx[32*i+31:32*i] = tx_data[i];
537      // GPIO
538      assign db_gpio_out_flat[DB_GPIO_WIDTH*i +: DB_GPIO_WIDTH] = db_gpio_out[i];
539      assign db_gpio_ddr_flat[DB_GPIO_WIDTH*i +: DB_GPIO_WIDTH] = db_gpio_ddr[i];
540      assign db_gpio_in[i] = db_gpio_in_flat[DB_GPIO_WIDTH*i +: DB_GPIO_WIDTH];
541      assign db_gpio_fab[i] = db_gpio_fab_flat[DB_GPIO_WIDTH*i +: DB_GPIO_WIDTH];
542      // LEDs
543      assign leds_flat[32*i+31:32*i] = leds[i];
544    end
545  endgenerate
546
547  /////////////////////////////////////////////////////////////////////////////
548  //
549  // Front-panel GPIO
550  //
551  /////////////////////////////////////////////////////////////////////////////
552
553  wire [FP_GPIO_WIDTH-1:0] radio_gpio_in_sync;
554  wire [FP_GPIO_WIDTH-1:0] radio_gpio_src_out;
555  reg  [FP_GPIO_WIDTH-1:0] radio_gpio_src_out_reg;
556  wire [FP_GPIO_WIDTH-1:0] radio_gpio_src_ddr;
557  reg  [FP_GPIO_WIDTH-1:0] radio_gpio_src_ddr_reg = ~0;
558
559  // Double-synchronize the inputs to the PS
560  synchronizer #(
561    .INITIAL_VAL(1'b0), .WIDTH(FP_GPIO_WIDTH)
562    ) ps_gpio_in_sync_i (
563    .clk(bus_clk), .rst(1'b0), .in(fp_gpio_in), .out(ps_gpio_in)
564  );
565
566  // Double-synchronize the inputs to the radio
567  synchronizer #(
568    .INITIAL_VAL(1'b0), .WIDTH(FP_GPIO_WIDTH)
569    ) radio_gpio_in_sync_i (
570    .clk(radio_clk), .rst(1'b0), .in(fp_gpio_in), .out(radio_gpio_in_sync)
571  );
572
573  // Map the double-synchronized inputs to all radio channels
574  generate
575    for (i=0; i<NUM_CHANNELS; i=i+1) begin: gen_fp_gpio_in_sync
576      assign radio_gpio_in[i][FP_GPIO_WIDTH-1:0] = radio_gpio_in_sync;
577    end
578  endgenerate
579
580  // For each of the FP GPIO bits, implement four control muxes
581  generate
582    for (i=0; i<FP_GPIO_WIDTH; i=i+1) begin: gpio_muxing_gen
583
584      // 1) Select which radio drives the output
585      assign radio_gpio_src_out[i] = radio_gpio_out[fp_gpio_src_reg[2*i+1:2*i]][i];
586      always @ (posedge radio_clk) begin
587        if (radio_rst) begin
588          radio_gpio_src_out_reg <= 0;
589        end else begin
590          radio_gpio_src_out_reg <= radio_gpio_src_out;
591        end
592      end
593
594      // 2) Select which radio drives the direction
595      assign radio_gpio_src_ddr[i] = radio_gpio_ddr[fp_gpio_src_reg[2*i+1:2*i]][i];
596      always @ (posedge radio_clk) begin
597        if (radio_rst) begin
598          radio_gpio_src_ddr_reg <= ~0;
599        end else begin
600          radio_gpio_src_ddr_reg <= radio_gpio_src_ddr;
601        end
602      end
603
604      // 3) Select if the radio or the ps drives the output
605      //
606      // The following implements a 2:1 mux in a LUT explicitly to avoid
607      // glitches that can be introduced by unexpected Vivado synthesis.
608      //
609      (* dont_touch = "TRUE" *) LUT3 #(
610        .INIT(8'hCA) // Specify LUT Contents. O = ~I2&I0 | I2&I1
611      ) mux_out_i (
612        .O(fp_gpio_out[i]),             // LUT general output. Mux output
613        .I0(radio_gpio_src_out_reg[i]), // LUT input. Input 1
614        .I1(ps_gpio_out[i]),            // LUT input. Input 2
615        .I2(fp_gpio_master_reg[i])      // LUT input. Select bit
616      );
617
618      // 4) Select if the radio or the PS drives the direction
619      //
620      (* dont_touch = "TRUE" *) LUT3 #(
621        .INIT(8'hC5) // Specify LUT Contents. O = ~I2&I0 | I2&~I1
622      ) mux_ddr_i (
623        .O(fp_gpio_tri[i]),             // LUT general output. Mux output
624        .I0(radio_gpio_src_ddr_reg[i]), // LUT input. Input 1
625        .I1(ps_gpio_tri[i]),            // LUT input. Input 2
626        .I2(fp_gpio_master_reg[i])      // LUT input. Select bit
627      );
628
629    end
630  endgenerate
631
632  /////////////////////////////////////////////////////////////////////////////
633  //
634  // Timekeeper
635  //
636  /////////////////////////////////////////////////////////////////////////////
637
638  wire [63:0] radio_time;
639
640  timekeeper #(
641   .BASE_ADDR      (0),      // ctrlport_decoder removes the base offset
642   .TIME_INCREMENT (1'b1)
643  ) timekeeper_i (
644   .tb_clk                (radio_clk),
645   .tb_rst                (radio_rst),
646   .s_ctrlport_clk        (bus_clk),
647   .s_ctrlport_req_wr     (cp_tk_req_wr),
648   .s_ctrlport_req_rd     (cp_tk_req_rd),
649   .s_ctrlport_req_addr   (cp_tk_req_addr),
650   .s_ctrlport_req_data   (cp_tk_req_data),
651   .s_ctrlport_resp_ack   (cp_tk_resp_ack),
652   .s_ctrlport_resp_data  (cp_tk_resp_data),
653   .sample_rx_stb         (rx_stb[0]),
654   .pps                   (pps_radioclk),
655   .tb_timestamp          (radio_time),
656   .tb_timestamp_last_pps (),
657   .tb_period_ns_q32      ()
658  );
659
660  /////////////////////////////////////////////////////////////////////////////
661  //
662  // RFNoC Image Core
663  //
664  /////////////////////////////////////////////////////////////////////////////
665
666  rfnoc_image_core #(
667    .PROTOVER(RFNOC_PROTOVER)
668  ) rfnoc_image_core_i (
669    .chdr_aclk               (bus_clk    ),
670    .ctrl_aclk               (clk40      ),
671    .core_arst               (bus_rst    ),
672    .device_id               (device_id  ),
673    .radio_clk               (radio_clk  ),
674    .m_ctrlport_req_wr       (m_ctrlport_req_wr      ),
675    .m_ctrlport_req_rd       (m_ctrlport_req_rd      ),
676    .m_ctrlport_req_addr     (m_ctrlport_req_addr    ),
677    .m_ctrlport_req_data     (m_ctrlport_req_data    ),
678    .m_ctrlport_req_byte_en  (),
679    .m_ctrlport_req_has_time (m_ctrlport_req_has_time),
680    .m_ctrlport_req_time     (m_ctrlport_req_time    ),
681    .m_ctrlport_resp_ack     (m_ctrlport_resp_ack    ),
682    .m_ctrlport_resp_status  (2'b0),
683    .m_ctrlport_resp_data    (m_ctrlport_resp_data   ),
684    .radio_time              (radio_time             ),
685    .radio_rx_stb            ({rx_stb[1],     rx_stb[0]    }),
686    .radio_rx_data           ({rx_data[1],    rx_data[0]   }),
687    .radio_rx_running        ({rx_running[1], rx_running[0]}),
688    .radio_tx_stb            ({tx_stb[1],     tx_stb[0]    }),
689    .radio_tx_data           ({tx_data[1],    tx_data[0]   }),
690    .radio_tx_running        ({tx_running[1], tx_running[0]}),
691    .s_dma_tdata             (s_dma_tdata),
692    .s_dma_tlast             (s_dma_tlast),
693    .s_dma_tvalid            (s_dma_tvalid),
694    .s_dma_tready            (s_dma_tready),
695    .m_dma_tdata             (m_dma_tdata),
696    .m_dma_tlast             (m_dma_tlast),
697    .m_dma_tvalid            (m_dma_tvalid),
698    .m_dma_tready            (m_dma_tready)
699  );
700
701  //---------------------------------------------------------------------------
702  // Convert Control Port to Settings Bus
703  //---------------------------------------------------------------------------
704
705  ctrlport_to_settings_bus # (
706    .NUM_PORTS (2),
707    .USE_TIME  (1)
708  ) ctrlport_to_settings_bus_i (
709    .ctrlport_clk             (radio_clk),
710    .ctrlport_rst             (radio_rst),
711    .s_ctrlport_req_wr        (m_ctrlport_req_wr),
712    .s_ctrlport_req_rd        (m_ctrlport_req_rd),
713    .s_ctrlport_req_addr      (m_ctrlport_req_addr),
714    .s_ctrlport_req_data      (m_ctrlport_req_data),
715    .s_ctrlport_req_has_time  (m_ctrlport_req_has_time),
716    .s_ctrlport_req_time      (m_ctrlport_req_time),
717    .s_ctrlport_resp_ack      (m_ctrlport_resp_ack),
718    .s_ctrlport_resp_data     (m_ctrlport_resp_data),
719    .set_data                 ({db_fe_set_data[1], db_fe_set_data[0]}),
720    .set_addr                 ({db_fe_set_addr[1], db_fe_set_addr[0]}),
721    .set_stb                  ({db_fe_set_stb[1],  db_fe_set_stb[0] }),
722    .set_time                 (),
723    .set_has_time             (),
724    .rb_stb                   ({db_fe_rb_stb[1],   db_fe_rb_stb[0]  }),
725    .rb_addr                  ({db_fe_rb_addr[1],  db_fe_rb_addr[0] }),
726    .rb_data                  ({db_fe_rb_data[1],  db_fe_rb_data[0] }),
727    .timestamp                (radio_time)
728  );
729
730endmodule //e31x_core
731`default_nettype wire
732
733