18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci NetWinder Floating Point Emulator 48c2ecf20Sopenharmony_ci (c) Rebel.COM, 1998,1999 58c2ecf20Sopenharmony_ci (c) Philip Blundell, 2001 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci Direct questions, comments to Scott Bambrough <scottb@netwinder.org> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci*/ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "fpa11.h" 128c2ecf20Sopenharmony_ci#include "fpopcode.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "fpmodule.h" 158c2ecf20Sopenharmony_ci#include "fpmodule.inl" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/compiler.h> 188c2ecf20Sopenharmony_ci#include <linux/string.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* Reset the FPA11 chip. Called to initialize and reset the emulator. */ 218c2ecf20Sopenharmony_cistatic void resetFPA11(void) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci int i; 248c2ecf20Sopenharmony_ci FPA11 *fpa11 = GET_FPA11(); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci /* initialize the register type array */ 278c2ecf20Sopenharmony_ci for (i = 0; i <= 7; i++) { 288c2ecf20Sopenharmony_ci fpa11->fType[i] = typeNone; 298c2ecf20Sopenharmony_ci } 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ 328c2ecf20Sopenharmony_ci fpa11->fpsr = FP_EMULATOR | BIT_AC; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ciint8 SetRoundingMode(const unsigned int opcode) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci switch (opcode & MASK_ROUNDING_MODE) { 388c2ecf20Sopenharmony_ci default: 398c2ecf20Sopenharmony_ci case ROUND_TO_NEAREST: 408c2ecf20Sopenharmony_ci return float_round_nearest_even; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci case ROUND_TO_PLUS_INFINITY: 438c2ecf20Sopenharmony_ci return float_round_up; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci case ROUND_TO_MINUS_INFINITY: 468c2ecf20Sopenharmony_ci return float_round_down; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci case ROUND_TO_ZERO: 498c2ecf20Sopenharmony_ci return float_round_to_zero; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ciint8 SetRoundingPrecision(const unsigned int opcode) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci#ifdef CONFIG_FPE_NWFPE_XP 568c2ecf20Sopenharmony_ci switch (opcode & MASK_ROUNDING_PRECISION) { 578c2ecf20Sopenharmony_ci case ROUND_SINGLE: 588c2ecf20Sopenharmony_ci return 32; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci case ROUND_DOUBLE: 618c2ecf20Sopenharmony_ci return 64; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci case ROUND_EXTENDED: 648c2ecf20Sopenharmony_ci return 80; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci default: 678c2ecf20Sopenharmony_ci return 80; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci#endif 708c2ecf20Sopenharmony_ci return 80; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_civoid nwfpe_init_fpa(union fp_state *fp) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci FPA11 *fpa11 = (FPA11 *)fp; 768c2ecf20Sopenharmony_ci#ifdef NWFPE_DEBUG 778c2ecf20Sopenharmony_ci printk("NWFPE: setting up state.\n"); 788c2ecf20Sopenharmony_ci#endif 798c2ecf20Sopenharmony_ci memset(fpa11, 0, sizeof(FPA11)); 808c2ecf20Sopenharmony_ci resetFPA11(); 818c2ecf20Sopenharmony_ci fpa11->initflag = 1; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* Emulate the instruction in the opcode. */ 858c2ecf20Sopenharmony_ciunsigned int EmulateAll(unsigned int opcode) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci unsigned int code; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#ifdef NWFPE_DEBUG 908c2ecf20Sopenharmony_ci printk("NWFPE: emulating opcode %08x\n", opcode); 918c2ecf20Sopenharmony_ci#endif 928c2ecf20Sopenharmony_ci code = opcode & 0x00000f00; 938c2ecf20Sopenharmony_ci if (code == 0x00000100 || code == 0x00000200) { 948c2ecf20Sopenharmony_ci /* For coprocessor 1 or 2 (FPA11) */ 958c2ecf20Sopenharmony_ci code = opcode & 0x0e000000; 968c2ecf20Sopenharmony_ci if (code == 0x0e000000) { 978c2ecf20Sopenharmony_ci if (opcode & 0x00000010) { 988c2ecf20Sopenharmony_ci /* Emulate conversion opcodes. */ 998c2ecf20Sopenharmony_ci /* Emulate register transfer opcodes. */ 1008c2ecf20Sopenharmony_ci /* Emulate comparison opcodes. */ 1018c2ecf20Sopenharmony_ci return EmulateCPRT(opcode); 1028c2ecf20Sopenharmony_ci } else { 1038c2ecf20Sopenharmony_ci /* Emulate monadic arithmetic opcodes. */ 1048c2ecf20Sopenharmony_ci /* Emulate dyadic arithmetic opcodes. */ 1058c2ecf20Sopenharmony_ci return EmulateCPDO(opcode); 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci } else if (code == 0x0c000000) { 1088c2ecf20Sopenharmony_ci /* Emulate load/store opcodes. */ 1098c2ecf20Sopenharmony_ci /* Emulate load/store multiple opcodes. */ 1108c2ecf20Sopenharmony_ci return EmulateCPDT(opcode); 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* Invalid instruction detected. Return FALSE. */ 1158c2ecf20Sopenharmony_ci return 0; 1168c2ecf20Sopenharmony_ci} 117