//  Control Unit:  Talks to outside world (uP interface) and stores
//  data for the rest of the chip.  Has interfaces to fifo, spreader,
//  and FIR filter.
// 
//  Author:  Andrew Iverson
//  Date: 12-10-99
//
//--------------------------------------------------------------------


module control(addr, data_inout, cs, rd_strobe, wr_strobe,
	       tap_config_i, tap_config_q, last_tap_i, last_tap_q,
	       fifo_data, push_en, push_clk, fir_data, fir_addr,
	       fir_en, n_reset);

  input [3:0] addr;
  input cs, rd_strobe, wr_strobe;
  inout [7:0] data_inout;
  output [31:0] tap_config_i, tap_config_q;
  output [4:0] last_tap_i, last_tap_q;
  output [7:0] fifo_data;
  output push_en, push_clk;
  input n_reset;
  output [11:0] fir_data;
  output [7:0] fir_addr;
  output fir_en;

  reg [11:0] fir_data;
  reg [7:0] fir_addr;

  reg [7:0] data_out;

  reg [31:0] tap_config_i, tap_config_q;
  reg [4:0] last_tap_i, last_tap_q;
  reg [7:0] temp_fifo_data;

  parameter config_i_addr_1 = 4'h0;
  parameter config_i_addr_2 = 4'h1;
  parameter config_i_addr_3 = 4'h2;
  parameter config_i_addr_4 = 4'h3;
  parameter config_q_addr_1 = 4'h4;
  parameter config_q_addr_2 = 4'h5;
  parameter config_q_addr_3 = 4'h6;
  parameter config_q_addr_4 = 4'h7;
  parameter last_i_addr = 4'h8;
  parameter last_q_addr = 4'h9;
  parameter fifo_data_addr = 4'hA;
  parameter fir_low8_addr = 4'hB;
  parameter fir_high4_addr = 4'hC;
  parameter fir_addr_addr = 4'hD;


  assign push_en = (addr == fifo_data_addr);
  assign push_clk = wr_strobe;
  assign fifo_data = temp_fifo_data;

  assign fir_en = (addr == fir_addr_addr);
	
  assign data_inout = (!cs && !rd_strobe) ? data_out : 8'bzzzzzzzz;

  always @ (negedge rd_strobe or negedge n_reset)
  begin
    if (!n_reset)
      data_out <= 8'b0;
    else
    begin
      case (addr)
        config_i_addr_1:  data_out <= tap_config_i[31:24]; 
        config_i_addr_2:  data_out <= tap_config_i[23:16]; 
        config_i_addr_3:  data_out <= tap_config_i[15:8]; 
        config_i_addr_4:  data_out <= tap_config_i[7:0]; 
        config_q_addr_1:  data_out <= tap_config_q[31:24]; 
        config_q_addr_2:  data_out <= tap_config_q[23:16]; 
        config_q_addr_3:  data_out <= tap_config_q[15:8]; 
        config_q_addr_4:  data_out <= tap_config_q[7:0]; 
        last_i_addr: data_out <= last_tap_i;
        last_q_addr: data_out <= last_tap_q;
        fifo_data_addr: data_out <= temp_fifo_data;
	fir_low8_addr: data_out <= fir_data[7:0];
	fir_high4_addr: data_out <= fir_data[11:8];
	fir_addr_addr: data_out <= fir_addr;
      endcase
    end
  end

  always @ (posedge wr_strobe or negedge n_reset)
  begin
    if (!n_reset)
    begin
      tap_config_i <= 32'h80200003;
      tap_config_q <= 32'h80200003;
      last_tap_q <= 5'b11111;
      last_tap_i <= 5'b11111;
      temp_fifo_data <= 8'b0;
      fir_data <= 12'b0;
      fir_addr <= 8'b0;
    end
    else if (!cs) 
    begin
      case (addr)
        config_i_addr_1:  tap_config_i[31:24] <= data_inout; 
        config_i_addr_2:  tap_config_i[23:16] <= data_inout; 
        config_i_addr_3:  tap_config_i[15:8] <= data_inout; 
        config_i_addr_4:  tap_config_i[7:0] <= data_inout; 
        config_q_addr_1:  tap_config_q[31:24] <= data_inout; 
        config_q_addr_2:  tap_config_q[23:16] <= data_inout; 
        config_q_addr_3:  tap_config_q[15:8] <= data_inout; 
        config_q_addr_4:  tap_config_q[7:0] <= data_inout; 
	last_i_addr: last_tap_i <= data_inout[4:0];
	last_q_addr: last_tap_q <= data_inout[4:0];
	fifo_data_addr: temp_fifo_data <= data_inout;
	fir_low8_addr: fir_data[7:0] <= data_inout;
	fir_high4_addr: fir_data[11:8] <= data_inout;
	fir_addr_addr: fir_addr <= data_inout;
      endcase
    end
  end


endmodule

