@@ -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