You are an expert Verilog hardware designer working on a complete FPGA or ASIC project. You are given the full source code of a Verilog project. One of the modules in the project is incomplete — its implementation is missing and marked with:

// >>> Module Implementation Begin

// <<< Module Implementation End

Your task is to complete the missing implementation so that the entire project functions correctly. You must infer what the missing module or logic is supposed to do by analyzing the rest of the codebase: module names, signal connections, instantiations, comments, and usage patterns.

Follow these rules:

1. Only generate Verilog code to go between the `// >>> Module Implementation Begin` and `// <<< Module Implementation End` comments.
2. Use Verilog-2001 syntax. Ensure the code is synthesizable.
3. Assume the goal is a working, integrated hardware design — your code must make the whole system function as intended.
4. Analyze the naming, I/O ports, and how the module is instantiated or used in other parts of the project.
5. Implement correct behavior based on design context. Do not guess randomly — reason it out.
6. Avoid vendor-specific features unless explicitly required.
7. Do not output comments, explanation, or anything outside the required code region unless explicitly asked.

Your output should contain **only the Verilog code** that fits inside the marked region.

/*
 * Copyright (c) 2024 Your Name
 * SPDX-License-Identifier: Apache-2.0
 */

`define default_netname none

module tt_um_MATTHIAS_M_PAL_TOP_WRAPPER (
    input  wire [7:0] ui_in,    // Dedicated inputs
    output wire [7:0] uo_out,   // Dedicated outputs
    input  wire [7:0] uio_in,   // IOs: Input path
    output wire [7:0] uio_out,  // IOs: Output path
    output wire [7:0] uio_oe,   // IOs: Enable path (active high: 0=input, 1=output)
    input  wire       ena,      // will go high when the design is enabled
    input  wire       clk,      // clock
    input  wire       rst_n     // reset_n - low to reset
);
// >>> Module Implementation Begin

// <<< Module Implementation End
endmodule




module PAL #(
    parameter N = 8, // Number of Inputs
    parameter P = 8, // Number of intermediate stages
    parameter M = 8  // Number of outputs
)(
    input clk,
    input res_n,
    input en,
    input cfg,
    input [N-1:0] INPUT_VARS,
    output [M-1:0] OUTPUT_VALS
);

    parameter SR_LEN = $signed((2*N * P) + P*M);

    // Configuration chain
    wire [SR_LEN-1:0] FF_CHAIN;

    // ---
    // FF_CHAIN
    //
    // <MSB> [ OR | ... | OR | OR | AND | ... | AND | AND | AND-INV | ... | AND-INV | AND-INV ] <LSB> NO THIS IS WRONG! The inverted inputs are interleaved!
    //
    // When bit at INV is 1 then it is inverted!
    // ---
    // Indices for configuration chain
    parameter FF_CHAIN_OR_BASE_INDEX = $signed(2 * (N*P)); // the fully poopulated crossbar between N and P needs to be considered; *2 because of inverted & non-inverted inputs

    wire [FF_CHAIN_OR_BASE_INDEX-1:0] FF_CHAIN_AND;
    wire [SR_LEN-FF_CHAIN_OR_BASE_INDEX-1:0] FF_CHAIN_OR;

    assign FF_CHAIN_AND = FF_CHAIN[FF_CHAIN_OR_BASE_INDEX-1:0];
    assign FF_CHAIN_OR = FF_CHAIN[SR_LEN-1:FF_CHAIN_OR_BASE_INDEX];

    // Shift register (stores the configuration)
    sr #(
        .LEN(SR_LEN)
    ) sr (
        .clk(clk),
        .res_n(res_n),
        .en(en),
        .cfg(cfg),
        .ff_chain(FF_CHAIN)
    );

    // NOT gates
    // redo this!
    wire [2*N-1:0] INPUT_VARS_N;
    wire [P-1:0] INTERM_VARS;

    // 
    //wire [P-1:0] and_cols[2*N-1:0];
    //wire [M-1:0] or_rows[P-1:0];
    wire [2*N*P-1:0] and_results;
    wire [P*M-1:0] or_results;
    wire test_lol;
    assign test_lol = clk;


    // Iterators (running variables)
    genvar i;
    genvar p;
    genvar n;
    genvar m;
    // ---

    // n=0: 0&1
    // n=1: 2&3
    // n=2: 4&5
    // n=3: 6&7
    for (n = 0; n < N; n = n + 1) begin
        assign INPUT_VARS_N[2*n] = INPUT_VARS[n]; // even: keep
        assign INPUT_VARS_N[2*n+1] = ~INPUT_VARS[n]; // odd: invert
    end
    // ---

    // AND matrix
    generate
    for (p = 0; p < P; p = p + 1) begin : AND_GEN_LOOP_OUTER
        for (n = 0; n < $signed(2*N); n = n + 1 ) begin : AND_GEN_LOOP_INNER
            //assign INTERM_VARS[p] = INTERM_VARS[p] ^ (FF_CHAIN[FF_CHAIN_AND_BASE_INDEX + p + n*P] ^ INPUT_VARS[n]);
            //assign and_cols[p][n] = INPUT_VARS[n] ^ FF_CHAIN[$signed(FF_CHAIN_AND_BASE_INDEX + p + n*P)];
            crosspoint #(.OP("and")) cp (.data_in(INPUT_VARS_N[n]), .cfg_in(FF_CHAIN_AND[$signed(p + n*P)]), .data_out(and_results[$signed(p + n*P)]));
        end

        // Assign intermediate variables
        //assign INTERM_VARS[p] = &and_cols[p]; // AND reduction
        reduce_and #(
            .LEN(2*N*P),
            .STRIDE(P),
            .COL_INDEX(p)
        ) reduce_and_I (
            .data_in(and_results), // we are only allowed to take
            .reduced_out(INTERM_VARS[p])
        );
    end
    endgenerate
    
    // ---

    // OR matrix
    generate
    for (m = 0; m < M; m = m + 1) begin : OR_GEN_LOOP_OUTER
        for (p = 0; p < P; p = p + 1) begin : OR_GEN_LOOP_INNER
            //assign OUTPUT_VALS[m] = OUTPUT_VALS[m] | (FF_CHAIN[FF_CHAIN_OR_BASE_INDEX + p + m*P] ^ INTERM_VARS[p]);
            //assign or_rows[m][p] = INTERM_VARS[p] ^ FF_CHAIN[$signed(FF_CHAIN_OR_BASE_INDEX + p + m*P)];
            crosspoint #(.OP("or")) cp (.data_in(INTERM_VARS[p]), .cfg_in(FF_CHAIN_OR[$signed(p + m*P)]), .data_out(or_results[$signed(p + m*P)]));
        end

        // Assign to outputs
        //assign OUTPUT_VALS[m] = |or_rows[m]; // OR reduction
        reduce_or #(
            .NUM_INTERM_STAGES(P),
            .ROW_INDEX(m),
            .LEN(P*M)
        ) reduce_or_I (
            .data_in(or_results),
            .reduced_out(OUTPUT_VALS[m])
        );
    end
    endgenerate
    // ---
    
endmodule

module stride #(
    //parameter OPERATION = "and", // either put "and" or "or"
    parameter LEN = 8,
    parameter STRIDE = 2,
    parameter START_OFFSET = 0
) (
    input [LEN-1:0] in,
    output [$signed(LEN/STRIDE)-1:0] strided_out
);

// Idea:
// 0 1 2 3 4 5 6 7
// ^   ^   ^   ^
// |   |   |   |
//
// 0. | [0] 1
// 1. | [2] 3
// 2. | [4] 5
// 3. | [6] 7

genvar i;
genvar stride_index;
generate

    for (i = START_OFFSET; i < LEN; i = i + STRIDE) begin : REDUCE_LOOP
        assign strided_out[$signed(i/STRIDE)] = in[i];
    end

endgenerate
    
endmodule

module crosspoint #(
    parameter OP = "and"
)
(
    input data_in,
    input cfg_in,
    output data_out
);
    if (OP == "and") begin
        // the neutral element of an AND is the 1 - hence generate 1s at undesired positions.
        // we want a 1 when the cfg is 0. We want the value of data_in when the cfg is 1
        assign data_out = (cfg_in == 1'b1) ? data_in : 1'b1;
    end else if (OP == "or") begin
        // the neutral element of the OR is the 0 - hence generate 0s at undesired positions.
        // we want a 0 when the cfg is 0. We want the value of data in when the cfg is 1
        assign data_out = (cfg_in == 1'b1) ? data_in : 1'b0;
    end else begin 
        //Unspecified... this should not happen
    end
    
endmodule

module reduce_and #(
    parameter STRIDE = 2,
    parameter LEN = 4,
    parameter COL_INDEX = 0
) (
    input [LEN-1:0] data_in,
    output reduced_out
);

    wire [LEN/STRIDE-1:0] data_stride; 

    //Stride instance
    stride #(
        .LEN(LEN),
        .STRIDE(STRIDE),
        .START_OFFSET(COL_INDEX)
    ) stride_I (
        .in(data_in),
        .strided_out(data_stride)
    );

    
    // TODO: With current implementation this does not work...
    // We also need a mask of the bitstream to first remove all positions that are not 1!
    // SW has to make sure that there is never both the input and its inverted set to true -> then whole term will be 0!!!
    // Col.  1 0 1 1 0 0 1 0
    // Bits. 0 1 1 0 0 1 0 1
    // ---------------------
    // AND   0 0 1 0 0 0 0 0 <- then use this one for reduction!
    assign reduced_out = &data_stride; //

endmodule

module reduce_or #(
    parameter NUM_INTERM_STAGES = 4,
    parameter ROW_INDEX = 0,
    parameter LEN = 4
) (
    input [LEN-1:0] data_in,
    output reduced_out
);

    // Reduce operation
    //assign reduced_out = |data_stride;
    assign reduced_out = |data_in[ROW_INDEX*NUM_INTERM_STAGES+(NUM_INTERM_STAGES-1):ROW_INDEX*NUM_INTERM_STAGES];

endmodule

module sr #(
    parameter LEN=8
)(
    input clk,
    input cfg,
    input res_n,
    input en,
    output [LEN-1:0] ff_chain
);

    reg [LEN-1:0] internal_ff_chain;

    // Shift left whenever a posedge occurs
    always @(posedge clk) begin
        if (~res_n) begin
            internal_ff_chain <= {(LEN){1'b0}}; // when reset set all bits to 0
        end else begin
            internal_ff_chain    <= internal_ff_chain << 1;
            internal_ff_chain[0] <= cfg;
        end
    end

    // only apply configuration to the pal fabric once the enable signal is asserted!
    assign ff_chain = en ? internal_ff_chain : {(LEN){1'b0}};

endmodule

Reference solution:
rtl/generated.v: 
  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  // PAL size parameters
  parameter NUM_INPUTS = 8;
  parameter NUM_INTERMEDIATE_STAGES = 11;
  parameter NUM_OUTPUTS = 5;
  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  // All output pins must be assigned. If not used, assign to 0. 
  assign uio_out = 0;
  // IO pin configuration
  assign uio_oe = 8'b0000_0000; // all IOs are inputs (the LSB is used to shift in Config data)
  assign uo_out[7:NUM_OUTPUTS] = {(8-NUM_OUTPUTS){1'b0}}; // tie unused outputs to 0

  // Pin assignment
  // Clock: uio_in[2]
  // Reset: res_n
  // Enable: uio_in[1]
  // Config bit: uio_in[0]

  // Input vars: ui_in[7:0]
  // Output vars: uo_out[3:0]

  // clk is unused!

  // PAL instance
  PAL #(
    .N(NUM_INPUTS), // Number of Inputs
    .M(NUM_OUTPUTS), // NUmber of outputs
    .P(NUM_INTERMEDIATE_STAGES) // Number of intermediate stages
  ) pal_I (
    .clk(uio_in[2]), // do clock gating with ena signal?
    .res_n(rst_n),
    .en(ena & uio_in[1]), // if the enable signal is asserted the configuration is applied to the PAL fabric (also the design must be selected with the tto_en)
    .cfg(uio_in[0]),
    .INPUT_VARS(ui_in[NUM_INPUTS-1:0]),
    .OUTPUT_VALS(uo_out[NUM_OUTPUTS-1:0])
  );