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
|
//
// Copyright 2016 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
module db_control #(
// Drive SPI core with input spi_clk instead of ce_clk. This is useful if ce_clk is very slow which
// would cause spi transactions to take a long time. WARNING: This adds a clock crossing FIFO!
parameter USE_SPI_CLK = 0,
parameter SR_BASE = 160,
parameter RB_BASE = 16,
parameter NUM_SPI_SEN = 8
)(
// Commands from Radio Core
input clk, input reset,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
output reg rb_stb, input [7:0] rb_addr, output reg [63:0] rb_data,
input run_rx, input run_tx,
// Frontend / Daughterboard I/O
input [31:0] misc_ins, output [31:0] misc_outs,
input [31:0] fp_gpio_in, output [31:0] fp_gpio_out, output [31:0] fp_gpio_ddr, input [31:0] fp_gpio_fab,
input [31:0] db_gpio_in, output [31:0] db_gpio_out, output [31:0] db_gpio_ddr, input [31:0] db_gpio_fab,
output [31:0] leds,
input spi_clk, input spi_rst, output [NUM_SPI_SEN-1:0] sen, output sclk, output mosi, input miso
);
localparam [7:0] SR_MISC_OUTS = SR_BASE + 8'd0;
localparam [7:0] SR_SPI = SR_BASE + 8'd8;
localparam [7:0] SR_LEDS = SR_BASE + 8'd16;
localparam [7:0] SR_FP_GPIO = SR_BASE + 8'd24;
localparam [7:0] SR_DB_GPIO = SR_BASE + 8'd32;
localparam [7:0] RB_MISC_IO = RB_BASE + 0;
localparam [7:0] RB_SPI = RB_BASE + 1;
localparam [7:0] RB_LEDS = RB_BASE + 2;
localparam [7:0] RB_DB_GPIO = RB_BASE + 3;
localparam [7:0] RB_FP_GPIO = RB_BASE + 4;
/********************************************************
** Settings registers
********************************************************/
setting_reg #(.my_addr(SR_MISC_OUTS), .width(32)) sr_misc_outs (
.clk(clk), .rst(reset),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(misc_outs), .changed());
// Readback
reg spi_readback_stb_hold;
reg [31:0] spi_readback_hold;
wire [31:0] spi_readback_sync;
wire [31:0] fp_gpio_readback, db_gpio_readback;
always @* begin
case(rb_addr)
// Use a latched spi readback stobe so additional readbacks after a SPI transaction will work
RB_MISC_IO : {rb_stb, rb_data} <= {spi_readback_stb_hold, {misc_ins, misc_outs}};
RB_SPI : {rb_stb, rb_data} <= {spi_readback_stb_hold, {32'd0, spi_readback_hold}};
RB_LEDS : {rb_stb, rb_data} <= {spi_readback_stb_hold, {32'd0, leds}};
RB_DB_GPIO : {rb_stb, rb_data} <= {spi_readback_stb_hold, {32'd0, db_gpio_readback}};
RB_FP_GPIO : {rb_stb, rb_data} <= {spi_readback_stb_hold, {32'd0, fp_gpio_readback}};
default : {rb_stb, rb_data} <= {spi_readback_stb_hold, {64'h0BADC0DE0BADC0DE}};
endcase
end
/********************************************************
** GPIO
********************************************************/
gpio_atr #(.BASE(SR_LEDS), .WIDTH(32), .FAB_CTRL_EN(0), .DEFAULT_DDR(32'hFFFF_FFFF), .DEFAULT_IDLE(32'd0)) leds_gpio_atr (
.clk(clk), .reset(reset),
.set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
.rx(run_rx), .tx(run_tx),
.gpio_in(32'd0), .gpio_out(leds), .gpio_ddr(/*unused, assumed output only*/),
.gpio_out_fab(32'h00000000 /*LEDs don't have fabric control*/), .gpio_sw_rb());
gpio_atr #(.BASE(SR_FP_GPIO), .WIDTH(32), .FAB_CTRL_EN(1), .DEFAULT_DDR(32'hFFFF_FFFF), .DEFAULT_IDLE(32'd0)) fp_gpio_atr (
.clk(clk), .reset(reset),
.set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
.rx(run_rx), .tx(run_tx),
.gpio_in(fp_gpio_in), .gpio_out(fp_gpio_out), .gpio_ddr(fp_gpio_ddr),
.gpio_out_fab(fp_gpio_fab), .gpio_sw_rb(fp_gpio_readback));
gpio_atr #(.BASE(SR_DB_GPIO), .WIDTH(32), .FAB_CTRL_EN(1), .DEFAULT_DDR(32'hFFFF_FFFF), .DEFAULT_IDLE(32'd0)) db_gpio_atr (
.clk(clk), .reset(reset),
.set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
.rx(run_rx), .tx(run_tx),
.gpio_in(db_gpio_in), .gpio_out(db_gpio_out), .gpio_ddr(db_gpio_ddr),
.gpio_out_fab(db_gpio_fab), .gpio_sw_rb(db_gpio_readback));
/********************************************************
** SPI
********************************************************/
wire spi_set_stb;
wire [7:0] spi_set_addr;
wire [31:0] spi_set_data;
wire spi_readback_stb, spi_readback_stb_sync;
wire [31:0] spi_readback;
wire spi_clk_int, spi_rst_int;
generate
if (USE_SPI_CLK) begin
axi_fifo_2clk #(.WIDTH(8 + 32), .SIZE(0)) set_2clk_i (
.reset(reset),
.i_aclk(clk), .i_tdata({set_addr, set_data}), .i_tvalid(set_stb), .i_tready(),
.o_aclk(spi_clk), .o_tdata({spi_set_addr, spi_set_data}), .o_tvalid(spi_set_stb), .o_tready(spi_set_stb));
axi_fifo_2clk #(.WIDTH(32), .SIZE(0)) rb_2clk_i (
.reset(reset),
.i_aclk(spi_clk), .i_tdata(spi_readback), .i_tvalid(spi_readback_stb), .i_tready(),
.o_aclk(clk), .o_tdata(spi_readback_sync), .o_tvalid(spi_readback_stb_sync), .o_tready(spi_readback_stb_sync));
assign spi_clk_int = spi_clk;
assign spi_rst_int = spi_rst;
end else begin
assign spi_set_stb = set_stb;
assign spi_set_addr = set_addr;
assign spi_set_data = set_data;
assign spi_readback_stb_sync = spi_readback_stb;
assign spi_readback_sync = spi_readback;
assign spi_clk_int = clk;
assign spi_rst_int = reset;
end
endgenerate
// Need to latch spi_readback_stb in case of additional readbacks
// after the initial spi transaction.
always @(posedge clk) begin
if (reset) begin
spi_readback_stb_hold <= 1'b1;
end else begin
if (set_stb & (set_addr == SR_SPI+2 /* Trigger address */)) begin
spi_readback_stb_hold <= 1'b0;
end else if (spi_readback_stb_sync) begin
spi_readback_hold <= spi_readback_sync;
spi_readback_stb_hold <= 1'b1;
end
end
end
// SPI Core instantiation
// Note: We don't use "ready" because we use readback_stb to backpressure the settings bus
simple_spi_core #(.BASE(SR_SPI), .WIDTH(NUM_SPI_SEN), .CLK_IDLE(0), .SEN_IDLE(8'hFF)) simple_spi_core (
.clock(spi_clk_int), .reset(spi_rst_int),
.set_stb(spi_set_stb), .set_addr(spi_set_addr), .set_data(spi_set_data),
.readback(spi_readback), .readback_stb(spi_readback_stb), .ready(/* Unused */),
.sen(sen), .sclk(sclk), .mosi(mosi), .miso(miso),
.debug());
endmodule
|