@@ -185,9 +185,18 @@ static inline uint32_t read_rs2(const hart_t *vm, uint32_t insn)
185185void mmu_invalidate (hart_t * vm )
186186{
187187 vm -> cache_fetch .n_pages = 0xFFFFFFFF ;
188- vm -> cache_load [0 ].n_pages = 0xFFFFFFFF ;
189- vm -> cache_load [1 ].n_pages = 0xFFFFFFFF ;
190- vm -> cache_store .n_pages = 0xFFFFFFFF ;
188+ /* Invalidate all 8 sets × 2 ways for load cache */
189+ for (int set = 0 ; set < 8 ; set ++ ) {
190+ for (int way = 0 ; way < 2 ; way ++ )
191+ vm -> cache_load [set ].ways [way ].n_pages = 0xFFFFFFFF ;
192+ vm -> cache_load [set ].lru = 0 ; /* Reset LRU to way 0 */
193+ }
194+ /* Invalidate all 8 sets × 2 ways for store cache */
195+ for (int set = 0 ; set < 8 ; set ++ ) {
196+ for (int way = 0 ; way < 2 ; way ++ )
197+ vm -> cache_store [set ].ways [way ].n_pages = 0xFFFFFFFF ;
198+ vm -> cache_store [set ].lru = 0 ; /* Reset LRU to way 0 */
199+ }
191200}
192201
193202/* Pre-verify the root page table to minimize page table access during
@@ -333,13 +342,36 @@ static void mmu_load(hart_t *vm,
333342{
334343 uint32_t vpn = addr >> RV_PAGE_SHIFT ;
335344 uint32_t phys_addr ;
336- /* 2-entry direct-mapped cache: use parity hash to select entry */
337- uint32_t index = __builtin_parity (vpn ) & 0x1 ;
345+ /* 8-set × 2-way set-associative cache: use 3-bit parity hash */
346+ uint32_t set_idx = (__builtin_parity (vpn & 0xAAAAAAAA ) << 2 ) |
347+ (__builtin_parity (vpn & 0x55555555 ) << 1 ) |
348+ __builtin_parity (vpn & 0xCCCCCCCC );
349+
350+ mmu_cache_set_t * set = & vm -> cache_load [set_idx ];
351+
352+ /* Check both ways in the set */
353+ int hit_way = -1 ;
354+ for (int way = 0 ; way < 2 ; way ++ ) {
355+ if (likely (set -> ways [way ].n_pages == vpn )) {
356+ hit_way = way ;
357+ break ;
358+ }
359+ }
338360
339- if (unlikely (vpn != vm -> cache_load [index ].n_pages )) {
361+ if (likely (hit_way >= 0 )) {
362+ /* Cache hit: reconstruct physical address from cached PPN */
363+ #ifdef MMU_CACHE_STATS
364+ set -> ways [hit_way ].hits ++ ;
365+ #endif
366+ phys_addr = (set -> ways [hit_way ].phys_ppn << RV_PAGE_SHIFT ) |
367+ (addr & MASK (RV_PAGE_SHIFT ));
368+ /* Update LRU: mark the other way as replacement candidate */
369+ set -> lru = 1 - hit_way ;
370+ } else {
340371 /* Cache miss: do full translation */
372+ int victim_way = set -> lru ; /* Use LRU bit to select victim */
341373#ifdef MMU_CACHE_STATS
342- vm -> cache_load [ index ].misses ++ ;
374+ set -> ways [ victim_way ].misses ++ ;
343375#endif
344376 phys_addr = addr ;
345377 mmu_translate (vm , & phys_addr ,
@@ -348,16 +380,11 @@ static void mmu_load(hart_t *vm,
348380 RV_EXC_LOAD_PFAULT );
349381 if (vm -> error )
350382 return ;
351- /* Cache physical page number (not a pointer) */
352- vm -> cache_load [index ].n_pages = vpn ;
353- vm -> cache_load [index ].phys_ppn = phys_addr >> RV_PAGE_SHIFT ;
354- } else {
355- /* Cache hit: reconstruct physical address from cached PPN */
356- #ifdef MMU_CACHE_STATS
357- vm -> cache_load [index ].hits ++ ;
358- #endif
359- phys_addr = (vm -> cache_load [index ].phys_ppn << RV_PAGE_SHIFT ) |
360- (addr & MASK (RV_PAGE_SHIFT ));
383+ /* Replace victim way with new translation */
384+ set -> ways [victim_way ].n_pages = vpn ;
385+ set -> ways [victim_way ].phys_ppn = phys_addr >> RV_PAGE_SHIFT ;
386+ /* Update LRU: mark the other way for next eviction */
387+ set -> lru = 1 - victim_way ;
361388 }
362389
363390 vm -> mem_load (vm , phys_addr , width , value );
@@ -376,28 +403,48 @@ static bool mmu_store(hart_t *vm,
376403{
377404 uint32_t vpn = addr >> RV_PAGE_SHIFT ;
378405 uint32_t phys_addr ;
406+ /* 8-set × 2-way set-associative cache: use 3-bit parity hash */
407+ uint32_t set_idx = (__builtin_parity (vpn & 0xAAAAAAAA ) << 2 ) |
408+ (__builtin_parity (vpn & 0x55555555 ) << 1 ) |
409+ __builtin_parity (vpn & 0xCCCCCCCC );
410+
411+ mmu_cache_set_t * set = & vm -> cache_store [set_idx ];
412+
413+ /* Check both ways in the set */
414+ int hit_way = -1 ;
415+ for (int way = 0 ; way < 2 ; way ++ ) {
416+ if (likely (set -> ways [way ].n_pages == vpn )) {
417+ hit_way = way ;
418+ break ;
419+ }
420+ }
379421
380- if (unlikely (vpn != vm -> cache_store .n_pages )) {
422+ if (likely (hit_way >= 0 )) {
423+ /* Cache hit: reconstruct physical address from cached PPN */
424+ #ifdef MMU_CACHE_STATS
425+ set -> ways [hit_way ].hits ++ ;
426+ #endif
427+ phys_addr = (set -> ways [hit_way ].phys_ppn << RV_PAGE_SHIFT ) |
428+ (addr & MASK (RV_PAGE_SHIFT ));
429+ /* Update LRU: mark the other way as replacement candidate */
430+ set -> lru = 1 - hit_way ;
431+ } else {
381432 /* Cache miss: do full translation */
433+ int victim_way = set -> lru ; /* Use LRU bit to select victim */
382434#ifdef MMU_CACHE_STATS
383- vm -> cache_store .misses ++ ;
435+ set -> ways [ victim_way ] .misses ++ ;
384436#endif
385437 phys_addr = addr ;
386438 mmu_translate (vm , & phys_addr , (1 << 2 ), (1 << 6 ) | (1 << 7 ),
387439 vm -> sstatus_sum && vm -> s_mode , RV_EXC_STORE_FAULT ,
388440 RV_EXC_STORE_PFAULT );
389441 if (vm -> error )
390442 return false;
391- /* Cache physical page number (not a pointer) */
392- vm -> cache_store .n_pages = vpn ;
393- vm -> cache_store .phys_ppn = phys_addr >> RV_PAGE_SHIFT ;
394- } else {
395- /* Cache hit: reconstruct physical address from cached PPN */
396- #ifdef MMU_CACHE_STATS
397- vm -> cache_store .hits ++ ;
398- #endif
399- phys_addr = (vm -> cache_store .phys_ppn << RV_PAGE_SHIFT ) |
400- (addr & MASK (RV_PAGE_SHIFT ));
443+ /* Replace victim way with new translation */
444+ set -> ways [victim_way ].n_pages = vpn ;
445+ set -> ways [victim_way ].phys_ppn = phys_addr >> RV_PAGE_SHIFT ;
446+ /* Update LRU: mark the other way for next eviction */
447+ set -> lru = 1 - victim_way ;
401448 }
402449
403450 if (unlikely (cond )) {
0 commit comments