/*
 * spi_regs.v
 * State machine which handles reading and writing from the test registers.
 * Currently, the test bus width is hardcoded as 37 bits wide, generalize
 * later.
 * Autogenerated code from the register .csv definition file.
 */
module spi_reg(
	       // Register read signals
                o_dco_rd, o_dcycle_cal_0_rd, o_dcycle_cal_1_rd, o_dlc_rd,
                o_dlc_f2p_rd, o_dlc_iir_0_rd, o_dlc_iir_1_rd, o_dlc_iir_2_rd,
                o_dlc_iir_3_rd, o_dlc_pi_rd, o_dlc_qnc_rd, o_fdelta_cal_0_rd,
                o_fdelta_cal_1_rd, o_fdelta_lms_0_rd, o_fdelta_lms_1_rd,
                o_rfdc_0_rd, o_rfdc_1_rd, o_rfdc_state_0_rd, o_rfdc_state_1_rd,
	       // Register write signals
                o_dco_wr, o_dcycle_cal_0_wr, o_dcycle_cal_1_wr, o_dlc_wr,
                o_dlc_f2p_wr, o_dlc_iir_0_wr, o_dlc_iir_1_wr, o_dlc_iir_2_wr,
                o_dlc_iir_3_wr, o_dlc_pi_wr, o_dlc_qnc_wr, o_fdelta_cal_0_wr,
                o_fdelta_cal_1_wr, o_fdelta_lms_0_wr, o_fdelta_lms_1_wr,
                o_rfdc_0_wr, o_rfdc_1_wr, o_rfdc_state_0_wr, o_rfdc_state_1_wr,
	       // Inouts
	       vio_data_regs, io_success, vio_tbus,
	       // Inputs
	       i_rstb, i_clk_ext_osc, i_spi_active, vi_data_rx, i_rx_valid,
	       vi_byte_num);
  // This global variable defines the number of registers
  localparam NUM_REGS = 19;
  // Global reset
  input        i_rstb;
  // State machine clock
  input        i_clk_ext_osc;
  // SPI interface
  input        i_spi_active;
  input [7:0]  vi_data_rx;
  input        i_rx_valid;
  input [2:0]  vi_byte_num;
  inout [7:0]  vio_data_regs;
  // Test bus
  inout        io_success;
  inout [36:0] vio_tbus;
  // Register read and write controls
  output            o_dco_rd;
  output            o_dcycle_cal_0_rd;
  output            o_dcycle_cal_1_rd;
  output            o_dlc_rd;
  output            o_dlc_f2p_rd;
  output            o_dlc_iir_0_rd;
  output            o_dlc_iir_1_rd;
  output            o_dlc_iir_2_rd;
  output            o_dlc_iir_3_rd;
  output            o_dlc_pi_rd;
  output            o_dlc_qnc_rd;
  output            o_fdelta_cal_0_rd;
  output            o_fdelta_cal_1_rd;
  output            o_fdelta_lms_0_rd;
  output            o_fdelta_lms_1_rd;
  output            o_rfdc_0_rd;
  output            o_rfdc_1_rd;
  output            o_rfdc_state_0_rd;
  output            o_rfdc_state_1_rd;
  output            o_dco_wr;
  output            o_dcycle_cal_0_wr;
  output            o_dcycle_cal_1_wr;
  output            o_dlc_wr;
  output            o_dlc_f2p_wr;
  output            o_dlc_iir_0_wr;
  output            o_dlc_iir_1_wr;
  output            o_dlc_iir_2_wr;
  output            o_dlc_iir_3_wr;
  output            o_dlc_pi_wr;
  output            o_dlc_qnc_wr;
  output            o_fdelta_cal_0_wr;
  output            o_fdelta_cal_1_wr;
  output            o_fdelta_lms_0_wr;
  output            o_fdelta_lms_1_wr;
  output            o_rfdc_0_wr;
  output            o_rfdc_1_wr;
  output            o_rfdc_state_0_wr;
  output            o_rfdc_state_1_wr;
  /*
   * These vectors define the data mask for the test bus reads
   */
  reg [7:0]    rv_addr;
  reg [36:0] rv_rd_mask;
  always @( * ) begin
    case ( rv_addr )
      0 : rv_rd_mask = {{7{1'b0}},{30{1'b1}}};
      1 : rv_rd_mask = {{12{1'b0}},{25{1'b1}}};
      2 : rv_rd_mask = {37{1'b1}};
      3 : rv_rd_mask = {{17{1'b0}},{20{1'b1}}};
      4 : rv_rd_mask = {{9{1'b0}},{28{1'b1}}};
      5 : rv_rd_mask = {{7{1'b0}},{30{1'b1}}};
      6 : rv_rd_mask = {{12{1'b0}},{25{1'b1}}};
      7 : rv_rd_mask = {37{1'b1}};
      8 : rv_rd_mask = {{17{1'b0}},{20{1'b1}}};
      9 : rv_rd_mask = {{9{1'b0}},{28{1'b1}}};
      10 : rv_rd_mask = {{17{1'b0}},{20{1'b1}}};
      11 : rv_rd_mask = {{4{1'b0}},{33{1'b1}}};
      12 : rv_rd_mask = {{15{1'b0}},{22{1'b1}}};
      13 : rv_rd_mask = {{15{1'b0}},{22{1'b1}}};
      14 : rv_rd_mask = {{15{1'b0}},{22{1'b1}}};
      15 : rv_rd_mask = {{15{1'b0}},{22{1'b1}}};
      16 : rv_rd_mask = {{3{1'b0}},{34{1'b1}}};
      17 : rv_rd_mask = {{15{1'b0}},{22{1'b1}}};
      18 : rv_rd_mask = {{28{1'b0}},{9{1'b1}}};
      default : rv_rd_mask = {NUM_REGS{1'b0}};
    endcase // case ( rv_addr )
  end
  /*
   * These vectors define the number of bytes transmitted for the
   * corresponding register. In the MSB register, unused bits are 0
   * due to the data coming in the test bus being masked off.
   */
  reg [NUM_REGS-1:0] rv_num_rd_bytes;
  always @( * ) begin
    case ( rv_addr )
      0 : rv_num_rd_bytes = 4; // rfdc_state_0
      1 : rv_num_rd_bytes = 4; // fdelta_cal_0
      2 : rv_num_rd_bytes = 5; // fdelta_lms_0
      3 : rv_num_rd_bytes = 3; // dcycle_cal_0
      4 : rv_num_rd_bytes = 4; // rfdc_0
      5 : rv_num_rd_bytes = 4; // rfdc_state_1
      6 : rv_num_rd_bytes = 4; // fdelta_cal_1
      7 : rv_num_rd_bytes = 5; // fdelta_lms_1
      8 : rv_num_rd_bytes = 3; // dcycle_cal_1
      9 : rv_num_rd_bytes = 4; // rfdc_1
      10 : rv_num_rd_bytes = 3; // dlc_f2p
      11 : rv_num_rd_bytes = 5; // dlc_qnc
      12 : rv_num_rd_bytes = 3; // dlc_iir_0
      13 : rv_num_rd_bytes = 3; // dlc_iir_1
      14 : rv_num_rd_bytes = 3; // dlc_iir_2
      15 : rv_num_rd_bytes = 3; // dlc_iir_3
      16 : rv_num_rd_bytes = 5; // dlc_pi
      17 : rv_num_rd_bytes = 3; // dlc
      18 : rv_num_rd_bytes = 2; // dco
      default : rv_num_rd_bytes = 0;
    endcase // case ( rv_addr )
  end
  /*
   * This register groups all the _rd wires into a single bus, such that
   * rv_rd_bus[n] corresponds to the _rd wire associated with the register
   * at address n.
   */
  reg [NUM_REGS-1:0] rv_rd_tbus;
  assign o_rfdc_state_0_rd = rv_rd_tbus[0];
  assign o_fdelta_cal_0_rd = rv_rd_tbus[1];
  assign o_fdelta_lms_0_rd = rv_rd_tbus[2];
  assign o_dcycle_cal_0_rd = rv_rd_tbus[3];
  assign o_rfdc_0_rd = rv_rd_tbus[4];
  assign o_rfdc_state_1_rd = rv_rd_tbus[5];
  assign o_fdelta_cal_1_rd = rv_rd_tbus[6];
  assign o_fdelta_lms_1_rd = rv_rd_tbus[7];
  assign o_dcycle_cal_1_rd = rv_rd_tbus[8];
  assign o_rfdc_1_rd = rv_rd_tbus[9];
  assign o_dlc_f2p_rd = rv_rd_tbus[10];
  assign o_dlc_qnc_rd = rv_rd_tbus[11];
  assign o_dlc_iir_0_rd = rv_rd_tbus[12];
  assign o_dlc_iir_1_rd = rv_rd_tbus[13];
  assign o_dlc_iir_2_rd = rv_rd_tbus[14];
  assign o_dlc_iir_3_rd = rv_rd_tbus[15];
  assign o_dlc_pi_rd = rv_rd_tbus[16];
  assign o_dlc_rd = rv_rd_tbus[17];
  assign o_dco_rd = rv_rd_tbus[18];
  /*
   * This does the same for the _wr wires
   */
  reg [NUM_REGS-1:0] rv_wr_tbus;
  assign o_rfdc_state_0_wr = rv_wr_tbus[0];
  assign o_fdelta_cal_0_wr = rv_wr_tbus[1];
  assign o_fdelta_lms_0_wr = rv_wr_tbus[2];
  assign o_dcycle_cal_0_wr = rv_wr_tbus[3];
  assign o_rfdc_0_wr = rv_wr_tbus[4];
  assign o_rfdc_state_1_wr = rv_wr_tbus[5];
  assign o_fdelta_cal_1_wr = rv_wr_tbus[6];
  assign o_fdelta_lms_1_wr = rv_wr_tbus[7];
  assign o_dcycle_cal_1_wr = rv_wr_tbus[8];
  assign o_rfdc_1_wr = rv_wr_tbus[9];
  assign o_dlc_f2p_wr = rv_wr_tbus[10];
  assign o_dlc_qnc_wr = rv_wr_tbus[11];
  assign o_dlc_iir_0_wr = rv_wr_tbus[12];
  assign o_dlc_iir_1_wr = rv_wr_tbus[13];
  assign o_dlc_iir_2_wr = rv_wr_tbus[14];
  assign o_dlc_iir_3_wr = rv_wr_tbus[15];
  assign o_dlc_pi_wr = rv_wr_tbus[16];
  assign o_dlc_wr = rv_wr_tbus[17];
  assign o_dco_wr = rv_wr_tbus[18];
  /*
   * Local reset
   */
  wire 	       active = i_rstb && i_spi_active; 
  /*
   * This state machine simply captures the opcode on the arrival
   * of the first (0th) byte, and enables the oscillator
   */
  reg 	       r_read_tbus;
  reg 	       r_write_tbus;
  reg 	       r_clamp_success;
  always @( posedge i_rx_valid or negedge active ) begin : opcode_fsm
    if ( !active ) begin
      r_read_tbus <= 0;
      r_write_tbus <= 0;
      r_clamp_success <= 1;
    end else begin
      if ( 0 == vi_byte_num ) begin
	if ( 128 == vi_data_rx ) begin
	  r_write_tbus <= 1;
	  r_clamp_success <= 0;
	end
	if ( 192 == vi_data_rx ) begin
	  r_read_tbus <= 1;
	  r_clamp_success <= 0;
	end
      end
    end
  end // block: opcode_fsm
  assign io_success = r_clamp_success ? 1'b0 : 1'bz;
  /*
   * This state machine captures the address arriving on byte 1 regardless
   * of whether the register interface is active or not.
   */
  always @( posedge i_rx_valid or negedge active ) begin : address_fsm
    if ( !active ) begin
      rv_addr <= 0;
    end else begin
      if ( 1 == vi_byte_num )
	rv_addr <= vi_data_rx;
    end
  end
  /*
   * This state machine handles register reads. When the address is loaded,
   * ena_reg_read triggers the state machine clocked by the internal oscillator
   * The data which is read from the test bus is then serialized out one
   * byte at a time, from the LSB chunk to the MSB chunk.
   * The shadow byte is initialized to an invalid value (7) which makes
   * the output mux drive a 0.
   */
  reg [2:0]  rv_shadow_byte;
  reg [7:0]  rv_reg2spi;
  reg 	     r_ena_reg_read;
  always @( posedge i_rx_valid or negedge active ) begin : read_fsm
    if ( !active ) begin
      rv_shadow_byte <= 7;
      r_ena_reg_read <= 0;
    end else begin
      if (( 1 == vi_byte_num ) && r_read_tbus )
	r_ena_reg_read <= 1;
      if ( rv_num_rd_bytes >= vi_byte_num )
	rv_shadow_byte <= vi_byte_num - 1;
      else
	rv_shadow_byte <= 7;
    end
  end
  // The byte of the shadow register is addressed by the byte number
  reg [36:0] rv_read_shadow;
  always @( * ) begin
    case ( rv_shadow_byte )
      0 : rv_reg2spi = rv_read_shadow[7:0];
      1 : rv_reg2spi = rv_read_shadow[15:8];
      2 : rv_reg2spi = rv_read_shadow[23:16];
      3 : rv_reg2spi = rv_read_shadow[31:24];
      4 : rv_reg2spi = {3'b000,rv_read_shadow[36:32]};
      default : rv_reg2spi = 0;
    endcase // case ( rv_shadow_byte )
  end
  /*
   * This state machine handles parallelizing the byte-widge chunks coming
   * from the SPI into the full 37 bit test bus vector. When the parallel
   * shadow bus is loaded, ena_reg_write is raised which initiates the state
   * machine clocked by the internal oscillator.
   */
  reg [36:0] rv_write_shadow;
  reg 	     r_ena_reg_write;
  reg 	     r_ser2par_done;
  always @( posedge i_rx_valid or negedge active ) begin : write_fsm
    if ( ! active ) begin
      r_ena_reg_write <= 0;
      r_ser2par_done <= 0;
      rv_write_shadow <= 0;
    end else begin
      if ( !r_ser2par_done ) begin
	// Serialize the data while the byte number is within the register size
	if ( 2 == vi_byte_num )
	  rv_write_shadow[7:0] <= vi_data_rx;
	if ( 3 == vi_byte_num )
	  rv_write_shadow[15:8] <= vi_data_rx;
	if ( 4 == vi_byte_num )
	  rv_write_shadow[23:16] <= vi_data_rx;
	if ( 5 == vi_byte_num )
	  rv_write_shadow[31:24] <= vi_data_rx;
	if ( 6 == vi_byte_num )
	  rv_write_shadow[36:32] <= vi_data_rx[4:0];
	if ( rv_num_rd_bytes < vi_byte_num ) begin
	  // When enough bytes are loaded, stop loading data
	  r_ser2par_done <= 1;
	  r_ena_reg_write <= r_write_tbus;
	end
      end
    end
  end
  /*
   * This state machine is clocked on the external oscillator. It
   * sends the appropriate _rd signal, waits for the success line to go
   * high, then latches the data on the test bus to the shadow register
   */
  reg [1:0] rv_rd_state;
  localparam READ_IDLE = 0;
  localparam READ_WAIT = 1;
  localparam READ_DONE = 2;
  always @( posedge i_clk_ext_osc or negedge active ) begin
    if ( !active ) begin
      rv_read_shadow <= 0;
      rv_rd_tbus <= 0;
      rv_rd_state <= READ_IDLE;
    end else begin
      if (( READ_IDLE == rv_rd_state ) && r_ena_reg_read ) begin
	// A read was just initiated, and we need to send the right _rd
	rv_rd_tbus[rv_addr] <= 1;
	rv_rd_state <= READ_WAIT;
      end
      if (( READ_WAIT == rv_rd_state ) && io_success ) begin
	// The read had been initiated, and now data has appeared on the bus
	rv_read_shadow <= vio_tbus & rv_rd_mask;
	rv_rd_tbus <= 0;
	rv_rd_state <= READ_DONE;
      end
      if ( READ_DONE == rv_rd_state ) begin
	// Wait here forever until SPI goes inactive again
	rv_rd_tbus <= 0;
	rv_rd_state <= READ_DONE;
      end
    end
  end
  /*
   * This state machine handles writing data to the register interface
   */
  reg [1:0] rv_wr_state;
  localparam WRITE_IDLE = 0;
  localparam WRITE_WAIT = 1;
  localparam WRITE_DONE = 2;
  always @( posedge i_clk_ext_osc or negedge active ) begin
    if ( !active ) begin
      rv_wr_tbus <= 0;
      rv_wr_state <= WRITE_IDLE;
    end else begin
      if (( WRITE_IDLE == rv_wr_state ) && r_ena_reg_write ) begin
	// A write was just initiated, now send the right _wr and wait
	rv_wr_tbus[rv_addr] <= 1;
	rv_wr_state <= WRITE_WAIT;
      end
      if (( WRITE_WAIT == rv_wr_state ) && io_success ) begin
	// The success signal indicates the data on vio_tbus was latched in
	rv_wr_tbus <= 0;
	rv_wr_state <= WRITE_DONE;
      end
      if ( WRITE_DONE == rv_wr_state ) begin
	// Stay here until bus resets
	rv_wr_tbus <= 0;
	rv_wr_state <= WRITE_DONE;
      end
    end
  end
  /*
   * Tristate bus driver: drive the test bus when in register write mode,
   * otherwise leave it floating.
   */
  assign vio_tbus = r_write_tbus ? rv_write_shadow : 37'bz;
  /*
   * Tristate bus driver: only drive data back to SPI when we are in
   * register read mode, otherwise float bus.
   */
  assign vio_data_regs = r_read_tbus ? rv_reg2spi : 8'bz;
endmodule // spi_regs
