// hardware/soc_combined/top.v
//
// Combined top-level: Sapphire SoC + Church Machine for Ti60F225.
//
// The Sapphire SoC runs a RISC-V firmware that:
//   1. Configures the Church Machine via the APB3 bridge.
//   2. Starts CM execution by asserting the kick register (cm_push_button LOW).
//   3. Monitors CM status (boot_complete, fault, NIA) via APB3 reads.
//
// Clock/Reset
//   clk        — 25 MHz raw crystal (GPIOL_P_18_PLLIN0); NO PLL configured.
//   system_reset — active-HIGH; generated by Sapphire SoC
//   rst_n      — active-LOW derived from system_reset (for APB3 bridge)
//
// UART partitioning
//   uart_tx / uart_rx — GPIOL_02 / GPIOL_01 → FT4232H interface 2 (ttyUSB2)
//                       Sapphire SoC UART0; SoC firmware talks to the host.
//   cm_uart_tx        — Church Machine UART debug output (NIA, fault codes,
//                       call-home packets) → GPIOL_P_03 → FT4232H interface 3
//                       (ttyUSB3).  115200 baud, 1.8 V LVCMOS.
//   cm_uart_rx        — PATCH_LUMP receive ← GPIOL_N_03 ← FT4232H interface 3
//                       (ttyUSB3).  115200 baud.  Previously tied 1'b1 (idle).
//
// APB3 bridge register map (see apb3_cm_bridge.v for full description):
//   0x00  CTRL        [0]=cm_pb  (0=button pressed → step/free-run, 1=released)
//   0x04  STATUS      [2:0]={fault_latched, fault_valid, boot_complete}
//   0x08  NIA         [31:0]=CM next-instruction address
//   0x0C  FAULT       [4:0]=CM fault code
//   0x18  FAULT_GT    [31:0]=GT word0 of faulting capability (Track 4-C)
//   0x1C  FAULT_INSTR [31:0]=instruction word at fault NIA (Track 4-C)
//   0x20  FAULT_CR14  [31:0]=CR14 word0 at fault time (Track 4-C, reserved=0)
//   0x24  FAULT_STAGE [3:0]=pipeline stage index (Track 4-C)
//
// LED assignment  (Ti60F225 devkit has exactly 3 user LEDs)
//   led0 — SoC out-of-reset (GPIOR_P_07)
//   led1 — CM boot complete (GPIOR_P_08)
//   led2 — CM fault / banner  (GPIOR_P_09)
//
// NOTE: sapphire.v, sapphire_define.vh, and church_ti60_f225.v must be
//       copied into this directory before synthesis — see BUILD_SOC_CM.md.

