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 matrag
 * SPDX-License-Identifier: Apache-2.0
 */

`default_nettype none

module tt_um_matrag_chirp_top (
    input  wire [7:0] ui_in,    // Dedicated inputs - ui_in[0] UART RX
    output wire [7:0] uo_out,   // Dedicated outputs - Out 8 bit data: uo_out[7:0]
    input  wire [7:0] uio_in,   // IOs: Input path - unused
    output wire [7:0] uio_out,  // IOs: Output path - Done signal from chirp generator: uio_out[0]
    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, always 1 when the design is powered, so you can ignore it
    input  wire       clk,      // clock
    input  wire       rst_n     // reset_n - low to reset
);
// >>> Module Implementation Begin

// <<< Module Implementation End
endmodule
















module chirpmod #(
  parameter PHASE_WIDTH        = 32,
  parameter MAX_SF_WIDTH       = 8,
  parameter BW_BITWIDTH        = 2,
  parameter ADDR_WIDTH         = 6,
  parameter DATA_WIDTH         = 8,
  parameter DIVIDER_BITWIDTH   = 7
)(
  input  wire                      i_clk,     //!Input clock: 10 MHz
  input  wire                      i_rst_n,   //!Input reset active Low
  input  wire                      i_rx,      //!Input UART rx (9600 bps)
  output wire                      o_done_n,  //!Output done active Low
  output wire [DATA_WIDTH-1:0]     o_data     //!Output bus data
);

  // Fixed configuration parameters
  wire [15:0]              w_baud_div  = 16'd1042;      //UART rx baud rate = i_clk/Baud Divider (9600 bps)
  wire [MAX_SF_WIDTH-1:0]  w_SF      = 8'd8;            //SF value (SF8)
  wire [PHASE_WIDTH-1:0]   w_slope   = 32'h0003_3333;   //Slope for the phase accumulator of the chirp nco
  wire [BW_BITWIDTH-1:0]   w_bw_cfg  = 2'd0;            //BW config: 0 = 125 kHz

  // Internal connections
  wire [7:0]               w_rx_data;
  wire                     w_rx_valid_n;
  wire [PHASE_WIDTH-1:0]   w_init_phase_inc;
  wire                     w_slope_done_n;
  wire                     w_sample_tick_n;
  wire [PHASE_WIDTH-1:0]   w_phase_acc;
  wire [ADDR_WIDTH-1:0]    w_rom_addr = w_phase_acc[PHASE_WIDTH-1 -: ADDR_WIDTH];

  //Reset input synchronizer
  wire w_rst_n_synch; //Synchronized reset signal for all the logic blocks
  rst_sync rst_sync_inst(
    .i_rst_n(i_rst_n),
    .i_clk(i_clk),
    .o_rst_n(w_rst_n_synch)
  );

  // UART Receiver
  uart_rx uart_rx_inst (
    .i_clk(i_clk),
    .i_rst_n(w_rst_n_synch),
    .i_rx(i_rx),
    .i_baud_div(w_baud_div),
    .o_data(w_rx_data),
    .o_valid_n(w_rx_valid_n)
  );

  // Slope Accumulator
  slope_accumulator slope_acc_inst (
    .i_clk(i_clk),
    .i_rst_n(w_rst_n_synch),
    .i_start_n(w_rx_valid_n),
    .i_symbol(w_rx_data),
    .i_slope(w_slope),
    .o_done_n(w_slope_done_n),
    .o_value(w_init_phase_inc)
  );

  // Tick Generator
  tick_generator #(
    .BW_BITWIDTH(BW_BITWIDTH),
    .DIVIDER_BITWIDTH(DIVIDER_BITWIDTH)
  ) tick_gen_inst (
    .i_clk(i_clk),
    .i_rst_n(w_rst_n_synch),
    .i_start_n(w_slope_done_n),
    .i_bw_config(w_bw_cfg),
    .o_sample_tick_n(w_sample_tick_n)
  );

  // NCO Chirp Generator
  nco_chirp #(
    .PHASE_WIDTH(PHASE_WIDTH),
    .MAX_SF_WIDTH(MAX_SF_WIDTH),
    .MAX_SF_VALUE(32),
    .BW_BITWIDTH(BW_BITWIDTH)
  ) nco_inst (
    .i_clk(i_clk),
    .i_rst_n(w_rst_n_synch),
    .i_start_n(w_slope_done_n),
    .i_SF(w_SF),
    .i_bw_config(w_bw_cfg),
    .i_init_phase_inc(w_init_phase_inc),
    .i_slope(w_slope),
    .i_sample_tick_n(w_sample_tick_n),
    .o_phase_acc(w_phase_acc),
    .o_done_n(o_done_n)
  );

  // ROM Sample Output
  sine_rom #(
    .ADDR_WIDTH(ADDR_WIDTH),
    .DATA_WIDTH(DATA_WIDTH)
  ) rom_inst (
    .i_clk(i_clk),
    .i_rst_n(w_rst_n_synch),
    .i_addr(w_rom_addr),
    .o_data(o_data)
  );

endmodule



module rst_sync (
    input wire i_rst_n,
    input wire i_clk,
    output reg o_rst_n
);

always@(posedge i_clk) begin
    o_rst_n <= i_rst_n;
end

endmodule

// Full-range sine_rom.v (0–255)
// Auto-generated 64-entry 8-bit sine wave ROM
module sine_rom #(
    parameter ADDR_WIDTH = 6,  // 64 entries
    parameter DATA_WIDTH = 8   // 8-bit output
)(
    input  wire                  i_clk,
    input  wire                  i_rst_n,
    input  wire [ADDR_WIDTH-1:0] i_addr,
    output reg  [DATA_WIDTH-1:0] o_data
);

    always @(posedge i_clk) begin
        if (!i_rst_n) begin
            o_data <= 8'd85;
        end else begin
            case (i_addr)
                6'd0: o_data <= 8'd128;
                6'd1: o_data <= 8'd140;
                6'd2: o_data <= 8'd152;
                6'd3: o_data <= 8'd165;
                6'd4: o_data <= 8'd176;
                6'd5: o_data <= 8'd188;
                6'd6: o_data <= 8'd198;
                6'd7: o_data <= 8'd208;
                6'd8: o_data <= 8'd218;
                6'd9: o_data <= 8'd226;
                6'd10: o_data <= 8'd234;
                6'd11: o_data <= 8'd240;
                6'd12: o_data <= 8'd245;
                6'd13: o_data <= 8'd250;
                6'd14: o_data <= 8'd253;
                6'd15: o_data <= 8'd254;
                6'd16: o_data <= 8'd255;
                6'd17: o_data <= 8'd254;
                6'd18: o_data <= 8'd253;
                6'd19: o_data <= 8'd250;
                6'd20: o_data <= 8'd245;
                6'd21: o_data <= 8'd240;
                6'd22: o_data <= 8'd234;
                6'd23: o_data <= 8'd226;
                6'd24: o_data <= 8'd218;
                6'd25: o_data <= 8'd208;
                6'd26: o_data <= 8'd198;
                6'd27: o_data <= 8'd188;
                6'd28: o_data <= 8'd176;
                6'd29: o_data <= 8'd165;
                6'd30: o_data <= 8'd152;
                6'd31: o_data <= 8'd140;
                6'd32: o_data <= 8'd128;
                6'd33: o_data <= 8'd115;
                6'd34: o_data <= 8'd103;
                6'd35: o_data <= 8'd90;
                6'd36: o_data <= 8'd79;
                6'd37: o_data <= 8'd67;
                6'd38: o_data <= 8'd57;
                6'd39: o_data <= 8'd47;
                6'd40: o_data <= 8'd37;
                6'd41: o_data <= 8'd29;
                6'd42: o_data <= 8'd21;
                6'd43: o_data <= 8'd15;
                6'd44: o_data <= 8'd10;
                6'd45: o_data <= 8'd5;
                6'd46: o_data <= 8'd2;
                6'd47: o_data <= 8'd1;
                6'd48: o_data <= 8'd0;
                6'd49: o_data <= 8'd1;
                6'd50: o_data <= 8'd2;
                6'd51: o_data <= 8'd5;
                6'd52: o_data <= 8'd10;
                6'd53: o_data <= 8'd15;
                6'd54: o_data <= 8'd21;
                6'd55: o_data <= 8'd29;
                6'd56: o_data <= 8'd37;
                6'd57: o_data <= 8'd47;
                6'd58: o_data <= 8'd57;
                6'd59: o_data <= 8'd67;
                6'd60: o_data <= 8'd79;
                6'd61: o_data <= 8'd90;
                6'd62: o_data <= 8'd103;
                6'd63: o_data <= 8'd115;
                default: o_data <= 8'd128;
            endcase
        end
    end

endmodule




// Serial adder FSM: o_value = i_symbol × i_slope using 1-cycle start pulse
module slope_accumulator (
    input  wire        i_clk,
    input  wire        i_rst_n,      // Active-low reset
    input  wire        i_start_n,    // Active-low start pulse
    input  wire [7:0]  i_symbol,     // Symbol to transmit
    input  wire [31:0] i_slope,      // Step to accumulate
    output reg         o_done_n,     // Active-low done pulse
    output reg [31:0]  o_value       // Output = symbol × slope
);

    // FSM state encoding
    
    localparam IDLE       = 2'd0;
    localparam LOAD       = 2'd1;
    localparam ACCUMULATE = 2'd2;
    localparam DONE       = 2'd3;

    reg [1:0] state, next_state;

    reg [7:0] r_count;

    // FSM sequential
    always @(posedge i_clk) begin
        if (!i_rst_n)
            state <= IDLE;
        else
            state <= next_state;
    end

    // FSM combinational
    always @(*) begin
        next_state = state;
        case (state)
            IDLE:       if (!i_start_n)        next_state = LOAD;
            LOAD:                             next_state = (i_symbol != 0) ? ACCUMULATE : DONE;
            ACCUMULATE: if (r_count == 1)     next_state = DONE;
            DONE:                              next_state = IDLE;
        endcase
    end

    // Outputs and datapath
    always @(posedge i_clk) begin
        if (!i_rst_n) begin
            o_value   <= 32'd0;
            r_count   <= 8'd0;
            o_done_n  <= 1'b1;
        end else begin
            case (state)
                IDLE: begin
                    o_done_n <= 1'b1;
                end
                LOAD: begin
                    o_value  <= 32'd0;
                    r_count  <= i_symbol;
                end
                ACCUMULATE: begin
                    o_value  <= o_value + i_slope;
                    r_count  <= r_count - 1;
                end
                DONE: begin
                    o_done_n <= 1'b0;  // Pulse done low
                end
            endcase
        end
    end

endmodule


module tick_generator #(
    parameter BW_BITWIDTH = 2,
    parameter DIVIDER_BITWIDTH = 7
)(
    input  wire                    i_clk,
    input  wire                    i_rst_n,
    input  wire                    i_start_n,        // Active-low level signal
    input  wire [BW_BITWIDTH-1:0]  i_bw_config,      // 00:125kHz, 01:250kHz, 10:500kHz
    output reg                     o_sample_tick_n   // Active-low 1-cycle pulse
);

    // --------------------------------------------------------------------------
    // State definition
    // --------------------------------------------------------------------------
    parameter  IDLE = 2'b00;
    parameter  RUN  = 2'b01;

    reg [1:0] r_state;

    // --------------------------------------------------------------------------
    // Divider selection
    // --------------------------------------------------------------------------
    wire [DIVIDER_BITWIDTH-1:0] w_divider_val =
        (i_bw_config == 2'd0) ? 7'd80 :  // 125kHz
        (i_bw_config == 2'd1) ? 7'd40 :  // 250kHz
        (i_bw_config == 2'd2) ? 7'd20 :  // 500kHz
                                7'd80;

    // --------------------------------------------------------------------------
    // Internal signals
    // --------------------------------------------------------------------------
    reg [DIVIDER_BITWIDTH-1:0] r_counter;

    always @(posedge i_clk) begin
        if (!i_rst_n) begin
            r_state <= IDLE;
            r_counter       <= 0;
            o_sample_tick_n <= 1'b1;  // inactive
        end else begin
            case (r_state)
                IDLE: begin
                    r_counter       <= 0;
                    o_sample_tick_n <= 1'b1;
                    if(i_start_n) begin
                        r_state <= RUN;
                    end
                end

                RUN: begin
                    if (r_counter == w_divider_val - 1) begin
                        r_counter       <= 0;
                        o_sample_tick_n <= 1'b0;  // active-low pulse
                        r_state <= IDLE;
                    end else begin
                        r_counter       <= r_counter + 1;
                        o_sample_tick_n <= 1'b1;
                        r_state <= RUN;
                    end
                end
            endcase
        end
    end

endmodule



module uart_rx (
    input  wire        i_clk,        // System clock
    input  wire        i_rst_n,      // Active-low reset
    input  wire        i_rx,         // UART RX line
    input  wire [15:0] i_baud_div,   // Baud rate divider

    output reg  [7:0]  o_data,       // Received data
    output reg         o_valid_n      // Data valid flag
);

    reg [3:0]  r_bit_cnt;
    reg [15:0] r_clk_cnt;
    reg [7:0]  r_shift_reg;
    reg        r_rx_active;
    reg        r_sample;

    localparam IDLE = 3'd0,
               WAIT = 3'd1,
               BUSY = 3'd2,
               STOP = 3'd3,
               DONE = 3'd4;


    reg [2:0]  r_state;

    always @(posedge i_clk) begin
        if (!i_rst_n) begin
            r_bit_cnt   <= 0;
            r_clk_cnt   <= 0;
            r_rx_active <= 0;
            r_shift_reg <= 0;
            r_sample <= 0;
            r_state     <= IDLE;
            o_data      <= 8'd0;
            o_valid_n     <= 1'b1;
        end else begin
            case (r_state)
                IDLE: begin
                    o_valid_n <= 1'b1;
                    if (i_rx == 1'b0) begin  // Start bit detected
                        r_state     <= WAIT;
                        r_bit_cnt   <= 0;
                        r_clk_cnt   <= 0;
                        r_shift_reg <= 0;
                        r_rx_active <= 1'b1;
                    end
                end

                WAIT: begin // wait start symbol to end
                    if(r_clk_cnt   == i_baud_div) begin
                        r_clk_cnt   <= i_baud_div >> 1; // sample in middle of bit: count to half total of bit clock cycles
                        r_state     <= BUSY;
                    end
                    else begin
                        r_clk_cnt <= r_clk_cnt + 1;
                    end
                end


                BUSY: begin
                    if (r_clk_cnt == i_baud_div) begin
                        r_clk_cnt <= 0;
                        r_shift_reg <= {i_rx, r_shift_reg[7:1]}; //fill shift reg with data
                        r_bit_cnt <= r_bit_cnt + 1;

                        if (r_bit_cnt == 7) begin
                            r_rx_active <= 0;
                            r_state <= STOP;
                            r_shift_reg <= {i_rx, r_shift_reg[7:1]}; //fill last bit
                        end
                    end else begin
                        r_clk_cnt <= r_clk_cnt + 1;
                    end
                end

                STOP: begin
                    if (r_clk_cnt == i_baud_div) begin
                        r_state <= DONE;
                    end else begin
                        r_clk_cnt <= r_clk_cnt +1; 
                    end                   
                end

                DONE: begin
                    o_valid_n <= 1'b0; //activate valid
                    o_data <= r_shift_reg;
                    r_state <= IDLE;
                end
            endcase
        end
    end
endmodule


// Optimized version of nco_chirp.v for low-area
module nco_chirp #(
    parameter PHASE_WIDTH   = 32,   // phase accumulator width
    parameter MAX_SF_WIDTH  = 8,    // SF bits
    parameter MAX_SF_VALUE  = 32,
    parameter BW_BITWIDTH   = 2     // BW config width
)(
    input  wire                      i_clk,
    input  wire                      i_rst_n,
    input  wire                      i_start_n,
    input  wire [MAX_SF_WIDTH-1:0]   i_SF,
    input  wire [1:0]                i_bw_config,
    input  wire [PHASE_WIDTH-1:0]    i_init_phase_inc,
    input  wire [PHASE_WIDTH-1:0]    i_slope,
    input  wire                      i_sample_tick_n,
    output reg  [PHASE_WIDTH-1:0]    o_phase_acc,
    output reg                       o_done_n
);
    reg [PHASE_WIDTH-1:0] r_phase_inc;

    reg [PHASE_WIDTH-1:0] PHASE_INC_MAX; //Phase inc maximum before chirp wraparound
    
    always @* begin
        case (i_bw_config)
            2'd0: PHASE_INC_MAX = 32'h0333_3333;
            2'd1: PHASE_INC_MAX = 32'h0666_6666;
            2'd2: PHASE_INC_MAX = 32'h0CCC_CCCC;
            default: PHASE_INC_MAX = 32'h0333_3333;
        endcase
    end

    localparam STATE_IDLE = 2'd0,
               STATE_LOAD = 2'd1,
               STATE_RUN  = 2'd2,
               STATE_DONE = 2'd3;

    reg [1:0] r_state, r_next_state;
    reg [MAX_SF_WIDTH-1:0] sample_cnt;
    wire [MAX_SF_VALUE-1:0] total_samples = (1 << i_SF);

    reg sample_tick_d;
    wire sample_tick_fall = sample_tick_d & ~i_sample_tick_n;

    reg [PHASE_WIDTH:0] next_inc;

    always @(posedge i_clk) begin
        sample_tick_d <= i_sample_tick_n;

        if (!i_rst_n) begin
            r_state     <= STATE_IDLE;
            sample_cnt  <= 0;
            o_phase_acc <= 0;
            r_phase_inc <= 0;
            o_done_n    <= 1;
        end else begin
            o_done_n <= 1;
            r_state  <= r_next_state;

            case (r_next_state)
                STATE_IDLE: begin
                    sample_cnt <= 0;
                    o_phase_acc <= 0;
                end
                STATE_LOAD: begin
                    sample_cnt  <= 0;
                    o_phase_acc <= 0;
                    r_phase_inc <= i_init_phase_inc;
                end
                STATE_RUN: begin
                    o_phase_acc <= o_phase_acc + r_phase_inc;
                    if (sample_tick_fall) begin
                        next_inc = r_phase_inc + i_slope;
                        r_phase_inc <= (next_inc >= PHASE_INC_MAX) ? (next_inc - PHASE_INC_MAX) : next_inc;
                        sample_cnt <= sample_cnt + 1;
                    end
                end
                STATE_DONE: begin
                    o_done_n <= 0;
                    o_phase_acc <= 0;
                end
            endcase
        end
    end

    always @(*) begin
        r_next_state = r_state;
        case (r_state)
            STATE_IDLE: if (!i_start_n) r_next_state = STATE_LOAD;
            STATE_LOAD:                r_next_state = STATE_RUN;
            STATE_RUN: if (sample_cnt == total_samples - 1) r_next_state = STATE_DONE;
            STATE_DONE:                r_next_state = STATE_IDLE;
        endcase
    end

endmodule




Reference solution:
rtl/generated.v: 
//-------------------Design instantiation-------------------------------
chirpmod #(
    .PHASE_WIDTH        (32),
    .MAX_SF_WIDTH       (8),
    .BW_BITWIDTH        (2),
    .ADDR_WIDTH         (6),
    .DATA_WIDTH         (8),
    .DIVIDER_BITWIDTH   (7)
  ) 
  chirp_module 
  (
    .i_clk   (clk),   //!Input clock: 10 MHz
    .i_rst_n (rst_n),   //!Input reset active Low
    .i_rx    (ui_in[0]),   //!Input UART rx (9600 bps) //UART RX input line: ui_in[0] port
    .o_done_n(uio_out[0]), //!Output done active Low
    .o_data  (uo_out)    //!Output bus data (8 bit)
  );

     //-------------------IO Ports assigned to Output ('1')------------------
    assign uio_oe   [7:0]   = 8'b0000_0001; //enable used uio outputs
    assign uio_out  [7:1]   = 7'b0000_000;   //set other to zero

    // List all unused inputs to prevent warnings
    wire _unused = &{ena, uio_oe[7:0], uio_out[7:1], ui_in[7:1], uio_in[7:0], 1'b0};