/* SPDX-License-Identifier: Apache-2.0
 * Copyright 2024 Google LLC
 *
 * ICache Core-Side ECC & Parity Fault Recovery Test
 *
 * Architecture & Test Intent:
 * Commit 7dd5354d ("Move iCache ECC and parity check into DCLS") moved the
 * ICache read data decoding logic (both 7-bit Hamming SECDED ECC and 4-bit byte parity)
 * inside the DCLS core domain (el2_ifu_mem_ctl.sv).
 *
 * This test verifies:
 * 1. Single-bit memory read data fault injection (mailbox command 0x89) triggers
 *    the core-side ECC/Parity error decoders (rvecc_decode_64 / rveven_paritycheck).
 * 2. The Trap Logic Unit (TLU) increments the ICache Error Counter CSR (micect 0x7F0)
 *    by exactly 1.
 * 3. The core hardware cleanly flushes the pipeline and re-fetches the instruction,
 *    allowing program execution to continue seamlessly (verified by function execution
 *    counter == 3).
 * 4. Works in both `icache_ecc=1` (ECC) and `icache_ecc=0` (Parity) simulation builds.
 */

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#define STDOUT_ADDR 0xD0580000
volatile uint32_t *mailbox = (uint32_t *)STDOUT_ADDR;

// Mailbox Command Protocols
#define CMD_INJECT_ICACHE_SINGLE_BIT 0x89
#define CMD_TEST_PASSED              0xFF
#define CMD_TEST_FAILED              0x01

// CSR Definitions
#define MICECT_CSR_ADDR          0x7F0  // ICache Error Counter CSR (micect)

#define read_csr(csr) ({ \
    unsigned long res; \
    asm volatile ("csrr %0, " #csr : "=r"(res)); \
    res; \
})

#define write_csr(csr, val) { \
    asm volatile ("csrw " #csr ", %0" : : "r"(val)); \
}

static volatile uint32_t counter = 0;

void trap_handler(void) {
    // Default trap handler stub
}

// Function aligned to 16-byte boundary to isolate instruction cache line fetch
__attribute__((noinline, aligned(16)))
void target_inst(void) {
    counter++;
}

int main(void) {
    printf("=====================================================\n");
    printf(" Starting ICache Core-Side ECC & Parity Recovery Test\n");
    printf("=====================================================\n");

    // Phase 1: Warm up target instruction in ICache (populates cache line)
    target_inst();
    printf("[Phase 1] Cache line warmup complete. Counter = %u\n", counter);

    // Phase 2: Inject single-bit ICache read data fault & verify micect CSR (0x7F0) increment
    printf("[Phase 2] Triggering single-bit ICache fault via mailbox (0x89)...\n");

    // Warm up target_inst() immediately before fault injection to guarantee ICache HIT
    // (prevents picolibc printf instruction fetches from evicting target_inst from ICache)
    target_inst();

    uint32_t count_before = read_csr(0x7F0);
    *mailbox = CMD_INJECT_ICACHE_SINGLE_BIT;
    target_inst();
    uint32_t count_after = read_csr(0x7F0);

    printf("[Phase 2] Pipeline flush & refetch complete. micect (0x7F0): before = %u, after = %u\n",
           count_before, count_after);

    // Verify exact CSR increment (+1)
    if (count_after != count_before + 1) {
        printf("FAIL: Hardware ICache error counter CSR (micect 0x7F0) expected %u, got %u!\n",
               count_before + 1, count_after);
        *mailbox = CMD_TEST_FAILED;
        return 1;
    }
    printf("[Phase 2] ICache hardware error counter increment (+1) verified successfully!\n");

    // Verify program execution continuation after pipeline flush and instruction refetch
    if (counter != 3) {
        printf("FAIL: Execution continuation check failed! Target instruction counter expected 3, got %u\n", counter);
        *mailbox = CMD_TEST_FAILED;
        return 1;
    }
    printf("[Phase 2] Post-fault execution continuation (counter = 3) verified successfully!\n");

    // Finish test cleanly with TEST_PASSED
    printf("All ICache ECC/Parity fault recovery test phases PASSED!\n");
    *mailbox = CMD_TEST_PASSED;

    return 0;
}
