`resetall
`timescale 1ns / 1ps
`default_nettype none

module util_reg #
(
    parameter integer AXI_ADDR_WIDTH	= 32,
    parameter integer AXI_DATA_WIDTH	= 32    
)
(
    // AXI4L Config Interface
    axi4l_intf.slave    ctrl_if,

    output wire [31:0]  gpo,
    input  wire [31:0]  gpi,
    output wire [15:0]  packet_size,
	output wire         fan_pwm,
	
    output wire         tx0_rf_attn_sin,    //ADRF5730
    output wire         tx0_rf_attn_clk,    //ADRF5730
    output wire         tx0_rf_attn_le,     //ADRF5730
    output wire         tx1_rf_attn_sin,    //ADRF5730
    output wire         tx1_rf_attn_clk,    //ADRF5730
    output wire         tx1_rf_attn_le,     //ADRF5730
    
    output wire         rx0_rf_attn_sin,    //ADRF5721
    output wire         rx0_rf_attn_clk,    //ADRF5721
    output wire         rx0_rf_attn_le,     //ADRF5721
    output wire         rx0_if_attn_sin,    //HMC624
    output wire         rx0_if_attn_clk,    //HMC624
    output wire         rx0_if_attn_le,     //HMC624
    
    output wire         rx1_rf_attn_sin,    //ADRF5721   
    output wire         rx1_rf_attn_clk,    //ADRF5721   
    output wire         rx1_rf_attn_le,     //ADRF5721   
    output wire         rx1_if_attn_sin,    //HMC624     
    output wire         rx1_if_attn_clk,    //HMC624     
    output wire         rx1_if_attn_le      //HMC624     
);

// ------------------------------
// AXIL Decode
// ------------------------------
wire [AXI_ADDR_WIDTH-1 : 0]		raddr;
wire [AXI_ADDR_WIDTH-1 : 0]		waddr;
wire 						    rden;
wire 						    wren;
wire [AXI_DATA_WIDTH-1 : 0]		wdata;
reg [AXI_DATA_WIDTH-1 : 0]		rdata;


axil_slave 
# (
	.DATA_WIDTH(AXI_DATA_WIDTH),
	.ADDR_WIDTH(AXI_ADDR_WIDTH)
) axil_slave_i 
(
	// AXIL Slave
	.S_AXI_ACLK(ctrl_if.clk),
	.S_AXI_ARESETN(ctrl_if.resetn),
	.S_AXI_AWADDR(ctrl_if.awaddr),
	.S_AXI_AWPROT(ctrl_if.awprot),
	.S_AXI_AWVALID(ctrl_if.awvalid),
	.S_AXI_AWREADY(ctrl_if.awready),
	.S_AXI_WDATA(ctrl_if.wdata),
	.S_AXI_WSTRB(ctrl_if.wstrb),
	.S_AXI_WVALID(ctrl_if.wvalid),
	.S_AXI_WREADY(ctrl_if.wready),
	.S_AXI_BRESP(ctrl_if.bresp),
	.S_AXI_BVALID(ctrl_if.bvalid),
	.S_AXI_BREADY(ctrl_if.bready),
	.S_AXI_ARADDR(ctrl_if.araddr),
	.S_AXI_ARPROT(ctrl_if.arprot),
	.S_AXI_ARVALID(ctrl_if.arvalid),
	.S_AXI_ARREADY(ctrl_if.arready),
	.S_AXI_RDATA(ctrl_if.rdata),
	.S_AXI_RRESP(ctrl_if.rresp),
	.S_AXI_RVALID(ctrl_if.rvalid),
	.S_AXI_RREADY(ctrl_if.rready),	
	
	.raddr(raddr),
	.waddr(waddr),
	.wren(wren),
	.rden(rden),
	.wdata(wdata),
	.rdata(rdata)
);

// ------------------------------
// Config Registers
// ------------------------------
wire reset;
assign reset = ~ctrl_if.resetn;
reg [31:0]  scratch;
reg [31:0]  reg_gpo; 
reg [24:0]  pwm_period; 
reg [24:0]  pwm_pulsewidth; 
reg [15:0]  reg_packet_size;
reg [7:0]  reg_num_bits;
reg [15:0]  reg_dev_sel;
reg [31:0]  reg_spi_data;
reg [7:0]   reg_spi_clk_div;
reg start_spi_transaction;         

always @ (posedge ctrl_if.clk) begin
    if (reset) begin
        scratch <= 0;
    end else if (wren && waddr[11:0] == 'h004) begin
        scratch <= wdata;
    end
end

always @ (posedge ctrl_if.clk) begin
    if (reset) begin
        reg_gpo <= 0;
    end else if (wren && waddr[11:0] == 'h008) begin
        reg_gpo <= wdata;
    end
end

always @ (posedge ctrl_if.clk) begin
    if (reset) begin
        pwm_period <= 1500000;
    end else if (wren && waddr[11:0] == 'h010) begin
        pwm_period <= wdata;
    end
end

always @ (posedge ctrl_if.clk) begin
    if (reset) begin
        pwm_pulsewidth <= 500000;
    end else if (wren && waddr[11:0] == 'h014) begin
        pwm_pulsewidth <= wdata;
    end
end

always @ (posedge ctrl_if.clk) begin
    if (reset) begin
        reg_packet_size <= 1024;
    end else if (wren && waddr[11:0] == 'h01C) begin
        reg_packet_size <= wdata;
    end
end

always @ (posedge ctrl_if.clk) begin
    if (reset) begin
        reg_num_bits <= 6;
        start_spi_transaction <= 0;
    end else if (wren && waddr[11:0] == 'h100) begin
        reg_num_bits <= wdata;
        start_spi_transaction <= 1;
    end else begin
        start_spi_transaction <= 0;
    end
end

always @ (posedge ctrl_if.clk) begin
    if (reset) begin
        reg_dev_sel <= 0;
    end else if (wren && waddr[11:0] == 'h104) begin
        reg_dev_sel <= wdata;
    end
end

always @ (posedge ctrl_if.clk) begin
    if (reset) begin
        reg_spi_data <= 0;
    end else if (wren && waddr[11:0] == 'h108) begin
        reg_spi_data <= wdata;
    end
end

always @ (posedge ctrl_if.clk) begin
    if (reset) begin
        reg_spi_clk_div <= 16;
    end else if (wren && waddr[11:0] == 'h10C) begin
        reg_spi_clk_div <= wdata;
    end
end

always @ (posedge ctrl_if.clk) begin
    if (rden) begin
        if (raddr[11:0] == 'h000)
            rdata <= 'h12345678;
        if (raddr[11:0] == 'h004)
            rdata <= scratch;
        if (raddr[11:0] == 'h008)
            rdata <= reg_gpo;        
        if (raddr[11:0] == 'h00C)
            rdata <= gpi;           
        if (raddr[11:0] == 'h010)
            rdata <= pwm_period;       
        if (raddr[11:0] == 'h014)
            rdata <= pwm_pulsewidth;    
        if (raddr[11:0] == 'h01C)
            rdata <= reg_packet_size;                               
        if (raddr[11:0] == 'h100)
            rdata <= reg_num_bits;        
        if (raddr[11:0] == 'h104)
            rdata <= reg_dev_sel;        
        if (raddr[11:0] == 'h108)
            rdata <= reg_spi_data;        
        if (raddr[11:0] == 'h10C)
            rdata <= reg_spi_clk_div;      
        if (raddr[11:0] == 'h110)
            rdata <= {28'b0000000, 2'b00, spi_active, le_active};                                                                           
    end
end

assign gpo = reg_gpo;
assign packet_size = reg_packet_size;

// ------------------------------
// Fan PWM
// ------------------------------
reg [24:0]  pwm_cnt; 
reg pwm_out;

assign fan_pwm = pwm_out;

always @ (posedge ctrl_if.clk) begin
	if (pwm_cnt < pwm_period) begin
		pwm_cnt <= pwm_cnt + 1;
	end else begin
		pwm_cnt <= 0;
	end

	if (pwm_cnt < pwm_pulsewidth) begin
		pwm_out <= 1'bz;
	end else begin
		pwm_out <= 1'b0;
	end

end

// ------------------------------
// Attenuator Serial Bus Control
// ------------------------------
reg [7:0]  spi_clk_cnt;
reg [7:0]  spi_bit_cnt;
reg spi_active;
reg le_active;
reg [31:0] spi_shift_data;
reg [7:0] le_count;
reg le;
 
always @ (posedge ctrl_if.clk) begin
    
    if (start_spi_transaction) begin
        spi_active <= 1;
    end
    
    if (spi_active) begin
        spi_clk_cnt <= spi_clk_cnt + 1;
        if (spi_clk_cnt == reg_spi_clk_div) begin
            spi_clk_cnt <= 0;
            spi_bit_cnt <= spi_bit_cnt + 1;
            // Shift Data Down One Bit
            spi_shift_data <= spi_shift_data >> 1;
            if (spi_bit_cnt == reg_num_bits) begin
                spi_active <= 0;
                le_active <= 1;
            end
        end
    end else begin
        spi_clk_cnt <= 0;
        spi_bit_cnt <= 0;
        spi_shift_data <= reg_spi_data;
    end
    
    if (le_active) begin
        le_count <= le_count + 1;
        if (le_count == 10) begin
            le = 1;
        end else if (le_count == 20) begin
            le = 0;
            le_active <= 0;
        end;        
    end else begin
        le_count <= 0;
        le = 0;
    end
        

end

wire spi_data;
wire spi_clk;
wire spi_le;


assign spi_data = spi_active ? spi_shift_data[0] : 0;
assign spi_clk = (spi_clk_cnt > reg_spi_clk_div[7:1]) ? 1 : 0;
assign spi_le = le;

assign tx0_rf_attn_sin = reg_dev_sel[0] ? spi_data : 0;
assign tx0_rf_attn_clk = reg_dev_sel[0] ? spi_clk : 0;
assign tx0_rf_attn_le  = reg_dev_sel[0] ? spi_le : 0;
assign tx1_rf_attn_sin = reg_dev_sel[1] ? spi_data : 0;
assign tx1_rf_attn_clk = reg_dev_sel[1] ? spi_clk : 0;
assign tx1_rf_attn_le  = reg_dev_sel[1] ? spi_le : 0;

assign rx0_rf_attn_sin = reg_dev_sel[2] ? spi_data : 0;
assign rx0_rf_attn_clk = reg_dev_sel[2] ? spi_clk : 0;
assign rx0_rf_attn_le  = reg_dev_sel[2] ? spi_le : 0;
assign rx0_if_attn_sin = reg_dev_sel[3] ? spi_data : 0;
assign rx0_if_attn_clk = reg_dev_sel[3] ? spi_clk : 0;
assign rx0_if_attn_le  = reg_dev_sel[3] ? spi_le : 0;

assign rx1_rf_attn_sin = reg_dev_sel[4] ? spi_data : 0;
assign rx1_rf_attn_clk = reg_dev_sel[4] ? spi_clk : 0;
assign rx1_rf_attn_le  = reg_dev_sel[4] ? spi_le : 0;
assign rx1_if_attn_sin = reg_dev_sel[5] ? spi_data : 0;
assign rx1_if_attn_clk = reg_dev_sel[5] ? spi_clk : 0;
assign rx1_if_attn_le  = reg_dev_sel[5] ? spi_le : 0;


endmodule


`resetall