diff --git a/src/hardware/cpu/mmu.c b/src/hardware/cpu/mmu.c index 8fc7f44..88aa4c7 100644 --- a/src/hardware/cpu/mmu.c +++ b/src/hardware/cpu/mmu.c @@ -17,19 +17,151 @@ #include "headers/common.h" #include "headers/address.h" +// -------------------------------------------- // +// TLB cache struct +// -------------------------------------------- // + +#define NUM_TLB_CACHE_LINE_PER_SET (8) + +typedef struct +{ + int valid; + uint64_t tag; + uint64_t ppn; +} tlb_cacheline_t; + +typedef struct +{ + tlb_cacheline_t lines[NUM_TLB_CACHE_LINE_PER_SET]; +} tlb_cacheset_t; + +typedef struct +{ + tlb_cacheset_t sets[(1 << TLB_CACHE_INDEX_LENGTH)]; +} tlb_cache_t; + +static tlb_cache_t mmu_tlb; + static uint64_t page_walk(uint64_t vaddr_value); static void page_fault_handler(pte4_t *pte, address_t vaddr); +static int read_tlb(uint64_t vaddr_value, uint64_t *paddr_value_ptr, + int *free_tlb_line_index); +static int write_tlb(uint64_t vaddr_value, uint64_t paddr_value, + int free_tlb_line_index); + int swap_in(uint64_t daddr, uint64_t ppn); int swap_out(uint64_t daddr, uint64_t ppn); // consider this function va2pa as functional uint64_t va2pa(uint64_t vaddr) { + uint64_t paddr = 0; + +#ifdef USE_TLB_HARDWARE + int free_tlb_line_index = -1; + int tlb_hit = read_tlb(vaddr, &paddr, &free_tlb_line_index); + + // TODO: add flag to read tlb failed + if (tlb_hit) + { + // TLB read hit + return paddr; + } + + // TLB read miss +#endif + + // assume that page_walk is consuming much time + paddr = page_walk(vaddr); + +#ifdef USE_TLB_HARDWARE + // refresh TLB + // TODO: check if this paddr from page table is a legal address + if (paddr != 0) + { + // TLB write + if (write_tlb(vaddr, paddr, free_tlb_line_index) == 1) + { + return paddr; + } + } +#endif + // use page table as va2pa - return page_walk(vaddr); + return paddr; +} + +static int read_tlb(uint64_t vaddr_value, uint64_t *paddr_value_ptr, + int *free_tlb_line_index) +{ + address_t vaddr = { + .address_value = vaddr_value + }; + + tlb_cacheset_t *set = &mmu_tlb.sets[vaddr.tlbi]; + *free_tlb_line_index = -1; + + for (int i = 0; i < NUM_TLB_CACHE_LINE_PER_SET; ++ i) + { + tlb_cacheline_t *line = &set->lines[i]; + + if (line->valid == 0) + { + *free_tlb_line_index = i; + } + + if (line->tag == vaddr.tlbt && + line->valid == 1) + { + // TLB read hit + *paddr_value_ptr = line->ppn; + return 1; + } + } + + // TLB read miss + *paddr_value_ptr = NULL; + return 0; } +static int write_tlb(uint64_t vaddr_value, uint64_t paddr_value, + int free_tlb_line_index) +{ + address_t vaddr = { + .address_value = vaddr_value + }; + + address_t paddr = { + .address_value = paddr_value + }; + + tlb_cacheset_t *set = &mmu_tlb.sets[vaddr.tlbi]; + + if (0 <= free_tlb_line_index && free_tlb_line_index < NUM_TLB_CACHE_LINE_PER_SET) + { + tlb_cacheline_t *line = &set->lines[free_tlb_line_index]; + + line->valid = 1; + line->ppn = paddr.ppn; + line->tag = vaddr.tlbt; + + return 1; + } + + // no free TLB cache line, select one RANDOM victim + int random_victim_index = random() % NUM_TLB_CACHE_LINE_PER_SET; + + tlb_cacheline_t *line = &set->lines[random_victim_index]; + + line->valid = 1; + line->ppn = paddr.ppn; + line->tag = vaddr.tlbt; + + return 1; +} + + // input - virtual address // output - physical address static uint64_t page_walk(uint64_t vaddr_value) diff --git a/src/hardware/memory/dram.c b/src/hardware/memory/dram.c index 5dbe7e9..e00df66 100644 --- a/src/hardware/memory/dram.c +++ b/src/hardware/memory/dram.c @@ -28,61 +28,55 @@ e.g. write 0x00007fd357a02ae0 to cache, the memory lapping should be: // memory accessing used in instructions uint64_t cpu_read64bits_dram(uint64_t paddr) { - if (DEBUG_ENABLE_SRAM_CACHE == 1) +#ifdef DEBUG_ENABLE_SRAM_CACHE + // try to load uint64_t from SRAM cache + // little-endian + uint64_t val = 0x0; + for (int i = 0; i < 8; ++ i) { - // try to load uint64_t from SRAM cache - // little-endian - uint64_t val = 0x0; - for (int i = 0; i < 8; ++ i) - { - val += (sram_cache_read(paddr + i) << (i * 8)); - } - return val; - } - else - { - // read from DRAM directly - // little-endian - uint64_t val = 0x0; - - val += (((uint64_t)pm[paddr + 0 ]) << 0); - val += (((uint64_t)pm[paddr + 1 ]) << 8); - val += (((uint64_t)pm[paddr + 2 ]) << 16); - val += (((uint64_t)pm[paddr + 3 ]) << 24); - val += (((uint64_t)pm[paddr + 4 ]) << 32); - val += (((uint64_t)pm[paddr + 5 ]) << 40); - val += (((uint64_t)pm[paddr + 6 ]) << 48); - val += (((uint64_t)pm[paddr + 7 ]) << 56); - - return val; + val += (sram_cache_read(paddr + i) << (i * 8)); } + return val; +#elif + // read from DRAM directly + // little-endian + uint64_t val = 0x0; + + val += (((uint64_t)pm[paddr + 0 ]) << 0); + val += (((uint64_t)pm[paddr + 1 ]) << 8); + val += (((uint64_t)pm[paddr + 2 ]) << 16); + val += (((uint64_t)pm[paddr + 3 ]) << 24); + val += (((uint64_t)pm[paddr + 4 ]) << 32); + val += (((uint64_t)pm[paddr + 5 ]) << 40); + val += (((uint64_t)pm[paddr + 6 ]) << 48); + val += (((uint64_t)pm[paddr + 7 ]) << 56); + + return val; +#endif } void cpu_write64bits_dram(uint64_t paddr, uint64_t data) { - if (DEBUG_ENABLE_SRAM_CACHE == 1) - { - // try to write uint64_t to SRAM cache - // little-endian - for (int i = 0; i < 8; ++ i) - { - sram_cache_write(paddr + i, (data >> (i * 8)) & 0xff); - } - return; - } - else +#ifdef DEBUG_ENABLE_SRAM_CACHE + // try to write uint64_t to SRAM cache + // little-endian + for (int i = 0; i < 8; ++ i) { - // write to DRAM directly - // little-endian - pm[paddr + 0] = (data >> 0 ) & 0xff; - pm[paddr + 1] = (data >> 8 ) & 0xff; - pm[paddr + 2] = (data >> 16) & 0xff; - pm[paddr + 3] = (data >> 24) & 0xff; - pm[paddr + 4] = (data >> 32) & 0xff; - pm[paddr + 5] = (data >> 40) & 0xff; - pm[paddr + 6] = (data >> 48) & 0xff; - pm[paddr + 7] = (data >> 56) & 0xff; + sram_cache_write(paddr + i, (data >> (i * 8)) & 0xff); } + return; +#elif + // write to DRAM directly + // little-endian + pm[paddr + 0] = (data >> 0 ) & 0xff; + pm[paddr + 1] = (data >> 8 ) & 0xff; + pm[paddr + 2] = (data >> 16) & 0xff; + pm[paddr + 3] = (data >> 24) & 0xff; + pm[paddr + 4] = (data >> 32) & 0xff; + pm[paddr + 5] = (data >> 40) & 0xff; + pm[paddr + 6] = (data >> 48) & 0xff; + pm[paddr + 7] = (data >> 56) & 0xff; +#endif } void cpu_readinst_dram(uint64_t paddr, char *buf) diff --git a/src/headers/address.h b/src/headers/address.h index 4fdd6b7..27fcf39 100644 --- a/src/headers/address.h +++ b/src/headers/address.h @@ -32,10 +32,13 @@ #define VIRTUAL_PAGE_NUMBER_LENGTH (9) // 9 + 9 + 9 + 9 = 36 #define VIRTUAL_ADDRESS_LENGTH (48) +#define TLB_CACHE_OFFSET_LENGTH (12) +#define TLB_CACHE_INDEX_LENGTH (4) +#define TLB_CACHE_TAG_LENGTH (32) /* +--------+--------+--------+--------+---------------+ -| VPN3 | VPN2 | VPN1 | VPN0 | | +| VPN1 | VPN2 | VPN3 | VPN4 | | +--------+--------+--------+-+------+ VPO | | TLBT | TLBI | | +---------------+------------+------+---------------+ @@ -62,6 +65,14 @@ typedef union }; }; + // sram cache: 52 + struct + { + uint64_t co : SRAM_CACHE_OFFSET_LENGTH; + uint64_t ci : SRAM_CACHE_INDEX_LENGTH; + uint64_t ct : SRAM_CACHE_TAG_LENGTH; + }; + // virtual address: 48 struct { @@ -79,12 +90,12 @@ typedef union }; }; - // sram cache: 52 + // TLB cache: 48 struct { - uint64_t co : SRAM_CACHE_OFFSET_LENGTH; - uint64_t ci : SRAM_CACHE_INDEX_LENGTH; - uint64_t ct : SRAM_CACHE_TAG_LENGTH; + uint64_t tlbo : TLB_CACHE_OFFSET_LENGTH; // virtual page offset + uint64_t tlbi : TLB_CACHE_INDEX_LENGTH; // TLB set index + uint64_t tlbt : TLB_CACHE_TAG_LENGTH; // TLB line tag }; } address_t;