// sv39.c — las macros de paginación de xv6-riscv (kernel/riscv.h), fuera
// del kernel, para ver qué calculan con números concretos.
#include <stdio.h>
#include <stdint.h>

typedef uint64_t uint64;

// Copiadas de kernel/riscv.h
#define PGSIZE  4096 // bytes per page
#define PGSHIFT 12   // bits of offset within a page
#define PTE_V (1L << 0) // valid
#define PTE_R (1L << 1)
#define PTE_W (1L << 2)
#define PTE_X (1L << 3)
#define PTE_U (1L << 4) // user can access
#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)
#define PTE2PA(pte) (((pte) >> 10) << 12)
#define PTE_FLAGS(pte) ((pte) & 0x3FF)
#define PXMASK         0x1FF // 9 bits
#define PXSHIFT(level) (PGSHIFT + (9 * (level)))
#define PX(level, va)  ((((uint64)(va)) >> PXSHIFT(level)) & PXMASK)
#define MAXVA (1L << (9 + 9 + 9 + 12 - 1))
// Copiada de kernel/memlayout.h
#define TRAMPOLINE (MAXVA - PGSIZE)

static void show_va(const char *name, uint64 va) {
    printf("%-10s  PX(2,1,0) = %3llu %3llu %3llu  offset 0x%03llx\n", name,
           (unsigned long long)PX(2, va), (unsigned long long)PX(1, va),
           (unsigned long long)PX(0, va), (unsigned long long)(va & (PGSIZE - 1)));
}

static void show_flags(uint64 pte) {
    printf("%c%c%c%c%c", (pte & PTE_U) ? 'U' : '-', (pte & PTE_X) ? 'X' : '-',
           (pte & PTE_W) ? 'W' : '-', (pte & PTE_R) ? 'R' : '-',
           (pte & PTE_V) ? 'V' : '-');
}

int main(void) {
    show_va("0x1234", 0x1234);
    show_va("0x40201abc", 0x40201abc);
    show_va("TRAMPOLINE", TRAMPOLINE);
    printf("TRAMPOLINE = 0x%llx, MAXVA = 0x%llx\n\n",
           (unsigned long long)TRAMPOLINE, (unsigned long long)MAXVA);

    // Una PTE de hoja: página de usuario, lectura y escritura.
    uint64 pa = 0x87f42000;
    uint64 pte = PA2PTE(pa) | PTE_U | PTE_W | PTE_R | PTE_V;
    printf("pa          = 0x%llx\n", (unsigned long long)pa);
    printf("PA2PTE(pa)  = 0x%llx\n", (unsigned long long)PA2PTE(pa));
    printf("pte         = 0x%llx  ", (unsigned long long)pte);
    show_flags(pte);
    printf("\nPTE_FLAGS   = 0x%03llx\n", (unsigned long long)PTE_FLAGS(pte));
    printf("PTE2PA(pte) = 0x%llx\n", (unsigned long long)PTE2PA(pte));
    return 0;
}
