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]); 834acb54baSEdgar E. Iglesias for (i = 0; i < 32; i++) { 844acb54baSEdgar E. Iglesias qemu_log("r%2.2d=%8.8x ", i, env->regs[i]); 854acb54baSEdgar E. Iglesias if ((i + 1) % 4 == 0) 864acb54baSEdgar E. Iglesias qemu_log("\n"); 874acb54baSEdgar E. Iglesias } 884acb54baSEdgar E. Iglesias qemu_log("\n\n"); 894acb54baSEdgar E. Iglesias } 904acb54baSEdgar E. Iglesias 914acb54baSEdgar E. Iglesias static inline uint32_t compute_carry(uint32_t a, uint32_t b, uint32_t cin) 924acb54baSEdgar E. Iglesias { 934acb54baSEdgar E. Iglesias uint32_t cout = 0; 944acb54baSEdgar E. Iglesias 954acb54baSEdgar E. Iglesias if ((b == ~0) && cin) 964acb54baSEdgar E. Iglesias cout = 1; 974acb54baSEdgar E. Iglesias else if ((~0 - a) < (b + cin)) 984acb54baSEdgar E. Iglesias cout = 1; 994acb54baSEdgar E. Iglesias return cout; 1004acb54baSEdgar E. Iglesias } 1014acb54baSEdgar E. Iglesias 1024acb54baSEdgar E. Iglesias uint32_t helper_cmp(uint32_t a, uint32_t b) 1034acb54baSEdgar E. Iglesias { 1044acb54baSEdgar E. Iglesias uint32_t t; 1054acb54baSEdgar E. Iglesias 1064acb54baSEdgar E. Iglesias t = b + ~a + 1; 1074acb54baSEdgar E. Iglesias if ((b & 0x80000000) ^ (a & 0x80000000)) 1084acb54baSEdgar E. Iglesias t = (t & 0x7fffffff) | (b & 0x80000000); 1094acb54baSEdgar E. Iglesias return t; 1104acb54baSEdgar E. Iglesias } 1114acb54baSEdgar E. Iglesias 1124acb54baSEdgar E. Iglesias uint32_t helper_cmpu(uint32_t a, uint32_t b) 1134acb54baSEdgar E. Iglesias { 1144acb54baSEdgar E. Iglesias uint32_t t; 1154acb54baSEdgar E. Iglesias 1164acb54baSEdgar E. Iglesias t = b + ~a + 1; 1174acb54baSEdgar E. Iglesias if ((b & 0x80000000) ^ (a & 0x80000000)) 1184acb54baSEdgar E. Iglesias t = (t & 0x7fffffff) | (a & 0x80000000); 1194acb54baSEdgar E. Iglesias return t; 1204acb54baSEdgar E. Iglesias } 1214acb54baSEdgar E. Iglesias 1224acb54baSEdgar E. Iglesias uint32_t helper_addkc(uint32_t a, uint32_t b, uint32_t k, uint32_t c) 1234acb54baSEdgar E. Iglesias { 1244acb54baSEdgar E. Iglesias uint32_t d, cf = 0, ncf; 1254acb54baSEdgar E. Iglesias 1264acb54baSEdgar E. Iglesias if (c) 1274acb54baSEdgar E. Iglesias cf = env->sregs[SR_MSR] >> 31; 1284acb54baSEdgar E. Iglesias assert(cf == 0 || cf == 1); 1294acb54baSEdgar E. Iglesias d = a + b + cf; 1304acb54baSEdgar E. Iglesias 1314acb54baSEdgar E. Iglesias if (!k) { 1324acb54baSEdgar E. Iglesias ncf = compute_carry(a, b, cf); 1334acb54baSEdgar E. Iglesias assert(ncf == 0 || ncf == 1); 1344acb54baSEdgar E. Iglesias if (ncf) 1354acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= MSR_C | MSR_CC; 1364acb54baSEdgar E. Iglesias else 1374acb54baSEdgar E. Iglesias env->sregs[SR_MSR] &= ~(MSR_C | MSR_CC); 1384acb54baSEdgar E. Iglesias } 1394acb54baSEdgar E. Iglesias D(qemu_log("%x = %x + %x cf=%d ncf=%d k=%d c=%d\n", 1404acb54baSEdgar E. Iglesias d, a, b, cf, ncf, k, c)); 1414acb54baSEdgar E. Iglesias return d; 1424acb54baSEdgar E. Iglesias } 1434acb54baSEdgar E. Iglesias 1444acb54baSEdgar E. Iglesias uint32_t helper_subkc(uint32_t a, uint32_t b, uint32_t k, uint32_t c) 1454acb54baSEdgar E. Iglesias { 1464acb54baSEdgar E. Iglesias uint32_t d, cf = 1, ncf; 1474acb54baSEdgar E. Iglesias 1484acb54baSEdgar E. Iglesias if (c) 1494acb54baSEdgar E. Iglesias cf = env->sregs[SR_MSR] >> 31; 1504acb54baSEdgar E. Iglesias assert(cf == 0 || cf == 1); 1514acb54baSEdgar E. Iglesias d = b + ~a + cf; 1524acb54baSEdgar E. Iglesias 1534acb54baSEdgar E. Iglesias if (!k) { 1544acb54baSEdgar E. Iglesias ncf = compute_carry(b, ~a, cf); 1554acb54baSEdgar E. Iglesias assert(ncf == 0 || ncf == 1); 1564acb54baSEdgar E. Iglesias if (ncf) 1574acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= MSR_C | MSR_CC; 1584acb54baSEdgar E. Iglesias else 1594acb54baSEdgar E. Iglesias env->sregs[SR_MSR] &= ~(MSR_C | MSR_CC); 1604acb54baSEdgar E. Iglesias } 1614acb54baSEdgar E. Iglesias D(qemu_log("%x = %x + %x cf=%d ncf=%d k=%d c=%d\n", 1624acb54baSEdgar E. Iglesias d, a, b, cf, ncf, k, c)); 1634acb54baSEdgar E. Iglesias return d; 1644acb54baSEdgar E. Iglesias } 1654acb54baSEdgar E. Iglesias 1664acb54baSEdgar E. Iglesias static inline int div_prepare(uint32_t a, uint32_t b) 1674acb54baSEdgar E. Iglesias { 1684acb54baSEdgar E. Iglesias if (b == 0) { 1694acb54baSEdgar E. Iglesias env->sregs[SR_MSR] |= MSR_DZ; 170821ebb33SEdgar E. Iglesias 171821ebb33SEdgar E. Iglesias if ((env->sregs[SR_MSR] & MSR_EE) 172821ebb33SEdgar E. Iglesias && !(env->pvr.regs[2] & PVR2_DIV_ZERO_EXC_MASK)) { 173821ebb33SEdgar E. Iglesias env->sregs[SR_ESR] = ESR_EC_DIVZERO; 174821ebb33SEdgar E. Iglesias helper_raise_exception(EXCP_HW_EXCP); 175821ebb33SEdgar E. Iglesias } 1764acb54baSEdgar E. Iglesias return 0; 1774acb54baSEdgar E. Iglesias } 1784acb54baSEdgar E. Iglesias env->sregs[SR_MSR] &= ~MSR_DZ; 1794acb54baSEdgar E. Iglesias return 1; 1804acb54baSEdgar E. Iglesias } 1814acb54baSEdgar E. Iglesias 1824acb54baSEdgar E. Iglesias uint32_t helper_divs(uint32_t a, uint32_t b) 1834acb54baSEdgar E. Iglesias { 1844acb54baSEdgar E. Iglesias if (!div_prepare(a, b)) 1854acb54baSEdgar E. Iglesias return 0; 1864acb54baSEdgar E. Iglesias return (int32_t)a / (int32_t)b; 1874acb54baSEdgar E. Iglesias } 1884acb54baSEdgar E. Iglesias 1894acb54baSEdgar E. Iglesias uint32_t helper_divu(uint32_t a, uint32_t b) 1904acb54baSEdgar E. Iglesias { 1914acb54baSEdgar E. Iglesias if (!div_prepare(a, b)) 1924acb54baSEdgar E. Iglesias return 0; 1934acb54baSEdgar E. Iglesias return a / b; 1944acb54baSEdgar E. Iglesias } 1954acb54baSEdgar E. Iglesias 1964acb54baSEdgar E. Iglesias uint32_t helper_pcmpbf(uint32_t a, uint32_t b) 1974acb54baSEdgar E. Iglesias { 1984acb54baSEdgar E. Iglesias unsigned int i; 1994acb54baSEdgar E. Iglesias uint32_t mask = 0xff000000; 2004acb54baSEdgar E. Iglesias 2014acb54baSEdgar E. Iglesias for (i = 0; i < 4; i++) { 2024acb54baSEdgar E. Iglesias if ((a & mask) == (b & mask)) 2034acb54baSEdgar E. Iglesias return i + 1; 2044acb54baSEdgar E. Iglesias mask >>= 8; 2054acb54baSEdgar E. Iglesias } 2064acb54baSEdgar E. Iglesias return 0; 2074acb54baSEdgar E. Iglesias } 2084acb54baSEdgar E. Iglesias 2094acb54baSEdgar E. Iglesias #if !defined(CONFIG_USER_ONLY) 2104acb54baSEdgar E. Iglesias /* Writes/reads to the MMU's special regs end up here. */ 2114acb54baSEdgar E. Iglesias uint32_t helper_mmu_read(uint32_t rn) 2124acb54baSEdgar E. Iglesias { 2134acb54baSEdgar E. Iglesias return mmu_read(env, rn); 2144acb54baSEdgar E. Iglesias } 2154acb54baSEdgar E. Iglesias 2164acb54baSEdgar E. Iglesias void helper_mmu_write(uint32_t rn, uint32_t v) 2174acb54baSEdgar E. Iglesias { 2184acb54baSEdgar E. Iglesias mmu_write(env, rn, v); 2194acb54baSEdgar E. Iglesias } 2204acb54baSEdgar E. Iglesias #endif 221