///////////////////////////////////////////////////////////////////
//
// Copyright 2018 Ettus Research, A National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: rhodium_top
//////////////////////////////////////////////////////////////////////

`default_nettype none

module rhodium_top(

input [13:0] usrp_io, // bank 1A, 1B and 6

input ADC_A_Over_Range_18, input ADC_B_Over_Range_18, // bank 1A

// bank 6
input      CPLD_PS_SPI_LE_25,
input      CPLD_PS_SPI_CLK_25,
input      CPLD_PS_ADDR0_25,
input      CPLD_PS_ADDR1_25,
input      CPLD_PS_SPI_SDI_25,
output reg CPLD_PS_SPI_SDO_25,
output     PHDAC_SPI_CS_L,
output     PHDAC_SPI_SCLK,
output     PHDAC_SPI_SDI,
input      LO_SYNC,

// bank 2
output reg CPLD_PL_SPI_SDO_18,
input      CPLD_PL_SPI_LE_18,
input      CPLD_PL_SPI_SCLK_18,
input      CPLD_PL_SPI_SDI_18,
input      CPLD_PL_SPI_ADDR0_18,
input      CPLD_PL_SPI_ADDR1_18,
input      CPLD_PL_SPI_ADDR2_18,
// NOTE: TxRx front-end switches are driven direct from the motherboard, so these ATR 
//       lines have no function at this time.
input      CPLD_ATR_TX_18,
input      CPLD_ATR_RX_18,
output     ADC_SPI_CS_L_18,
output     ADC_SPI_SCLK_18,
inout      ADC_SPI_SDIO_18,
output     DAC_SPI_CS_L_18,
output     DAC_SPI_SCLK_18,
inout      DAC_SPI_SDIO_18,
input      DAC_Alarm_18, // TODO: drive to gpio?

// bank 3

output     CLKDIST_SPI_CS_L,
output     CLKDIST_SPI_SCLK,
inout      CLKDIST_SPI_SDIO,
output     Tx_DSA_C1,
output     Tx_DSA_C2,
output     Tx_DSA_C4,
output     Tx_DSA_C8,
output     Tx_DSA_C16,
output     Tx_DSA1_LE,
output     Tx_DSA2_LE,
output     Tx_Sw1_Ctrl_1,
output     Tx_Sw1_Ctrl_2,
output     Tx_Sw2_Ctrl_1,
output     Tx_Sw2_Ctrl_2,
output     Tx_Sw3_Ctrl_1,
output     Tx_Sw3_Ctrl_2,
output     Tx_Sw3_Ctrl_3,
output     Tx_Sw3_Ctrl_4,
output     Rx_LO_Input_Select,
output     Rx_LO_Filter_Sw_1,
output     Rx_LO_Filter_Sw_2,
output     Tx_LO_Input_Select,
output     Tx_LO_Filter_Sw_1,
output     Tx_LO_Filter_Sw_2,
input      CLKDIST_Status_LD1,
input      CLKDIST_Status_LD2,
input      LOSYNTH_RX_MUXOUT,
input      LOSYNTH_TX_MUXOUT,

// bank 8
output     LO_SPI_SCLK, // fans out to both rx & tx synths
output     LO_SPI_SDI,
output     LO_TX_CS_L,
output     LO_RX_CS_L,
output     Rx_Sw1_Ctrl_1,
output     Rx_Sw1_Ctrl_2,
output     Rx_DSA_C1,
output     Rx_DSA_C2,
output     Rx_DSA_C4,
output     Rx_DSA_C8,
output     Rx_DSA_C16,
output     Rx_DSA1_LE,
output     Rx_DSA2_LE,
output     Rx_Sw2_Ctrl,
output     Rx_Sw3_Ctrl_1,
output     Rx_Sw3_Ctrl_2,
output     Rx_Sw4_Ctrl_1,
output     Rx_Sw4_Ctrl_2,
output     Rx_Sw4_Ctrl_3,
output     Rx_Sw4_Ctrl_4,
output     Rx_Demod_ADJ_1,
output     Rx_Demod_ADJ_2,

// bank 5
output     LO_DSA_C1,
output     LO_DSA_C2,
output     LO_DSA_C4,
output     LO_DSA_C8,
output     LO_DSA_C16,
output     RxLO_DSA_LE,
output     TxLO_DSA_LE,
output     LODIST_Bd_SPI_CS_L,
output     LODIST_Bd_SPI_SDI,
output     LODIST_Bd_SPI_SCLK,
inout      LODIST_Bd_IO1,
output     Tx_Sw5_Ctrl_1,
output     Tx_Sw5_Ctrl_2,
output     Rx_Sw6_Ctrl_1,
output     Rx_Sw6_Ctrl_2,

output    Tx_HB_LB_Select,
output    Rx_HB_LB_Select,
output    Cal_iso_Sw_Ctrl


);

/* PS SPI */

localparam GIT_HASH = `GIT_HASH;
localparam PROD_SIGNATURE   = 16'h0045; // Product signature (Rhodium atomic number in BCD)
localparam REVISION_MINOR   = 16'h0003;
localparam REVISION_MAJOR   = 16'h0004;
localparam CPLD_BUILD_LSB   = GIT_HASH[15:0]; // Build code LSB
localparam CPLD_BUILD_MSB   = GIT_HASH[31:16]; // Build code MSB
localparam PSADDR_SIGNATURE = 3'd0;
localparam PSADDR_REV_MINOR = 3'd1; // Minor version register
localparam PSADDR_REV_MAJOR = 3'd2; // Major version register
localparam PSADDR_BUILD_LSB = 3'd3;
localparam PSADDR_BUILD_MSB = 3'd4;
localparam PSADDR_SCRATCH   = 3'd5; // scratchpad register
localparam PSADDR_GAIN_SEL  = 3'd6; // band select for gain table loader
localparam PSADDR_DAC_ALARM = 3'd7; // DAC alarm pin register

