Resolve an address to a (`set_idx`, `way_idx`, `was_miss`) tuple. On a miss the block is fetched from the next level; dirty victims are written back. On a hit or after a fill, the LRU age of the line is updated.
(&mut self, addr: u64)
| 132 | // Hit? |
| 133 | let hit_way = self.sets[set_idx] |
| 134 | .ways |
| 135 | .iter() |
| 136 | .position(|w| w.valid && w.tag == tag); |
| 137 | if let Some(way_idx) = hit_way { |
| 138 | self.access_tick += 1; |
| 139 | self.sets[set_idx].ways[way_idx].lru_age = self.access_tick; |
| 140 | return Ok((set_idx, way_idx, false)); |
| 141 | } |
| 142 | |
| 143 | // Miss: choose victim (first invalid way, else true LRU with smallest age) |
| 144 | let victim_idx = { |
| 145 | let set = &self.sets[set_idx]; |
| 146 | set.ways.iter().position(|w| !w.valid).unwrap_or_else(|| { |
| 147 | set.ways |
| 148 | .iter() |
| 149 | .enumerate() |
| 150 | .min_by_key(|(_, w)| w.lru_age) |
| 151 | .map(|(i, _)| i) |
| 152 | .unwrap_or(0) |
| 153 | }) |
| 154 | }; |
| 155 | |
| 156 | // Write back dirty victim |
| 157 | let need_evict = { |
| 158 | let line = &self.sets[set_idx].ways[victim_idx]; |
| 159 | line.valid && line.dirty |
| 160 | }; |
| 161 | if need_evict { |
| 162 | let (victim_tag, victim_data) = { |
| 163 | let line = &self.sets[set_idx].ways[victim_idx]; |
| 164 | (line.tag, line.data.clone()) |
| 165 | }; |
| 166 | let base_old = self.line_base_address(victim_tag, index); |
| 167 | for (i, &byte) in victim_data.iter().enumerate() { |
| 168 | self.next.write_byte(base_old + i as u64, byte)?; |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | // Fetch new block from the next level |
| 173 | let block_mask = !(self.params.block_size as u64 - 1); |
| 174 | let fetch_base = addr & block_mask; |
| 175 | let mut new_data = vec![0u8; self.params.block_size]; |
| 176 | for i in 0..self.params.block_size { |
| 177 | new_data[i] = self.next.read_byte(fetch_base + i as u64)?; |
| 178 | } |
| 179 | |
| 180 | // Install and assign LRU age |
| 181 | self.access_tick += 1; |
| 182 | { |
| 183 | let line = &mut self.sets[set_idx].ways[victim_idx]; |
| 184 | line.valid = true; |
| 185 | line.dirty = false; |
| 186 | line.tag = tag; |
| 187 | line.data = new_data; |
| 188 | line.lru_age = self.access_tick; |
| 189 | } |
| 190 | |
| 191 | Ok((set_idx, victim_idx, true)) |
no test coverage detected