/*
 * bank_local_data — demonstrates that a banked function can own its own
 * static (BSS) array and a const lookup table without burning HOME
 * memory.  When the function executes, BANK1 is mapped into window 3
 * and both code and data are directly addressable.
 *
 * No bank_read / bank_write needed — the trampoline maps the bank for
 * us and the C code touches the arrays normally.
 */

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

extern void     bank1_fill   (int seed) __banked;
extern uint16_t bank1_sumtab (void)     __banked;
extern uint8_t  bank1_peek   (int idx)  __banked;
extern void     bank1_map_print(void)   __banked;
extern uint8_t *bank1_alloc_and_fill(int n, uint8_t pattern) __banked;
extern void     bank1_free   (void *p)  __banked;

/* MUST be `const`: crt0_banked reads _n_banks BEFORE gsinit, so
 * non-const initialized variables haven't been copied yet and would
 * read 0 → bank loading is skipped → garbage in window 3. */
const uint8_t n_banks = 1;

uint8_t local0_buf[16];


int main(int argc, char **argv)
{
    puts("bank_local_data: testing static data in BANK1");

    bank1_map_print();

    /* Verify crt0_banked parsed argv correctly. */
    printf("argc=%d, argv[0]=\"%s\"\n", argc, argv[0]);

    printf("local0_buf = %p\n", local0_buf);
    for (int i = 1; i < argc; i++)
        printf("  argv[%d]=\"%s\"\n", i, argv[i]);

    /* Seed the BSS array in BANK1. */
    bank1_fill(0x10);

    /* Read it back through another banked function — verifies the data
     * survived after the trampoline returned to HOME and re-entered. */
    int ok = 1;
    for (int i = 0; i < 8; i++) {
        uint8_t v = bank1_peek(i);
        uint8_t expected = (uint8_t)(0x10 + i);
        if (v != expected) {
            printf("  bank1_buf[%d] = 0x%02X, expected 0x%02X\n",
                   i, v, expected);
            ok = 0;
        }
    }
    if (ok)
        puts("  buf[0..7] OK");

    /* Use the const lookup table that lives in BANK1. */
    uint16_t sum = bank1_sumtab();
    printf("  bank1_sumtab() = %u (expected 1500)\n", sum);

    /* malloc from a banked function — the heap lives in W2 (HOME),
     * which stays mapped across W3 page swaps.  Returned pointer
     * should be usable both inside the bank AND from HOME afterwards. */
    uint8_t *heap_p = bank1_alloc_and_fill(32, 0xA0);
    if (heap_p == NULL) {
        puts("  malloc from bank FAILED");
    } else {
        printf("  caller sees pointer = %p\n", heap_p);
        int ok = 1;
        for (int i = 0; i < 32; i++) {
            uint8_t expected = (uint8_t)(0xA0 + i);
            if (heap_p[i] != expected) {
                printf("  heap_p[%d] = 0x%02X, expected 0x%02X\n",
                       i, heap_p[i], expected);
                ok = 0;
            }
        }
        if (ok) puts("  bank-allocated heap [0..31] OK from HOME");
        bank1_free(heap_p);
    }

    puts("done");
    return 0;
}