`default_nettype none

module top (
    input  wire clk,           // 25 MHz raw crystal — no PLL (peri.xml has no PLL_TL0)
    output wire uart_tx,       // GPIOL_02 → FT4232H interface 2 → ttyUSB2
    input  wire uart_rx,       // GPIOL_01 ← FT4232H interface 2
    output wire cm_uart_tx,    // GPIOL_P_03 → FT4232H interface 3 → ttyUSB3
    input  wire cm_uart_rx,    // GPIOL_N_03 ← FT4232H interface 3 → ttyUSB3 (PATCH_LUMP RX)
    input  wire push_button,   // GPIOT_N_06, active-low, weak pull-up (to SoC GPIO)
    output wire led0,          // GPIOR_P_07  SoC out of reset
    output wire led1,          // GPIOR_P_08  CM boot complete
    output wire led2           // GPIOR_P_09  CM fault / banner
);

    // ----------------------------------------------------------------
    // Internal signals
    // ----------------------------------------------------------------
    wire system_reset;   // active-HIGH from Sapphire SoC

    // APB3 slave 0 — wired to apb3_cm_bridge
    wire [31:0] apb_paddr;
    wire        apb_penable;
    wire        apb_psel;
    wire        apb_pwrite;
    wire [31:0] apb_pwdata;
    wire [31:0] apb_prdata;
    wire        apb_pready;
    wire        apb_pslverror;

    // Church Machine control / status
    wire        cm_push_button_driven;  // from APB3 bridge → CM push_button input
    wire        cm_boot_complete;
    wire        cm_fault_valid;
    wire [31:0] cm_nia;
    wire [4:0]  cm_fault;
    wire [3:0]  cm_fault_raw;    // dbg_fault[3:0] from CM core; bit 4 always 0

    // CM debug signals — tied to 0 until the RTL is regenerated with
    // dedicated debug output ports (dbg_boot_complete, dbg_nia, dbg_fault,
    // dbg_fault_valid).  The pre-built bitstream in outflow/ was built from
    // the full debug-port RTL; use 'make bitstream' to rebuild with debug ports.

    // GT fault telemetry (Track 4-C — tied to 0 until CM Verilog is regenerated)
    wire [31:0] cm_fault_gt;
    wire [31:0] cm_fault_instr;
    wire [31:0] cm_fault_cr14;
    wire [3:0]  cm_fault_stage;

    // CM LED outputs (raw from church_ti60_f225)
    wire cm_led0, cm_led1, cm_led2, cm_led3;

    // cm_uart_tx is a top-level output port (GPIOL_P_03 → ttyUSB3)

    // UART-TX relay — SoC firmware serialises LUMP bytes via APB3 bridge
    // and drives them into the CM's UART_RX input (OR-gated with the pin).
    // ttyUSB3 pin input is preserved for future direct-flash use.
    wire relay_tx;
    wire cm_uart_rx_int;
    assign cm_uart_rx_int = relay_tx | cm_uart_rx;

    // ----------------------------------------------------------------
    // Power-on reset — down-counter from 0xFF → 0x00 (~255 cycles, ~10 µs
    // at 25 MHz).  por_reset is HIGH while any bit is set, then LOW forever.
    //
    // (* syn_keep = "true" *) is the Efinity attribute (NOT Xilinx's "keep").
    // Without it efx_map proves por_reset constant and folds it to 0, which
    // ties io_asyncReset=0 permanently → io_systemReset stuck HIGH → LED0 OFF.
    //
    // init=8'hFF is robust against Efinity FF power-up state: whether EFX_FF
    // initialises to 0 or 1, the Verilog initial value forces the correct start.
    // ----------------------------------------------------------------
    (* syn_keep = "true" *) reg [7:0] por_cnt = 8'hFF;
    always @(posedge clk)
        if (|por_cnt) por_cnt <= por_cnt - 1'b1;
    wire por_reset = (|por_cnt);    // HIGH for 255 cycles then LOW forever

    // ----------------------------------------------------------------
    // Sapphire SoC instantiation
    //
    // Port list from sapphire_tmpl.v (Efinix IP 2025.2).
    // APB slave 0 wired to the CM bridge; JTAG and SPI tied off.
    // ----------------------------------------------------------------
    sapphire u_sapphire (
        // Clocks and resets
        .io_systemClk           (clk),
        .io_asyncReset          (por_reset),   // POR: HIGH 128 cycles → LOW
        .io_systemReset         (system_reset),

        // UART0 — SoC console to FT4232H interface 2
        .system_uart_0_io_txd   (uart_tx),
        .system_uart_0_io_rxd   (uart_rx),

        // SPI0 — not used
        .system_spi_0_io_data_0_read        (1'b0),
        .system_spi_0_io_data_0_write       (),
        .system_spi_0_io_data_0_writeEnable (),
        .system_spi_0_io_data_1_read        (1'b0),
        .system_spi_0_io_data_1_write       (),
        .system_spi_0_io_data_1_writeEnable (),
        .system_spi_0_io_data_2_read        (1'b0),
        .system_spi_0_io_data_2_write       (),
        .system_spi_0_io_data_2_writeEnable (),
        .system_spi_0_io_data_3_read        (1'b0),
        .system_spi_0_io_data_3_write       (),
        .system_spi_0_io_data_3_writeEnable (),
        .system_spi_0_io_sclk_write         (),
        .system_spi_0_io_ss                 (),

        // APB slave 0 — wired to Church Machine bridge
        .io_apbSlave_0_PADDR    (apb_paddr),
        .io_apbSlave_0_PENABLE  (apb_penable),
        .io_apbSlave_0_PSEL     (apb_psel),
        .io_apbSlave_0_PWRITE   (apb_pwrite),
        .io_apbSlave_0_PWDATA   (apb_pwdata),
        .io_apbSlave_0_PREADY   (apb_pready),
        .io_apbSlave_0_PSLVERROR(apb_pslverror),
        .io_apbSlave_0_PRDATA   (apb_prdata),

        // JTAG — tied off (debug disabled).
        // jtagCtrl_reset = 1 means "TAP not in reset" (active-LOW polarity in
        // VexRiscv Sapphire).  Driving it LOW keeps the debug clock domain in
        // permanent reset, which propagates to io_systemReset → LED0 stays OFF.
        .jtagCtrl_enable  (1'b0),
        .jtagCtrl_tdi     (1'b0),
        .jtagCtrl_capture (1'b0),
        .jtagCtrl_shift   (1'b0),
        .jtagCtrl_update  (1'b0),
        .jtagCtrl_reset   (1'b1),   // 1 = TAP not in reset; was 1'b0 → stuck reset
        .jtagCtrl_tdo     (),
        .jtagCtrl_tck     (1'b0)
    );

    // ----------------------------------------------------------------
    // APB3 → CM bridge
    // ----------------------------------------------------------------
    apb3_cm_bridge #(
        .CLK_FREQ(25_000_000)
    ) u_bridge (
        .clk         (clk),
        .rst_n       (~system_reset),

        // APB3 slave
        .PADDR       (apb_paddr),
        .PENABLE     (apb_penable),
        .PSEL        (apb_psel),
        .PWRITE      (apb_pwrite),
        .PWDATA      (apb_pwdata),
        .PRDATA      (apb_prdata),
        .PREADY      (apb_pready),
        .PSLVERROR   (apb_pslverror),

        // CM control
        .cm_push_button  (cm_push_button_driven),

        // CM status
        .cm_boot_complete(cm_boot_complete),
        .cm_fault_valid  (cm_fault_valid),
        .cm_nia          (cm_nia),
        .cm_fault        (cm_fault),

        // GT fault telemetry (Track 4-C)
        .cm_fault_gt     (cm_fault_gt),
        .cm_fault_instr  (cm_fault_instr),
        .cm_fault_cr14   (cm_fault_cr14),
        .cm_fault_stage  (cm_fault_stage),

        // UART-TX relay output
        .relay_tx        (relay_tx)
    );

    // ----------------------------------------------------------------
    // Church Machine top-level instantiation
    //
    // Generated by: python hardware/gen_verilog.py
    //               → build/church_ti60_f225.v
    //               (module: church_ti60f225 — no underscore, Amaranth-generated)
    //
    // The push_button port (active-low) is driven by the APB3 bridge:
    //   1 = idle (released), 0 = pressed.
    // Holding LOW for ≥ 25 000 000 cycles (1 s @ 25 MHz) enters free-run.
    // A brief LOW pulse (< 1 s) triggers single-step.
    //
    // The CM UART port runs at 57,600 baud, 3.3 V LVCMOS.
    // TX (cm_uart_tx) goes to GPIOL_P_03 → ttyUSB3 for call-home/NIA.
    // RX (cm_uart_rx_int) is OR-gated: relay_tx (APB3 bridge) | cm_uart_rx pin
    // so the SoC firmware can push LUMPs directly without needing ttyUSB3.
    // ----------------------------------------------------------------
    church_ti60f225 u_cm (
        .clk              (clk),
        .uart_tx          (cm_uart_tx),          // CM UART TX → GPIOL_P_03 → ttyUSB3
        .uart_rx          (cm_uart_rx_int),       // relay_tx | GPIOL_N_03 ← ttyUSB3
        .push_button      (cm_push_button_driven),
        .dbg_boot_complete(cm_boot_complete),     // → APB3 STATUS[0] → SoC CALLHOME
        .dbg_fault_valid  (cm_fault_valid),       // → APB3 STATUS[1]
        .dbg_fault        (cm_fault_raw),           // → APB3 FAULT[3:0]
        .dbg_nia          (cm_nia),               // → APB3 NIA

        // CM LEDs — individual 1-bit outputs from generated Verilog
        .led0        (cm_led0),
        .led1        (cm_led1),
        .led2        (cm_led2),
        .led3        (cm_led3)
    );

    // Route CM signals to APB3 bridge inputs.
    // dbg_boot_complete / dbg_fault_valid / dbg_fault / dbg_nia are now wired
    // directly from the church_ti60f225 port list above.
    assign cm_fault         = {1'b0, cm_fault_raw}; // bit 4 not driven by CM core
    assign cm_fault_gt      = 32'b0;
    assign cm_fault_instr   = 32'b0;
    assign cm_fault_cr14    = 32'b0;
    assign cm_fault_stage   = 4'b0;

    // ----------------------------------------------------------------
    // LED logic  (Ti60F225 devkit: 3 user LEDs only)
    //   led0 — SoC out of reset         (GPIOR_P_07, active-HIGH)
    //   led1 — CM boot complete          (GPIOR_P_08, active-HIGH)
    //   led2 — CM fault / banner sent    (GPIOR_P_09, active-HIGH)
    //
    // cm_led3 (CM heartbeat) has no physical LED on this board — left
    // unconnected; synthesis will optimise it away.
    // ----------------------------------------------------------------
    assign led0 = ~system_reset;
    assign led1 = cm_boot_complete;
    assign led2 = cm_led2;

endmodule

`default_nettype wire
