int tlb_set_page_exec(CPUState *env, target_ulong vaddr,

                      target_phys_addr_t paddr, int prot,

                      int mmu_idx, int is_softmmu)

{

    PhysPageDesc *p;

    unsigned long pd;

    unsigned int index;

    target_ulong address;

    target_ulong code_address;

    target_phys_addr_t addend;

    int ret;

    CPUTLBEntry *te;

    CPUWatchpoint *wp;

    target_phys_addr_t iotlb;



    p = phys_page_find(paddr >> TARGET_PAGE_BITS);

    if (!p) {

        pd = IO_MEM_UNASSIGNED;

    } else {

        pd = p->phys_offset;

    }

#if defined(DEBUG_TLB)

    printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",

           vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);

#endif



    ret = 0;

    address = vaddr;

    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {

        /* IO memory case (romd handled later) */

        address |= TLB_MMIO;

    }

    addend = (unsigned long)qemu_get_ram_ptr(pd & TARGET_PAGE_MASK);

    if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {

        /* Normal RAM.  */

        iotlb = pd & TARGET_PAGE_MASK;

        if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM)

            iotlb |= IO_MEM_NOTDIRTY;

        else

            iotlb |= IO_MEM_ROM;

    } else {

        /* IO handlers are currently passed a physical address.

           It would be nice to pass an offset from the base address

           of that region.  This would avoid having to special case RAM,

           and avoid full address decoding in every device.

           We can't use the high bits of pd for this because

           IO_MEM_ROMD uses these as a ram address.  */

        iotlb = (pd & ~TARGET_PAGE_MASK);

        if (p) {

            iotlb += p->region_offset;

        } else {

            iotlb += paddr;

        }

    }



    code_address = address;

    /* Make accesses to pages with watchpoints go via the

       watchpoint trap routines.  */

    TAILQ_FOREACH(wp, &env->watchpoints, entry) {

        if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) {

            iotlb = io_mem_watch + paddr;

            /* TODO: The memory case can be optimized by not trapping

               reads of pages with a write breakpoint.  */

            address |= TLB_MMIO;

        }

    }



    index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);

    env->iotlb[mmu_idx][index] = iotlb - vaddr;

    te = &env->tlb_table[mmu_idx][index];

    te->addend = addend - vaddr;

    if (prot & PAGE_READ) {

        te->addr_read = address;

    } else {

        te->addr_read = -1;

    }



    if (prot & PAGE_EXEC) {

        te->addr_code = code_address;

    } else {

        te->addr_code = -1;

    }

    if (prot & PAGE_WRITE) {

        if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||

            (pd & IO_MEM_ROMD)) {

            /* Write access calls the I/O callback.  */

            te->addr_write = address | TLB_MMIO;

        } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&

                   !cpu_physical_memory_is_dirty(pd)) {

            te->addr_write = address | TLB_NOTDIRTY;

        } else {

            te->addr_write = address;

        }

    } else {

        te->addr_write = -1;

    }

    return ret;

}
