aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/control/gpio_atr.v
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/lib/control/gpio_atr.v')
-rw-r--r--fpga/usrp3/lib/control/gpio_atr.v98
1 files changed, 98 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/control/gpio_atr.v b/fpga/usrp3/lib/control/gpio_atr.v
new file mode 100644
index 000000000..f99ac55b1
--- /dev/null
+++ b/fpga/usrp3/lib/control/gpio_atr.v
@@ -0,0 +1,98 @@
+
+//
+// Copyright 2011 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+
+module gpio_atr #(
+ parameter BASE = 0,
+ parameter WIDTH = 32,
+ parameter FAB_CTRL_EN = 0,
+ parameter DEFAULT_DDR = 0,
+ parameter DEFAULT_IDLE = 0
+) (
+ input clk, input reset, //Clock and reset
+ input set_stb, input [7:0] set_addr, input [31:0] set_data, //Settings control interface
+ input rx, input tx, //Run signals that indicate tx and rx operation
+ input [WIDTH-1:0] gpio_in, //GPIO input state
+ output reg [WIDTH-1:0] gpio_out, //GPIO output state
+ output reg [WIDTH-1:0] gpio_ddr, //GPIO direction (0=input, 1=output)
+ input [WIDTH-1:0] gpio_out_fab, //GPIO driver bus from fabric
+ output reg [WIDTH-1:0] gpio_sw_rb //Readback value for software
+);
+ genvar i;
+
+ wire [WIDTH-1:0] in_idle, in_tx, in_rx, in_fdx, ddr_reg, atr_disable, fabric_ctrl;
+ reg [WIDTH-1:0] ogpio, igpio;
+
+ setting_reg #(.my_addr(BASE+0), .width(WIDTH), .at_reset(DEFAULT_IDLE)) reg_idle (
+ .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
+ .out(in_idle),.changed());
+
+ setting_reg #(.my_addr(BASE+1), .width(WIDTH)) reg_rx (
+ .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
+ .out(in_rx),.changed());
+
+ setting_reg #(.my_addr(BASE+2), .width(WIDTH)) reg_tx (
+ .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
+ .out(in_tx),.changed());
+
+ setting_reg #(.my_addr(BASE+3), .width(WIDTH)) reg_fdx (
+ .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
+ .out(in_fdx),.changed());
+
+ setting_reg #(.my_addr(BASE+4), .width(WIDTH), .at_reset(DEFAULT_DDR)) reg_ddr (
+ .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
+ .out(ddr_reg),.changed());
+
+ setting_reg #(.my_addr(BASE+5), .width(WIDTH)) reg_atr_disable (
+ .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
+ .out(atr_disable),.changed());
+
+ generate if (FAB_CTRL_EN == 1) begin
+ setting_reg #(.my_addr(BASE+6), .width(WIDTH)) reg_fabric_ctrl (
+ .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
+ .out(fabric_ctrl),.changed());
+ end else begin
+ assign fabric_ctrl = {WIDTH{1'b0}};
+ end endgenerate
+
+ //Pipeline rx and tx signals for easier timing closure
+ reg rx_d, tx_d;
+ always @(posedge clk)
+ {rx_d, tx_d} <= {rx, tx};
+
+ generate for (i=0; i<WIDTH; i=i+1) begin: gpio_mux_gen
+ //ATR selection MUX
+ always @(posedge clk) begin
+ case({atr_disable[i], tx_d, rx_d})
+ 3'b000: ogpio[i] <= in_idle[i];
+ 3'b001: ogpio[i] <= in_rx[i];
+ 3'b010: ogpio[i] <= in_tx[i];
+ 3'b011: ogpio[i] <= in_fdx[i];
+ default: ogpio[i] <= in_idle[i]; //If ATR mode is disabled, always use IDLE value
+ endcase
+ end
+
+ //Pipeline input, output and direction
+ //For fabric access, insert MUX as close to the IO as possible
+ always @(posedge clk) begin
+ gpio_out[i] <= fabric_ctrl[i] ? gpio_out_fab[i] : ogpio[i];
+ end
+ end endgenerate
+
+ always @(posedge clk)
+ igpio <= gpio_in;
+
+ always @(posedge clk)
+ gpio_ddr <= ddr_reg;
+
+ //Generate software readback state
+ generate for (i=0; i<WIDTH; i=i+1) begin: gpio_rb_gen
+ always @(posedge clk)
+ gpio_sw_rb[i] <= gpio_ddr[i] ? gpio_out[i] : igpio[i];
+ end endgenerate
+
+endmodule // gpio_atr