- int shift=TARGET_SIZE_2-3; // Divide into 8 blocks
- uintptr_t base_offs = ((uintptr_t)(expirep >> 13) << shift); // Base offset of this block
- uintptr_t base_offs_s = base_offs >> shift;
- inv_debug("EXP: Phase %d\n",expirep);
- switch((expirep>>11)&3)
- {
- case 0:
- // Clear jump_in and jump_dirty
- ll_remove_matching_addrs(jump_in+(expirep&2047),base_offs_s,shift);
- ll_remove_matching_addrs(jump_dirty+(expirep&2047),base_offs_s,shift);
- ll_remove_matching_addrs(jump_in+2048+(expirep&2047),base_offs_s,shift);
- ll_remove_matching_addrs(jump_dirty+2048+(expirep&2047),base_offs_s,shift);
- break;
- case 1:
- // Clear pointers
- ll_kill_pointers(jump_out[expirep&2047],base_offs_s,shift);
- ll_kill_pointers(jump_out[(expirep&2047)+2048],base_offs_s,shift);
- break;
- case 2:
- // Clear hash table
- for(i=0;i<32;i++) {
- struct ht_entry *ht_bin = &hash_table[((expirep&2047)<<5)+i];
- uintptr_t o1 = (u_char *)ht_bin->tcaddr[1] - ndrc->translation_cache;
- uintptr_t o2 = o1 - MAX_OUTPUT_BLOCK_SIZE;
- if ((o1 >> shift) == base_offs_s || (o2 >> shift) == base_offs_s) {
- inv_debug("EXP: Remove hash %x -> %p\n",ht_bin->vaddr[1],ht_bin->tcaddr[1]);
- ht_bin->vaddr[1] = -1;
- ht_bin->tcaddr[1] = NULL;
- }
- o1 = (u_char *)ht_bin->tcaddr[0] - ndrc->translation_cache;
- o2 = o1 - MAX_OUTPUT_BLOCK_SIZE;
- if ((o1 >> shift) == base_offs_s || (o2 >> shift) == base_offs_s) {
- inv_debug("EXP: Remove hash %x -> %p\n",ht_bin->vaddr[0],ht_bin->tcaddr[0]);
- ht_bin->vaddr[0] = ht_bin->vaddr[1];
- ht_bin->tcaddr[0] = ht_bin->tcaddr[1];
- ht_bin->vaddr[1] = -1;
- ht_bin->tcaddr[1] = NULL;
- }
- }
- break;
- case 3:
- // Clear jump_out
- if((expirep&2047)==0)
- do_clear_cache();
- ll_remove_matching_addrs(jump_out+(expirep&2047),base_offs_s,shift);
- ll_remove_matching_addrs(jump_out+2048+(expirep&2047),base_offs_s,shift);
- break;
+ u_int base_offs = expirep & ~(MAX_OUTPUT_BLOCK_SIZE - 1);
+ u_int block_i = expirep / step & (PAGE_COUNT - 1);
+ u_int phase = (expirep >> (base_shift - 1)) & 1u;
+ if (!(expirep & (MAX_OUTPUT_BLOCK_SIZE / 2 - 1))) {
+ inv_debug("EXP: base_offs %x/%x phase %u\n", base_offs,
+ out - ndrc->translation_cache, phase);
+ }
+
+ if (!phase) {
+ hit = blocks_remove_matching_addrs(&blocks[block_i], base_offs, base_shift);
+ if (hit) {
+ do_clear_cache();
+ #ifdef USE_MINI_HT
+ memset(mini_ht, -1, sizeof(mini_ht));
+ #endif
+ }
+ }
+ else
+ unlink_jumps_tc_range(jumps[block_i], base_offs, base_shift);
+ }
+}
+
+static struct block_info *new_block_info(u_int start, u_int len,
+ const void *source, const void *copy, u_char *beginning, u_short jump_in_count)
+{
+ struct block_info **b_pptr;
+ struct block_info *block;
+ u_int page = get_page(start);
+
+ block = malloc(sizeof(*block) + jump_in_count * sizeof(block->jump_in[0]));
+ assert(block);
+ assert(jump_in_count > 0);
+ block->source = source;
+ block->copy = copy;
+ block->start = start;
+ block->len = len;
+ block->reg_sv_flags = 0;
+ block->tc_offs = beginning - ndrc->translation_cache;
+ //block->tc_len = out - beginning;
+ block->is_dirty = 0;
+ block->inv_near_misses = 0;
+ block->jump_in_cnt = jump_in_count;
+
+ // insert sorted by start mirror-unmasked vaddr
+ for (b_pptr = &blocks[page]; ; b_pptr = &((*b_pptr)->next)) {
+ if (*b_pptr == NULL || (*b_pptr)->start >= start) {
+ block->next = *b_pptr;
+ *b_pptr = block;
+ break;