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.

`timescale 1ns/1ps

module tt_um_sha256_processor_dvirdc (
    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,      // always 1 when the design is powered, so you can ignore it
    input  wire       clk,      // clock
    input  wire       rst_n
);

    wire  busy;
    wire  dvalid;
    wire  ready;

    assign uio_out = {
        3'b000,         // bits 7..5 unused
        ready,          // bit 4 – processor input-ready flag
        busy,           // bit 3
        dvalid,         // bit 2
        2'b00           // bits 1..0 unused
    };
    
    assign uio_oe = 8'b0001_1100; // bits 4,3,2 are outputs

    wire internal_rst = ~rst_n;

    top_gpio_sha256 top (
        .clk(clk),
        .rst(internal_rst),
        .din(ui_in),
        .valid(uio_in[0]),
        .last(uio_in[1]),
        .busy(busy),
        .dout(uo_out),
        .dvalid(dvalid),
        .ready(ready)
    );

endmodule


`timescale 1ns/1ps
/* verilator lint_off WIDTHEXPAND */
/* verilator lint_off WIDTH */
/* verilator lint_off CASEINCOMPLETE */
/* verilator lint_off UNUSEDPARAM */
module top_gpio_sha256 (
    input              clk,
    input              rst,            // active high
    input       [7:0]  din,            // ui_in[7:0]
    input              valid,          // uio_in[0]
    input              last,           // uio_in[1]
    output reg         busy,           // uio_out[2]
    output reg  [7:0]  dout,           // uo_out[7:0]
    output reg         dvalid,
    output              ready
    
);

    //----------------------------------------------------------
    // 1.  Wire up the existing streaming SHA-256 processor
    //----------------------------------------------------------
    reg start_core;
    reg data_valid;
    reg data_last;
    // Byte driven into the streaming processor
    reg [7:0] data_byte;
    
    wire proc_in_ready;   // handshake from processor

    wire [255:0] hash;
    wire         proc_done;

    sha256_processor u_proc (
        .clk(clk),
        .rst(rst),
        .start(start_core),
        .data_in(data_byte),
        .data_valid(data_valid),
        .data_last(data_last),
        .hash_out(hash),
        .done(proc_done),
        .in_ready(proc_in_ready)
    );

    // Export to top level
    assign ready = proc_in_ready;

    // Simple 2-byte skid buffer to avoid losing bytes across ready deassertions
    reg        pend0_valid, pend1_valid;
    reg [7:0]  pend0_byte,  pend1_byte;
    reg        pend0_last,  pend1_last;

    //----------------------------------------------------------
    // 2.  FSM: IDLE → FEED → WAIT → DUMP → IDLE
    //----------------------------------------------------------
    localparam IDLE=0, FEED=1, WAIT=2, DUMP=3;
    reg [1:0]   state = IDLE;
    reg [4:0]   byte_cntr;     // 0-31 during digest dump

    always @(posedge clk) begin
        if (rst) begin
            state       <= IDLE;
            busy        <= 1'b0;
            dvalid      <= 1'b0;
            start_core  <= 1'b0;
            data_valid  <= 1'b0;
            data_last   <= 1'b0;
            dout        <= 8'h00;
            data_byte   <= 8'h00;
            byte_cntr   <= 5'd0;
            pend0_valid <= 1'b0;
            pend1_valid <= 1'b0;
            pend0_byte  <= 8'h00;
            pend1_byte  <= 8'h00;
            pend0_last  <= 1'b0;
            pend1_last  <= 1'b0;
        end else begin
            // default strobes
            dvalid     <= 1'b0;
            data_valid <= 1'b0;
            data_last  <= 1'b0;
            start_core <= 1'b0;

            // Capture incoming byte into skid buffer if processor is not ready this cycle
            if (valid && !proc_in_ready) begin
                if (!pend0_valid) begin
                    pend0_valid <= 1'b1;
                    pend0_byte  <= din;
                    pend0_last  <= last;
                end else if (!pend1_valid) begin
                    pend1_valid <= 1'b1;
                    pend1_byte  <= din;
                    pend1_last  <= last;
                end
            end

            case (state)
            IDLE: begin
                busy <= 1'b0;
                // Choose source: pending buffer has priority when present
                if (proc_in_ready && (pend0_valid || valid)) begin
                    start_core <= 1'b1;     // starting a (possibly continued) message
                    data_valid <= 1'b1;
                    busy       <= 1'b1;
                    if (pend0_valid) begin
                        data_byte  <= pend0_byte;
                        data_last  <= pend0_last;
                        // shift buffer
                        pend0_valid <= pend1_valid;
                        pend0_byte  <= pend1_byte;
                        pend0_last  <= pend1_last;
                        pend1_valid <= 1'b0;
                    end else begin
                        data_byte <= din;
                        data_last <= last;
                    end
                    state <= ((pend0_valid ? pend0_last : last) ? WAIT : FEED);
                end
            end

            FEED: begin
                // Send pending first when ready, otherwise pass through current byte
                if (proc_in_ready && (pend0_valid || valid)) begin
                    data_valid <= 1'b1;
                    if (pend0_valid) begin
                        data_byte  <= pend0_byte;
                        data_last  <= pend0_last;
                        // shift buffer
                        pend0_valid <= pend1_valid;
                        pend0_byte  <= pend1_byte;
                        pend0_last  <= pend1_last;
                        pend1_valid <= 1'b0;
                    end else begin
                        data_byte <= din;
                        data_last <= last;
                    end
                    if ((pend0_valid ? pend0_last : last)) state <= WAIT;
                end else if (valid && !proc_in_ready) begin
                    // Already handled above: store into pending when not ready
                end
            end

            WAIT: if (proc_done) begin
                byte_cntr <= 5'd0;
                state     <= DUMP;
            end

            DUMP: begin
                dout   <= hash[255 - byte_cntr*8 -: 8];
                dvalid <= 1'b1;
                byte_cntr <= byte_cntr + 1'b1;
                if (byte_cntr == 5'd31) state <= IDLE;
            end
            endcase
        end
    end
endmodule

`timescale 1ns/1ps
/* verilator lint_off WIDTHEXPAND */
/* verilator lint_off WIDTH */
/* verilator lint_off CASEINCOMPLETE */
/* verilator lint_off UNUSEDPARAM */

module sha256_processor (
    input         clk,
    input         rst,
    input         start,
    input  [7:0]  data_in,
    input         data_valid,
    input         data_last,
    output [255:0] hash_out,
    output        done,
    output        in_ready        // HIGH when processor can accept a byte
);
// >>> Module Implementation Begin

// <<< Module Implementation End
endmodule




`timescale 1ns/1ps
/* verilator lint_off WIDTHEXPAND */
/* verilator lint_off WIDTH */
/* verilator lint_off CASEINCOMPLETE */
/* verilator lint_off UNUSEDPARAM */
module sha256_core_v3 (
    input         clk,
    input         rst,
    input         start,
    input  [511:0] block_in,
    input         first_run,     // 0 = use existing state, 1 = use IV
    output [255:0] hash_out,
    output reg    ready
);

    // Round counter
    reg  [6:0] t;                      // 0-63

    // State machine
    reg [1:0] state;
    localparam IDLE = 2'd0, COMP = 2'd1, DONE = 2'd2;

    wire [31:0] k_value;
    sha256_k_rom_soft KROM (.addr(t[5:0]), .data(k_value));

    // register K ROM output once
    // reg [31:0] k_q; 
    // always @(posedge clk) k_q <= k_value;

    // register W[t] output similarly
    // reg [31:0] w_q; 
    // always @(posedge clk) w_q <= w_t;

    localparam H0_INIT = 32'h6a09e667, H1_INIT = 32'hbb67ae85, H2_INIT = 32'h3c6ef372, H3_INIT = 32'ha54ff53a,
               H4_INIT = 32'h510e527f, H5_INIT = 32'h9b05688c, H6_INIT = 32'h1f83d9ab, H7_INIT = 32'h5be0cd19;

    // ─────────────────────────────────────────────────────────────
    // 2. Registers and Wires
    // ─────────────────────────────────────────────────────────────
    reg [31:0] a, b, c, d, e, f, g, h;
    reg [31:0] h0, h1, h2, h3, h4, h5, h6, h7;
    reg [31:0] w[0:15]; // Optimized: 16-word circular buffer for message schedule
    

    // Corrected, portable syntax for circular buffer indexing
    wire [3:0] w_idx_m2   = t - 7'd2;
    wire [3:0] w_idx_m7   = t - 7'd7;
    wire [3:0] w_idx_m15  = t - 7'd15;
    wire [3:0] w_idx_m16  = t - 7'd16;

    // Combinational logic for on-the-fly message schedule expansion
    wire [31:0] w_expanded = sig1(w[w_idx_m2]) + w[w_idx_m7] + sig0(w[w_idx_m15]) + w[w_idx_m16];

    // Select the correct message word for the current round
    wire [31:0] w_t = (t < 16) ? w[t[3:0]] : w_expanded;

    // Combinational logic for round calculations
    wire [31:0] S1 = (ror(e,6) ^ ror(e,11) ^ ror(e,25));
    wire [31:0] ch = (e & f) ^ ((~e) & g);

    wire [31:0] T1 = h + S1 + ch + k_value + w_t;

    wire [31:0] S0 = (ror(a,2) ^ ror(a,13) ^ ror(a,22));
    wire [31:0] maj = (a & b) ^ (a & c) ^ (b & c);
    wire [31:0] T2 = S0 + maj;

    // The additions from COMP are now registered in h0-h7. Output the final hash.
    assign hash_out = {h0, h1, h2, h3, h4, h5, h6, h7};

    // ─────────────────────────────────────────────────────────────
    // 3. Helper Functions
    // ─────────────────────────────────────────────────────────────
    function [31:0] ror; input[31:0] x; input integer n; begin ror = (x >> n) | (x << (32 - n)); end endfunction
    function [31:0] sig0; input[31:0] x; begin sig0 = ror(x, 7) ^ ror(x, 18) ^ (x >> 3); end endfunction
    function [31:0] sig1; input[31:0] x; begin sig1 = ror(x, 17) ^ ror(x, 19) ^ (x >> 10); end endfunction

    // ─────────────────────────────────────────────────────────────
    // 4. Main State Machine
    // ─────────────────────────────────────────────────────────────
    always @(posedge clk) begin
        if (rst) begin
            state <= IDLE;
            ready <= 1'b0;
            t <= 7'b0;
            // (t_next removed – no longer needed)
            a <= 0; b <= 0; c <= 0; d <= 0;
            e <= 0; f <= 0; g <= 0; h <= 0;
            
            h0 <= 0; h1 <= 0; h2 <= 0; h3 <= 0; 
            h4 <= 0; h5 <= 0; h6 <= 0; h7 <= 0;

            w[0] <= 0; w[1] <= 0; w[2] <= 0; w[3] <= 0;
            w[4] <= 0; w[5] <= 0; w[6] <= 0; w[7] <= 0;
            w[8] <= 0; w[9] <= 0; w[10] <= 0; w[11] <= 0;
            w[12] <= 0; w[13] <= 0; w[14] <= 0; w[15] <= 0;

        end else begin
            case (state)
                IDLE: begin
                    if (start) begin
                        ready <= 1'b0;
                        // Initialize working variables for compression.
                        if (first_run) begin
                            {h0,h1,h2,h3,h4,h5,h6,h7} <= {H0_INIT,H1_INIT,H2_INIT,H3_INIT,H4_INIT,H5_INIT,H6_INIT,H7_INIT};
                            {a,b,c,d,e,f,g,h} <= {H0_INIT,H1_INIT,H2_INIT,H3_INIT,H4_INIT,H5_INIT,H6_INIT,H7_INIT};
                        end else begin
                            {a,b,c,d,e,f,g,h} <= {h0,h1,h2,h3,h4,h5,h6,h7};
                        end
                        // Load the first 16 words of the message block into the circular buffer.
                        w[0] <= block_in[511 - 32*0 -: 32];
                        w[1] <= block_in[511 - 32*1 -: 32];
                        w[2] <= block_in[511 - 32*2 -: 32];
                        w[3] <= block_in[511 - 32*3 -: 32];
                        w[4] <= block_in[511 - 32*4 -: 32];
                        w[5] <= block_in[511 - 32*5 -: 32];
                        w[6] <= block_in[511 - 32*6 -: 32];
                        w[7] <= block_in[511 - 32*7 -: 32];
                        w[8] <= block_in[511 - 32*8 -: 32];
                        w[9] <= block_in[511 - 32*9 -: 32];
                        w[10] <= block_in[511 - 32*10 -: 32];
                        w[11] <= block_in[511 - 32*11 -: 32];
                        w[12] <= block_in[511 - 32*12 -: 32];
                        w[13] <= block_in[511 - 32*13 -: 32];
                        w[14] <= block_in[511 - 32*14 -: 32];
                        w[15] <= block_in[511 - 32*15 -: 32];
                        t <= 7'b0;
                        // (k_addr logic removed – replaced by combinational case table)
                        state <= COMP;
                    end
                end

                COMP: begin
                    if (t < 64) begin
                        // Update working variables for one round.
                        a <= T1 + T2;
                        b <= a;
                        c <= b;
                        d <= c;
                        e <= d + T1;
                        f <= e;
                        g <= f;
                        h <= g;
                        
                        // For rounds 16-63, store the newly calculated schedule word
                        // into the circular buffer, overwriting the old value.
                        if (t >= 16) begin
                            w[t[3:0]] <= w_expanded;
                        end
                        
                        t <= t + 1;
                        // (k_addr logic removed – replaced by combinational case table)
                    end else begin
                        // 64 rounds are complete. Add the results to the hash state registers.
                        h0 <= h0 + a;
                        h1 <= h1 + b;
                        h2 <= h2 + c;
                        h3 <= h3 + d;
                        h4 <= h4 + e;
                        h5 <= h5 + f;
                        h6 <= h6 + g;
                        h7 <= h7 + h;
                        state <= DONE;
                    end
                end

                DONE: begin
                    // The additions from COMP are now registered in h0-h7. Set ready bit.
                    ready <= 1'b1;
                    if (!start) begin
                        state <= IDLE;
                    end
                end
            endcase
        end
    end

endmodule

// sha256_k_rom_soft.v — synthesizable read-only K table (64 x 32)
module sha256_k_rom_soft (
  input  wire [5:0] addr,   // round 0..63
  output reg  [31:0] data
);
  always @* begin
    case (addr)
      6'd0  : data = 32'h428a2f98; 6'd1  : data = 32'h71374491;
      6'd2  : data = 32'hb5c0fbcf; 6'd3  : data = 32'he9b5dba5;
      6'd4  : data = 32'h3956c25b; 6'd5  : data = 32'h59f111f1;
      6'd6  : data = 32'h923f82a4; 6'd7  : data = 32'hab1c5ed5;
      6'd8  : data = 32'hd807aa98; 6'd9  : data = 32'h12835b01;
      6'd10 : data = 32'h243185be; 6'd11 : data = 32'h550c7dc3;
      6'd12 : data = 32'h72be5d74; 6'd13 : data = 32'h80deb1fe;
      6'd14 : data = 32'h9bdc06a7; 6'd15 : data = 32'hc19bf174;
      6'd16 : data = 32'he49b69c1; 6'd17 : data = 32'hefbe4786;
      6'd18 : data = 32'h0fc19dc6; 6'd19 : data = 32'h240ca1cc;
      6'd20 : data = 32'h2de92c6f; 6'd21 : data = 32'h4a7484aa;
      6'd22 : data = 32'h5cb0a9dc; 6'd23 : data = 32'h76f988da;
      6'd24 : data = 32'h983e5152; 6'd25 : data = 32'ha831c66d;
      6'd26 : data = 32'hb00327c8; 6'd27 : data = 32'hbf597fc7;
      6'd28 : data = 32'hc6e00bf3; 6'd29 : data = 32'hd5a79147;
      6'd30 : data = 32'h06ca6351; 6'd31 : data = 32'h14292967;
      6'd32 : data = 32'h27b70a85; 6'd33 : data = 32'h2e1b2138;
      6'd34 : data = 32'h4d2c6dfc; 6'd35 : data = 32'h53380d13;
      6'd36 : data = 32'h650a7354; 6'd37 : data = 32'h766a0abb;
      6'd38 : data = 32'h81c2c92e; 6'd39 : data = 32'h92722c85;
      6'd40 : data = 32'ha2bfe8a1; 6'd41 : data = 32'ha81a664b;
      6'd42 : data = 32'hc24b8b70; 6'd43 : data = 32'hc76c51a3;
      6'd44 : data = 32'hd192e819; 6'd45 : data = 32'hd6990624;
      6'd46 : data = 32'hf40e3585; 6'd47 : data = 32'h106aa070;
      6'd48 : data = 32'h19a4c116; 6'd49 : data = 32'h1e376c08;
      6'd50 : data = 32'h2748774c; 6'd51 : data = 32'h34b0bcb5;
      6'd52 : data = 32'h391c0cb3; 6'd53 : data = 32'h4ed8aa4a;
      6'd54 : data = 32'h5b9cca4f; 6'd55 : data = 32'h682e6ff3;
      6'd56 : data = 32'h748f82ee; 6'd57 : data = 32'h78a5636f;
      6'd58 : data = 32'h84c87814; 6'd59 : data = 32'h8cc70208;
      6'd60 : data = 32'h90befffa; 6'd61 : data = 32'ha4506ceb;
      6'd62 : data = 32'hbef9a3f7; 6'd63 : data = 32'hc67178f2;
      default: data = 32'h00000000;
    endcase
  end
endmodule

Reference solution:
rtl/generated.v: 
    // Constants
    localparam BLOCK_SIZE = 64;

    // Internal memory to hold a block (64 bytes)
    reg [511:0] block_buffer;
    reg [5:0]   byte_index;
    reg         block_ready;

    // FSM
    // Only four states are needed once padding is handled externally
    reg [1:0] state;
    localparam IDLE = 0, LOAD = 1, HASH = 2, DONE = 3;

    // SHA-256 Core
    wire [255:0] core_hash_out;
    wire         core_ready;
    reg          core_start;
    reg          core_first_run;
    reg          core_busy;
    // Previous value of core_ready to detect rising edge (completion)
    reg          core_ready_prev;

    sha256_core_v3 sha_core (
        .clk(clk),
        .rst(rst),
        .start(core_start),
        .block_in(block_buffer),
        .first_run(core_first_run),
        .hash_out(core_hash_out),
        .ready(core_ready)
    );

    assign hash_out = core_hash_out;
    assign done     = (state == DONE);
    assign in_ready = (state == LOAD) || (state == IDLE);

    // Tracks when the last byte of the overall message has been seen
    reg        seen_last;

    // Staging for the first byte of the next block if it arrives while hashing
    reg        has_staged_byte;
    reg  [7:0] staged_byte;
    reg        staged_last;

    integer i;

    always @(posedge clk) begin
        if (rst) begin
            state <= IDLE;
            byte_index <= 0;
            block_ready <= 0;
            block_buffer <= 512'b0;
            core_start <= 0;
            core_first_run <= 0;
            core_busy <= 0;
            core_ready_prev <= 0;
            seen_last <= 0;
            has_staged_byte <= 0;
            staged_byte <= 8'h00;
            staged_last <= 1'b0;
        end else begin
            case (state)
                IDLE: begin
                    if (start) begin
                        core_first_run <= 1;
                        state <= LOAD;
                        seen_last <= 0;
                        // Start of a new message: clear the block buffer
                        block_buffer <= 512'b0;
                        has_staged_byte <= 0;

                        // If a data byte is already present together with the start
                        if (data_valid) begin
                            // Store as byte 0 of the block (big-endian MSB first)
                            block_buffer[511 -: 8] <= data_in;
                            byte_index <= 1;
                            if (data_last)
                                seen_last <= 1;
                        end else begin
                            byte_index <= 0;
                        end
                    end
                end

                LOAD: begin
                    if (data_valid && byte_index < BLOCK_SIZE) begin
                        // Store incoming byte into the correct position (big-endian)
                        block_buffer[511 - byte_index*8 -: 8] <= data_in;

                        // Track whether this is the final byte of the entire message
                        if (data_last)
                            seen_last <= 1;

                        byte_index <= byte_index + 1;

                        // When we have accumulated a full 64-byte block, trigger hashing
                        if (byte_index + 1 == BLOCK_SIZE) begin
                            block_ready <= 1;
                            state <= HASH;
                        end
                    end
                end

                HASH: begin
                    // Issue a new block to the core only when it is not busy.
                    if (block_ready && !core_busy) begin
                        core_start <= 1;
                        block_ready <= 0;
                        core_busy <= 1;   // Core is now busy with this block
                    end else begin
                        core_first_run <= 0;
                        core_start <= 0;
                    end

                    // Capture one early byte for the next block if it arrives while hashing
                    if (data_valid && !has_staged_byte) begin
                        staged_byte <= data_in;
                        staged_last <= data_last;
                        has_staged_byte <= 1'b1;
                        if (data_last)
                            seen_last <= 1'b1;
                    end

                    // Detect rising edge of core_ready (block just finished)
                    if (core_ready && !core_ready_prev) begin
                        core_busy <= 0;           // Core is no longer busy

                        if (seen_last) begin
                            state <= DONE;        // All data processed
                        end else begin
                            // Clear buffer before accepting the next block
                            block_buffer <= 512'b0;
                            // Preload staged first byte if any
                            if (has_staged_byte) begin
                                block_buffer[511 -: 8] <= staged_byte;
                                byte_index <= 1;
                            end else begin
                                byte_index <= 0;
                            end
                            has_staged_byte <= 1'b0;
                            state <= LOAD;
                        end
                        // Clear last indicator so future blocks are treated normally
                        seen_last <= 0;
                    end

                    // Update previous-ready tracker each cycle
                    core_ready_prev <= core_ready;
                end

                DONE: begin
                    core_start <= 0;
                end
            endcase
        end
    end