module slicel #(
    parameter S_XX_BASE=4, 
    parameter NUM_LUTS = 4,
    // 2x configs bits for the dual LUTs in SXX + 1 config bit for internal LUT select
    parameter CFG_SIZE=2*(2**S_XX_BASE)+1,
    // assume NUM_LUTS is a power of 2
    parameter MUX_LVLS = $clog2(NUM_LUTS)
) (
    input clk,
    // Set config bits for comb logic
    input comb_set,
    // Set register initial states
    input mem_set,

    // Input to LUTS (from fabric)
    input [2*S_XX_BASE*NUM_LUTS-1:0] luts_in,
    // Input to MUXS (from fabric)
    input [MUX_LVLS-1:0] higher_order_addr,

    // Config bits
    input [CFG_SIZE*NUM_LUTS-1:0] luts_config_in,
    input [MUX_LVLS-1:0] inter_lut_mux_config,
    // Output register initial state
    input [2*NUM_LUTS-1:0] regs_config_in,
    // Enable Carry
    input config_use_cc,

    // Output Register Write Enable (from fabric)
    input reg_ce,
    // Carry in (from fabric)
    input Ci,
    // Carry out (to fabric)
    output Co,

    // Unregistered output (to fabric)
    output [2*NUM_LUTS-1:0] out,
    // Unregistered output (to fabric)
    output reg [2*NUM_LUTS-1:0] sync_out
);

wire [2*NUM_LUTS-1:0] luts_out;
wire [NUM_LUTS-1:0] muxes_out;
wire [NUM_LUTS-1:0] muxes_in;
wire [NUM_LUTS-1:0] cc_p;
wire [NUM_LUTS-1:0] cc_g;
wire [NUM_LUTS-1:0] cc_s;

reg use_cc;
always @(posedge clk) begin
    if (comb_set) begin
        use_cc <= config_use_cc;
    end
end
             
generate
    genvar i;
    genvar j;
    for (i = 0; i < NUM_LUTS; i=i+1) begin
        lut_sXX_softcode #(.INPUTS(S_XX_BASE)) lut (
            .addr(luts_in[2*S_XX_BASE*(i+1)-1:2*S_XX_BASE*i]),
            .out(luts_out[2*i+1:2*i]),
            .clk(clk),
            .comb_set(comb_set),
            .config_in(luts_config_in[CFG_SIZE*(i+1)-1:CFG_SIZE*i])
        );

        assign cc_p[i] = luts_out[2*i];
        assign cc_g[i] = luts_out[2*i+1];
        assign muxes_in[i] = luts_out[2*i];
        assign out[2*i+1:2*i] = use_cc ? 
                        {luts_out[2*i+1], cc_s[i]} :
                        {luts_out[2*i+1], muxes_out[i]};

        // Registers capture main CLB outputs
        always @(posedge clk) begin
            if (mem_set) begin
                // set the initial states of the FFs from the configuration bits
                sync_out[2*i+1:2*i] <= regs_config_in[2*i+1:2*i];
            end
            else if (reg_ce) begin
                sync_out[2*i+1:2*i] <= out[2*i+1:2*i];
            end
        end
    end
endgenerate

// carry chain will utilize outputs of smallest fracture size
// 2**(fraclvl-1) will be the number of propegate/generates
carry_chain #(.INPUTS(NUM_LUTS)) cc (
    .P(cc_p),
    .G(cc_g),
    .S(cc_s),
    .Ci(Ci),
    .Co(Co)
);

// MUX the primary S44 outputs, analog to MUX7 and MUX8
mux_f_slice #(
    .NUM_LUTS(NUM_LUTS), .MUX_LEVEL(MUX_LVLS)
) muxes (
    .luts_out(muxes_in),
    .addr(higher_order_addr),
    .out(muxes_out),
    .clk(clk),
    .comb_set(comb_set),
    .config_in(inter_lut_mux_config)
);

endmodule