// Sub-device selection for PS SPI
localparam PS_CPLD_REGS   = 2'b00;
localparam GAIN_TABLE_RX  = 2'b01;
localparam GAIN_TABLE_TX  = 2'b10;
localparam GAIN_TABLE_LO  = 2'b11;

// Setting to put TX SW1 in isolation mode
localparam [1:0] TX_SW1_TERM = 2'b11;

wire clkdis_cs_b = CPLD_PS_SPI_LE_25;
wire cpld_ps_cs_b = CPLD_PS_ADDR0_25;
wire phdac_cs_b = CPLD_PS_ADDR1_25;
wire adc_cs_b = usrp_io[12];
wire dac_cs_b = usrp_io[13];

// CPLD PS SPI format (left-most bit first):
// {table_sel[1:0], rsvd, reg_addr[3:0], rnw, data[15:0]}
wire [1:0] cpld_ps_table_sel;
wire [6:0] cpld_ps_spi_addr;
wire cpld_ps_spi_rnw;
reg [7:0] cpld_ps_spi_cmd;
reg [15:0] cpld_ps_spi_rdata;
reg [14:0] cpld_ps_spi_wdata;
reg cpld_ps_spi_sdo;
reg [4:0] cpld_ps_cnt;

assign {cpld_ps_spi_addr, cpld_ps_spi_rnw} = cpld_ps_spi_cmd;

// CPLD registers
reg [15:0] spad;
reg [15:0] gain_load_sel;

// Double sync. the DAC ALARM pin (async).
reg dac_alarm_ms, dac_alarm = 0;
always @(posedge CPLD_PS_SPI_CLK_25) begin
  {dac_alarm, dac_alarm_ms} <= {dac_alarm_ms, DAC_Alarm_18};
end

wire rx_gain_load_tbl_sel;
wire rx_gain_load_miso;
wire rx_gain_ctrl_tbl_sel;
wire rx_gain_ctrl_miso;
wire tx_gain_load_tbl_sel;
wire tx_gain_load_miso;
wire tx_gain_ctrl_tbl_sel;
wire tx_gain_ctrl_miso;
wire lo_gain_ctrl_miso;

assign rx_gain_load_tbl_sel = gain_load_sel[0];
assign tx_gain_load_tbl_sel = gain_load_sel[8];

