CPlay/riscv-vm.c
2025-12-27 02:09:32 +01:00

66 lines
2 KiB
C

#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#define PPN_MASK (UINT64_MAX >> 20)
#define PPN_TO_PA(PPN) ((PPN & PPN_MASK) << 12)
#define PA_TO_PPN(PA) (PA >> 12)
#define ALIGN_UP(n, align) (((n) + (align) - 1) & ~((align) - 1))
#define ALIGN_DOWN(n, align) ((n) & ~((align) - 1))
#define IS_ALIGNED(x, align) (((uintptr_t)(x) & ((uintptr_t)(align) - 1)) == 0)
#define IS_ALIGNED_ANY(x, align) (((uintptr_t)(x) % (uintptr_t)(align)) == 0)
#define IS_POWER_OF_TWO(x) (((x) != 0) && (((x) & ((x) - 1)) == 0))
#define IS_ALIGNED_POW2(x, align) \
(assert(IS_POWER_OF_TWO((uintptr_t)(align))), (((uintptr_t)(x) & ((uintptr_t)(align) - 1)) == 0))
#define VM_MODE_SV39 (2 << 64)
#define PTE_V (1 << 0)
#define PTE_R (1 << 1)
#define PTE_W (1 << 2)
#define PTE_X (1 << 3)
/* And so on... */
#define IS_LEAF(PTE) ((PTE & (PTE_R | PTE_W | PTE_X)) != 0)
#define PTE_PPN(PTE, LEVEL) (((PTE) >> (10 + ((LEVEL) * 9)) & 0x1FF))
int main(void) {
assert(IS_ALIGNED(0, 1));
assert(IS_ALIGNED(8, 8));
assert(IS_ALIGNED(12, 4));
assert(!IS_ALIGNED(66, 16));
assert(!IS_ALIGNED(234, 4096));
assert(!IS_ALIGNED(4099, 4096));
assert(PPN_MASK == 0b11111111111111111111111111111111111111111111);
assert(PPN_MASK == 17592186044415);
assert(PPN_MASK == 0xFFFFFFFFFFF);
printf("%lu", PPN_TO_PA(0xAAAAAA));
assert(IS_ALIGNED(PPN_TO_PA(0xAAAAAAAAAAAA), 4096));
uint64_t pte = 0b11111111110000000001111111110000000001111111111;
assert(pte & PTE_V);
assert(pte & PTE_R);
assert(pte & PTE_W);
assert(pte & PTE_X);
assert(IS_LEAF(pte));
assert(PTE_PPN(pte, 0) == 0);
assert(PTE_PPN(pte, 1) == 0b111111111);
assert(PTE_PPN(pte, 2) == 0);
pte <<= 9;
assert(PTE_PPN(pte, 0) == 0b111111111);
assert(PTE_PPN(pte, 1) == 0);
assert(PTE_PPN(pte, 2) == 0b111111111);
assert(!IS_LEAF(pte)); // Rightmost bits are now shifted out
}