1 2// 3// Copyright 2011 Ettus Research LLC 4// Copyright 2018 Ettus Research, a National Instruments Company 5// 6// SPDX-License-Identifier: LGPL-3.0-or-later 7// 8 9module gpio_atr #( 10 parameter BASE = 0, 11 parameter WIDTH = 32, 12 parameter FAB_CTRL_EN = 0, 13 parameter DEFAULT_DDR = 0, 14 parameter DEFAULT_IDLE = 0 15) ( 16 input clk, input reset, //Clock and reset 17 input set_stb, input [7:0] set_addr, input [31:0] set_data, //Settings control interface 18 input rx, input tx, //Run signals that indicate tx and rx operation 19 input [WIDTH-1:0] gpio_in, //GPIO input state 20 output reg [WIDTH-1:0] gpio_out, //GPIO output state 21 output reg [WIDTH-1:0] gpio_ddr, //GPIO direction (0=input, 1=output) 22 input [WIDTH-1:0] gpio_out_fab, //GPIO driver bus from fabric 23 output reg [WIDTH-1:0] gpio_sw_rb //Readback value for software 24); 25 genvar i; 26 27 wire [WIDTH-1:0] in_idle, in_tx, in_rx, in_fdx, ddr_reg, atr_disable, fabric_ctrl; 28 reg [WIDTH-1:0] ogpio, igpio; 29 30 setting_reg #(.my_addr(BASE+0), .width(WIDTH), .at_reset(DEFAULT_IDLE)) reg_idle ( 31 .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data), 32 .out(in_idle),.changed()); 33 34 setting_reg #(.my_addr(BASE+1), .width(WIDTH)) reg_rx ( 35 .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data), 36 .out(in_rx),.changed()); 37 38 setting_reg #(.my_addr(BASE+2), .width(WIDTH)) reg_tx ( 39 .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data), 40 .out(in_tx),.changed()); 41 42 setting_reg #(.my_addr(BASE+3), .width(WIDTH)) reg_fdx ( 43 .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data), 44 .out(in_fdx),.changed()); 45 46 setting_reg #(.my_addr(BASE+4), .width(WIDTH), .at_reset(DEFAULT_DDR)) reg_ddr ( 47 .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data), 48 .out(ddr_reg),.changed()); 49 50 setting_reg #(.my_addr(BASE+5), .width(WIDTH)) reg_atr_disable ( 51 .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data), 52 .out(atr_disable),.changed()); 53 54 generate if (FAB_CTRL_EN == 1) begin 55 setting_reg #(.my_addr(BASE+6), .width(WIDTH)) reg_fabric_ctrl ( 56 .clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data), 57 .out(fabric_ctrl),.changed()); 58 end else begin 59 assign fabric_ctrl = {WIDTH{1'b0}}; 60 end endgenerate 61 62 //Pipeline rx and tx signals for easier timing closure 63 reg rx_d, tx_d; 64 always @(posedge clk) 65 {rx_d, tx_d} <= {rx, tx}; 66 67 generate for (i=0; i<WIDTH; i=i+1) begin: gpio_mux_gen 68 //ATR selection MUX 69 always @(posedge clk) begin 70 case({atr_disable[i], tx_d, rx_d}) 71 3'b000: ogpio[i] <= in_idle[i]; 72 3'b001: ogpio[i] <= in_rx[i]; 73 3'b010: ogpio[i] <= in_tx[i]; 74 3'b011: ogpio[i] <= in_fdx[i]; 75 default: ogpio[i] <= in_idle[i]; //If ATR mode is disabled, always use IDLE value 76 endcase 77 end 78 79 //Pipeline input, output and direction 80 //For fabric access, insert MUX as close to the IO as possible 81 always @(posedge clk) begin 82 gpio_out[i] <= fabric_ctrl[i] ? gpio_out_fab[i] : ogpio[i]; 83 end 84 end endgenerate 85 86 always @(posedge clk) 87 igpio <= gpio_in; 88 89 always @(posedge clk) 90 gpio_ddr <= ddr_reg; 91 92 //Generate software readback state 93 generate for (i=0; i<WIDTH; i=i+1) begin: gpio_rb_gen 94 always @(posedge clk) 95 gpio_sw_rb[i] <= gpio_ddr[i] ? gpio_out[i] : igpio[i]; 96 end endgenerate 97 98endmodule // gpio_atr 99