14acb54baSEdgar E. Iglesias /* 24acb54baSEdgar E. Iglesias * Microblaze helper routines. 34acb54baSEdgar E. Iglesias * 44acb54baSEdgar E. Iglesias * Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>. 54acb54baSEdgar E. Iglesias * 64acb54baSEdgar E. Iglesias * This library is free software; you can redistribute it and/or 74acb54baSEdgar E. Iglesias * modify it under the terms of the GNU Lesser General Public 84acb54baSEdgar E. Iglesias * License as published by the Free Software Foundation; either 94acb54baSEdgar E. Iglesias * version 2 of the License, or (at your option) any later version. 104acb54baSEdgar E. Iglesias * 114acb54baSEdgar E. Iglesias * This library is distributed in the hope that it will be useful, 124acb54baSEdgar E. Iglesias * but WITHOUT ANY WARRANTY; without even the implied warranty of 134acb54baSEdgar E. Iglesias * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 144acb54baSEdgar E. Iglesias * Lesser General Public License for more details. 154acb54baSEdgar E. Iglesias * 164acb54baSEdgar E. Iglesias * You should have received a copy of the GNU Lesser General Public 178167ee88SBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 184acb54baSEdgar E. Iglesias */ 194acb54baSEdgar E. Iglesias 204acb54baSEdgar E. Iglesias #include <assert.h> 214acb54baSEdgar E. Iglesias #include "exec.h" 224acb54baSEdgar E. Iglesias #include "helper.h" 234acb54baSEdgar E. Iglesias #include "host-utils.h" 244acb54baSEdgar E. Iglesias 254acb54baSEdgar E. Iglesias #define D(x) 264acb54baSEdgar E. Iglesias 274acb54baSEdgar E. Iglesias #if !defined(CONFIG_USER_ONLY) 284acb54baSEdgar E. Iglesias #define MMUSUFFIX _mmu 294acb54baSEdgar E. Iglesias #define SHIFT 0 304acb54baSEdgar E. Iglesias #include "softmmu_template.h" 314acb54baSEdgar E. Iglesias #define SHIFT 1 324acb54baSEdgar E. Iglesias #include "softmmu_template.h" 334acb54baSEdgar E. Iglesias #define SHIFT 2 344acb54baSEdgar E. Iglesias #include "softmmu_template.h" 354acb54baSEdgar E. Iglesias #define SHIFT 3 364acb54baSEdgar E. Iglesias #include "softmmu_template.h" 374acb54baSEdgar E. Iglesias 384acb54baSEdgar E. Iglesias /* Try to fill the TLB and return an exception if error. If retaddr is 394acb54baSEdgar E. Iglesias NULL, it means that the function was called in C code (i.e. not 404acb54baSEdgar E. Iglesias from generated code or from helper.c) */ 414acb54baSEdgar E. Iglesias /* XXX: fix it to restore all registers */ 424acb54baSEdgar E. Iglesias void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) 434acb54baSEdgar E. Iglesias { 444acb54baSEdgar E. Iglesias TranslationBlock *tb; 454acb54baSEdgar E. Iglesias CPUState *saved_env; 464acb54baSEdgar E. Iglesias unsigned long pc; 474acb54baSEdgar E. Iglesias int ret; 484acb54baSEdgar E. Iglesias 494acb54baSEdgar E. Iglesias /* XXX: hack to restore env in all cases, even if not called from 504acb54baSEdgar E. Iglesias generated code */ 514acb54baSEdgar E. Iglesias saved_env = env; 524acb54baSEdgar E. Iglesias env = cpu_single_env; 534acb54baSEdgar E. Iglesias 544acb54baSEdgar E. Iglesias ret = cpu_mb_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); 554acb54baSEdgar E. Iglesias if (unlikely(ret)) { 564acb54baSEdgar E. Iglesias if (retaddr) { 574acb54baSEdgar E. Iglesias /* now we have a real cpu fault */ 584acb54baSEdgar E. Iglesias pc = (unsigned long)retaddr; 594acb54baSEdgar E. Iglesias tb = tb_find_pc(pc); 604acb54baSEdgar E. Iglesias if (tb) { 614acb54baSEdgar E. Iglesias /* the PC is inside the translated code. It means that we have 624acb54baSEdgar E. Iglesias a virtual CPU fault */ 634acb54baSEdgar E. Iglesias cpu_restore_state(tb, env, pc, NULL); 644acb54baSEdgar E. Iglesias } 654acb54baSEdgar E. Iglesias } 664acb54baSEdgar E. Iglesias cpu_loop_exit(); 674acb54baSEdgar E. Iglesias } 684acb54baSEdgar E. Iglesias env = saved_env; 694acb54baSEdgar E. Iglesias } 704acb54baSEdgar E. Iglesias #endif 714acb54baSEdgar E. Iglesias 724acb54baSEdgar E. Iglesias void helper_raise_exception(uint32_t index) 734acb54baSEdgar E. Iglesias { 744acb54baSEdgar E. Iglesias env->exception_index = index; 754acb54baSEdgar E. Iglesias cpu_loop_exit(); 764acb54baSEdgar E. Iglesias } 774acb54baSEdgar E. Iglesias 784acb54baSEdgar E. Iglesias void helper_debug(void) 794acb54baSEdgar E. Iglesias { 804acb54baSEdgar E. Iglesias int i; 814acb54baSEdgar E. Iglesias 824acb54baSEdgar E. Iglesias qemu_log("PC=%8.8x\n", env->sregs[SR_PC]); 834c24aa0aSMichal Simek qemu_log("rmsr=%x resr=%x rear=%x debug[%x] imm=%x iflags=%x\n", 844c24aa0aSMichal Simek env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR], 8517c52a43SEdgar E. Iglesias env->debug, env->imm, env->iflags); 8617c52a43SEdgar E. Iglesias qemu_log("btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n", 8717c52a43SEdgar E. Iglesias env->btaken, env->btarget, 8817c52a43SEdgar E. Iglesias (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel", 8917c52a43SEdgar E. Iglesias (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel", 9017c52a43SEdgar E. Iglesias (env->sregs[SR_MSR] & MSR_EIP), 9117c52a43SEdgar E. Iglesias (env->sregs[SR_MSR] & MSR_IE)); 924acb54baSEdgar E. Iglesias for (i = 0; i < 32; i++) { 934acb54baSEdgar E. Iglesias qemu_log("r%2.2d=%8.8x ", i, env->regs[i]); 944acb54baSEdgar E. Iglesias if ((i + 1) % 4 == 0) 954acb54baSEdgar E. Iglesias qemu_log("\n"); 964acb54baSEdgar E. Iglesias } 974acb54baSEdgar E. Iglesias qemu_log("\n\n"); 984acb54baSEdgar E. Iglesias } 994acb54baSEdgar E. Iglesias 1004acb54baSEdgar E. Iglesias static inline uint32_t compute_carry(uint32_t a, uint32_t b, uint32_t cin) 1014acb54baSEdgar E. Iglesias { 1024acb54baSEdgar E. Iglesias uint32_t cout = 0; 1034acb54baSEdgar E. Iglesias 1044acb54baSEdgar E. Iglesias if ((b == ~0) && cin) 1054acb54baSEdgar E. Iglesias cout = 1; 1064acb54baSEdgar E. Iglesias else if ((~0 - a) < (b + cin)) 1074acb54baSEdgar E. Iglesias cout = 1; 1084acb54baSEdgar E. Iglesias return cout; 1094acb54baSEdgar E. Iglesias } 1104acb54baSEdgar E. Iglesias 1114acb54baSEdgar E. Iglesias uint32_t helper_cmp(uint32_t a, uint32_t b) 1124acb54baSEdgar E. Iglesias { 1134acb54baSEdgar E. Iglesias uint32_t t; 1144acb54baSEdgar E. Iglesias 1154acb54baSEdgar E. Iglesias t = b + ~a + 1; 1164acb54baSEdgar E. Iglesias if ((b & 0x80000000) ^ (a & 0x80000000)) 1174acb54baSEdgar E. Iglesias t = (t & 0x7fffffff) | (b & 0x80000000); 1184acb54baSEdgar E. Iglesias return t; 1194acb54baSEdgar E. Iglesias } 1204acb54baSEdgar E. Iglesias 1214acb54baSEdgar E. Iglesias uint32_t helper_cmpu(uint32_t a, uint32_t b) 1224acb54baSEdgar E. Iglesias { 1234acb54baSEdgar E. Iglesias uint32_t t; 1244acb54baSEdgar E. Iglesias 1254acb54baSEdgar E. Iglesias t = b + ~a + 1; 1264acb54baSEdgar E. Iglesias if ((b & 0x80000000) ^ (a & 0x80000000)) 1274acb54baSEdgar E. Iglesias t = (t & 0x7fffffff) | (a & 0x80000000); 1284acb54baSEdgar E. Iglesias return t; 1294acb54baSEdgar E. Iglesias } 1304acb54baSEdgar E. Iglesias 1314acb54baSEdgar E. Iglesias uint32_t helper_addkc(uint32_t a, uint32_t b, uint32_t k, uint32_t c) 1324acb54baSEdgar E. Iglesias { 1334acb54baSEdgar E. Iglesias uint32_t d, cf = 0, ncf; 1344acb54baSEdgar E. Iglesias 1354acb54baSEdgar E. Iglesias if (c) 1364acb54baSEdgar E. Iglesias cf = env->sregs[SR_MSR] >> 31; 1374acb54baSEdgar E. Iglesias assert(cf == 0 || cf == 1); 1384acb54baSEdgar E. Iglesias d = a + b + cf; 1394acb54baSEdgar E. Iglesias 1404acb54baSEdgar E. Iglesias if (!k) { 1414acb54baSEdgar E. Iglesias ncf = compute_carry(a, b, cf); 1424acb54baSEdgar E. Iglesias assert(ncf == 0 || ncf == 1); 1434acb54baSEdgar E. Iglesias if (ncf) 1444acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= MSR_C | MSR_CC; 1454acb54baSEdgar E. Iglesias else 1464acb54baSEdgar E. Iglesias env->sregs[SR_MSR] &= ~(MSR_C | MSR_CC); 1474acb54baSEdgar E. Iglesias } 1484acb54baSEdgar E. Iglesias D(qemu_log("%x = %x + %x cf=%d ncf=%d k=%d c=%d\n", 1494acb54baSEdgar E. Iglesias d, a, b, cf, ncf, k, c)); 1504acb54baSEdgar E. Iglesias return d; 1514acb54baSEdgar E. Iglesias } 1524acb54baSEdgar E. Iglesias 1534acb54baSEdgar E. Iglesias uint32_t helper_subkc(uint32_t a, uint32_t b, uint32_t k, uint32_t c) 1544acb54baSEdgar E. Iglesias { 1554acb54baSEdgar E. Iglesias uint32_t d, cf = 1, ncf; 1564acb54baSEdgar E. Iglesias 1574acb54baSEdgar E. Iglesias if (c) 1584acb54baSEdgar E. Iglesias cf = env->sregs[SR_MSR] >> 31; 1594acb54baSEdgar E. Iglesias assert(cf == 0 || cf == 1); 1604acb54baSEdgar E. Iglesias d = b + ~a + cf; 1614acb54baSEdgar E. Iglesias 1624acb54baSEdgar E. Iglesias if (!k) { 1634acb54baSEdgar E. Iglesias ncf = compute_carry(b, ~a, cf); 1644acb54baSEdgar E. Iglesias assert(ncf == 0 || ncf == 1); 1654acb54baSEdgar E. Iglesias if (ncf) 1664acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= MSR_C | MSR_CC; 1674acb54baSEdgar E. Iglesias else 1684acb54baSEdgar E. Iglesias env->sregs[SR_MSR] &= ~(MSR_C | MSR_CC); 1694acb54baSEdgar E. Iglesias } 1704acb54baSEdgar E. Iglesias D(qemu_log("%x = %x + %x cf=%d ncf=%d k=%d c=%d\n", 1714acb54baSEdgar E. Iglesias d, a, b, cf, ncf, k, c)); 1724acb54baSEdgar E. Iglesias return d; 1734acb54baSEdgar E. Iglesias } 1744acb54baSEdgar E. Iglesias 1754acb54baSEdgar E. Iglesias static inline int div_prepare(uint32_t a, uint32_t b) 1764acb54baSEdgar E. Iglesias { 1774acb54baSEdgar E. Iglesias if (b == 0) { 1784acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= MSR_DZ; 179821ebb33SEdgar E. Iglesias 180821ebb33SEdgar E. Iglesias if ((env->sregs[SR_MSR] & MSR_EE) 181821ebb33SEdgar E. Iglesias && !(env->pvr.regs[2] & PVR2_DIV_ZERO_EXC_MASK)) { 182821ebb33SEdgar E. Iglesias env->sregs[SR_ESR] = ESR_EC_DIVZERO; 183821ebb33SEdgar E. Iglesias helper_raise_exception(EXCP_HW_EXCP); 184821ebb33SEdgar E. Iglesias } 1854acb54baSEdgar E. Iglesias return 0; 1864acb54baSEdgar E. Iglesias } 1874acb54baSEdgar E. Iglesias env->sregs[SR_MSR] &= ~MSR_DZ; 1884acb54baSEdgar E. Iglesias return 1; 1894acb54baSEdgar E. Iglesias } 1904acb54baSEdgar E. Iglesias 1914acb54baSEdgar E. Iglesias uint32_t helper_divs(uint32_t a, uint32_t b) 1924acb54baSEdgar E. Iglesias { 1934acb54baSEdgar E. Iglesias if (!div_prepare(a, b)) 1944acb54baSEdgar E. Iglesias return 0; 1954acb54baSEdgar E. Iglesias return (int32_t)a / (int32_t)b; 1964acb54baSEdgar E. Iglesias } 1974acb54baSEdgar E. Iglesias 1984acb54baSEdgar E. Iglesias uint32_t helper_divu(uint32_t a, uint32_t b) 1994acb54baSEdgar E. Iglesias { 2004acb54baSEdgar E. Iglesias if (!div_prepare(a, b)) 2014acb54baSEdgar E. Iglesias return 0; 2024acb54baSEdgar E. Iglesias return a / b; 2034acb54baSEdgar E. Iglesias } 2044acb54baSEdgar E. Iglesias 2054acb54baSEdgar E. Iglesias uint32_t helper_pcmpbf(uint32_t a, uint32_t b) 2064acb54baSEdgar E. Iglesias { 2074acb54baSEdgar E. Iglesias unsigned int i; 2084acb54baSEdgar E. Iglesias uint32_t mask = 0xff000000; 2094acb54baSEdgar E. Iglesias 2104acb54baSEdgar E. Iglesias for (i = 0; i < 4; i++) { 2114acb54baSEdgar E. Iglesias if ((a & mask) == (b & mask)) 2124acb54baSEdgar E. Iglesias return i + 1; 2134acb54baSEdgar E. Iglesias mask >>= 8; 2144acb54baSEdgar E. Iglesias } 2154acb54baSEdgar E. Iglesias return 0; 2164acb54baSEdgar E. Iglesias } 2174acb54baSEdgar E. Iglesias 2183aa80988SEdgar E. Iglesias void helper_memalign(uint32_t addr, uint32_t dr, uint32_t wr, uint32_t mask) 219968a40f6SEdgar E. Iglesias { 220968a40f6SEdgar E. Iglesias if (addr & mask) { 22197f90cbfSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, 22297f90cbfSEdgar E. Iglesias "unaligned access addr=%x mask=%x, wr=%d dr=r%d\n", 22397f90cbfSEdgar E. Iglesias addr, mask, wr, dr); 22497f90cbfSEdgar E. Iglesias env->sregs[SR_EAR] = addr; 225968a40f6SEdgar E. Iglesias env->sregs[SR_ESR] = ESR_EC_UNALIGNED_DATA | (wr << 10) \ 226968a40f6SEdgar E. Iglesias | (dr & 31) << 5; 2273aa80988SEdgar E. Iglesias if (mask == 3) { 228968a40f6SEdgar E. Iglesias env->sregs[SR_ESR] |= 1 << 11; 229968a40f6SEdgar E. Iglesias } 23097f90cbfSEdgar E. Iglesias if (!(env->sregs[SR_MSR] & MSR_EE)) { 23197f90cbfSEdgar E. Iglesias return; 23297f90cbfSEdgar E. Iglesias } 233968a40f6SEdgar E. Iglesias helper_raise_exception(EXCP_HW_EXCP); 234968a40f6SEdgar E. Iglesias } 235968a40f6SEdgar E. Iglesias } 236968a40f6SEdgar E. Iglesias 2374acb54baSEdgar E. Iglesias #if !defined(CONFIG_USER_ONLY) 2384acb54baSEdgar E. Iglesias /* Writes/reads to the MMU's special regs end up here. */ 2394acb54baSEdgar E. Iglesias uint32_t helper_mmu_read(uint32_t rn) 2404acb54baSEdgar E. Iglesias { 2414acb54baSEdgar E. Iglesias return mmu_read(env, rn); 2424acb54baSEdgar E. Iglesias } 2434acb54baSEdgar E. Iglesias 2444acb54baSEdgar E. Iglesias void helper_mmu_write(uint32_t rn, uint32_t v) 2454acb54baSEdgar E. Iglesias { 2464acb54baSEdgar E. Iglesias mmu_write(env, rn, v); 2474acb54baSEdgar E. Iglesias } 2484acb54baSEdgar E. Iglesias #endif 249faed1c2aSEdgar E. Iglesias 250c227f099SAnthony Liguori void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, 251faed1c2aSEdgar E. Iglesias int is_asi, int size) 252faed1c2aSEdgar E. Iglesias { 253faed1c2aSEdgar E. Iglesias CPUState *saved_env; 254e1aa3254SEdgar E. Iglesias 255e1aa3254SEdgar E. Iglesias if (!cpu_single_env) { 256e1aa3254SEdgar E. Iglesias /* XXX: ??? */ 257e1aa3254SEdgar E. Iglesias return; 258e1aa3254SEdgar E. Iglesias } 259e1aa3254SEdgar E. Iglesias 260faed1c2aSEdgar E. Iglesias /* XXX: hack to restore env in all cases, even if not called from 261faed1c2aSEdgar E. Iglesias generated code */ 262faed1c2aSEdgar E. Iglesias saved_env = env; 263faed1c2aSEdgar E. Iglesias env = cpu_single_env; 26497f90cbfSEdgar E. Iglesias qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n", 265faed1c2aSEdgar E. Iglesias addr, is_write, is_exec); 266faed1c2aSEdgar E. Iglesias if (!(env->sregs[SR_MSR] & MSR_EE)) { 26795b279deSEdgar E. Iglesias env = saved_env; 268faed1c2aSEdgar E. Iglesias return; 269faed1c2aSEdgar E. Iglesias } 270faed1c2aSEdgar E. Iglesias 27197f90cbfSEdgar E. Iglesias env->sregs[SR_EAR] = addr; 272faed1c2aSEdgar E. Iglesias if (is_exec) { 27397f90cbfSEdgar E. Iglesias if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) { 274faed1c2aSEdgar E. Iglesias env->sregs[SR_ESR] = ESR_EC_INSN_BUS; 275faed1c2aSEdgar E. Iglesias helper_raise_exception(EXCP_HW_EXCP); 276faed1c2aSEdgar E. Iglesias } 277faed1c2aSEdgar E. Iglesias } else { 27897f90cbfSEdgar E. Iglesias if ((env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) { 279faed1c2aSEdgar E. Iglesias env->sregs[SR_ESR] = ESR_EC_DATA_BUS; 280faed1c2aSEdgar E. Iglesias helper_raise_exception(EXCP_HW_EXCP); 281faed1c2aSEdgar E. Iglesias } 282faed1c2aSEdgar E. Iglesias } 28395b279deSEdgar E. Iglesias env = saved_env; 284faed1c2aSEdgar E. Iglesias } 285