always @(posedge CPLD_PS_SPI_CLK_25 or posedge cpld_ps_cs_b)
begin
  if (cpld_ps_cs_b) begin
    cpld_ps_cnt <= 5'd0;
  end else if (!cpld_ps_cs_b) begin
    if (cpld_ps_cnt < 8) begin // Address / command
      cpld_ps_spi_cmd <= {cpld_ps_spi_cmd[6:0], CPLD_PS_SPI_SDI_25};
      cpld_ps_cnt <= cpld_ps_cnt + 5'd1;
    end else if (cpld_ps_cnt < 23) begin // Shift in write data
      cpld_ps_spi_wdata <= {cpld_ps_spi_wdata[13:0], CPLD_PS_SPI_SDI_25};
      cpld_ps_cnt <= cpld_ps_cnt + 5'd1;
    end else if (!cpld_ps_spi_rnw && cpld_ps_cnt == 23 && cpld_ps_spi_addr[6:5] == PS_CPLD_REGS) begin // Write
      case (cpld_ps_spi_addr[2:0])
      PSADDR_SIGNATURE: ;
      PSADDR_REV_MINOR: ;
      PSADDR_REV_MAJOR: ;
      PSADDR_BUILD_LSB: ;
      PSADDR_BUILD_MSB: ;
      PSADDR_SCRATCH:   spad <= {cpld_ps_spi_wdata, CPLD_PS_SPI_SDI_25};
      PSADDR_GAIN_SEL:  gain_load_sel <= {cpld_ps_spi_wdata, CPLD_PS_SPI_SDI_25};
      endcase
    end
    if (cpld_ps_cnt == 7) begin // Set up read one cycle earlier
      case (cpld_ps_spi_cmd[2:0])

      PSADDR_SIGNATURE: cpld_ps_spi_rdata <= PROD_SIGNATURE;
      PSADDR_REV_MINOR: cpld_ps_spi_rdata <= REVISION_MINOR;
      PSADDR_REV_MAJOR: cpld_ps_spi_rdata <= REVISION_MAJOR;
      PSADDR_BUILD_LSB: cpld_ps_spi_rdata <= CPLD_BUILD_LSB;
      PSADDR_BUILD_MSB: cpld_ps_spi_rdata <= CPLD_BUILD_MSB;
      PSADDR_SCRATCH:   cpld_ps_spi_rdata <= spad;
      PSADDR_GAIN_SEL:  cpld_ps_spi_rdata <= gain_load_sel;
      PSADDR_DAC_ALARM: cpld_ps_spi_rdata <= {15'b0, dac_alarm};
      endcase
    end else begin
      cpld_ps_spi_rdata <= {cpld_ps_spi_rdata[14:0], 1'b1};
    end
  end
end

always @(negedge CPLD_PS_SPI_CLK_25)
begin
  cpld_ps_spi_sdo <= cpld_ps_spi_rdata[15]; // Shift out on negative edge
end

// CLKDIST 3-wire to 4-wire
reg [4:0] clkdis_cnt;
reg       clkdis_rd_pre, clkdis_rd, clkdis_sdio_t;

always @(posedge CPLD_PS_SPI_CLK_25 or posedge clkdis_cs_b)
begin
  if (clkdis_cs_b) begin
    clkdis_cnt <= 5'd0;
    clkdis_rd <= 1'b0;
    clkdis_rd_pre <= 1'b0;
  end else if (!clkdis_cs_b) begin
    if (clkdis_cnt < 23)
      clkdis_cnt <= clkdis_cnt + 5'd1;

    if (clkdis_cnt == 5'd0) // Check if read
      clkdis_rd_pre <= CPLD_PS_SPI_SDI_25;

    if (clkdis_cnt == 5'd15)
      clkdis_rd <= clkdis_rd_pre;
  end
end

always @(negedge CPLD_PS_SPI_CLK_25 or posedge clkdis_cs_b)
begin
  if (clkdis_cs_b) begin
    clkdis_sdio_t <= 1'b0;
  end else begin
    clkdis_sdio_t <= clkdis_rd;
  end
end

// ADC 3-wire to 4-wire
reg [4:0] adc_cnt;
reg       adc_rd_pre, adc_rd, adc_sdio_t;

always @(posedge CPLD_PS_SPI_CLK_25 or posedge adc_cs_b)
begin
  if (adc_cs_b) begin
    adc_cnt <= 5'd0;
    adc_rd <= 1'b0;
    adc_rd_pre <= 1'b0;
  end else if (!adc_cs_b) begin
    if (adc_cnt < 23)
      adc_cnt <= adc_cnt + 5'd1;

    if (adc_cnt == 5'd0) // Check if read
      adc_rd_pre <= CPLD_PS_SPI_SDI_25;

    if (adc_cnt == 5'd15)
      adc_rd <= adc_rd_pre;
  end
end

always @(negedge CPLD_PS_SPI_CLK_25 or posedge adc_cs_b)
begin
  if (adc_cs_b) begin
    adc_sdio_t <= 1'b0;
  end else begin
    adc_sdio_t <= adc_rd;
  end
end

// DAC 3-wire to 4-wire
reg [4:0] dac_cnt;
reg       dac_rd_pre, dac_rd, dac_sdio_t;

always @(posedge CPLD_PS_SPI_CLK_25 or posedge dac_cs_b)
begin
  if (dac_cs_b) begin
    dac_cnt <= 5'd0;
    dac_rd <= 1'b0;
    dac_rd_pre <= 1'b0;
  end else if (!dac_cs_b) begin
    if (dac_cnt < 23)
      dac_cnt <= dac_cnt + 5'd1;

    if (dac_cnt == 5'd0) // Check if read
      dac_rd_pre <= CPLD_PS_SPI_SDI_25;

    if (dac_cnt == 5'd7)
      dac_rd <= dac_rd_pre;
  end
end

always @(negedge CPLD_PS_SPI_CLK_25 or posedge dac_cs_b)
begin
  if (dac_cs_b) begin
    dac_sdio_t <= 1'b0;
  end else begin
    dac_sdio_t <= dac_rd;
  end
end

// multiplexed slave device SPI ports
wire phdac_sck, phdac_sdi; 
wire clkdis_sck, adc_sck, dac_sck;
assign clkdis_sck = (clkdis_cs_b == 1'b0) ? CPLD_PS_SPI_CLK_25 : 1'b0;

assign CLKDIST_SPI_CS_L = clkdis_cs_b;  
assign CLKDIST_SPI_SCLK = clkdis_sck;

assign adc_sck = !adc_cs_b ? CPLD_PS_SPI_CLK_25 : 1'b0;
assign dac_sck = !dac_cs_b ? CPLD_PS_SPI_CLK_25 : 1'b0;

assign ADC_SPI_CS_L_18 = adc_cs_b;
assign ADC_SPI_SCLK_18 = adc_sck;

assign DAC_SPI_CS_L_18 = dac_cs_b;
assign DAC_SPI_SCLK_18 = dac_sck;

assign CLKDIST_SPI_SDIO = (!clkdis_sdio_t && !clkdis_cs_b) ? CPLD_PS_SPI_SDI_25 : 1'bz ;
assign ADC_SPI_SDIO_18  = (!adc_sdio_t && !adc_cs_b)       ? CPLD_PS_SPI_SDI_25 : 1'bz ;
assign DAC_SPI_SDIO_18  = (!dac_sdio_t && !dac_cs_b)       ? CPLD_PS_SPI_SDI_25 : 1'bz ;

always @(*)
begin
  CPLD_PS_SPI_SDO_25 = 1'b1;
  case ({cpld_ps_cs_b, clkdis_cs_b, adc_cs_b, dac_cs_b})
  4'b0111: begin
    case (cpld_ps_spi_addr[6:5])
    PS_CPLD_REGS : CPLD_PS_SPI_SDO_25 = cpld_ps_spi_sdo;
    GAIN_TABLE_RX: CPLD_PS_SPI_SDO_25 = rx_gain_load_miso;
    GAIN_TABLE_TX: CPLD_PS_SPI_SDO_25 = tx_gain_load_miso;
    GAIN_TABLE_LO: CPLD_PS_SPI_SDO_25 = 1'b1;
    endcase
  end
  4'b1011: CPLD_PS_SPI_SDO_25 = CLKDIST_SPI_SDIO;
  4'b1101: CPLD_PS_SPI_SDO_25 = ADC_SPI_SDIO_18;
  4'b1110: CPLD_PS_SPI_SDO_25 = DAC_SPI_SDIO_18;
  default: ;
  endcase
end  

// note: no readback from PHDAC
assign phdac_sck = (phdac_cs_b == 1'b0) ? CPLD_PS_SPI_CLK_25 : 1'b0;
assign phdac_sdi = (phdac_cs_b == 1'b0) ? CPLD_PS_SPI_SDI_25 : 1'b1;


assign PHDAC_SPI_SCLK = phdac_sck;
assign PHDAC_SPI_CS_L = phdac_cs_b;
assign PHDAC_SPI_SDI = phdac_sdi;


/* PL SPI */ 
// CPLD PL SPI format (left-most bit first):
// {table_sel[1:0], reg_addr[4:0], rnw, data[15:0]}

//TXLO, RXLO, LODIS, CPLD
localparam PLADDR_SCRATCH = 4'b0101; // scratchpad register
localparam PLADDR_RXBS    = 4'b0110;
localparam PLADDR_TXBS    = 4'b0111;
localparam PLADDR_RFCTRL  = 4'b1000;
localparam PL_CPLD_REGS   = 2'b00;

// CPLD PL registers
reg [15:0] rxbs = 'h0;
reg [15:0] txbs = 'h0;
reg [15:0] rfctrl = 'h0;

// register address on the falling edge of chip-select
wire txlo_cs_b    = CPLD_PL_SPI_LE_18;
wire rxlo_cs_b    = CPLD_PL_SPI_ADDR1_18;
wire lodis_cs_b   = CPLD_PL_SPI_ADDR2_18;
wire cpld_pl_cs_b = CPLD_PL_SPI_ADDR0_18;

wire cpld_pl_spi_rnw;
wire [6:0] cpld_pl_spi_addr;
reg [7:0] cpld_pl_spi_cmd;
reg [15:0] cpld_pl_spi_rdata;
reg [14:0] cpld_pl_spi_wdata;
reg cpld_pl_spi_sdo;
reg [4:0] cpld_pl_cnt;

assign {cpld_pl_spi_addr, cpld_pl_spi_rnw} = cpld_pl_spi_cmd;

reg [15:0] pl_spad;

always @(posedge CPLD_PL_SPI_SCLK_18 or posedge cpld_pl_cs_b)
begin
  if (cpld_pl_cs_b) begin
    cpld_pl_cnt <= 5'd0;
  end else if (!cpld_pl_cs_b) begin
    if (cpld_pl_cnt < 8) begin // Address / command
      cpld_pl_spi_cmd <= {cpld_pl_spi_cmd[6:0], CPLD_PL_SPI_SDI_18};
      cpld_pl_cnt <= cpld_pl_cnt + 5'd1;
    end else if (cpld_pl_cnt < 23) begin // Shift in write data
      cpld_pl_spi_wdata <= {cpld_pl_spi_wdata[13:0], CPLD_PL_SPI_SDI_18};
      cpld_pl_cnt <= cpld_pl_cnt + 5'd1;
    end else if (!cpld_pl_spi_rnw && cpld_pl_cnt == 23 && cpld_pl_spi_addr[6:5] == PL_CPLD_REGS) begin // Write
      case (cpld_pl_spi_addr[3:0])
      PLADDR_SCRATCH: pl_spad <= {cpld_pl_spi_wdata, CPLD_PL_SPI_SDI_18};
      PLADDR_RXBS:    rxbs    <= {cpld_pl_spi_wdata, CPLD_PL_SPI_SDI_18};
      PLADDR_TXBS:    txbs    <= {cpld_pl_spi_wdata, CPLD_PL_SPI_SDI_18};
      PLADDR_RFCTRL:  rfctrl  <= {cpld_pl_spi_wdata, CPLD_PL_SPI_SDI_18};
      endcase
    end
    if (cpld_pl_cnt == 7) begin // Set up read one cycle earlier
      case (cpld_pl_spi_cmd[3:0])
      PLADDR_SCRATCH: cpld_pl_spi_rdata <= pl_spad;
      PLADDR_RXBS:    cpld_pl_spi_rdata <= rxbs;
      PLADDR_TXBS:    cpld_pl_spi_rdata <= txbs;
      PLADDR_RFCTRL:  cpld_pl_spi_rdata <= rfctrl;
      endcase
    end else begin
      cpld_pl_spi_rdata <= {cpld_pl_spi_rdata[14:0], 1'b1};
    end
  end
end

always @(negedge CPLD_PL_SPI_SCLK_18)
begin
  cpld_pl_spi_sdo <= cpld_pl_spi_rdata[15]; // Shift out on negative edge
end

// multiplexed slave device SPI ports, names aliased to protect the innocent
wire lo_sck, lodis_sck;
wire lo_sdi, lodis_sdi;
// Note: lo_sck and lo_sdi -> fan out to both rxlo and txlo synths

assign { LO_TX_CS_L, LO_RX_CS_L } = { txlo_cs_b, rxlo_cs_b};
assign LO_SPI_SCLK = lo_sck;
assign LO_SPI_SDI = lo_sdi;


assign LODIST_Bd_SPI_CS_L = lodis_cs_b;
assign LODIST_Bd_SPI_SDI = lodis_sdi;
assign LODIST_Bd_SPI_SCLK = lodis_sck;


assign lodis_sck = !lodis_cs_b ? CPLD_PL_SPI_SCLK_18 : 1'b0;
assign lodis_sdi = !lodis_cs_b ? CPLD_PL_SPI_SDI_18 : 1'b1;

assign { lo_sck, lo_sdi } = (!txlo_cs_b | !rxlo_cs_b) ? {CPLD_PL_SPI_SCLK_18,CPLD_PL_SPI_SDI_18} : 2'b01;

	 
always @(*)
begin
  CPLD_PL_SPI_SDO_18 = 1'bz;
  case ({cpld_pl_cs_b, txlo_cs_b, rxlo_cs_b})
  3'b110: CPLD_PL_SPI_SDO_18 = LOSYNTH_RX_MUXOUT;
  3'b101: CPLD_PL_SPI_SDO_18 = LOSYNTH_TX_MUXOUT; 
  3'b011: begin
    case (cpld_pl_spi_addr[6:5])
    PL_CPLD_REGS : CPLD_PL_SPI_SDO_18 = cpld_pl_spi_sdo;
    GAIN_TABLE_RX: CPLD_PL_SPI_SDO_18 = rx_gain_ctrl_miso;
    GAIN_TABLE_TX: CPLD_PL_SPI_SDO_18 = tx_gain_ctrl_miso;
    GAIN_TABLE_LO: CPLD_PL_SPI_SDO_18 = lo_gain_ctrl_miso;
    endcase
  end
  default: ;
  endcase
end  

assign rx_gain_ctrl_tbl_sel = rxbs[12];
assign { Rx_Sw6_Ctrl_2,
         Rx_Sw6_Ctrl_1,
         Rx_Sw4_Ctrl_4,
         Rx_Sw4_Ctrl_3,
         Rx_Sw4_Ctrl_2,
         Rx_Sw4_Ctrl_1,
         Rx_Sw3_Ctrl_2,
         Rx_Sw3_Ctrl_1,
         Rx_Sw2_Ctrl,
         Rx_Sw1_Ctrl_2,
         Rx_Sw1_Ctrl_1	} = { rxbs[11:1] };

assign tx_gain_ctrl_tbl_sel = txbs[12];
assign { Tx_Sw5_Ctrl_2,
         Tx_Sw5_Ctrl_1,
         Tx_Sw3_Ctrl_4,
         Tx_Sw3_Ctrl_3,
         Tx_Sw3_Ctrl_2,
         Tx_Sw3_Ctrl_1,
         Tx_Sw2_Ctrl_2,
         Tx_Sw2_Ctrl_1} = { txbs[11:4] };

// Terminate TX when idle
assign {Tx_Sw1_Ctrl_2, Tx_Sw1_Ctrl_1} = CPLD_ATR_TX_18 ? txbs[3:2] : TX_SW1_TERM;

assign { Rx_LO_Filter_Sw_2,
  Rx_LO_Filter_Sw_1,
  Tx_LO_Filter_Sw_2,
  Tx_LO_Filter_Sw_1,
  Rx_Demod_ADJ_1,
  Rx_Demod_ADJ_2, 
  Rx_LO_Input_Select } = rfctrl[15:9];

assign { Rx_HB_LB_Select,
  Tx_LO_Input_Select } = rfctrl[7:6];

assign { Tx_HB_LB_Select,
  Cal_iso_Sw_Ctrl } 
  = { rfctrl[4:3] };
  

// RX Gain Table
wire [4:0] rx_dsa;

rhodium_gain_ctrl #(
  .TABLE_NUM(GAIN_TABLE_RX)
) rx_gain_table (
  .load_table_sel(rx_gain_load_tbl_sel),
  .load_sck(CPLD_PS_SPI_CLK_25),
  .load_csb(cpld_ps_cs_b),
  .load_mosi(CPLD_PS_SPI_SDI_25),
  .load_miso(rx_gain_load_miso),
  .ctrl_table_sel(rx_gain_ctrl_tbl_sel),
  .ctrl_sck(CPLD_PL_SPI_SCLK_18),
  .ctrl_csb(cpld_pl_cs_b),
  .ctrl_mosi(CPLD_PL_SPI_SDI_18),
  .ctrl_miso(rx_gain_ctrl_miso),
  .dsa(rx_dsa),
  .dsa1_le(Rx_DSA1_LE),
  .dsa2_le(Rx_DSA2_LE)
);

// TX Gain Table
wire [4:0] tx_dsa;

rhodium_gain_ctrl #(
  .TABLE_NUM(GAIN_TABLE_TX)
) tx_gain_table (
  .load_table_sel(tx_gain_load_tbl_sel),
  .load_sck(CPLD_PS_SPI_CLK_25),
  .load_csb(cpld_ps_cs_b),
  .load_mosi(CPLD_PS_SPI_SDI_25),
  .load_miso(tx_gain_load_miso),
  .ctrl_table_sel(tx_gain_ctrl_tbl_sel),
  .ctrl_sck(CPLD_PL_SPI_SCLK_18),
  .ctrl_csb(cpld_pl_cs_b),
  .ctrl_mosi(CPLD_PL_SPI_SDI_18),
  .ctrl_miso(tx_gain_ctrl_miso),
  .dsa(tx_dsa),
  .dsa1_le(Tx_DSA1_LE),
  .dsa2_le(Tx_DSA2_LE)
);

// LO Gain Table
wire [4:0] lo_dsa;

rhodium_lo_gain #(
  .TABLE_NUM(GAIN_TABLE_LO)
) lo_gain_table (
  .ctrl_sck(CPLD_PL_SPI_SCLK_18),
  .ctrl_csb(cpld_pl_cs_b),
  .ctrl_mosi(CPLD_PL_SPI_SDI_18),
  .ctrl_miso(lo_gain_ctrl_miso),
  .dsa(lo_dsa),
  .dsa1_le(RxLO_DSA_LE),
  .dsa2_le(TxLO_DSA_LE)
);

// Rx data shared by DSA1, DSA2
assign  { Rx_DSA_C16, Rx_DSA_C8, Rx_DSA_C4, Rx_DSA_C2, Rx_DSA_C1 } = rx_dsa;

// Tx data shared by DSA1, DSA2	
assign  { Tx_DSA_C16, Tx_DSA_C8, Tx_DSA_C4, Tx_DSA_C2, Tx_DSA_C1 } = tx_dsa;

// data shared by both tx and rx lo DSAs	
assign  { LO_DSA_C16, LO_DSA_C8, LO_DSA_C4, LO_DSA_C2, LO_DSA_C1 } =  lo_dsa;

endmodule
`default_nettype wire

