|
|
1.1 ! root 1: /* ! 2: * Microblaze helper routines. ! 3: * ! 4: * Copyright (c) 2009 Edgar E. Iglesias <[email protected]>. ! 5: * ! 6: * This library is free software; you can redistribute it and/or ! 7: * modify it under the terms of the GNU Lesser General Public ! 8: * License as published by the Free Software Foundation; either ! 9: * version 2 of the License, or (at your option) any later version. ! 10: * ! 11: * This library is distributed in the hope that it will be useful, ! 12: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 14: * Lesser General Public License for more details. ! 15: * ! 16: * You should have received a copy of the GNU Lesser General Public ! 17: * License along with this library; if not, see <http://www.gnu.org/licenses/>. ! 18: */ ! 19: ! 20: #include <assert.h> ! 21: #include "exec.h" ! 22: #include "helper.h" ! 23: #include "host-utils.h" ! 24: ! 25: #define D(x) ! 26: ! 27: #if !defined(CONFIG_USER_ONLY) ! 28: #define MMUSUFFIX _mmu ! 29: #define SHIFT 0 ! 30: #include "softmmu_template.h" ! 31: #define SHIFT 1 ! 32: #include "softmmu_template.h" ! 33: #define SHIFT 2 ! 34: #include "softmmu_template.h" ! 35: #define SHIFT 3 ! 36: #include "softmmu_template.h" ! 37: ! 38: /* Try to fill the TLB and return an exception if error. If retaddr is ! 39: NULL, it means that the function was called in C code (i.e. not ! 40: from generated code or from helper.c) */ ! 41: /* XXX: fix it to restore all registers */ ! 42: void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) ! 43: { ! 44: TranslationBlock *tb; ! 45: CPUState *saved_env; ! 46: unsigned long pc; ! 47: int ret; ! 48: ! 49: /* XXX: hack to restore env in all cases, even if not called from ! 50: generated code */ ! 51: saved_env = env; ! 52: env = cpu_single_env; ! 53: ! 54: ret = cpu_mb_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); ! 55: if (unlikely(ret)) { ! 56: if (retaddr) { ! 57: /* now we have a real cpu fault */ ! 58: pc = (unsigned long)retaddr; ! 59: tb = tb_find_pc(pc); ! 60: if (tb) { ! 61: /* the PC is inside the translated code. It means that we have ! 62: a virtual CPU fault */ ! 63: cpu_restore_state(tb, env, pc, NULL); ! 64: } ! 65: } ! 66: cpu_loop_exit(); ! 67: } ! 68: env = saved_env; ! 69: } ! 70: #endif ! 71: ! 72: void helper_raise_exception(uint32_t index) ! 73: { ! 74: env->exception_index = index; ! 75: cpu_loop_exit(); ! 76: } ! 77: ! 78: void helper_debug(void) ! 79: { ! 80: int i; ! 81: ! 82: qemu_log("PC=%8.8x\n", env->sregs[SR_PC]); ! 83: for (i = 0; i < 32; i++) { ! 84: qemu_log("r%2.2d=%8.8x ", i, env->regs[i]); ! 85: if ((i + 1) % 4 == 0) ! 86: qemu_log("\n"); ! 87: } ! 88: qemu_log("\n\n"); ! 89: } ! 90: ! 91: static inline uint32_t compute_carry(uint32_t a, uint32_t b, uint32_t cin) ! 92: { ! 93: uint32_t cout = 0; ! 94: ! 95: if ((b == ~0) && cin) ! 96: cout = 1; ! 97: else if ((~0 - a) < (b + cin)) ! 98: cout = 1; ! 99: return cout; ! 100: } ! 101: ! 102: uint32_t helper_cmp(uint32_t a, uint32_t b) ! 103: { ! 104: uint32_t t; ! 105: ! 106: t = b + ~a + 1; ! 107: if ((b & 0x80000000) ^ (a & 0x80000000)) ! 108: t = (t & 0x7fffffff) | (b & 0x80000000); ! 109: return t; ! 110: } ! 111: ! 112: uint32_t helper_cmpu(uint32_t a, uint32_t b) ! 113: { ! 114: uint32_t t; ! 115: ! 116: t = b + ~a + 1; ! 117: if ((b & 0x80000000) ^ (a & 0x80000000)) ! 118: t = (t & 0x7fffffff) | (a & 0x80000000); ! 119: return t; ! 120: } ! 121: ! 122: uint32_t helper_addkc(uint32_t a, uint32_t b, uint32_t k, uint32_t c) ! 123: { ! 124: uint32_t d, cf = 0, ncf; ! 125: ! 126: if (c) ! 127: cf = env->sregs[SR_MSR] >> 31; ! 128: assert(cf == 0 || cf == 1); ! 129: d = a + b + cf; ! 130: ! 131: if (!k) { ! 132: ncf = compute_carry(a, b, cf); ! 133: assert(ncf == 0 || ncf == 1); ! 134: if (ncf) ! 135: env->sregs[SR_MSR] |= MSR_C | MSR_CC; ! 136: else ! 137: env->sregs[SR_MSR] &= ~(MSR_C | MSR_CC); ! 138: } ! 139: D(qemu_log("%x = %x + %x cf=%d ncf=%d k=%d c=%d\n", ! 140: d, a, b, cf, ncf, k, c)); ! 141: return d; ! 142: } ! 143: ! 144: uint32_t helper_subkc(uint32_t a, uint32_t b, uint32_t k, uint32_t c) ! 145: { ! 146: uint32_t d, cf = 1, ncf; ! 147: ! 148: if (c) ! 149: cf = env->sregs[SR_MSR] >> 31; ! 150: assert(cf == 0 || cf == 1); ! 151: d = b + ~a + cf; ! 152: ! 153: if (!k) { ! 154: ncf = compute_carry(b, ~a, cf); ! 155: assert(ncf == 0 || ncf == 1); ! 156: if (ncf) ! 157: env->sregs[SR_MSR] |= MSR_C | MSR_CC; ! 158: else ! 159: env->sregs[SR_MSR] &= ~(MSR_C | MSR_CC); ! 160: } ! 161: D(qemu_log("%x = %x + %x cf=%d ncf=%d k=%d c=%d\n", ! 162: d, a, b, cf, ncf, k, c)); ! 163: return d; ! 164: } ! 165: ! 166: static inline int div_prepare(uint32_t a, uint32_t b) ! 167: { ! 168: if (b == 0) { ! 169: env->sregs[SR_MSR] |= MSR_DZ; ! 170: /* FIXME: Raise the div by zero exception. */ ! 171: return 0; ! 172: } ! 173: env->sregs[SR_MSR] &= ~MSR_DZ; ! 174: return 1; ! 175: } ! 176: ! 177: uint32_t helper_divs(uint32_t a, uint32_t b) ! 178: { ! 179: if (!div_prepare(a, b)) ! 180: return 0; ! 181: return (int32_t)a / (int32_t)b; ! 182: } ! 183: ! 184: uint32_t helper_divu(uint32_t a, uint32_t b) ! 185: { ! 186: if (!div_prepare(a, b)) ! 187: return 0; ! 188: return a / b; ! 189: } ! 190: ! 191: uint32_t helper_pcmpbf(uint32_t a, uint32_t b) ! 192: { ! 193: unsigned int i; ! 194: uint32_t mask = 0xff000000; ! 195: ! 196: for (i = 0; i < 4; i++) { ! 197: if ((a & mask) == (b & mask)) ! 198: return i + 1; ! 199: mask >>= 8; ! 200: } ! 201: return 0; ! 202: } ! 203: ! 204: #if !defined(CONFIG_USER_ONLY) ! 205: /* Writes/reads to the MMU's special regs end up here. */ ! 206: uint32_t helper_mmu_read(uint32_t rn) ! 207: { ! 208: return mmu_read(env, rn); ! 209: } ! 210: ! 211: void helper_mmu_write(uint32_t rn, uint32_t v) ! 212: { ! 213: mmu_write(env, rn, v); ! 214: } ! 215: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.