module link_signal_mgmt(
        input        mgmt_clk,

        input        tx_powerup,
        
        input        status_de,
        input        adjust_de,
        input  [7:0] addr,
        input  [7:0] data,
        //-----------------------------------------
        input  [2:0] sink_channel_count,
        input  [2:0] source_channel_count,
        input  [2:0] stream_channel_count,
        output [2:0] active_channel_count,
        //-----------------------------------------
        output reg [3:0] powerup_channel,
        //-----------------------------------------
        output reg   clock_locked,
        output reg   equ_locked,
        output reg   symbol_locked,
        output reg   align_locked,

        output  reg  preemp_0p0,
        output  reg  preemp_3p5,
        output  reg  preemp_6p0,
    
        output  reg  swing_0p4,
        output  reg  swing_0p6,
        output  reg  swing_0p8
    );

    reg  [3:0]  power_mask;
    wire [1:0]  preemp_level;
    wire  [1:0] voltage_level;
    reg  [23:0] channel_state;
    reg  [15:0] channel_adjust;
    reg  [2:0]  active_channel_count_i;
    reg  [2:0]  pipe_channel_count;


    assign active_channel_count = active_channel_count_i;
    assign voltage_level = channel_adjust[1:0];
    assign preemp_level  = channel_adjust[3:0];
    
initial begin
    active_channel_count_i = 3'b0;
        //-----------------------------------------
    powerup_channel = 4'b0;
        //-----------------------------------------
    clock_locked = 3'b0;
    equ_locked = 3'b0;
    symbol_locked = 3'b0;
    align_locked = 3'b0;
    channel_adjust = 15'b0;
    channel_state  = 24'b0;

    preemp_0p0 = 3'b0;
    preemp_3p5 = 3'b0;
    preemp_6p0 = 3'b0;
    
    swing_0p4 = 3'b0;
    swing_0p6 = 3'b0;
    swing_0p8 = 3'b0;
end

always @(posedge mgmt_clk) begin
    //--------------------------------------------------------
    // Work out how many channels will be active 
    // (the min of source_channel_count and sink_channel_count
    //
    // Also work out the power-up mask for the transceivers
    //---------------------------------------------------------
    case(source_channel_count)
        3'b100: begin
                    case(sink_channel_count)
                        3'b100:  pipe_channel_count <= 3'b100;
                        3'b010:  pipe_channel_count <= 3'b010;
                        default: pipe_channel_count <= 3'b001;
                    endcase
                end
        3'b010: begin
                    case(sink_channel_count)
                        3'b100:  pipe_channel_count <= 3'b010;
                        3'b010:  pipe_channel_count <= 3'b010;
                        default: pipe_channel_count <= 3'b001;
                    endcase
                end
        default: pipe_channel_count <= 3'b001;
    endcase
   
    case(stream_channel_count)
        3'b100:
            case(pipe_channel_count)
                3'b100:  begin active_channel_count_i <= 3'b100; power_mask <= 4'b1111; end
                3'b010:  begin active_channel_count_i <= 3'b010; power_mask <= 4'b0000; end
                default: begin active_channel_count_i <= 3'b000; power_mask <= 4'b0000; end
            endcase
        3'b010:
            case(pipe_channel_count)
                3'b100:  begin active_channel_count_i <= 3'b010; power_mask <= 4'b0011; end
                3'b010:  begin active_channel_count_i <= 3'b010; power_mask <= 4'b0011; end
                default: begin active_channel_count_i <= 3'b000; power_mask <= 4'b0000; end
            endcase
        default: begin
                     active_channel_count_i <= 3'b001;
                     power_mask             <= 4'b0001;
                 end
    endcase

            
    //-------------------------------------------
    // If the powerup is not asserted, then reset 
    // everything.
    //-------------------------------------------
    if(tx_powerup == 1'b1) begin
        powerup_channel  <= power_mask;
    end else begin
        powerup_channel  <= 0;
        channel_adjust   <= 15'b0;
        channel_state    <= 24'b0;
    end

    //-------------------------------------------
    // Decode the power and pre-emphasis levels
    //-------------------------------------------
    case(preemp_level)
        2'b00:   begin preemp_0p0 <= 1'b1; preemp_3p5 <= 1'b0; preemp_6p0 <= 1'b0; end
        2'b01:   begin preemp_0p0 <= 1'b0; preemp_3p5 <= 1'b1; preemp_6p0 <= 1'b0; end
        default: begin preemp_0p0 <= 1'b0; preemp_3p5 <= 1'b0; preemp_6p0 <= 1'b1; end
    endcase

    case(voltage_level)
        2'b00:   begin
                     swing_0p4 <= 1'b1;
                     swing_0p6 <= 1'b0;
                     swing_0p8 <= 1'b0;
                 end
        2'b01:   begin 
                     swing_0p4 <= 1'b0; 
                     swing_0p6 <= 1'b1;
                     swing_0p8 <= 1'b0;
                 end
        default: begin
                     swing_0p4 <= 1'b0;
                     swing_0p6 <= 1'b0; 
                     swing_0p8 <= 1'b1;
                 end
    endcase

    //---------------------------------------------
    // Receive the status data from the AUX channel
    //---------------------------------------------
    if(status_de == 1'b1) begin
        case(addr)
            8'b00000010: channel_state[7:0]   <= data;
            8'b00000011: channel_state[15:8]  <= data;                                  
            8'b00000100: channel_state[23:16] <= data;                                  
        endcase
    end

    //---------------------------------------------
    // Receive the channel adjustment request 
    //---------------------------------------------
    if(adjust_de == 1'b1) begin
        case(addr) 
            8'b00000000: channel_adjust[7:0] <= data;
            8'b00000001: channel_adjust[15:8] <= data;                                  
        endcase
    end 

    //---------------------------------------------
    // Update the status signals based on the 
    // register data recieved over from the AUX
    // channel. 
    //---------------------------------------------
    clock_locked  <= 1'b0;
    equ_locked    <= 1'b0;
    symbol_locked <= 1'b0;
    case(active_channel_count_i) 
        3'b001: begin
                    if((channel_state[3:0] & 4'h1)      == 4'h1)     clock_locked  <= 1'b1;
                    if((channel_state[3:0] & 4'h3)      == 4'h3)     equ_locked    <= 1'b1;
                    if((channel_state[3:0] & 4'h7)      == 4'h7)     symbol_locked <= 1'b1;
                end

        3'b010: begin
                    if((channel_state[7:0] & 8'h11)     == 8'h11)    clock_locked  <= 1'b1;
                    if((channel_state[7:0] & 8'h33)     == 8'h33)    equ_locked    <= 1'b1;
                    if((channel_state[7:0] & 8'h77)     == 8'h77)    symbol_locked <= 1'b1;
                end

        3'b100: begin
                    if((channel_state[15:0] & 16'h1111) == 16'h1111) clock_locked  <= 1'b1;
                    if((channel_state[15:0] & 16'h3333) == 16'h3333) equ_locked    <= 1'b1;
                    if((channel_state[15:0] & 16'h7777) == 16'h7777) symbol_locked <= 1'b1;
                end
    endcase
    align_locked <= channel_state[16];
end

endmodule