162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci NetWinder Floating Point Emulator 462306a36Sopenharmony_ci (c) Rebel.COM, 1998,1999 562306a36Sopenharmony_ci (c) Philip Blundell, 2001 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci Direct questions, comments to Scott Bambrough <scottb@netwinder.org> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci*/ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "fpa11.h" 1262306a36Sopenharmony_ci#include "fpopcode.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "fpmodule.h" 1562306a36Sopenharmony_ci#include "fpmodule.inl" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/compiler.h> 1862306a36Sopenharmony_ci#include <linux/string.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* Reset the FPA11 chip. Called to initialize and reset the emulator. */ 2162306a36Sopenharmony_cistatic void resetFPA11(void) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci int i; 2462306a36Sopenharmony_ci FPA11 *fpa11 = GET_FPA11(); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci /* initialize the register type array */ 2762306a36Sopenharmony_ci for (i = 0; i <= 7; i++) { 2862306a36Sopenharmony_ci fpa11->fType[i] = typeNone; 2962306a36Sopenharmony_ci } 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ 3262306a36Sopenharmony_ci fpa11->fpsr = FP_EMULATOR | BIT_AC; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciint8 SetRoundingMode(const unsigned int opcode) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci switch (opcode & MASK_ROUNDING_MODE) { 3862306a36Sopenharmony_ci default: 3962306a36Sopenharmony_ci case ROUND_TO_NEAREST: 4062306a36Sopenharmony_ci return float_round_nearest_even; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci case ROUND_TO_PLUS_INFINITY: 4362306a36Sopenharmony_ci return float_round_up; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci case ROUND_TO_MINUS_INFINITY: 4662306a36Sopenharmony_ci return float_round_down; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci case ROUND_TO_ZERO: 4962306a36Sopenharmony_ci return float_round_to_zero; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciint8 SetRoundingPrecision(const unsigned int opcode) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci#ifdef CONFIG_FPE_NWFPE_XP 5662306a36Sopenharmony_ci switch (opcode & MASK_ROUNDING_PRECISION) { 5762306a36Sopenharmony_ci case ROUND_SINGLE: 5862306a36Sopenharmony_ci return 32; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci case ROUND_DOUBLE: 6162306a36Sopenharmony_ci return 64; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci case ROUND_EXTENDED: 6462306a36Sopenharmony_ci return 80; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci default: 6762306a36Sopenharmony_ci return 80; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci#endif 7062306a36Sopenharmony_ci return 80; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_civoid nwfpe_init_fpa(union fp_state *fp) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci FPA11 *fpa11 = (FPA11 *)fp; 7662306a36Sopenharmony_ci#ifdef NWFPE_DEBUG 7762306a36Sopenharmony_ci printk("NWFPE: setting up state.\n"); 7862306a36Sopenharmony_ci#endif 7962306a36Sopenharmony_ci memset(fpa11, 0, sizeof(FPA11)); 8062306a36Sopenharmony_ci resetFPA11(); 8162306a36Sopenharmony_ci fpa11->initflag = 1; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* Emulate the instruction in the opcode. */ 8562306a36Sopenharmony_ciunsigned int EmulateAll(unsigned int opcode) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci unsigned int code; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#ifdef NWFPE_DEBUG 9062306a36Sopenharmony_ci printk("NWFPE: emulating opcode %08x\n", opcode); 9162306a36Sopenharmony_ci#endif 9262306a36Sopenharmony_ci code = opcode & 0x00000f00; 9362306a36Sopenharmony_ci if (code == 0x00000100 || code == 0x00000200) { 9462306a36Sopenharmony_ci /* For coprocessor 1 or 2 (FPA11) */ 9562306a36Sopenharmony_ci code = opcode & 0x0e000000; 9662306a36Sopenharmony_ci if (code == 0x0e000000) { 9762306a36Sopenharmony_ci if (opcode & 0x00000010) { 9862306a36Sopenharmony_ci /* Emulate conversion opcodes. */ 9962306a36Sopenharmony_ci /* Emulate register transfer opcodes. */ 10062306a36Sopenharmony_ci /* Emulate comparison opcodes. */ 10162306a36Sopenharmony_ci return EmulateCPRT(opcode); 10262306a36Sopenharmony_ci } else { 10362306a36Sopenharmony_ci /* Emulate monadic arithmetic opcodes. */ 10462306a36Sopenharmony_ci /* Emulate dyadic arithmetic opcodes. */ 10562306a36Sopenharmony_ci return EmulateCPDO(opcode); 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci } else if (code == 0x0c000000) { 10862306a36Sopenharmony_ci /* Emulate load/store opcodes. */ 10962306a36Sopenharmony_ci /* Emulate load/store multiple opcodes. */ 11062306a36Sopenharmony_ci return EmulateCPDT(opcode); 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* Invalid instruction detected. Return FALSE. */ 11562306a36Sopenharmony_ci return 0; 11662306a36Sopenharmony_ci} 117