// retroDE_ps2 — trace_sink_stub
//
// Simulation-only text trace writer for Wave 1 stubs.
//
// Purpose, owns, success condition, replacement path: see
//   docs/stub_module_plan.md  (Wave 1, item 1)
//   docs/contracts/validation.md
//   docs/decisions/0000-trace-format.md
//
// Interface shape:
//   - One sink instance per output file. A testbench instantiates multiple
//     sinks (one per stub under test) and wires each stub's event port to
//     its own sink. Offline tooling merges files by cycle when needed.
//   - The cycle counter is internal and advances on clk while rst_n is high.
//     Multi-clock-domain correlation is a later-wave concern.
//
// Line format (docs/decisions/0000):
//     cycle  subsys  event  arg0  arg1  arg2  arg3  flags
//   where flags is rendered as `-` when zero.

`timescale 1ns/1ps

module trace_sink_stub
    import trace_pkg::*;
#(
    parameter string FILENAME       = "trace.txt",
    parameter int    SCHEMA_VERSION = 1,
    parameter string SINK_LABEL     = "trace"
) (
    input  logic          clk,
    input  logic          rst_n,

    input  logic          ev_valid,
    input  subsys_e       ev_subsys,
    input  event_e        ev_event,
    input  logic [63:0]   ev_arg0,
    input  logic [63:0]   ev_arg1,
    input  logic [63:0]   ev_arg2,
    input  logic [63:0]   ev_arg3,
    input  logic [31:0]   ev_flags
);

    integer          fd;
    longint unsigned cycle_count;

    initial begin
        fd = $fopen(FILENAME, "w");
        if (fd == 0) begin
            $fatal(1, "[trace_sink_stub %0s] cannot open %0s", SINK_LABEL, FILENAME);
        end
        $fdisplay(fd, "# retroDE_ps2 trace, schema v%0d, sink=%0s",
                  SCHEMA_VERSION, SINK_LABEL);
        $fdisplay(fd, "# columns: cycle subsystem event arg0 arg1 arg2 arg3 flags");
        cycle_count = 64'd0;
    end

    always_ff @(posedge clk) begin
        if (!rst_n) begin
            cycle_count <= 64'd0;
        end else begin
            cycle_count <= cycle_count + 64'd1;

            if (ev_valid) begin
                if (ev_flags == 32'd0) begin
                    $fdisplay(fd,
                              "%0d %0s %0s 0x%016h 0x%016h 0x%016h 0x%016h -",
                              cycle_count,
                              subsys_str(ev_subsys),
                              event_str(ev_event),
                              ev_arg0, ev_arg1, ev_arg2, ev_arg3);
                end else begin
                    $fdisplay(fd,
                              "%0d %0s %0s 0x%016h 0x%016h 0x%016h 0x%016h 0x%08h",
                              cycle_count,
                              subsys_str(ev_subsys),
                              event_str(ev_event),
                              ev_arg0, ev_arg1, ev_arg2, ev_arg3,
                              ev_flags);
                end
            end
        end
    end

    final begin
        if (fd != 0) $fclose(fd);
    end

endmodule : trace_sink_stub
