From 07ce45cac3fba6cf8ad163ed17b507ce84f7b8f6 Mon Sep 17 00:00:00 2001 From: nelson0720j Date: Mon, 24 Jun 2024 22:09:24 +0800 Subject: [PATCH 1/2] Implement LRU TLB Implement LRU TLB with doubly link list. However, the error of not being able to execute correctly has not been resolved yet. --- riscv.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ riscv.h | 21 ++++++++++++ 2 files changed, 121 insertions(+) diff --git a/riscv.c b/riscv.c index 699846fd..a38b75af 100644 --- a/riscv.c +++ b/riscv.c @@ -1,4 +1,5 @@ #include +#include #include "riscv.h" #include "riscv_private.h" @@ -170,6 +171,21 @@ static inline uint32_t read_rs2(const vm_t *vm, uint32_t insn) static void mmu_invalidate(vm_t *vm) { vm->cache_fetch.n_pages = 0xFFFFFFFF; + + struct node_t *current = vm->tlb_list.head; + while (current != NULL) { + struct node_t *next = current->next; + free(current); + current = next; + } + + vm->tlb_list.head = malloc(sizeof(struct node_t)); + vm->tlb_list.tail = malloc(sizeof(struct node_t)); + vm->tlb_list.head->next = vm->tlb_list.tail; + vm->tlb_list.head->prev = NULL; + vm->tlb_list.tail->next = NULL; + vm->tlb_list.tail->prev = vm->tlb_list.head; + vm->tlb_list.size = 0; } /* Pre-verify the root page table to minimize page table access during @@ -234,6 +250,76 @@ static bool mmu_lookup(const vm_t *vm, return true; } +/* remove node. */ +void tlb_remove(struct node_t *node) +{ + if (node == NULL || node->prev == NULL || node->next == NULL) { + return; + } + + struct node_t *tmp_prev = node->prev; + struct node_t *tmp_next = node->next; + tmp_prev->next = tmp_next; + tmp_next->prev = tmp_prev; +} + +/* insert new node to head. */ +void tlb_insert(struct node_t *node, tlb_list_t *tlb_list) +{ + if (node == NULL || tlb_list == NULL || tlb_list->head == NULL) { + return; + } + + struct node_t *tmp_next = tlb_list->head->next; + tlb_list->head->next = node; + node->prev = tlb_list->head; + node->next = tmp_next; + tmp_next->prev = node; +} + +/* search TLB */ +static uint32_t *tlb_lookup(vm_t *vm, uint32_t vpn, bool write) +{ + struct node_t *current = vm->tlb_list.head->next; + + while (current != vm->tlb_list.tail) { + if (current->entry.valid && current->entry.vpn == vpn) { + if (write) { + current->entry.dirty = true; + *current->entry.pte |= (1 << 7); + } + + /* hit then remove and insert to head->next. */ + tlb_remove(current); + tlb_insert(current, &vm->tlb_list); + return current->entry.pte; + } + current = current->next; + } + return NULL; +} + +/* miss in TLB then insert new entry to tlb. */ +static void tlb_insert_entry(vm_t *vm, uint32_t vpn, uint32_t *pte) +{ + struct node_t *new_node = malloc(sizeof(struct node_t)); + + new_node->entry.vpn = vpn; + new_node->entry.pte = pte; + new_node->entry.valid = true; + new_node->entry.dirty = false; + + tlb_insert(new_node, &vm->tlb_list); + vm->tlb_list.size++; + + if (vm->tlb_list.size > TLB_SIZE) { + struct node_t *victim = vm->tlb_list.tail->prev; + tlb_remove(vm->tlb_list.tail->prev); + free(victim); + vm->tlb_list.size--; + } +} + static void mmu_translate(vm_t *vm, uint32_t *addr, const uint32_t access_bits, @@ -249,6 +335,17 @@ static void mmu_translate(vm_t *vm, uint32_t *pte_ref; uint32_t ppn; + + /* load and store fecth cache lookup. */ + if (skip_privilege_test) { + pte_ref = tlb_lookup(vm, (*addr) >> RV_PAGE_SHIFT, set_bits & (1 << 7)); + if (pte_ref && (*pte_ref & access_bits)) { + *addr = ((*addr) & MASK(RV_PAGE_SHIFT)) | + ((*pte_ref >> 10) << RV_PAGE_SHIFT); + return; + } + } + bool ok = mmu_lookup(vm, (*addr) >> RV_PAGE_SHIFT, &pte_ref, &ppn); if (unlikely(!ok)) { vm_set_exception(vm, fault, *addr); @@ -270,6 +367,9 @@ static void mmu_translate(vm_t *vm, if (new_pte != pte) *pte_ref = new_pte; + /* update tlb. */ + tlb_insert_entry(vm, (*addr) >> RV_PAGE_SHIFT, pte_ref); + *addr = ((*addr) & MASK(RV_PAGE_SHIFT)) | (ppn << RV_PAGE_SHIFT); } diff --git a/riscv.h b/riscv.h index d318c317..5f27fb34 100644 --- a/riscv.h +++ b/riscv.h @@ -34,6 +34,26 @@ typedef struct { uint32_t *page_addr; } mmu_cache_t; +#define TLB_SIZE 16 +typedef struct { + uint32_t vpn; + uint32_t *pte; + bool valid; + bool dirty; +} tlb_entry_t; + +struct node_t{ + tlb_entry_t entry; + struct node_t *prev; + struct node_t *next; +}; + +typedef struct { + struct node_t *head; + struct node_t *tail; + uint32_t size; +} tlb_list_t; + /* To use the emulator, start by initializing a vm_t object with zero values, * invoke vm_init(), and set the required environment-supplied callbacks. You * may also set other necessary fields such as argument registers and s_mode, @@ -83,6 +103,7 @@ struct __vm_internal { uint32_t exc_cause, exc_val; mmu_cache_t cache_fetch; + tlb_list_t tlb_list; /* Supervisor state */ bool s_mode; From 827f99ef3f3ae99f9531a3425243a9946f64ec74 Mon Sep 17 00:00:00 2001 From: nelson0720j Date: Thu, 27 Jun 2024 21:53:46 +0800 Subject: [PATCH 2/2] Replace while loop with for loop Use for loop and run clang-format before commit. --- riscv.c | 16 +++++++--------- riscv.h | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/riscv.c b/riscv.c index a38b75af..422dc7bf 100644 --- a/riscv.c +++ b/riscv.c @@ -172,13 +172,13 @@ static void mmu_invalidate(vm_t *vm) { vm->cache_fetch.n_pages = 0xFFFFFFFF; - struct node_t *current = vm->tlb_list.head; - while (current != NULL) { - struct node_t *next = current->next; + /* free all nodes. */ + for (struct node_t *current = vm->tlb_list.head, *next; current; + current = next) { + next = current->next; free(current); - current = next; } - + /* reset head and tail. */ vm->tlb_list.head = malloc(sizeof(struct node_t)); vm->tlb_list.tail = malloc(sizeof(struct node_t)); vm->tlb_list.head->next = vm->tlb_list.tail; @@ -280,9 +280,8 @@ void tlb_insert(struct node_t *node, tlb_list_t *tlb_list) /* search TLB */ static uint32_t *tlb_lookup(vm_t *vm, uint32_t vpn, bool write) { - struct node_t *current = vm->tlb_list.head->next; - - while (current != vm->tlb_list.tail) { + for (struct node_t *current = vm->tlb_list.head->next; + current != vm->tlb_list.tail; current = current->next) { if (current->entry.valid && current->entry.vpn == vpn) { if (write) { current->entry.dirty = true; @@ -294,7 +293,6 @@ static uint32_t *tlb_lookup(vm_t *vm, uint32_t vpn, bool write) tlb_insert(current, &vm->tlb_list); return current->entry.pte; } - current = current->next; } return NULL; } diff --git a/riscv.h b/riscv.h index 5f27fb34..60915329 100644 --- a/riscv.h +++ b/riscv.h @@ -42,7 +42,7 @@ typedef struct { bool dirty; } tlb_entry_t; -struct node_t{ +struct node_t { tlb_entry_t entry; struct node_t *prev; struct node_t *next;