1706f2543Smrg/**************************************************************************** 2706f2543Smrg* 3706f2543Smrg* Realmode X86 Emulator Library 4706f2543Smrg* 5706f2543Smrg* Copyright (C) 1996-1999 SciTech Software, Inc. 6706f2543Smrg* Copyright (C) David Mosberger-Tang 7706f2543Smrg* Copyright (C) 1999 Egbert Eich 8706f2543Smrg* 9706f2543Smrg* ======================================================================== 10706f2543Smrg* 11706f2543Smrg* Permission to use, copy, modify, distribute, and sell this software and 12706f2543Smrg* its documentation for any purpose is hereby granted without fee, 13706f2543Smrg* provided that the above copyright notice appear in all copies and that 14706f2543Smrg* both that copyright notice and this permission notice appear in 15706f2543Smrg* supporting documentation, and that the name of the authors not be used 16706f2543Smrg* in advertising or publicity pertaining to distribution of the software 17706f2543Smrg* without specific, written prior permission. The authors makes no 18706f2543Smrg* representations about the suitability of this software for any purpose. 19706f2543Smrg* It is provided "as is" without express or implied warranty. 20706f2543Smrg* 21706f2543Smrg* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 22706f2543Smrg* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 23706f2543Smrg* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 24706f2543Smrg* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 25706f2543Smrg* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 26706f2543Smrg* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 27706f2543Smrg* PERFORMANCE OF THIS SOFTWARE. 28706f2543Smrg* 29706f2543Smrg* ======================================================================== 30706f2543Smrg* 31706f2543Smrg* Language: ANSI C 32706f2543Smrg* Environment: Any 33706f2543Smrg* Developer: Kendall Bennett 34706f2543Smrg* 35706f2543Smrg* Description: This file contains the code to implement the primitive 36706f2543Smrg* machine operations used by the emulation code in ops.c 37706f2543Smrg* 38706f2543Smrg* Carry Chain Calculation 39706f2543Smrg* 40706f2543Smrg* This represents a somewhat expensive calculation which is 41706f2543Smrg* apparently required to emulate the setting of the OF and AF flag. 42706f2543Smrg* The latter is not so important, but the former is. The overflow 43706f2543Smrg* flag is the XOR of the top two bits of the carry chain for an 44706f2543Smrg* addition (similar for subtraction). Since we do not want to 45706f2543Smrg* simulate the addition in a bitwise manner, we try to calculate the 46706f2543Smrg* carry chain given the two operands and the result. 47706f2543Smrg* 48706f2543Smrg* So, given the following table, which represents the addition of two 49706f2543Smrg* bits, we can derive a formula for the carry chain. 50706f2543Smrg* 51706f2543Smrg* a b cin r cout 52706f2543Smrg* 0 0 0 0 0 53706f2543Smrg* 0 0 1 1 0 54706f2543Smrg* 0 1 0 1 0 55706f2543Smrg* 0 1 1 0 1 56706f2543Smrg* 1 0 0 1 0 57706f2543Smrg* 1 0 1 0 1 58706f2543Smrg* 1 1 0 0 1 59706f2543Smrg* 1 1 1 1 1 60706f2543Smrg* 61706f2543Smrg* Construction of table for cout: 62706f2543Smrg* 63706f2543Smrg* ab 64706f2543Smrg* r \ 00 01 11 10 65706f2543Smrg* |------------------ 66706f2543Smrg* 0 | 0 1 1 1 67706f2543Smrg* 1 | 0 0 1 0 68706f2543Smrg* 69706f2543Smrg* By inspection, one gets: cc = ab + r'(a + b) 70706f2543Smrg* 71706f2543Smrg* That represents alot of operations, but NO CHOICE.... 72706f2543Smrg* 73706f2543Smrg* Borrow Chain Calculation. 74706f2543Smrg* 75706f2543Smrg* The following table represents the subtraction of two bits, from 76706f2543Smrg* which we can derive a formula for the borrow chain. 77706f2543Smrg* 78706f2543Smrg* a b bin r bout 79706f2543Smrg* 0 0 0 0 0 80706f2543Smrg* 0 0 1 1 1 81706f2543Smrg* 0 1 0 1 1 82706f2543Smrg* 0 1 1 0 1 83706f2543Smrg* 1 0 0 1 0 84706f2543Smrg* 1 0 1 0 0 85706f2543Smrg* 1 1 0 0 0 86706f2543Smrg* 1 1 1 1 1 87706f2543Smrg* 88706f2543Smrg* Construction of table for cout: 89706f2543Smrg* 90706f2543Smrg* ab 91706f2543Smrg* r \ 00 01 11 10 92706f2543Smrg* |------------------ 93706f2543Smrg* 0 | 0 1 0 0 94706f2543Smrg* 1 | 1 1 1 0 95706f2543Smrg* 96706f2543Smrg* By inspection, one gets: bc = a'b + r(a' + b) 97706f2543Smrg* 98706f2543Smrg****************************************************************************/ 99706f2543Smrg 100706f2543Smrg#include <stdlib.h> 101706f2543Smrg 102706f2543Smrg#define PRIM_OPS_NO_REDEFINE_ASM 103706f2543Smrg#include "x86emu/x86emui.h" 104706f2543Smrg 105706f2543Smrg#if defined(__GNUC__) 106706f2543Smrg# if defined (__i386__) || defined(__i386) || defined(__AMD64__) || defined(__amd64__) 107706f2543Smrg# include "x86emu/prim_x86_gcc.h" 108706f2543Smrg# endif 109706f2543Smrg#endif 110706f2543Smrg 111706f2543Smrg/*------------------------- Global Variables ------------------------------*/ 112706f2543Smrg 113706f2543Smrgstatic u32 x86emu_parity_tab[8] = 114706f2543Smrg{ 115706f2543Smrg 0x96696996, 116706f2543Smrg 0x69969669, 117706f2543Smrg 0x69969669, 118706f2543Smrg 0x96696996, 119706f2543Smrg 0x69969669, 120706f2543Smrg 0x96696996, 121706f2543Smrg 0x96696996, 122706f2543Smrg 0x69969669, 123706f2543Smrg}; 124706f2543Smrg 125706f2543Smrg#define PARITY(x) (((x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0) 126706f2543Smrg#define XOR2(x) (((x) ^ ((x)>>1)) & 0x1) 127706f2543Smrg 128706f2543Smrg/*----------------------------- Implementation ----------------------------*/ 129706f2543Smrg 130706f2543Smrg/**************************************************************************** 131706f2543SmrgREMARKS: 132706f2543SmrgImplements the AAA instruction and side effects. 133706f2543Smrg****************************************************************************/ 134706f2543Smrgu16 aaa_word(u16 d) 135706f2543Smrg{ 136706f2543Smrg u16 res; 137706f2543Smrg if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) { 138706f2543Smrg d += 0x6; 139706f2543Smrg d += 0x100; 140706f2543Smrg SET_FLAG(F_AF); 141706f2543Smrg SET_FLAG(F_CF); 142706f2543Smrg } else { 143706f2543Smrg CLEAR_FLAG(F_CF); 144706f2543Smrg CLEAR_FLAG(F_AF); 145706f2543Smrg } 146706f2543Smrg res = (u16)(d & 0xFF0F); 147706f2543Smrg CLEAR_FLAG(F_SF); 148706f2543Smrg CONDITIONAL_SET_FLAG(res == 0, F_ZF); 149706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 150706f2543Smrg return res; 151706f2543Smrg} 152706f2543Smrg 153706f2543Smrg/**************************************************************************** 154706f2543SmrgREMARKS: 155706f2543SmrgImplements the AAA instruction and side effects. 156706f2543Smrg****************************************************************************/ 157706f2543Smrgu16 aas_word(u16 d) 158706f2543Smrg{ 159706f2543Smrg u16 res; 160706f2543Smrg if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) { 161706f2543Smrg d -= 0x6; 162706f2543Smrg d -= 0x100; 163706f2543Smrg SET_FLAG(F_AF); 164706f2543Smrg SET_FLAG(F_CF); 165706f2543Smrg } else { 166706f2543Smrg CLEAR_FLAG(F_CF); 167706f2543Smrg CLEAR_FLAG(F_AF); 168706f2543Smrg } 169706f2543Smrg res = (u16)(d & 0xFF0F); 170706f2543Smrg CLEAR_FLAG(F_SF); 171706f2543Smrg CONDITIONAL_SET_FLAG(res == 0, F_ZF); 172706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 173706f2543Smrg return res; 174706f2543Smrg} 175706f2543Smrg 176706f2543Smrg/**************************************************************************** 177706f2543SmrgREMARKS: 178706f2543SmrgImplements the AAD instruction and side effects. 179706f2543Smrg****************************************************************************/ 180706f2543Smrgu16 aad_word(u16 d) 181706f2543Smrg{ 182706f2543Smrg u16 l; 183706f2543Smrg u8 hb, lb; 184706f2543Smrg 185706f2543Smrg hb = (u8)((d >> 8) & 0xff); 186706f2543Smrg lb = (u8)((d & 0xff)); 187706f2543Smrg l = (u16)((lb + 10 * hb) & 0xFF); 188706f2543Smrg 189706f2543Smrg CLEAR_FLAG(F_CF); 190706f2543Smrg CLEAR_FLAG(F_AF); 191706f2543Smrg CLEAR_FLAG(F_OF); 192706f2543Smrg CONDITIONAL_SET_FLAG(l & 0x80, F_SF); 193706f2543Smrg CONDITIONAL_SET_FLAG(l == 0, F_ZF); 194706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF); 195706f2543Smrg return l; 196706f2543Smrg} 197706f2543Smrg 198706f2543Smrg/**************************************************************************** 199706f2543SmrgREMARKS: 200706f2543SmrgImplements the AAM instruction and side effects. 201706f2543Smrg****************************************************************************/ 202706f2543Smrgu16 aam_word(u8 d) 203706f2543Smrg{ 204706f2543Smrg u16 h, l; 205706f2543Smrg 206706f2543Smrg h = (u16)(d / 10); 207706f2543Smrg l = (u16)(d % 10); 208706f2543Smrg l |= (u16)(h << 8); 209706f2543Smrg 210706f2543Smrg CLEAR_FLAG(F_CF); 211706f2543Smrg CLEAR_FLAG(F_AF); 212706f2543Smrg CLEAR_FLAG(F_OF); 213706f2543Smrg CONDITIONAL_SET_FLAG(l & 0x80, F_SF); 214706f2543Smrg CONDITIONAL_SET_FLAG(l == 0, F_ZF); 215706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF); 216706f2543Smrg return l; 217706f2543Smrg} 218706f2543Smrg 219706f2543Smrg/**************************************************************************** 220706f2543SmrgREMARKS: 221706f2543SmrgImplements the ADC instruction and side effects. 222706f2543Smrg****************************************************************************/ 223706f2543Smrgu8 adc_byte(u8 d, u8 s) 224706f2543Smrg{ 225706f2543Smrg register u32 res; /* all operands in native machine order */ 226706f2543Smrg register u32 cc; 227706f2543Smrg 228706f2543Smrg if (ACCESS_FLAG(F_CF)) 229706f2543Smrg res = 1 + d + s; 230706f2543Smrg else 231706f2543Smrg res = d + s; 232706f2543Smrg 233706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x100, F_CF); 234706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); 235706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_SF); 236706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 237706f2543Smrg 238706f2543Smrg /* calculate the carry chain SEE NOTE AT TOP. */ 239706f2543Smrg cc = (s & d) | ((~res) & (s | d)); 240706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); 241706f2543Smrg CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); 242706f2543Smrg return (u8)res; 243706f2543Smrg} 244706f2543Smrg 245706f2543Smrg/**************************************************************************** 246706f2543SmrgREMARKS: 247706f2543SmrgImplements the ADC instruction and side effects. 248706f2543Smrg****************************************************************************/ 249706f2543Smrgu16 adc_word(u16 d, u16 s) 250706f2543Smrg{ 251706f2543Smrg register u32 res; /* all operands in native machine order */ 252706f2543Smrg register u32 cc; 253706f2543Smrg 254706f2543Smrg if (ACCESS_FLAG(F_CF)) 255706f2543Smrg res = 1 + d + s; 256706f2543Smrg else 257706f2543Smrg res = d + s; 258706f2543Smrg 259706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x10000, F_CF); 260706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); 261706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 262706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 263706f2543Smrg 264706f2543Smrg /* calculate the carry chain SEE NOTE AT TOP. */ 265706f2543Smrg cc = (s & d) | ((~res) & (s | d)); 266706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); 267706f2543Smrg CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); 268706f2543Smrg return (u16)res; 269706f2543Smrg} 270706f2543Smrg 271706f2543Smrg/**************************************************************************** 272706f2543SmrgREMARKS: 273706f2543SmrgImplements the ADC instruction and side effects. 274706f2543Smrg****************************************************************************/ 275706f2543Smrgu32 adc_long(u32 d, u32 s) 276706f2543Smrg{ 277706f2543Smrg register u32 lo; /* all operands in native machine order */ 278706f2543Smrg register u32 hi; 279706f2543Smrg register u32 res; 280706f2543Smrg register u32 cc; 281706f2543Smrg 282706f2543Smrg if (ACCESS_FLAG(F_CF)) { 283706f2543Smrg lo = 1 + (d & 0xFFFF) + (s & 0xFFFF); 284706f2543Smrg res = 1 + d + s; 285706f2543Smrg } 286706f2543Smrg else { 287706f2543Smrg lo = (d & 0xFFFF) + (s & 0xFFFF); 288706f2543Smrg res = d + s; 289706f2543Smrg } 290706f2543Smrg hi = (lo >> 16) + (d >> 16) + (s >> 16); 291706f2543Smrg 292706f2543Smrg CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF); 293706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); 294706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 295706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 296706f2543Smrg 297706f2543Smrg /* calculate the carry chain SEE NOTE AT TOP. */ 298706f2543Smrg cc = (s & d) | ((~res) & (s | d)); 299706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); 300706f2543Smrg CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); 301706f2543Smrg return res; 302706f2543Smrg} 303706f2543Smrg 304706f2543Smrg/**************************************************************************** 305706f2543SmrgREMARKS: 306706f2543SmrgImplements the ADD instruction and side effects. 307706f2543Smrg****************************************************************************/ 308706f2543Smrgu8 add_byte(u8 d, u8 s) 309706f2543Smrg{ 310706f2543Smrg register u32 res; /* all operands in native machine order */ 311706f2543Smrg register u32 cc; 312706f2543Smrg 313706f2543Smrg res = d + s; 314706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x100, F_CF); 315706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); 316706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_SF); 317706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 318706f2543Smrg 319706f2543Smrg /* calculate the carry chain SEE NOTE AT TOP. */ 320706f2543Smrg cc = (s & d) | ((~res) & (s | d)); 321706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); 322706f2543Smrg CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); 323706f2543Smrg return (u8)res; 324706f2543Smrg} 325706f2543Smrg 326706f2543Smrg/**************************************************************************** 327706f2543SmrgREMARKS: 328706f2543SmrgImplements the ADD instruction and side effects. 329706f2543Smrg****************************************************************************/ 330706f2543Smrgu16 add_word(u16 d, u16 s) 331706f2543Smrg{ 332706f2543Smrg register u32 res; /* all operands in native machine order */ 333706f2543Smrg register u32 cc; 334706f2543Smrg 335706f2543Smrg res = d + s; 336706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x10000, F_CF); 337706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); 338706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 339706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 340706f2543Smrg 341706f2543Smrg /* calculate the carry chain SEE NOTE AT TOP. */ 342706f2543Smrg cc = (s & d) | ((~res) & (s | d)); 343706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); 344706f2543Smrg CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); 345706f2543Smrg return (u16)res; 346706f2543Smrg} 347706f2543Smrg 348706f2543Smrg/**************************************************************************** 349706f2543SmrgREMARKS: 350706f2543SmrgImplements the ADD instruction and side effects. 351706f2543Smrg****************************************************************************/ 352706f2543Smrgu32 add_long(u32 d, u32 s) 353706f2543Smrg{ 354706f2543Smrg register u32 lo; /* all operands in native machine order */ 355706f2543Smrg register u32 hi; 356706f2543Smrg register u32 res; 357706f2543Smrg register u32 cc; 358706f2543Smrg 359706f2543Smrg lo = (d & 0xFFFF) + (s & 0xFFFF); 360706f2543Smrg res = d + s; 361706f2543Smrg hi = (lo >> 16) + (d >> 16) + (s >> 16); 362706f2543Smrg 363706f2543Smrg CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF); 364706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); 365706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 366706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 367706f2543Smrg 368706f2543Smrg /* calculate the carry chain SEE NOTE AT TOP. */ 369706f2543Smrg cc = (s & d) | ((~res) & (s | d)); 370706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); 371706f2543Smrg CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); 372706f2543Smrg 373706f2543Smrg return res; 374706f2543Smrg} 375706f2543Smrg 376706f2543Smrg/**************************************************************************** 377706f2543SmrgREMARKS: 378706f2543SmrgImplements the AND instruction and side effects. 379706f2543Smrg****************************************************************************/ 380706f2543Smrgu8 and_byte(u8 d, u8 s) 381706f2543Smrg{ 382706f2543Smrg register u8 res; /* all operands in native machine order */ 383706f2543Smrg 384706f2543Smrg res = d & s; 385706f2543Smrg 386706f2543Smrg /* set the flags */ 387706f2543Smrg CLEAR_FLAG(F_OF); 388706f2543Smrg CLEAR_FLAG(F_CF); 389706f2543Smrg CLEAR_FLAG(F_AF); 390706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_SF); 391706f2543Smrg CONDITIONAL_SET_FLAG(res == 0, F_ZF); 392706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res), F_PF); 393706f2543Smrg return res; 394706f2543Smrg} 395706f2543Smrg 396706f2543Smrg/**************************************************************************** 397706f2543SmrgREMARKS: 398706f2543SmrgImplements the AND instruction and side effects. 399706f2543Smrg****************************************************************************/ 400706f2543Smrgu16 and_word(u16 d, u16 s) 401706f2543Smrg{ 402706f2543Smrg register u16 res; /* all operands in native machine order */ 403706f2543Smrg 404706f2543Smrg res = d & s; 405706f2543Smrg 406706f2543Smrg /* set the flags */ 407706f2543Smrg CLEAR_FLAG(F_OF); 408706f2543Smrg CLEAR_FLAG(F_CF); 409706f2543Smrg CLEAR_FLAG(F_AF); 410706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 411706f2543Smrg CONDITIONAL_SET_FLAG(res == 0, F_ZF); 412706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 413706f2543Smrg return res; 414706f2543Smrg} 415706f2543Smrg 416706f2543Smrg/**************************************************************************** 417706f2543SmrgREMARKS: 418706f2543SmrgImplements the AND instruction and side effects. 419706f2543Smrg****************************************************************************/ 420706f2543Smrgu32 and_long(u32 d, u32 s) 421706f2543Smrg{ 422706f2543Smrg register u32 res; /* all operands in native machine order */ 423706f2543Smrg 424706f2543Smrg res = d & s; 425706f2543Smrg 426706f2543Smrg /* set the flags */ 427706f2543Smrg CLEAR_FLAG(F_OF); 428706f2543Smrg CLEAR_FLAG(F_CF); 429706f2543Smrg CLEAR_FLAG(F_AF); 430706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 431706f2543Smrg CONDITIONAL_SET_FLAG(res == 0, F_ZF); 432706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 433706f2543Smrg return res; 434706f2543Smrg} 435706f2543Smrg 436706f2543Smrg/**************************************************************************** 437706f2543SmrgREMARKS: 438706f2543SmrgImplements the CMP instruction and side effects. 439706f2543Smrg****************************************************************************/ 440706f2543Smrgu8 cmp_byte(u8 d, u8 s) 441706f2543Smrg{ 442706f2543Smrg register u32 res; /* all operands in native machine order */ 443706f2543Smrg register u32 bc; 444706f2543Smrg 445706f2543Smrg res = d - s; 446706f2543Smrg CLEAR_FLAG(F_CF); 447706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_SF); 448706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); 449706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 450706f2543Smrg 451706f2543Smrg /* calculate the borrow chain. See note at top */ 452706f2543Smrg bc = (res & (~d | s)) | (~d & s); 453706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); 454706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); 455706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); 456706f2543Smrg return d; 457706f2543Smrg} 458706f2543Smrg 459706f2543Smrg/**************************************************************************** 460706f2543SmrgREMARKS: 461706f2543SmrgImplements the CMP instruction and side effects. 462706f2543Smrg****************************************************************************/ 463706f2543Smrgu16 cmp_word(u16 d, u16 s) 464706f2543Smrg{ 465706f2543Smrg register u32 res; /* all operands in native machine order */ 466706f2543Smrg register u32 bc; 467706f2543Smrg 468706f2543Smrg res = d - s; 469706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 470706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); 471706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 472706f2543Smrg 473706f2543Smrg /* calculate the borrow chain. See note at top */ 474706f2543Smrg bc = (res & (~d | s)) | (~d & s); 475706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); 476706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); 477706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); 478706f2543Smrg return d; 479706f2543Smrg} 480706f2543Smrg 481706f2543Smrg/**************************************************************************** 482706f2543SmrgREMARKS: 483706f2543SmrgImplements the CMP instruction and side effects. 484706f2543Smrg****************************************************************************/ 485706f2543Smrgu32 cmp_long(u32 d, u32 s) 486706f2543Smrg{ 487706f2543Smrg register u32 res; /* all operands in native machine order */ 488706f2543Smrg register u32 bc; 489706f2543Smrg 490706f2543Smrg res = d - s; 491706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 492706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); 493706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 494706f2543Smrg 495706f2543Smrg /* calculate the borrow chain. See note at top */ 496706f2543Smrg bc = (res & (~d | s)) | (~d & s); 497706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); 498706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); 499706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); 500706f2543Smrg return d; 501706f2543Smrg} 502706f2543Smrg 503706f2543Smrg/**************************************************************************** 504706f2543SmrgREMARKS: 505706f2543SmrgImplements the DAA instruction and side effects. 506706f2543Smrg****************************************************************************/ 507706f2543Smrgu8 daa_byte(u8 d) 508706f2543Smrg{ 509706f2543Smrg u32 res = d; 510706f2543Smrg if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) { 511706f2543Smrg res += 6; 512706f2543Smrg SET_FLAG(F_AF); 513706f2543Smrg } 514706f2543Smrg if (res > 0x9F || ACCESS_FLAG(F_CF)) { 515706f2543Smrg res += 0x60; 516706f2543Smrg SET_FLAG(F_CF); 517706f2543Smrg } 518706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_SF); 519706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xFF) == 0, F_ZF); 520706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 521706f2543Smrg return (u8)res; 522706f2543Smrg} 523706f2543Smrg 524706f2543Smrg/**************************************************************************** 525706f2543SmrgREMARKS: 526706f2543SmrgImplements the DAS instruction and side effects. 527706f2543Smrg****************************************************************************/ 528706f2543Smrgu8 das_byte(u8 d) 529706f2543Smrg{ 530706f2543Smrg if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) { 531706f2543Smrg d -= 6; 532706f2543Smrg SET_FLAG(F_AF); 533706f2543Smrg } 534706f2543Smrg if (d > 0x9F || ACCESS_FLAG(F_CF)) { 535706f2543Smrg d -= 0x60; 536706f2543Smrg SET_FLAG(F_CF); 537706f2543Smrg } 538706f2543Smrg CONDITIONAL_SET_FLAG(d & 0x80, F_SF); 539706f2543Smrg CONDITIONAL_SET_FLAG(d == 0, F_ZF); 540706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(d & 0xff), F_PF); 541706f2543Smrg return d; 542706f2543Smrg} 543706f2543Smrg 544706f2543Smrg/**************************************************************************** 545706f2543SmrgREMARKS: 546706f2543SmrgImplements the DEC instruction and side effects. 547706f2543Smrg****************************************************************************/ 548706f2543Smrgu8 dec_byte(u8 d) 549706f2543Smrg{ 550706f2543Smrg register u32 res; /* all operands in native machine order */ 551706f2543Smrg register u32 bc; 552706f2543Smrg 553706f2543Smrg res = d - 1; 554706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_SF); 555706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); 556706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 557706f2543Smrg 558706f2543Smrg /* calculate the borrow chain. See note at top */ 559706f2543Smrg /* based on sub_byte, uses s==1. */ 560706f2543Smrg bc = (res & (~d | 1)) | (~d & 1); 561706f2543Smrg /* carry flag unchanged */ 562706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); 563706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); 564706f2543Smrg return (u8)res; 565706f2543Smrg} 566706f2543Smrg 567706f2543Smrg/**************************************************************************** 568706f2543SmrgREMARKS: 569706f2543SmrgImplements the DEC instruction and side effects. 570706f2543Smrg****************************************************************************/ 571706f2543Smrgu16 dec_word(u16 d) 572706f2543Smrg{ 573706f2543Smrg register u32 res; /* all operands in native machine order */ 574706f2543Smrg register u32 bc; 575706f2543Smrg 576706f2543Smrg res = d - 1; 577706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 578706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); 579706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 580706f2543Smrg 581706f2543Smrg /* calculate the borrow chain. See note at top */ 582706f2543Smrg /* based on the sub_byte routine, with s==1 */ 583706f2543Smrg bc = (res & (~d | 1)) | (~d & 1); 584706f2543Smrg /* carry flag unchanged */ 585706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); 586706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); 587706f2543Smrg return (u16)res; 588706f2543Smrg} 589706f2543Smrg 590706f2543Smrg/**************************************************************************** 591706f2543SmrgREMARKS: 592706f2543SmrgImplements the DEC instruction and side effects. 593706f2543Smrg****************************************************************************/ 594706f2543Smrgu32 dec_long(u32 d) 595706f2543Smrg{ 596706f2543Smrg register u32 res; /* all operands in native machine order */ 597706f2543Smrg register u32 bc; 598706f2543Smrg 599706f2543Smrg res = d - 1; 600706f2543Smrg 601706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 602706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); 603706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 604706f2543Smrg 605706f2543Smrg /* calculate the borrow chain. See note at top */ 606706f2543Smrg bc = (res & (~d | 1)) | (~d & 1); 607706f2543Smrg /* carry flag unchanged */ 608706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); 609706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); 610706f2543Smrg return res; 611706f2543Smrg} 612706f2543Smrg 613706f2543Smrg/**************************************************************************** 614706f2543SmrgREMARKS: 615706f2543SmrgImplements the INC instruction and side effects. 616706f2543Smrg****************************************************************************/ 617706f2543Smrgu8 inc_byte(u8 d) 618706f2543Smrg{ 619706f2543Smrg register u32 res; /* all operands in native machine order */ 620706f2543Smrg register u32 cc; 621706f2543Smrg 622706f2543Smrg res = d + 1; 623706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); 624706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_SF); 625706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 626706f2543Smrg 627706f2543Smrg /* calculate the carry chain SEE NOTE AT TOP. */ 628706f2543Smrg cc = ((1 & d) | (~res)) & (1 | d); 629706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); 630706f2543Smrg CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); 631706f2543Smrg return (u8)res; 632706f2543Smrg} 633706f2543Smrg 634706f2543Smrg/**************************************************************************** 635706f2543SmrgREMARKS: 636706f2543SmrgImplements the INC instruction and side effects. 637706f2543Smrg****************************************************************************/ 638706f2543Smrgu16 inc_word(u16 d) 639706f2543Smrg{ 640706f2543Smrg register u32 res; /* all operands in native machine order */ 641706f2543Smrg register u32 cc; 642706f2543Smrg 643706f2543Smrg res = d + 1; 644706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); 645706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 646706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 647706f2543Smrg 648706f2543Smrg /* calculate the carry chain SEE NOTE AT TOP. */ 649706f2543Smrg cc = (1 & d) | ((~res) & (1 | d)); 650706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); 651706f2543Smrg CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); 652706f2543Smrg return (u16)res; 653706f2543Smrg} 654706f2543Smrg 655706f2543Smrg/**************************************************************************** 656706f2543SmrgREMARKS: 657706f2543SmrgImplements the INC instruction and side effects. 658706f2543Smrg****************************************************************************/ 659706f2543Smrgu32 inc_long(u32 d) 660706f2543Smrg{ 661706f2543Smrg register u32 res; /* all operands in native machine order */ 662706f2543Smrg register u32 cc; 663706f2543Smrg 664706f2543Smrg res = d + 1; 665706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); 666706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 667706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 668706f2543Smrg 669706f2543Smrg /* calculate the carry chain SEE NOTE AT TOP. */ 670706f2543Smrg cc = (1 & d) | ((~res) & (1 | d)); 671706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); 672706f2543Smrg CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); 673706f2543Smrg return res; 674706f2543Smrg} 675706f2543Smrg 676706f2543Smrg/**************************************************************************** 677706f2543SmrgREMARKS: 678706f2543SmrgImplements the OR instruction and side effects. 679706f2543Smrg****************************************************************************/ 680706f2543Smrgu8 or_byte(u8 d, u8 s) 681706f2543Smrg{ 682706f2543Smrg register u8 res; /* all operands in native machine order */ 683706f2543Smrg 684706f2543Smrg res = d | s; 685706f2543Smrg CLEAR_FLAG(F_OF); 686706f2543Smrg CLEAR_FLAG(F_CF); 687706f2543Smrg CLEAR_FLAG(F_AF); 688706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_SF); 689706f2543Smrg CONDITIONAL_SET_FLAG(res == 0, F_ZF); 690706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res), F_PF); 691706f2543Smrg return res; 692706f2543Smrg} 693706f2543Smrg 694706f2543Smrg/**************************************************************************** 695706f2543SmrgREMARKS: 696706f2543SmrgImplements the OR instruction and side effects. 697706f2543Smrg****************************************************************************/ 698706f2543Smrgu16 or_word(u16 d, u16 s) 699706f2543Smrg{ 700706f2543Smrg register u16 res; /* all operands in native machine order */ 701706f2543Smrg 702706f2543Smrg res = d | s; 703706f2543Smrg /* set the carry flag to be bit 8 */ 704706f2543Smrg CLEAR_FLAG(F_OF); 705706f2543Smrg CLEAR_FLAG(F_CF); 706706f2543Smrg CLEAR_FLAG(F_AF); 707706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 708706f2543Smrg CONDITIONAL_SET_FLAG(res == 0, F_ZF); 709706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 710706f2543Smrg return res; 711706f2543Smrg} 712706f2543Smrg 713706f2543Smrg/**************************************************************************** 714706f2543SmrgREMARKS: 715706f2543SmrgImplements the OR instruction and side effects. 716706f2543Smrg****************************************************************************/ 717706f2543Smrgu32 or_long(u32 d, u32 s) 718706f2543Smrg{ 719706f2543Smrg register u32 res; /* all operands in native machine order */ 720706f2543Smrg 721706f2543Smrg res = d | s; 722706f2543Smrg 723706f2543Smrg /* set the carry flag to be bit 8 */ 724706f2543Smrg CLEAR_FLAG(F_OF); 725706f2543Smrg CLEAR_FLAG(F_CF); 726706f2543Smrg CLEAR_FLAG(F_AF); 727706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 728706f2543Smrg CONDITIONAL_SET_FLAG(res == 0, F_ZF); 729706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 730706f2543Smrg return res; 731706f2543Smrg} 732706f2543Smrg 733706f2543Smrg/**************************************************************************** 734706f2543SmrgREMARKS: 735706f2543SmrgImplements the OR instruction and side effects. 736706f2543Smrg****************************************************************************/ 737706f2543Smrgu8 neg_byte(u8 s) 738706f2543Smrg{ 739706f2543Smrg register u8 res; 740706f2543Smrg register u8 bc; 741706f2543Smrg 742706f2543Smrg CONDITIONAL_SET_FLAG(s != 0, F_CF); 743706f2543Smrg res = (u8)-s; 744706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); 745706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_SF); 746706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res), F_PF); 747706f2543Smrg /* calculate the borrow chain --- modified such that d=0. 748706f2543Smrg substitutiing d=0 into bc= res&(~d|s)|(~d&s); 749706f2543Smrg (the one used for sub) and simplifying, since ~d=0xff..., 750706f2543Smrg ~d|s == 0xffff..., and res&0xfff... == res. Similarly 751706f2543Smrg ~d&s == s. So the simplified result is: */ 752706f2543Smrg bc = res | s; 753706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); 754706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); 755706f2543Smrg return res; 756706f2543Smrg} 757706f2543Smrg 758706f2543Smrg/**************************************************************************** 759706f2543SmrgREMARKS: 760706f2543SmrgImplements the OR instruction and side effects. 761706f2543Smrg****************************************************************************/ 762706f2543Smrgu16 neg_word(u16 s) 763706f2543Smrg{ 764706f2543Smrg register u16 res; 765706f2543Smrg register u16 bc; 766706f2543Smrg 767706f2543Smrg CONDITIONAL_SET_FLAG(s != 0, F_CF); 768706f2543Smrg res = (u16)-s; 769706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); 770706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 771706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 772706f2543Smrg 773706f2543Smrg /* calculate the borrow chain --- modified such that d=0. 774706f2543Smrg substitutiing d=0 into bc= res&(~d|s)|(~d&s); 775706f2543Smrg (the one used for sub) and simplifying, since ~d=0xff..., 776706f2543Smrg ~d|s == 0xffff..., and res&0xfff... == res. Similarly 777706f2543Smrg ~d&s == s. So the simplified result is: */ 778706f2543Smrg bc = res | s; 779706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); 780706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); 781706f2543Smrg return res; 782706f2543Smrg} 783706f2543Smrg 784706f2543Smrg/**************************************************************************** 785706f2543SmrgREMARKS: 786706f2543SmrgImplements the OR instruction and side effects. 787706f2543Smrg****************************************************************************/ 788706f2543Smrgu32 neg_long(u32 s) 789706f2543Smrg{ 790706f2543Smrg register u32 res; 791706f2543Smrg register u32 bc; 792706f2543Smrg 793706f2543Smrg CONDITIONAL_SET_FLAG(s != 0, F_CF); 794706f2543Smrg res = (u32)-s; 795706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); 796706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 797706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 798706f2543Smrg 799706f2543Smrg /* calculate the borrow chain --- modified such that d=0. 800706f2543Smrg substitutiing d=0 into bc= res&(~d|s)|(~d&s); 801706f2543Smrg (the one used for sub) and simplifying, since ~d=0xff..., 802706f2543Smrg ~d|s == 0xffff..., and res&0xfff... == res. Similarly 803706f2543Smrg ~d&s == s. So the simplified result is: */ 804706f2543Smrg bc = res | s; 805706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); 806706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); 807706f2543Smrg return res; 808706f2543Smrg} 809706f2543Smrg 810706f2543Smrg/**************************************************************************** 811706f2543SmrgREMARKS: 812706f2543SmrgImplements the NOT instruction and side effects. 813706f2543Smrg****************************************************************************/ 814706f2543Smrgu8 not_byte(u8 s) 815706f2543Smrg{ 816706f2543Smrg return ~s; 817706f2543Smrg} 818706f2543Smrg 819706f2543Smrg/**************************************************************************** 820706f2543SmrgREMARKS: 821706f2543SmrgImplements the NOT instruction and side effects. 822706f2543Smrg****************************************************************************/ 823706f2543Smrgu16 not_word(u16 s) 824706f2543Smrg{ 825706f2543Smrg return ~s; 826706f2543Smrg} 827706f2543Smrg 828706f2543Smrg/**************************************************************************** 829706f2543SmrgREMARKS: 830706f2543SmrgImplements the NOT instruction and side effects. 831706f2543Smrg****************************************************************************/ 832706f2543Smrgu32 not_long(u32 s) 833706f2543Smrg{ 834706f2543Smrg return ~s; 835706f2543Smrg} 836706f2543Smrg 837706f2543Smrg/**************************************************************************** 838706f2543SmrgREMARKS: 839706f2543SmrgImplements the RCL instruction and side effects. 840706f2543Smrg****************************************************************************/ 841706f2543Smrgu8 rcl_byte(u8 d, u8 s) 842706f2543Smrg{ 843706f2543Smrg register unsigned int res, cnt, mask, cf; 844706f2543Smrg 845706f2543Smrg /* s is the rotate distance. It varies from 0 - 8. */ 846706f2543Smrg /* have 847706f2543Smrg 848706f2543Smrg CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0 849706f2543Smrg 850706f2543Smrg want to rotate through the carry by "s" bits. We could 851706f2543Smrg loop, but that's inefficient. So the width is 9, 852706f2543Smrg and we split into three parts: 853706f2543Smrg 854706f2543Smrg The new carry flag (was B_n) 855706f2543Smrg the stuff in B_n-1 .. B_0 856706f2543Smrg the stuff in B_7 .. B_n+1 857706f2543Smrg 858706f2543Smrg The new rotate is done mod 9, and given this, 859706f2543Smrg for a rotation of n bits (mod 9) the new carry flag is 860706f2543Smrg then located n bits from the MSB. The low part is 861706f2543Smrg then shifted up cnt bits, and the high part is or'd 862706f2543Smrg in. Using CAPS for new values, and lowercase for the 863706f2543Smrg original values, this can be expressed as: 864706f2543Smrg 865706f2543Smrg IF n > 0 866706f2543Smrg 1) CF <- b_(8-n) 867706f2543Smrg 2) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0 868706f2543Smrg 3) B_(n-1) <- cf 869706f2543Smrg 4) B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1)) 870706f2543Smrg */ 871706f2543Smrg res = d; 872706f2543Smrg if ((cnt = s % 9) != 0) { 873706f2543Smrg /* extract the new CARRY FLAG. */ 874706f2543Smrg /* CF <- b_(8-n) */ 875706f2543Smrg cf = (d >> (8 - cnt)) & 0x1; 876706f2543Smrg 877706f2543Smrg /* get the low stuff which rotated 878706f2543Smrg into the range B_7 .. B_cnt */ 879706f2543Smrg /* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0 */ 880706f2543Smrg /* note that the right hand side done by the mask */ 881706f2543Smrg res = (d << cnt) & 0xff; 882706f2543Smrg 883706f2543Smrg /* now the high stuff which rotated around 884706f2543Smrg into the positions B_cnt-2 .. B_0 */ 885706f2543Smrg /* B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1)) */ 886706f2543Smrg /* shift it downward, 7-(n-2) = 9-n positions. 887706f2543Smrg and mask off the result before or'ing in. 888706f2543Smrg */ 889706f2543Smrg mask = (1 << (cnt - 1)) - 1; 890706f2543Smrg res |= (d >> (9 - cnt)) & mask; 891706f2543Smrg 892706f2543Smrg /* if the carry flag was set, or it in. */ 893706f2543Smrg if (ACCESS_FLAG(F_CF)) { /* carry flag is set */ 894706f2543Smrg /* B_(n-1) <- cf */ 895706f2543Smrg res |= 1 << (cnt - 1); 896706f2543Smrg } 897706f2543Smrg /* set the new carry flag, based on the variable "cf" */ 898706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 899706f2543Smrg /* OVERFLOW is set *IFF* cnt==1, then it is the 900706f2543Smrg xor of CF and the most significant bit. Blecck. */ 901706f2543Smrg /* parenthesized this expression since it appears to 902706f2543Smrg be causing OF to be misset */ 903706f2543Smrg CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 6) & 0x2)), 904706f2543Smrg F_OF); 905706f2543Smrg 906706f2543Smrg } 907706f2543Smrg return (u8)res; 908706f2543Smrg} 909706f2543Smrg 910706f2543Smrg/**************************************************************************** 911706f2543SmrgREMARKS: 912706f2543SmrgImplements the RCL instruction and side effects. 913706f2543Smrg****************************************************************************/ 914706f2543Smrgu16 rcl_word(u16 d, u8 s) 915706f2543Smrg{ 916706f2543Smrg register unsigned int res, cnt, mask, cf; 917706f2543Smrg 918706f2543Smrg res = d; 919706f2543Smrg if ((cnt = s % 17) != 0) { 920706f2543Smrg cf = (d >> (16 - cnt)) & 0x1; 921706f2543Smrg res = (d << cnt) & 0xffff; 922706f2543Smrg mask = (1 << (cnt - 1)) - 1; 923706f2543Smrg res |= (d >> (17 - cnt)) & mask; 924706f2543Smrg if (ACCESS_FLAG(F_CF)) { 925706f2543Smrg res |= 1 << (cnt - 1); 926706f2543Smrg } 927706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 928706f2543Smrg CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 14) & 0x2)), 929706f2543Smrg F_OF); 930706f2543Smrg } 931706f2543Smrg return (u16)res; 932706f2543Smrg} 933706f2543Smrg 934706f2543Smrg/**************************************************************************** 935706f2543SmrgREMARKS: 936706f2543SmrgImplements the RCL instruction and side effects. 937706f2543Smrg****************************************************************************/ 938706f2543Smrgu32 rcl_long(u32 d, u8 s) 939706f2543Smrg{ 940706f2543Smrg register u32 res, cnt, mask, cf; 941706f2543Smrg 942706f2543Smrg res = d; 943706f2543Smrg if ((cnt = s % 33) != 0) { 944706f2543Smrg cf = (d >> (32 - cnt)) & 0x1; 945706f2543Smrg res = (d << cnt) & 0xffffffff; 946706f2543Smrg mask = (1 << (cnt - 1)) - 1; 947706f2543Smrg res |= (d >> (33 - cnt)) & mask; 948706f2543Smrg if (ACCESS_FLAG(F_CF)) { /* carry flag is set */ 949706f2543Smrg res |= 1 << (cnt - 1); 950706f2543Smrg } 951706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 952706f2543Smrg CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 30) & 0x2)), 953706f2543Smrg F_OF); 954706f2543Smrg } 955706f2543Smrg return res; 956706f2543Smrg} 957706f2543Smrg 958706f2543Smrg/**************************************************************************** 959706f2543SmrgREMARKS: 960706f2543SmrgImplements the RCR instruction and side effects. 961706f2543Smrg****************************************************************************/ 962706f2543Smrgu8 rcr_byte(u8 d, u8 s) 963706f2543Smrg{ 964706f2543Smrg u32 res, cnt; 965706f2543Smrg u32 mask, cf, ocf = 0; 966706f2543Smrg 967706f2543Smrg /* rotate right through carry */ 968706f2543Smrg /* 969706f2543Smrg s is the rotate distance. It varies from 0 - 8. 970706f2543Smrg d is the byte object rotated. 971706f2543Smrg 972706f2543Smrg have 973706f2543Smrg 974706f2543Smrg CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0 975706f2543Smrg 976706f2543Smrg The new rotate is done mod 9, and given this, 977706f2543Smrg for a rotation of n bits (mod 9) the new carry flag is 978706f2543Smrg then located n bits from the LSB. The low part is 979706f2543Smrg then shifted up cnt bits, and the high part is or'd 980706f2543Smrg in. Using CAPS for new values, and lowercase for the 981706f2543Smrg original values, this can be expressed as: 982706f2543Smrg 983706f2543Smrg IF n > 0 984706f2543Smrg 1) CF <- b_(n-1) 985706f2543Smrg 2) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) 986706f2543Smrg 3) B_(8-n) <- cf 987706f2543Smrg 4) B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0) 988706f2543Smrg */ 989706f2543Smrg res = d; 990706f2543Smrg if ((cnt = s % 9) != 0) { 991706f2543Smrg /* extract the new CARRY FLAG. */ 992706f2543Smrg /* CF <- b_(n-1) */ 993706f2543Smrg if (cnt == 1) { 994706f2543Smrg cf = d & 0x1; 995706f2543Smrg /* note hackery here. Access_flag(..) evaluates to either 996706f2543Smrg 0 if flag not set 997706f2543Smrg non-zero if flag is set. 998706f2543Smrg doing access_flag(..) != 0 casts that into either 999706f2543Smrg 0..1 in any representation of the flags register 1000706f2543Smrg (i.e. packed bit array or unpacked.) 1001706f2543Smrg */ 1002706f2543Smrg ocf = ACCESS_FLAG(F_CF) != 0; 1003706f2543Smrg } else 1004706f2543Smrg cf = (d >> (cnt - 1)) & 0x1; 1005706f2543Smrg 1006706f2543Smrg /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_n */ 1007706f2543Smrg /* note that the right hand side done by the mask 1008706f2543Smrg This is effectively done by shifting the 1009706f2543Smrg object to the right. The result must be masked, 1010706f2543Smrg in case the object came in and was treated 1011706f2543Smrg as a negative number. Needed??? */ 1012706f2543Smrg 1013706f2543Smrg mask = (1 << (8 - cnt)) - 1; 1014706f2543Smrg res = (d >> cnt) & mask; 1015706f2543Smrg 1016706f2543Smrg /* now the high stuff which rotated around 1017706f2543Smrg into the positions B_cnt-2 .. B_0 */ 1018706f2543Smrg /* B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0) */ 1019706f2543Smrg /* shift it downward, 7-(n-2) = 9-n positions. 1020706f2543Smrg and mask off the result before or'ing in. 1021706f2543Smrg */ 1022706f2543Smrg res |= (d << (9 - cnt)); 1023706f2543Smrg 1024706f2543Smrg /* if the carry flag was set, or it in. */ 1025706f2543Smrg if (ACCESS_FLAG(F_CF)) { /* carry flag is set */ 1026706f2543Smrg /* B_(8-n) <- cf */ 1027706f2543Smrg res |= 1 << (8 - cnt); 1028706f2543Smrg } 1029706f2543Smrg /* set the new carry flag, based on the variable "cf" */ 1030706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 1031706f2543Smrg /* OVERFLOW is set *IFF* cnt==1, then it is the 1032706f2543Smrg xor of CF and the most significant bit. Blecck. */ 1033706f2543Smrg /* parenthesized... */ 1034706f2543Smrg if (cnt == 1) { 1035706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 6) & 0x2)), 1036706f2543Smrg F_OF); 1037706f2543Smrg } 1038706f2543Smrg } 1039706f2543Smrg return (u8)res; 1040706f2543Smrg} 1041706f2543Smrg 1042706f2543Smrg/**************************************************************************** 1043706f2543SmrgREMARKS: 1044706f2543SmrgImplements the RCR instruction and side effects. 1045706f2543Smrg****************************************************************************/ 1046706f2543Smrgu16 rcr_word(u16 d, u8 s) 1047706f2543Smrg{ 1048706f2543Smrg u32 res, cnt; 1049706f2543Smrg u32 mask, cf, ocf = 0; 1050706f2543Smrg 1051706f2543Smrg /* rotate right through carry */ 1052706f2543Smrg res = d; 1053706f2543Smrg if ((cnt = s % 17) != 0) { 1054706f2543Smrg if (cnt == 1) { 1055706f2543Smrg cf = d & 0x1; 1056706f2543Smrg ocf = ACCESS_FLAG(F_CF) != 0; 1057706f2543Smrg } else 1058706f2543Smrg cf = (d >> (cnt - 1)) & 0x1; 1059706f2543Smrg mask = (1 << (16 - cnt)) - 1; 1060706f2543Smrg res = (d >> cnt) & mask; 1061706f2543Smrg res |= (d << (17 - cnt)); 1062706f2543Smrg if (ACCESS_FLAG(F_CF)) { 1063706f2543Smrg res |= 1 << (16 - cnt); 1064706f2543Smrg } 1065706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 1066706f2543Smrg if (cnt == 1) { 1067706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 14) & 0x2)), 1068706f2543Smrg F_OF); 1069706f2543Smrg } 1070706f2543Smrg } 1071706f2543Smrg return (u16)res; 1072706f2543Smrg} 1073706f2543Smrg 1074706f2543Smrg/**************************************************************************** 1075706f2543SmrgREMARKS: 1076706f2543SmrgImplements the RCR instruction and side effects. 1077706f2543Smrg****************************************************************************/ 1078706f2543Smrgu32 rcr_long(u32 d, u8 s) 1079706f2543Smrg{ 1080706f2543Smrg u32 res, cnt; 1081706f2543Smrg u32 mask, cf, ocf = 0; 1082706f2543Smrg 1083706f2543Smrg /* rotate right through carry */ 1084706f2543Smrg res = d; 1085706f2543Smrg if ((cnt = s % 33) != 0) { 1086706f2543Smrg if (cnt == 1) { 1087706f2543Smrg cf = d & 0x1; 1088706f2543Smrg ocf = ACCESS_FLAG(F_CF) != 0; 1089706f2543Smrg } else 1090706f2543Smrg cf = (d >> (cnt - 1)) & 0x1; 1091706f2543Smrg mask = (1 << (32 - cnt)) - 1; 1092706f2543Smrg res = (d >> cnt) & mask; 1093706f2543Smrg if (cnt != 1) 1094706f2543Smrg res |= (d << (33 - cnt)); 1095706f2543Smrg if (ACCESS_FLAG(F_CF)) { /* carry flag is set */ 1096706f2543Smrg res |= 1 << (32 - cnt); 1097706f2543Smrg } 1098706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 1099706f2543Smrg if (cnt == 1) { 1100706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 30) & 0x2)), 1101706f2543Smrg F_OF); 1102706f2543Smrg } 1103706f2543Smrg } 1104706f2543Smrg return res; 1105706f2543Smrg} 1106706f2543Smrg 1107706f2543Smrg/**************************************************************************** 1108706f2543SmrgREMARKS: 1109706f2543SmrgImplements the ROL instruction and side effects. 1110706f2543Smrg****************************************************************************/ 1111706f2543Smrgu8 rol_byte(u8 d, u8 s) 1112706f2543Smrg{ 1113706f2543Smrg register unsigned int res, cnt, mask; 1114706f2543Smrg 1115706f2543Smrg /* rotate left */ 1116706f2543Smrg /* 1117706f2543Smrg s is the rotate distance. It varies from 0 - 8. 1118706f2543Smrg d is the byte object rotated. 1119706f2543Smrg 1120706f2543Smrg have 1121706f2543Smrg 1122706f2543Smrg CF B_7 ... B_0 1123706f2543Smrg 1124706f2543Smrg The new rotate is done mod 8. 1125706f2543Smrg Much simpler than the "rcl" or "rcr" operations. 1126706f2543Smrg 1127706f2543Smrg IF n > 0 1128706f2543Smrg 1) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) 1129706f2543Smrg 2) B_(n-1) .. B_(0) <- b_(7) .. b_(8-n) 1130706f2543Smrg */ 1131706f2543Smrg res = d; 1132706f2543Smrg if ((cnt = s % 8) != 0) { 1133706f2543Smrg /* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) */ 1134706f2543Smrg res = (d << cnt); 1135706f2543Smrg 1136706f2543Smrg /* B_(n-1) .. B_(0) <- b_(7) .. b_(8-n) */ 1137706f2543Smrg mask = (1 << cnt) - 1; 1138706f2543Smrg res |= (d >> (8 - cnt)) & mask; 1139706f2543Smrg 1140706f2543Smrg /* set the new carry flag, Note that it is the low order 1141706f2543Smrg bit of the result!!! */ 1142706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x1, F_CF); 1143706f2543Smrg /* OVERFLOW is set *IFF* s==1, then it is the 1144706f2543Smrg xor of CF and the most significant bit. Blecck. */ 1145706f2543Smrg CONDITIONAL_SET_FLAG(s == 1 && 1146706f2543Smrg XOR2((res & 0x1) + ((res >> 6) & 0x2)), 1147706f2543Smrg F_OF); 1148706f2543Smrg } if (s != 0) { 1149706f2543Smrg /* set the new carry flag, Note that it is the low order 1150706f2543Smrg bit of the result!!! */ 1151706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x1, F_CF); 1152706f2543Smrg } 1153706f2543Smrg return (u8)res; 1154706f2543Smrg} 1155706f2543Smrg 1156706f2543Smrg/**************************************************************************** 1157706f2543SmrgREMARKS: 1158706f2543SmrgImplements the ROL instruction and side effects. 1159706f2543Smrg****************************************************************************/ 1160706f2543Smrgu16 rol_word(u16 d, u8 s) 1161706f2543Smrg{ 1162706f2543Smrg register unsigned int res, cnt, mask; 1163706f2543Smrg 1164706f2543Smrg res = d; 1165706f2543Smrg if ((cnt = s % 16) != 0) { 1166706f2543Smrg res = (d << cnt); 1167706f2543Smrg mask = (1 << cnt) - 1; 1168706f2543Smrg res |= (d >> (16 - cnt)) & mask; 1169706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x1, F_CF); 1170706f2543Smrg CONDITIONAL_SET_FLAG(s == 1 && 1171706f2543Smrg XOR2((res & 0x1) + ((res >> 14) & 0x2)), 1172706f2543Smrg F_OF); 1173706f2543Smrg } if (s != 0) { 1174706f2543Smrg /* set the new carry flag, Note that it is the low order 1175706f2543Smrg bit of the result!!! */ 1176706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x1, F_CF); 1177706f2543Smrg } 1178706f2543Smrg return (u16)res; 1179706f2543Smrg} 1180706f2543Smrg 1181706f2543Smrg/**************************************************************************** 1182706f2543SmrgREMARKS: 1183706f2543SmrgImplements the ROL instruction and side effects. 1184706f2543Smrg****************************************************************************/ 1185706f2543Smrgu32 rol_long(u32 d, u8 s) 1186706f2543Smrg{ 1187706f2543Smrg register u32 res, cnt, mask; 1188706f2543Smrg 1189706f2543Smrg res = d; 1190706f2543Smrg if ((cnt = s % 32) != 0) { 1191706f2543Smrg res = (d << cnt); 1192706f2543Smrg mask = (1 << cnt) - 1; 1193706f2543Smrg res |= (d >> (32 - cnt)) & mask; 1194706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x1, F_CF); 1195706f2543Smrg CONDITIONAL_SET_FLAG(s == 1 && 1196706f2543Smrg XOR2((res & 0x1) + ((res >> 30) & 0x2)), 1197706f2543Smrg F_OF); 1198706f2543Smrg } if (s != 0) { 1199706f2543Smrg /* set the new carry flag, Note that it is the low order 1200706f2543Smrg bit of the result!!! */ 1201706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x1, F_CF); 1202706f2543Smrg } 1203706f2543Smrg return res; 1204706f2543Smrg} 1205706f2543Smrg 1206706f2543Smrg/**************************************************************************** 1207706f2543SmrgREMARKS: 1208706f2543SmrgImplements the ROR instruction and side effects. 1209706f2543Smrg****************************************************************************/ 1210706f2543Smrgu8 ror_byte(u8 d, u8 s) 1211706f2543Smrg{ 1212706f2543Smrg register unsigned int res, cnt, mask; 1213706f2543Smrg 1214706f2543Smrg /* rotate right */ 1215706f2543Smrg /* 1216706f2543Smrg s is the rotate distance. It varies from 0 - 8. 1217706f2543Smrg d is the byte object rotated. 1218706f2543Smrg 1219706f2543Smrg have 1220706f2543Smrg 1221706f2543Smrg B_7 ... B_0 1222706f2543Smrg 1223706f2543Smrg The rotate is done mod 8. 1224706f2543Smrg 1225706f2543Smrg IF n > 0 1226706f2543Smrg 1) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) 1227706f2543Smrg 2) B_(7) .. B_(8-n) <- b_(n-1) .. b_(0) 1228706f2543Smrg */ 1229706f2543Smrg res = d; 1230706f2543Smrg if ((cnt = s % 8) != 0) { /* not a typo, do nada if cnt==0 */ 1231706f2543Smrg /* B_(7) .. B_(8-n) <- b_(n-1) .. b_(0) */ 1232706f2543Smrg res = (d << (8 - cnt)); 1233706f2543Smrg 1234706f2543Smrg /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) */ 1235706f2543Smrg mask = (1 << (8 - cnt)) - 1; 1236706f2543Smrg res |= (d >> (cnt)) & mask; 1237706f2543Smrg 1238706f2543Smrg /* set the new carry flag, Note that it is the low order 1239706f2543Smrg bit of the result!!! */ 1240706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_CF); 1241706f2543Smrg /* OVERFLOW is set *IFF* s==1, then it is the 1242706f2543Smrg xor of the two most significant bits. Blecck. */ 1243706f2543Smrg CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 6), F_OF); 1244706f2543Smrg } else if (s != 0) { 1245706f2543Smrg /* set the new carry flag, Note that it is the low order 1246706f2543Smrg bit of the result!!! */ 1247706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_CF); 1248706f2543Smrg } 1249706f2543Smrg return (u8)res; 1250706f2543Smrg} 1251706f2543Smrg 1252706f2543Smrg/**************************************************************************** 1253706f2543SmrgREMARKS: 1254706f2543SmrgImplements the ROR instruction and side effects. 1255706f2543Smrg****************************************************************************/ 1256706f2543Smrgu16 ror_word(u16 d, u8 s) 1257706f2543Smrg{ 1258706f2543Smrg register unsigned int res, cnt, mask; 1259706f2543Smrg 1260706f2543Smrg res = d; 1261706f2543Smrg if ((cnt = s % 16) != 0) { 1262706f2543Smrg res = (d << (16 - cnt)); 1263706f2543Smrg mask = (1 << (16 - cnt)) - 1; 1264706f2543Smrg res |= (d >> (cnt)) & mask; 1265706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_CF); 1266706f2543Smrg CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 14), F_OF); 1267706f2543Smrg } else if (s != 0) { 1268706f2543Smrg /* set the new carry flag, Note that it is the low order 1269706f2543Smrg bit of the result!!! */ 1270706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_CF); 1271706f2543Smrg } 1272706f2543Smrg return (u16)res; 1273706f2543Smrg} 1274706f2543Smrg 1275706f2543Smrg/**************************************************************************** 1276706f2543SmrgREMARKS: 1277706f2543SmrgImplements the ROR instruction and side effects. 1278706f2543Smrg****************************************************************************/ 1279706f2543Smrgu32 ror_long(u32 d, u8 s) 1280706f2543Smrg{ 1281706f2543Smrg register u32 res, cnt, mask; 1282706f2543Smrg 1283706f2543Smrg res = d; 1284706f2543Smrg if ((cnt = s % 32) != 0) { 1285706f2543Smrg res = (d << (32 - cnt)); 1286706f2543Smrg mask = (1 << (32 - cnt)) - 1; 1287706f2543Smrg res |= (d >> (cnt)) & mask; 1288706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF); 1289706f2543Smrg CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 30), F_OF); 1290706f2543Smrg } else if (s != 0) { 1291706f2543Smrg /* set the new carry flag, Note that it is the low order 1292706f2543Smrg bit of the result!!! */ 1293706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF); 1294706f2543Smrg } 1295706f2543Smrg return res; 1296706f2543Smrg} 1297706f2543Smrg 1298706f2543Smrg/**************************************************************************** 1299706f2543SmrgREMARKS: 1300706f2543SmrgImplements the SHL instruction and side effects. 1301706f2543Smrg****************************************************************************/ 1302706f2543Smrgu8 shl_byte(u8 d, u8 s) 1303706f2543Smrg{ 1304706f2543Smrg unsigned int cnt, res, cf; 1305706f2543Smrg 1306706f2543Smrg if (s < 8) { 1307706f2543Smrg cnt = s % 8; 1308706f2543Smrg 1309706f2543Smrg /* last bit shifted out goes into carry flag */ 1310706f2543Smrg if (cnt > 0) { 1311706f2543Smrg res = d << cnt; 1312706f2543Smrg cf = d & (1 << (8 - cnt)); 1313706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 1314706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); 1315706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_SF); 1316706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1317706f2543Smrg } else { 1318706f2543Smrg res = (u8) d; 1319706f2543Smrg } 1320706f2543Smrg 1321706f2543Smrg if (cnt == 1) { 1322706f2543Smrg /* Needs simplification. */ 1323706f2543Smrg CONDITIONAL_SET_FLAG( 1324706f2543Smrg (((res & 0x80) == 0x80) ^ 1325706f2543Smrg (ACCESS_FLAG(F_CF) != 0)), 1326706f2543Smrg /* was (M.x86.R_FLG&F_CF)==F_CF)), */ 1327706f2543Smrg F_OF); 1328706f2543Smrg } else { 1329706f2543Smrg CLEAR_FLAG(F_OF); 1330706f2543Smrg } 1331706f2543Smrg } else { 1332706f2543Smrg res = 0; 1333706f2543Smrg CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80, F_CF); 1334706f2543Smrg CLEAR_FLAG(F_OF); 1335706f2543Smrg CLEAR_FLAG(F_SF); 1336706f2543Smrg SET_FLAG(F_PF); 1337706f2543Smrg SET_FLAG(F_ZF); 1338706f2543Smrg } 1339706f2543Smrg return (u8)res; 1340706f2543Smrg} 1341706f2543Smrg 1342706f2543Smrg/**************************************************************************** 1343706f2543SmrgREMARKS: 1344706f2543SmrgImplements the SHL instruction and side effects. 1345706f2543Smrg****************************************************************************/ 1346706f2543Smrgu16 shl_word(u16 d, u8 s) 1347706f2543Smrg{ 1348706f2543Smrg unsigned int cnt, res, cf; 1349706f2543Smrg 1350706f2543Smrg if (s < 16) { 1351706f2543Smrg cnt = s % 16; 1352706f2543Smrg if (cnt > 0) { 1353706f2543Smrg res = d << cnt; 1354706f2543Smrg cf = d & (1 << (16 - cnt)); 1355706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 1356706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); 1357706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 1358706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1359706f2543Smrg } else { 1360706f2543Smrg res = (u16) d; 1361706f2543Smrg } 1362706f2543Smrg 1363706f2543Smrg if (cnt == 1) { 1364706f2543Smrg CONDITIONAL_SET_FLAG( 1365706f2543Smrg (((res & 0x8000) == 0x8000) ^ 1366706f2543Smrg (ACCESS_FLAG(F_CF) != 0)), 1367706f2543Smrg F_OF); 1368706f2543Smrg } else { 1369706f2543Smrg CLEAR_FLAG(F_OF); 1370706f2543Smrg } 1371706f2543Smrg } else { 1372706f2543Smrg res = 0; 1373706f2543Smrg CONDITIONAL_SET_FLAG((d << (s-1)) & 0x8000, F_CF); 1374706f2543Smrg CLEAR_FLAG(F_OF); 1375706f2543Smrg CLEAR_FLAG(F_SF); 1376706f2543Smrg SET_FLAG(F_PF); 1377706f2543Smrg SET_FLAG(F_ZF); 1378706f2543Smrg } 1379706f2543Smrg return (u16)res; 1380706f2543Smrg} 1381706f2543Smrg 1382706f2543Smrg/**************************************************************************** 1383706f2543SmrgREMARKS: 1384706f2543SmrgImplements the SHL instruction and side effects. 1385706f2543Smrg****************************************************************************/ 1386706f2543Smrgu32 shl_long(u32 d, u8 s) 1387706f2543Smrg{ 1388706f2543Smrg unsigned int cnt, res, cf; 1389706f2543Smrg 1390706f2543Smrg if (s < 32) { 1391706f2543Smrg cnt = s % 32; 1392706f2543Smrg if (cnt > 0) { 1393706f2543Smrg res = d << cnt; 1394706f2543Smrg cf = d & (1 << (32 - cnt)); 1395706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 1396706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); 1397706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 1398706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1399706f2543Smrg } else { 1400706f2543Smrg res = d; 1401706f2543Smrg } 1402706f2543Smrg if (cnt == 1) { 1403706f2543Smrg CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^ 1404706f2543Smrg (ACCESS_FLAG(F_CF) != 0)), F_OF); 1405706f2543Smrg } else { 1406706f2543Smrg CLEAR_FLAG(F_OF); 1407706f2543Smrg } 1408706f2543Smrg } else { 1409706f2543Smrg res = 0; 1410706f2543Smrg CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80000000, F_CF); 1411706f2543Smrg CLEAR_FLAG(F_OF); 1412706f2543Smrg CLEAR_FLAG(F_SF); 1413706f2543Smrg SET_FLAG(F_PF); 1414706f2543Smrg SET_FLAG(F_ZF); 1415706f2543Smrg } 1416706f2543Smrg return res; 1417706f2543Smrg} 1418706f2543Smrg 1419706f2543Smrg/**************************************************************************** 1420706f2543SmrgREMARKS: 1421706f2543SmrgImplements the SHR instruction and side effects. 1422706f2543Smrg****************************************************************************/ 1423706f2543Smrgu8 shr_byte(u8 d, u8 s) 1424706f2543Smrg{ 1425706f2543Smrg unsigned int cnt, res, cf; 1426706f2543Smrg 1427706f2543Smrg if (s < 8) { 1428706f2543Smrg cnt = s % 8; 1429706f2543Smrg if (cnt > 0) { 1430706f2543Smrg cf = d & (1 << (cnt - 1)); 1431706f2543Smrg res = d >> cnt; 1432706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 1433706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); 1434706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_SF); 1435706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1436706f2543Smrg } else { 1437706f2543Smrg res = (u8) d; 1438706f2543Smrg } 1439706f2543Smrg 1440706f2543Smrg if (cnt == 1) { 1441706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(res >> 6), F_OF); 1442706f2543Smrg } else { 1443706f2543Smrg CLEAR_FLAG(F_OF); 1444706f2543Smrg } 1445706f2543Smrg } else { 1446706f2543Smrg res = 0; 1447706f2543Smrg CONDITIONAL_SET_FLAG((d >> (s-1)) & 0x1, F_CF); 1448706f2543Smrg CLEAR_FLAG(F_OF); 1449706f2543Smrg CLEAR_FLAG(F_SF); 1450706f2543Smrg SET_FLAG(F_PF); 1451706f2543Smrg SET_FLAG(F_ZF); 1452706f2543Smrg } 1453706f2543Smrg return (u8)res; 1454706f2543Smrg} 1455706f2543Smrg 1456706f2543Smrg/**************************************************************************** 1457706f2543SmrgREMARKS: 1458706f2543SmrgImplements the SHR instruction and side effects. 1459706f2543Smrg****************************************************************************/ 1460706f2543Smrgu16 shr_word(u16 d, u8 s) 1461706f2543Smrg{ 1462706f2543Smrg unsigned int cnt, res, cf; 1463706f2543Smrg 1464706f2543Smrg if (s < 16) { 1465706f2543Smrg cnt = s % 16; 1466706f2543Smrg if (cnt > 0) { 1467706f2543Smrg cf = d & (1 << (cnt - 1)); 1468706f2543Smrg res = d >> cnt; 1469706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 1470706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); 1471706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 1472706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1473706f2543Smrg } else { 1474706f2543Smrg res = d; 1475706f2543Smrg } 1476706f2543Smrg 1477706f2543Smrg if (cnt == 1) { 1478706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF); 1479706f2543Smrg } else { 1480706f2543Smrg CLEAR_FLAG(F_OF); 1481706f2543Smrg } 1482706f2543Smrg } else { 1483706f2543Smrg res = 0; 1484706f2543Smrg CLEAR_FLAG(F_CF); 1485706f2543Smrg CLEAR_FLAG(F_OF); 1486706f2543Smrg SET_FLAG(F_ZF); 1487706f2543Smrg CLEAR_FLAG(F_SF); 1488706f2543Smrg CLEAR_FLAG(F_PF); 1489706f2543Smrg } 1490706f2543Smrg return (u16)res; 1491706f2543Smrg} 1492706f2543Smrg 1493706f2543Smrg/**************************************************************************** 1494706f2543SmrgREMARKS: 1495706f2543SmrgImplements the SHR instruction and side effects. 1496706f2543Smrg****************************************************************************/ 1497706f2543Smrgu32 shr_long(u32 d, u8 s) 1498706f2543Smrg{ 1499706f2543Smrg unsigned int cnt, res, cf; 1500706f2543Smrg 1501706f2543Smrg if (s < 32) { 1502706f2543Smrg cnt = s % 32; 1503706f2543Smrg if (cnt > 0) { 1504706f2543Smrg cf = d & (1 << (cnt - 1)); 1505706f2543Smrg res = d >> cnt; 1506706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 1507706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); 1508706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 1509706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1510706f2543Smrg } else { 1511706f2543Smrg res = d; 1512706f2543Smrg } 1513706f2543Smrg if (cnt == 1) { 1514706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF); 1515706f2543Smrg } else { 1516706f2543Smrg CLEAR_FLAG(F_OF); 1517706f2543Smrg } 1518706f2543Smrg } else { 1519706f2543Smrg res = 0; 1520706f2543Smrg CLEAR_FLAG(F_CF); 1521706f2543Smrg CLEAR_FLAG(F_OF); 1522706f2543Smrg SET_FLAG(F_ZF); 1523706f2543Smrg CLEAR_FLAG(F_SF); 1524706f2543Smrg CLEAR_FLAG(F_PF); 1525706f2543Smrg } 1526706f2543Smrg return res; 1527706f2543Smrg} 1528706f2543Smrg 1529706f2543Smrg/**************************************************************************** 1530706f2543SmrgREMARKS: 1531706f2543SmrgImplements the SAR instruction and side effects. 1532706f2543Smrg****************************************************************************/ 1533706f2543Smrgu8 sar_byte(u8 d, u8 s) 1534706f2543Smrg{ 1535706f2543Smrg unsigned int cnt, res, cf, mask, sf; 1536706f2543Smrg 1537706f2543Smrg res = d; 1538706f2543Smrg sf = d & 0x80; 1539706f2543Smrg cnt = s % 8; 1540706f2543Smrg if (cnt > 0 && cnt < 8) { 1541706f2543Smrg mask = (1 << (8 - cnt)) - 1; 1542706f2543Smrg cf = d & (1 << (cnt - 1)); 1543706f2543Smrg res = (d >> cnt) & mask; 1544706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 1545706f2543Smrg if (sf) { 1546706f2543Smrg res |= ~mask; 1547706f2543Smrg } 1548706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); 1549706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1550706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_SF); 1551706f2543Smrg } else if (cnt >= 8) { 1552706f2543Smrg if (sf) { 1553706f2543Smrg res = 0xff; 1554706f2543Smrg SET_FLAG(F_CF); 1555706f2543Smrg CLEAR_FLAG(F_ZF); 1556706f2543Smrg SET_FLAG(F_SF); 1557706f2543Smrg SET_FLAG(F_PF); 1558706f2543Smrg } else { 1559706f2543Smrg res = 0; 1560706f2543Smrg CLEAR_FLAG(F_CF); 1561706f2543Smrg SET_FLAG(F_ZF); 1562706f2543Smrg CLEAR_FLAG(F_SF); 1563706f2543Smrg CLEAR_FLAG(F_PF); 1564706f2543Smrg } 1565706f2543Smrg } 1566706f2543Smrg return (u8)res; 1567706f2543Smrg} 1568706f2543Smrg 1569706f2543Smrg/**************************************************************************** 1570706f2543SmrgREMARKS: 1571706f2543SmrgImplements the SAR instruction and side effects. 1572706f2543Smrg****************************************************************************/ 1573706f2543Smrgu16 sar_word(u16 d, u8 s) 1574706f2543Smrg{ 1575706f2543Smrg unsigned int cnt, res, cf, mask, sf; 1576706f2543Smrg 1577706f2543Smrg sf = d & 0x8000; 1578706f2543Smrg cnt = s % 16; 1579706f2543Smrg res = d; 1580706f2543Smrg if (cnt > 0 && cnt < 16) { 1581706f2543Smrg mask = (1 << (16 - cnt)) - 1; 1582706f2543Smrg cf = d & (1 << (cnt - 1)); 1583706f2543Smrg res = (d >> cnt) & mask; 1584706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 1585706f2543Smrg if (sf) { 1586706f2543Smrg res |= ~mask; 1587706f2543Smrg } 1588706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); 1589706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 1590706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1591706f2543Smrg } else if (cnt >= 16) { 1592706f2543Smrg if (sf) { 1593706f2543Smrg res = 0xffff; 1594706f2543Smrg SET_FLAG(F_CF); 1595706f2543Smrg CLEAR_FLAG(F_ZF); 1596706f2543Smrg SET_FLAG(F_SF); 1597706f2543Smrg SET_FLAG(F_PF); 1598706f2543Smrg } else { 1599706f2543Smrg res = 0; 1600706f2543Smrg CLEAR_FLAG(F_CF); 1601706f2543Smrg SET_FLAG(F_ZF); 1602706f2543Smrg CLEAR_FLAG(F_SF); 1603706f2543Smrg CLEAR_FLAG(F_PF); 1604706f2543Smrg } 1605706f2543Smrg } 1606706f2543Smrg return (u16)res; 1607706f2543Smrg} 1608706f2543Smrg 1609706f2543Smrg/**************************************************************************** 1610706f2543SmrgREMARKS: 1611706f2543SmrgImplements the SAR instruction and side effects. 1612706f2543Smrg****************************************************************************/ 1613706f2543Smrgu32 sar_long(u32 d, u8 s) 1614706f2543Smrg{ 1615706f2543Smrg u32 cnt, res, cf, mask, sf; 1616706f2543Smrg 1617706f2543Smrg sf = d & 0x80000000; 1618706f2543Smrg cnt = s % 32; 1619706f2543Smrg res = d; 1620706f2543Smrg if (cnt > 0 && cnt < 32) { 1621706f2543Smrg mask = (1 << (32 - cnt)) - 1; 1622706f2543Smrg cf = d & (1 << (cnt - 1)); 1623706f2543Smrg res = (d >> cnt) & mask; 1624706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 1625706f2543Smrg if (sf) { 1626706f2543Smrg res |= ~mask; 1627706f2543Smrg } 1628706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); 1629706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 1630706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1631706f2543Smrg } else if (cnt >= 32) { 1632706f2543Smrg if (sf) { 1633706f2543Smrg res = 0xffffffff; 1634706f2543Smrg SET_FLAG(F_CF); 1635706f2543Smrg CLEAR_FLAG(F_ZF); 1636706f2543Smrg SET_FLAG(F_SF); 1637706f2543Smrg SET_FLAG(F_PF); 1638706f2543Smrg } else { 1639706f2543Smrg res = 0; 1640706f2543Smrg CLEAR_FLAG(F_CF); 1641706f2543Smrg SET_FLAG(F_ZF); 1642706f2543Smrg CLEAR_FLAG(F_SF); 1643706f2543Smrg CLEAR_FLAG(F_PF); 1644706f2543Smrg } 1645706f2543Smrg } 1646706f2543Smrg return res; 1647706f2543Smrg} 1648706f2543Smrg 1649706f2543Smrg/**************************************************************************** 1650706f2543SmrgREMARKS: 1651706f2543SmrgImplements the SHLD instruction and side effects. 1652706f2543Smrg****************************************************************************/ 1653706f2543Smrgu16 shld_word (u16 d, u16 fill, u8 s) 1654706f2543Smrg{ 1655706f2543Smrg unsigned int cnt, res, cf; 1656706f2543Smrg 1657706f2543Smrg if (s < 16) { 1658706f2543Smrg cnt = s % 16; 1659706f2543Smrg if (cnt > 0) { 1660706f2543Smrg res = (d << cnt) | (fill >> (16-cnt)); 1661706f2543Smrg cf = d & (1 << (16 - cnt)); 1662706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 1663706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); 1664706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 1665706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1666706f2543Smrg } else { 1667706f2543Smrg res = d; 1668706f2543Smrg } 1669706f2543Smrg if (cnt == 1) { 1670706f2543Smrg CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^ 1671706f2543Smrg (ACCESS_FLAG(F_CF) != 0)), F_OF); 1672706f2543Smrg } else { 1673706f2543Smrg CLEAR_FLAG(F_OF); 1674706f2543Smrg } 1675706f2543Smrg } else { 1676706f2543Smrg res = 0; 1677706f2543Smrg CONDITIONAL_SET_FLAG((d << (s-1)) & 0x8000, F_CF); 1678706f2543Smrg CLEAR_FLAG(F_OF); 1679706f2543Smrg CLEAR_FLAG(F_SF); 1680706f2543Smrg SET_FLAG(F_PF); 1681706f2543Smrg SET_FLAG(F_ZF); 1682706f2543Smrg } 1683706f2543Smrg return (u16)res; 1684706f2543Smrg} 1685706f2543Smrg 1686706f2543Smrg/**************************************************************************** 1687706f2543SmrgREMARKS: 1688706f2543SmrgImplements the SHLD instruction and side effects. 1689706f2543Smrg****************************************************************************/ 1690706f2543Smrgu32 shld_long (u32 d, u32 fill, u8 s) 1691706f2543Smrg{ 1692706f2543Smrg unsigned int cnt, res, cf; 1693706f2543Smrg 1694706f2543Smrg if (s < 32) { 1695706f2543Smrg cnt = s % 32; 1696706f2543Smrg if (cnt > 0) { 1697706f2543Smrg res = (d << cnt) | (fill >> (32-cnt)); 1698706f2543Smrg cf = d & (1 << (32 - cnt)); 1699706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 1700706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); 1701706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 1702706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1703706f2543Smrg } else { 1704706f2543Smrg res = d; 1705706f2543Smrg } 1706706f2543Smrg if (cnt == 1) { 1707706f2543Smrg CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^ 1708706f2543Smrg (ACCESS_FLAG(F_CF) != 0)), F_OF); 1709706f2543Smrg } else { 1710706f2543Smrg CLEAR_FLAG(F_OF); 1711706f2543Smrg } 1712706f2543Smrg } else { 1713706f2543Smrg res = 0; 1714706f2543Smrg CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80000000, F_CF); 1715706f2543Smrg CLEAR_FLAG(F_OF); 1716706f2543Smrg CLEAR_FLAG(F_SF); 1717706f2543Smrg SET_FLAG(F_PF); 1718706f2543Smrg SET_FLAG(F_ZF); 1719706f2543Smrg } 1720706f2543Smrg return res; 1721706f2543Smrg} 1722706f2543Smrg 1723706f2543Smrg/**************************************************************************** 1724706f2543SmrgREMARKS: 1725706f2543SmrgImplements the SHRD instruction and side effects. 1726706f2543Smrg****************************************************************************/ 1727706f2543Smrgu16 shrd_word (u16 d, u16 fill, u8 s) 1728706f2543Smrg{ 1729706f2543Smrg unsigned int cnt, res, cf; 1730706f2543Smrg 1731706f2543Smrg if (s < 16) { 1732706f2543Smrg cnt = s % 16; 1733706f2543Smrg if (cnt > 0) { 1734706f2543Smrg cf = d & (1 << (cnt - 1)); 1735706f2543Smrg res = (d >> cnt) | (fill << (16 - cnt)); 1736706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 1737706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); 1738706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 1739706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1740706f2543Smrg } else { 1741706f2543Smrg res = d; 1742706f2543Smrg } 1743706f2543Smrg 1744706f2543Smrg if (cnt == 1) { 1745706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF); 1746706f2543Smrg } else { 1747706f2543Smrg CLEAR_FLAG(F_OF); 1748706f2543Smrg } 1749706f2543Smrg } else { 1750706f2543Smrg res = 0; 1751706f2543Smrg CLEAR_FLAG(F_CF); 1752706f2543Smrg CLEAR_FLAG(F_OF); 1753706f2543Smrg SET_FLAG(F_ZF); 1754706f2543Smrg CLEAR_FLAG(F_SF); 1755706f2543Smrg CLEAR_FLAG(F_PF); 1756706f2543Smrg } 1757706f2543Smrg return (u16)res; 1758706f2543Smrg} 1759706f2543Smrg 1760706f2543Smrg/**************************************************************************** 1761706f2543SmrgREMARKS: 1762706f2543SmrgImplements the SHRD instruction and side effects. 1763706f2543Smrg****************************************************************************/ 1764706f2543Smrgu32 shrd_long (u32 d, u32 fill, u8 s) 1765706f2543Smrg{ 1766706f2543Smrg unsigned int cnt, res, cf; 1767706f2543Smrg 1768706f2543Smrg if (s < 32) { 1769706f2543Smrg cnt = s % 32; 1770706f2543Smrg if (cnt > 0) { 1771706f2543Smrg cf = d & (1 << (cnt - 1)); 1772706f2543Smrg res = (d >> cnt) | (fill << (32 - cnt)); 1773706f2543Smrg CONDITIONAL_SET_FLAG(cf, F_CF); 1774706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); 1775706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 1776706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1777706f2543Smrg } else { 1778706f2543Smrg res = d; 1779706f2543Smrg } 1780706f2543Smrg if (cnt == 1) { 1781706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF); 1782706f2543Smrg } else { 1783706f2543Smrg CLEAR_FLAG(F_OF); 1784706f2543Smrg } 1785706f2543Smrg } else { 1786706f2543Smrg res = 0; 1787706f2543Smrg CLEAR_FLAG(F_CF); 1788706f2543Smrg CLEAR_FLAG(F_OF); 1789706f2543Smrg SET_FLAG(F_ZF); 1790706f2543Smrg CLEAR_FLAG(F_SF); 1791706f2543Smrg CLEAR_FLAG(F_PF); 1792706f2543Smrg } 1793706f2543Smrg return res; 1794706f2543Smrg} 1795706f2543Smrg 1796706f2543Smrg/**************************************************************************** 1797706f2543SmrgREMARKS: 1798706f2543SmrgImplements the SBB instruction and side effects. 1799706f2543Smrg****************************************************************************/ 1800706f2543Smrgu8 sbb_byte(u8 d, u8 s) 1801706f2543Smrg{ 1802706f2543Smrg register u32 res; /* all operands in native machine order */ 1803706f2543Smrg register u32 bc; 1804706f2543Smrg 1805706f2543Smrg if (ACCESS_FLAG(F_CF)) 1806706f2543Smrg res = d - s - 1; 1807706f2543Smrg else 1808706f2543Smrg res = d - s; 1809706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_SF); 1810706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); 1811706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1812706f2543Smrg 1813706f2543Smrg /* calculate the borrow chain. See note at top */ 1814706f2543Smrg bc = (res & (~d | s)) | (~d & s); 1815706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); 1816706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); 1817706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); 1818706f2543Smrg return (u8)res; 1819706f2543Smrg} 1820706f2543Smrg 1821706f2543Smrg/**************************************************************************** 1822706f2543SmrgREMARKS: 1823706f2543SmrgImplements the SBB instruction and side effects. 1824706f2543Smrg****************************************************************************/ 1825706f2543Smrgu16 sbb_word(u16 d, u16 s) 1826706f2543Smrg{ 1827706f2543Smrg register u32 res; /* all operands in native machine order */ 1828706f2543Smrg register u32 bc; 1829706f2543Smrg 1830706f2543Smrg if (ACCESS_FLAG(F_CF)) 1831706f2543Smrg res = d - s - 1; 1832706f2543Smrg else 1833706f2543Smrg res = d - s; 1834706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 1835706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); 1836706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1837706f2543Smrg 1838706f2543Smrg /* calculate the borrow chain. See note at top */ 1839706f2543Smrg bc = (res & (~d | s)) | (~d & s); 1840706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); 1841706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); 1842706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); 1843706f2543Smrg return (u16)res; 1844706f2543Smrg} 1845706f2543Smrg 1846706f2543Smrg/**************************************************************************** 1847706f2543SmrgREMARKS: 1848706f2543SmrgImplements the SBB instruction and side effects. 1849706f2543Smrg****************************************************************************/ 1850706f2543Smrgu32 sbb_long(u32 d, u32 s) 1851706f2543Smrg{ 1852706f2543Smrg register u32 res; /* all operands in native machine order */ 1853706f2543Smrg register u32 bc; 1854706f2543Smrg 1855706f2543Smrg if (ACCESS_FLAG(F_CF)) 1856706f2543Smrg res = d - s - 1; 1857706f2543Smrg else 1858706f2543Smrg res = d - s; 1859706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 1860706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); 1861706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1862706f2543Smrg 1863706f2543Smrg /* calculate the borrow chain. See note at top */ 1864706f2543Smrg bc = (res & (~d | s)) | (~d & s); 1865706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); 1866706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); 1867706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); 1868706f2543Smrg return res; 1869706f2543Smrg} 1870706f2543Smrg 1871706f2543Smrg/**************************************************************************** 1872706f2543SmrgREMARKS: 1873706f2543SmrgImplements the SUB instruction and side effects. 1874706f2543Smrg****************************************************************************/ 1875706f2543Smrgu8 sub_byte(u8 d, u8 s) 1876706f2543Smrg{ 1877706f2543Smrg register u32 res; /* all operands in native machine order */ 1878706f2543Smrg register u32 bc; 1879706f2543Smrg 1880706f2543Smrg res = d - s; 1881706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_SF); 1882706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); 1883706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1884706f2543Smrg 1885706f2543Smrg /* calculate the borrow chain. See note at top */ 1886706f2543Smrg bc = (res & (~d | s)) | (~d & s); 1887706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); 1888706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); 1889706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); 1890706f2543Smrg return (u8)res; 1891706f2543Smrg} 1892706f2543Smrg 1893706f2543Smrg/**************************************************************************** 1894706f2543SmrgREMARKS: 1895706f2543SmrgImplements the SUB instruction and side effects. 1896706f2543Smrg****************************************************************************/ 1897706f2543Smrgu16 sub_word(u16 d, u16 s) 1898706f2543Smrg{ 1899706f2543Smrg register u32 res; /* all operands in native machine order */ 1900706f2543Smrg register u32 bc; 1901706f2543Smrg 1902706f2543Smrg res = d - s; 1903706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 1904706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); 1905706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1906706f2543Smrg 1907706f2543Smrg /* calculate the borrow chain. See note at top */ 1908706f2543Smrg bc = (res & (~d | s)) | (~d & s); 1909706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); 1910706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF); 1911706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); 1912706f2543Smrg return (u16)res; 1913706f2543Smrg} 1914706f2543Smrg 1915706f2543Smrg/**************************************************************************** 1916706f2543SmrgREMARKS: 1917706f2543SmrgImplements the SUB instruction and side effects. 1918706f2543Smrg****************************************************************************/ 1919706f2543Smrgu32 sub_long(u32 d, u32 s) 1920706f2543Smrg{ 1921706f2543Smrg register u32 res; /* all operands in native machine order */ 1922706f2543Smrg register u32 bc; 1923706f2543Smrg 1924706f2543Smrg res = d - s; 1925706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 1926706f2543Smrg CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); 1927706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1928706f2543Smrg 1929706f2543Smrg /* calculate the borrow chain. See note at top */ 1930706f2543Smrg bc = (res & (~d | s)) | (~d & s); 1931706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF); 1932706f2543Smrg CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF); 1933706f2543Smrg CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); 1934706f2543Smrg return res; 1935706f2543Smrg} 1936706f2543Smrg 1937706f2543Smrg/**************************************************************************** 1938706f2543SmrgREMARKS: 1939706f2543SmrgImplements the TEST instruction and side effects. 1940706f2543Smrg****************************************************************************/ 1941706f2543Smrgvoid test_byte(u8 d, u8 s) 1942706f2543Smrg{ 1943706f2543Smrg register u32 res; /* all operands in native machine order */ 1944706f2543Smrg 1945706f2543Smrg res = d & s; 1946706f2543Smrg 1947706f2543Smrg CLEAR_FLAG(F_OF); 1948706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_SF); 1949706f2543Smrg CONDITIONAL_SET_FLAG(res == 0, F_ZF); 1950706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1951706f2543Smrg /* AF == dont care */ 1952706f2543Smrg CLEAR_FLAG(F_CF); 1953706f2543Smrg} 1954706f2543Smrg 1955706f2543Smrg/**************************************************************************** 1956706f2543SmrgREMARKS: 1957706f2543SmrgImplements the TEST instruction and side effects. 1958706f2543Smrg****************************************************************************/ 1959706f2543Smrgvoid test_word(u16 d, u16 s) 1960706f2543Smrg{ 1961706f2543Smrg register u32 res; /* all operands in native machine order */ 1962706f2543Smrg 1963706f2543Smrg res = d & s; 1964706f2543Smrg 1965706f2543Smrg CLEAR_FLAG(F_OF); 1966706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 1967706f2543Smrg CONDITIONAL_SET_FLAG(res == 0, F_ZF); 1968706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1969706f2543Smrg /* AF == dont care */ 1970706f2543Smrg CLEAR_FLAG(F_CF); 1971706f2543Smrg} 1972706f2543Smrg 1973706f2543Smrg/**************************************************************************** 1974706f2543SmrgREMARKS: 1975706f2543SmrgImplements the TEST instruction and side effects. 1976706f2543Smrg****************************************************************************/ 1977706f2543Smrgvoid test_long(u32 d, u32 s) 1978706f2543Smrg{ 1979706f2543Smrg register u32 res; /* all operands in native machine order */ 1980706f2543Smrg 1981706f2543Smrg res = d & s; 1982706f2543Smrg 1983706f2543Smrg CLEAR_FLAG(F_OF); 1984706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 1985706f2543Smrg CONDITIONAL_SET_FLAG(res == 0, F_ZF); 1986706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 1987706f2543Smrg /* AF == dont care */ 1988706f2543Smrg CLEAR_FLAG(F_CF); 1989706f2543Smrg} 1990706f2543Smrg 1991706f2543Smrg/**************************************************************************** 1992706f2543SmrgREMARKS: 1993706f2543SmrgImplements the XOR instruction and side effects. 1994706f2543Smrg****************************************************************************/ 1995706f2543Smrgu8 xor_byte(u8 d, u8 s) 1996706f2543Smrg{ 1997706f2543Smrg register u8 res; /* all operands in native machine order */ 1998706f2543Smrg 1999706f2543Smrg res = d ^ s; 2000706f2543Smrg CLEAR_FLAG(F_OF); 2001706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80, F_SF); 2002706f2543Smrg CONDITIONAL_SET_FLAG(res == 0, F_ZF); 2003706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res), F_PF); 2004706f2543Smrg CLEAR_FLAG(F_CF); 2005706f2543Smrg CLEAR_FLAG(F_AF); 2006706f2543Smrg return res; 2007706f2543Smrg} 2008706f2543Smrg 2009706f2543Smrg/**************************************************************************** 2010706f2543SmrgREMARKS: 2011706f2543SmrgImplements the XOR instruction and side effects. 2012706f2543Smrg****************************************************************************/ 2013706f2543Smrgu16 xor_word(u16 d, u16 s) 2014706f2543Smrg{ 2015706f2543Smrg register u16 res; /* all operands in native machine order */ 2016706f2543Smrg 2017706f2543Smrg res = d ^ s; 2018706f2543Smrg CLEAR_FLAG(F_OF); 2019706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); 2020706f2543Smrg CONDITIONAL_SET_FLAG(res == 0, F_ZF); 2021706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 2022706f2543Smrg CLEAR_FLAG(F_CF); 2023706f2543Smrg CLEAR_FLAG(F_AF); 2024706f2543Smrg return res; 2025706f2543Smrg} 2026706f2543Smrg 2027706f2543Smrg/**************************************************************************** 2028706f2543SmrgREMARKS: 2029706f2543SmrgImplements the XOR instruction and side effects. 2030706f2543Smrg****************************************************************************/ 2031706f2543Smrgu32 xor_long(u32 d, u32 s) 2032706f2543Smrg{ 2033706f2543Smrg register u32 res; /* all operands in native machine order */ 2034706f2543Smrg 2035706f2543Smrg res = d ^ s; 2036706f2543Smrg CLEAR_FLAG(F_OF); 2037706f2543Smrg CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); 2038706f2543Smrg CONDITIONAL_SET_FLAG(res == 0, F_ZF); 2039706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); 2040706f2543Smrg CLEAR_FLAG(F_CF); 2041706f2543Smrg CLEAR_FLAG(F_AF); 2042706f2543Smrg return res; 2043706f2543Smrg} 2044706f2543Smrg 2045706f2543Smrg/**************************************************************************** 2046706f2543SmrgREMARKS: 2047706f2543SmrgImplements the IMUL instruction and side effects. 2048706f2543Smrg****************************************************************************/ 2049706f2543Smrgvoid imul_byte(u8 s) 2050706f2543Smrg{ 2051706f2543Smrg s16 res = (s16)((s8)M.x86.R_AL * (s8)s); 2052706f2543Smrg 2053706f2543Smrg M.x86.R_AX = res; 2054706f2543Smrg if (((M.x86.R_AL & 0x80) == 0 && M.x86.R_AH == 0x00) || 2055706f2543Smrg ((M.x86.R_AL & 0x80) != 0 && M.x86.R_AH == 0xFF)) { 2056706f2543Smrg CLEAR_FLAG(F_CF); 2057706f2543Smrg CLEAR_FLAG(F_OF); 2058706f2543Smrg } else { 2059706f2543Smrg SET_FLAG(F_CF); 2060706f2543Smrg SET_FLAG(F_OF); 2061706f2543Smrg } 2062706f2543Smrg} 2063706f2543Smrg 2064706f2543Smrg/**************************************************************************** 2065706f2543SmrgREMARKS: 2066706f2543SmrgImplements the IMUL instruction and side effects. 2067706f2543Smrg****************************************************************************/ 2068706f2543Smrgvoid imul_word(u16 s) 2069706f2543Smrg{ 2070706f2543Smrg s32 res = (s16)M.x86.R_AX * (s16)s; 2071706f2543Smrg 2072706f2543Smrg M.x86.R_AX = (u16)res; 2073706f2543Smrg M.x86.R_DX = (u16)(res >> 16); 2074706f2543Smrg if (((M.x86.R_AX & 0x8000) == 0 && M.x86.R_DX == 0x00) || 2075706f2543Smrg ((M.x86.R_AX & 0x8000) != 0 && M.x86.R_DX == 0xFF)) { 2076706f2543Smrg CLEAR_FLAG(F_CF); 2077706f2543Smrg CLEAR_FLAG(F_OF); 2078706f2543Smrg } else { 2079706f2543Smrg SET_FLAG(F_CF); 2080706f2543Smrg SET_FLAG(F_OF); 2081706f2543Smrg } 2082706f2543Smrg} 2083706f2543Smrg 2084706f2543Smrg/**************************************************************************** 2085706f2543SmrgREMARKS: 2086706f2543SmrgImplements the IMUL instruction and side effects. 2087706f2543Smrg****************************************************************************/ 2088706f2543Smrgvoid imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s) 2089706f2543Smrg{ 2090706f2543Smrg#ifdef __HAS_LONG_LONG__ 2091706f2543Smrg s64 res = (s64)(s32)d * (s32)s; 2092706f2543Smrg 2093706f2543Smrg *res_lo = (u32)res; 2094706f2543Smrg *res_hi = (u32)(res >> 32); 2095706f2543Smrg#else 2096706f2543Smrg u32 d_lo,d_hi,d_sign; 2097706f2543Smrg u32 s_lo,s_hi,s_sign; 2098706f2543Smrg u32 rlo_lo,rlo_hi,rhi_lo; 2099706f2543Smrg 2100706f2543Smrg if ((d_sign = d & 0x80000000) != 0) 2101706f2543Smrg d = -d; 2102706f2543Smrg d_lo = d & 0xFFFF; 2103706f2543Smrg d_hi = d >> 16; 2104706f2543Smrg if ((s_sign = s & 0x80000000) != 0) 2105706f2543Smrg s = -s; 2106706f2543Smrg s_lo = s & 0xFFFF; 2107706f2543Smrg s_hi = s >> 16; 2108706f2543Smrg rlo_lo = d_lo * s_lo; 2109706f2543Smrg rlo_hi = (d_hi * s_lo + d_lo * s_hi) + (rlo_lo >> 16); 2110706f2543Smrg rhi_lo = d_hi * s_hi + (rlo_hi >> 16); 2111706f2543Smrg *res_lo = (rlo_hi << 16) | (rlo_lo & 0xFFFF); 2112706f2543Smrg *res_hi = rhi_lo; 2113706f2543Smrg if (d_sign != s_sign) { 2114706f2543Smrg d = ~*res_lo; 2115706f2543Smrg s = (((d & 0xFFFF) + 1) >> 16) + (d >> 16); 2116706f2543Smrg *res_lo = ~*res_lo+1; 2117706f2543Smrg *res_hi = ~*res_hi+(s >> 16); 2118706f2543Smrg } 2119706f2543Smrg#endif 2120706f2543Smrg} 2121706f2543Smrg 2122706f2543Smrg/**************************************************************************** 2123706f2543SmrgREMARKS: 2124706f2543SmrgImplements the IMUL instruction and side effects. 2125706f2543Smrg****************************************************************************/ 2126706f2543Smrgvoid imul_long(u32 s) 2127706f2543Smrg{ 2128706f2543Smrg imul_long_direct(&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,s); 2129706f2543Smrg if (((M.x86.R_EAX & 0x80000000) == 0 && M.x86.R_EDX == 0x00) || 2130706f2543Smrg ((M.x86.R_EAX & 0x80000000) != 0 && M.x86.R_EDX == 0xFF)) { 2131706f2543Smrg CLEAR_FLAG(F_CF); 2132706f2543Smrg CLEAR_FLAG(F_OF); 2133706f2543Smrg } else { 2134706f2543Smrg SET_FLAG(F_CF); 2135706f2543Smrg SET_FLAG(F_OF); 2136706f2543Smrg } 2137706f2543Smrg} 2138706f2543Smrg 2139706f2543Smrg/**************************************************************************** 2140706f2543SmrgREMARKS: 2141706f2543SmrgImplements the MUL instruction and side effects. 2142706f2543Smrg****************************************************************************/ 2143706f2543Smrgvoid mul_byte(u8 s) 2144706f2543Smrg{ 2145706f2543Smrg u16 res = (u16)(M.x86.R_AL * s); 2146706f2543Smrg 2147706f2543Smrg M.x86.R_AX = res; 2148706f2543Smrg if (M.x86.R_AH == 0) { 2149706f2543Smrg CLEAR_FLAG(F_CF); 2150706f2543Smrg CLEAR_FLAG(F_OF); 2151706f2543Smrg } else { 2152706f2543Smrg SET_FLAG(F_CF); 2153706f2543Smrg SET_FLAG(F_OF); 2154706f2543Smrg } 2155706f2543Smrg} 2156706f2543Smrg 2157706f2543Smrg/**************************************************************************** 2158706f2543SmrgREMARKS: 2159706f2543SmrgImplements the MUL instruction and side effects. 2160706f2543Smrg****************************************************************************/ 2161706f2543Smrgvoid mul_word(u16 s) 2162706f2543Smrg{ 2163706f2543Smrg u32 res = M.x86.R_AX * s; 2164706f2543Smrg 2165706f2543Smrg M.x86.R_AX = (u16)res; 2166706f2543Smrg M.x86.R_DX = (u16)(res >> 16); 2167706f2543Smrg if (M.x86.R_DX == 0) { 2168706f2543Smrg CLEAR_FLAG(F_CF); 2169706f2543Smrg CLEAR_FLAG(F_OF); 2170706f2543Smrg } else { 2171706f2543Smrg SET_FLAG(F_CF); 2172706f2543Smrg SET_FLAG(F_OF); 2173706f2543Smrg } 2174706f2543Smrg} 2175706f2543Smrg 2176706f2543Smrg/**************************************************************************** 2177706f2543SmrgREMARKS: 2178706f2543SmrgImplements the MUL instruction and side effects. 2179706f2543Smrg****************************************************************************/ 2180706f2543Smrgvoid mul_long(u32 s) 2181706f2543Smrg{ 2182706f2543Smrg#ifdef __HAS_LONG_LONG__ 2183706f2543Smrg u64 res = (u64)M.x86.R_EAX * s; 2184706f2543Smrg 2185706f2543Smrg M.x86.R_EAX = (u32)res; 2186706f2543Smrg M.x86.R_EDX = (u32)(res >> 32); 2187706f2543Smrg#else 2188706f2543Smrg u32 a,a_lo,a_hi; 2189706f2543Smrg u32 s_lo,s_hi; 2190706f2543Smrg u32 rlo_lo,rlo_hi,rhi_lo; 2191706f2543Smrg 2192706f2543Smrg a = M.x86.R_EAX; 2193706f2543Smrg a_lo = a & 0xFFFF; 2194706f2543Smrg a_hi = a >> 16; 2195706f2543Smrg s_lo = s & 0xFFFF; 2196706f2543Smrg s_hi = s >> 16; 2197706f2543Smrg rlo_lo = a_lo * s_lo; 2198706f2543Smrg rlo_hi = (a_hi * s_lo + a_lo * s_hi) + (rlo_lo >> 16); 2199706f2543Smrg rhi_lo = a_hi * s_hi + (rlo_hi >> 16); 2200706f2543Smrg M.x86.R_EAX = (rlo_hi << 16) | (rlo_lo & 0xFFFF); 2201706f2543Smrg M.x86.R_EDX = rhi_lo; 2202706f2543Smrg#endif 2203706f2543Smrg 2204706f2543Smrg if (M.x86.R_EDX == 0) { 2205706f2543Smrg CLEAR_FLAG(F_CF); 2206706f2543Smrg CLEAR_FLAG(F_OF); 2207706f2543Smrg } else { 2208706f2543Smrg SET_FLAG(F_CF); 2209706f2543Smrg SET_FLAG(F_OF); 2210706f2543Smrg } 2211706f2543Smrg} 2212706f2543Smrg 2213706f2543Smrg/**************************************************************************** 2214706f2543SmrgREMARKS: 2215706f2543SmrgImplements the IDIV instruction and side effects. 2216706f2543Smrg****************************************************************************/ 2217706f2543Smrgvoid idiv_byte(u8 s) 2218706f2543Smrg{ 2219706f2543Smrg s32 dvd, div, mod; 2220706f2543Smrg 2221706f2543Smrg dvd = (s16)M.x86.R_AX; 2222706f2543Smrg if (s == 0) { 2223706f2543Smrg x86emu_intr_raise(0); 2224706f2543Smrg return; 2225706f2543Smrg } 2226706f2543Smrg div = dvd / (s8)s; 2227706f2543Smrg mod = dvd % (s8)s; 2228706f2543Smrg if (abs(div) > 0x7f) { 2229706f2543Smrg x86emu_intr_raise(0); 2230706f2543Smrg return; 2231706f2543Smrg } 2232706f2543Smrg M.x86.R_AL = (s8) div; 2233706f2543Smrg M.x86.R_AH = (s8) mod; 2234706f2543Smrg} 2235706f2543Smrg 2236706f2543Smrg/**************************************************************************** 2237706f2543SmrgREMARKS: 2238706f2543SmrgImplements the IDIV instruction and side effects. 2239706f2543Smrg****************************************************************************/ 2240706f2543Smrgvoid idiv_word(u16 s) 2241706f2543Smrg{ 2242706f2543Smrg s32 dvd, div, mod; 2243706f2543Smrg 2244706f2543Smrg dvd = (((s32)M.x86.R_DX) << 16) | M.x86.R_AX; 2245706f2543Smrg if (s == 0) { 2246706f2543Smrg x86emu_intr_raise(0); 2247706f2543Smrg return; 2248706f2543Smrg } 2249706f2543Smrg div = dvd / (s16)s; 2250706f2543Smrg mod = dvd % (s16)s; 2251706f2543Smrg if (abs(div) > 0x7fff) { 2252706f2543Smrg x86emu_intr_raise(0); 2253706f2543Smrg return; 2254706f2543Smrg } 2255706f2543Smrg CLEAR_FLAG(F_CF); 2256706f2543Smrg CLEAR_FLAG(F_SF); 2257706f2543Smrg CONDITIONAL_SET_FLAG(div == 0, F_ZF); 2258706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF); 2259706f2543Smrg 2260706f2543Smrg M.x86.R_AX = (u16)div; 2261706f2543Smrg M.x86.R_DX = (u16)mod; 2262706f2543Smrg} 2263706f2543Smrg 2264706f2543Smrg/**************************************************************************** 2265706f2543SmrgREMARKS: 2266706f2543SmrgImplements the IDIV instruction and side effects. 2267706f2543Smrg****************************************************************************/ 2268706f2543Smrgvoid idiv_long(u32 s) 2269706f2543Smrg{ 2270706f2543Smrg#ifdef __HAS_LONG_LONG__ 2271706f2543Smrg s64 dvd, div, mod; 2272706f2543Smrg 2273706f2543Smrg dvd = (((s64)M.x86.R_EDX) << 32) | M.x86.R_EAX; 2274706f2543Smrg if (s == 0) { 2275706f2543Smrg x86emu_intr_raise(0); 2276706f2543Smrg return; 2277706f2543Smrg } 2278706f2543Smrg div = dvd / (s32)s; 2279706f2543Smrg mod = dvd % (s32)s; 2280706f2543Smrg if (abs(div) > 0x7fffffff) { 2281706f2543Smrg x86emu_intr_raise(0); 2282706f2543Smrg return; 2283706f2543Smrg } 2284706f2543Smrg#else 2285706f2543Smrg s32 div = 0, mod; 2286706f2543Smrg s32 h_dvd = M.x86.R_EDX; 2287706f2543Smrg u32 l_dvd = M.x86.R_EAX; 2288706f2543Smrg u32 abs_s = s & 0x7FFFFFFF; 2289706f2543Smrg u32 abs_h_dvd = h_dvd & 0x7FFFFFFF; 2290706f2543Smrg u32 h_s = abs_s >> 1; 2291706f2543Smrg u32 l_s = abs_s << 31; 2292706f2543Smrg int counter = 31; 2293706f2543Smrg int carry; 2294706f2543Smrg 2295706f2543Smrg if (s == 0) { 2296706f2543Smrg x86emu_intr_raise(0); 2297706f2543Smrg return; 2298706f2543Smrg } 2299706f2543Smrg do { 2300706f2543Smrg div <<= 1; 2301706f2543Smrg carry = (l_dvd >= l_s) ? 0 : 1; 2302706f2543Smrg 2303706f2543Smrg if (abs_h_dvd < (h_s + carry)) { 2304706f2543Smrg h_s >>= 1; 2305706f2543Smrg l_s = abs_s << (--counter); 2306706f2543Smrg continue; 2307706f2543Smrg } else { 2308706f2543Smrg abs_h_dvd -= (h_s + carry); 2309706f2543Smrg l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1) 2310706f2543Smrg : (l_dvd - l_s); 2311706f2543Smrg h_s >>= 1; 2312706f2543Smrg l_s = abs_s << (--counter); 2313706f2543Smrg div |= 1; 2314706f2543Smrg continue; 2315706f2543Smrg } 2316706f2543Smrg 2317706f2543Smrg } while (counter > -1); 2318706f2543Smrg /* overflow */ 2319706f2543Smrg if (abs_h_dvd || (l_dvd > abs_s)) { 2320706f2543Smrg x86emu_intr_raise(0); 2321706f2543Smrg return; 2322706f2543Smrg } 2323706f2543Smrg /* sign */ 2324706f2543Smrg div |= ((h_dvd & 0x10000000) ^ (s & 0x10000000)); 2325706f2543Smrg mod = l_dvd; 2326706f2543Smrg 2327706f2543Smrg#endif 2328706f2543Smrg CLEAR_FLAG(F_CF); 2329706f2543Smrg CLEAR_FLAG(F_AF); 2330706f2543Smrg CLEAR_FLAG(F_SF); 2331706f2543Smrg SET_FLAG(F_ZF); 2332706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF); 2333706f2543Smrg 2334706f2543Smrg M.x86.R_EAX = (u32)div; 2335706f2543Smrg M.x86.R_EDX = (u32)mod; 2336706f2543Smrg} 2337706f2543Smrg 2338706f2543Smrg/**************************************************************************** 2339706f2543SmrgREMARKS: 2340706f2543SmrgImplements the DIV instruction and side effects. 2341706f2543Smrg****************************************************************************/ 2342706f2543Smrgvoid div_byte(u8 s) 2343706f2543Smrg{ 2344706f2543Smrg u32 dvd, div, mod; 2345706f2543Smrg 2346706f2543Smrg dvd = M.x86.R_AX; 2347706f2543Smrg if (s == 0) { 2348706f2543Smrg x86emu_intr_raise(0); 2349706f2543Smrg return; 2350706f2543Smrg } 2351706f2543Smrg div = dvd / (u8)s; 2352706f2543Smrg mod = dvd % (u8)s; 2353706f2543Smrg if (div > 0xff) { 2354706f2543Smrg x86emu_intr_raise(0); 2355706f2543Smrg return; 2356706f2543Smrg } 2357706f2543Smrg M.x86.R_AL = (u8)div; 2358706f2543Smrg M.x86.R_AH = (u8)mod; 2359706f2543Smrg} 2360706f2543Smrg 2361706f2543Smrg/**************************************************************************** 2362706f2543SmrgREMARKS: 2363706f2543SmrgImplements the DIV instruction and side effects. 2364706f2543Smrg****************************************************************************/ 2365706f2543Smrgvoid div_word(u16 s) 2366706f2543Smrg{ 2367706f2543Smrg u32 dvd, div, mod; 2368706f2543Smrg 2369706f2543Smrg dvd = (((u32)M.x86.R_DX) << 16) | M.x86.R_AX; 2370706f2543Smrg if (s == 0) { 2371706f2543Smrg x86emu_intr_raise(0); 2372706f2543Smrg return; 2373706f2543Smrg } 2374706f2543Smrg div = dvd / (u16)s; 2375706f2543Smrg mod = dvd % (u16)s; 2376706f2543Smrg if (div > 0xffff) { 2377706f2543Smrg x86emu_intr_raise(0); 2378706f2543Smrg return; 2379706f2543Smrg } 2380706f2543Smrg CLEAR_FLAG(F_CF); 2381706f2543Smrg CLEAR_FLAG(F_SF); 2382706f2543Smrg CONDITIONAL_SET_FLAG(div == 0, F_ZF); 2383706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF); 2384706f2543Smrg 2385706f2543Smrg M.x86.R_AX = (u16)div; 2386706f2543Smrg M.x86.R_DX = (u16)mod; 2387706f2543Smrg} 2388706f2543Smrg 2389706f2543Smrg/**************************************************************************** 2390706f2543SmrgREMARKS: 2391706f2543SmrgImplements the DIV instruction and side effects. 2392706f2543Smrg****************************************************************************/ 2393706f2543Smrgvoid div_long(u32 s) 2394706f2543Smrg{ 2395706f2543Smrg#ifdef __HAS_LONG_LONG__ 2396706f2543Smrg u64 dvd, div, mod; 2397706f2543Smrg 2398706f2543Smrg dvd = (((u64)M.x86.R_EDX) << 32) | M.x86.R_EAX; 2399706f2543Smrg if (s == 0) { 2400706f2543Smrg x86emu_intr_raise(0); 2401706f2543Smrg return; 2402706f2543Smrg } 2403706f2543Smrg div = dvd / (u32)s; 2404706f2543Smrg mod = dvd % (u32)s; 2405706f2543Smrg if (abs(div) > 0xffffffff) { 2406706f2543Smrg x86emu_intr_raise(0); 2407706f2543Smrg return; 2408706f2543Smrg } 2409706f2543Smrg#else 2410706f2543Smrg s32 div = 0, mod; 2411706f2543Smrg s32 h_dvd = M.x86.R_EDX; 2412706f2543Smrg u32 l_dvd = M.x86.R_EAX; 2413706f2543Smrg 2414706f2543Smrg u32 h_s = s; 2415706f2543Smrg u32 l_s = 0; 2416706f2543Smrg int counter = 32; 2417706f2543Smrg int carry; 2418706f2543Smrg 2419706f2543Smrg if (s == 0) { 2420706f2543Smrg x86emu_intr_raise(0); 2421706f2543Smrg return; 2422706f2543Smrg } 2423706f2543Smrg do { 2424706f2543Smrg div <<= 1; 2425706f2543Smrg carry = (l_dvd >= l_s) ? 0 : 1; 2426706f2543Smrg 2427706f2543Smrg if (h_dvd < (h_s + carry)) { 2428706f2543Smrg h_s >>= 1; 2429706f2543Smrg l_s = s << (--counter); 2430706f2543Smrg continue; 2431706f2543Smrg } else { 2432706f2543Smrg h_dvd -= (h_s + carry); 2433706f2543Smrg l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1) 2434706f2543Smrg : (l_dvd - l_s); 2435706f2543Smrg h_s >>= 1; 2436706f2543Smrg l_s = s << (--counter); 2437706f2543Smrg div |= 1; 2438706f2543Smrg continue; 2439706f2543Smrg } 2440706f2543Smrg 2441706f2543Smrg } while (counter > -1); 2442706f2543Smrg /* overflow */ 2443706f2543Smrg if (h_dvd || (l_dvd > s)) { 2444706f2543Smrg x86emu_intr_raise(0); 2445706f2543Smrg return; 2446706f2543Smrg } 2447706f2543Smrg mod = l_dvd; 2448706f2543Smrg#endif 2449706f2543Smrg CLEAR_FLAG(F_CF); 2450706f2543Smrg CLEAR_FLAG(F_AF); 2451706f2543Smrg CLEAR_FLAG(F_SF); 2452706f2543Smrg SET_FLAG(F_ZF); 2453706f2543Smrg CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF); 2454706f2543Smrg 2455706f2543Smrg M.x86.R_EAX = (u32)div; 2456706f2543Smrg M.x86.R_EDX = (u32)mod; 2457706f2543Smrg} 2458706f2543Smrg 2459706f2543Smrg/**************************************************************************** 2460706f2543SmrgREMARKS: 2461706f2543SmrgImplements the IN string instruction and side effects. 2462706f2543Smrg****************************************************************************/ 2463706f2543Smrgvoid ins(int size) 2464706f2543Smrg{ 2465706f2543Smrg int inc = size; 2466706f2543Smrg 2467706f2543Smrg if (ACCESS_FLAG(F_DF)) { 2468706f2543Smrg inc = -size; 2469706f2543Smrg } 2470706f2543Smrg if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { 2471706f2543Smrg /* dont care whether REPE or REPNE */ 2472706f2543Smrg /* in until CX is ZERO. */ 2473706f2543Smrg u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ? 2474706f2543Smrg M.x86.R_ECX : M.x86.R_CX); 2475706f2543Smrg switch (size) { 2476706f2543Smrg case 1: 2477706f2543Smrg while (count--) { 2478706f2543Smrg store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, 2479706f2543Smrg (*sys_inb)(M.x86.R_DX)); 2480706f2543Smrg M.x86.R_DI += inc; 2481706f2543Smrg } 2482706f2543Smrg break; 2483706f2543Smrg 2484706f2543Smrg case 2: 2485706f2543Smrg while (count--) { 2486706f2543Smrg store_data_word_abs(M.x86.R_ES, M.x86.R_DI, 2487706f2543Smrg (*sys_inw)(M.x86.R_DX)); 2488706f2543Smrg M.x86.R_DI += inc; 2489706f2543Smrg } 2490706f2543Smrg break; 2491706f2543Smrg case 4: 2492706f2543Smrg while (count--) { 2493706f2543Smrg store_data_long_abs(M.x86.R_ES, M.x86.R_DI, 2494706f2543Smrg (*sys_inl)(M.x86.R_DX)); 2495706f2543Smrg M.x86.R_DI += inc; 2496706f2543Smrg break; 2497706f2543Smrg } 2498706f2543Smrg } 2499706f2543Smrg M.x86.R_CX = 0; 2500706f2543Smrg if (M.x86.mode & SYSMODE_PREFIX_DATA) { 2501706f2543Smrg M.x86.R_ECX = 0; 2502706f2543Smrg } 2503706f2543Smrg M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); 2504706f2543Smrg } else { 2505706f2543Smrg switch (size) { 2506706f2543Smrg case 1: 2507706f2543Smrg store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, 2508706f2543Smrg (*sys_inb)(M.x86.R_DX)); 2509706f2543Smrg break; 2510706f2543Smrg case 2: 2511706f2543Smrg store_data_word_abs(M.x86.R_ES, M.x86.R_DI, 2512706f2543Smrg (*sys_inw)(M.x86.R_DX)); 2513706f2543Smrg break; 2514706f2543Smrg case 4: 2515706f2543Smrg store_data_long_abs(M.x86.R_ES, M.x86.R_DI, 2516706f2543Smrg (*sys_inl)(M.x86.R_DX)); 2517706f2543Smrg break; 2518706f2543Smrg } 2519706f2543Smrg M.x86.R_DI += inc; 2520706f2543Smrg } 2521706f2543Smrg} 2522706f2543Smrg 2523706f2543Smrg/**************************************************************************** 2524706f2543SmrgREMARKS: 2525706f2543SmrgImplements the OUT string instruction and side effects. 2526706f2543Smrg****************************************************************************/ 2527706f2543Smrgvoid outs(int size) 2528706f2543Smrg{ 2529706f2543Smrg int inc = size; 2530706f2543Smrg 2531706f2543Smrg if (ACCESS_FLAG(F_DF)) { 2532706f2543Smrg inc = -size; 2533706f2543Smrg } 2534706f2543Smrg if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { 2535706f2543Smrg /* dont care whether REPE or REPNE */ 2536706f2543Smrg /* out until CX is ZERO. */ 2537706f2543Smrg u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ? 2538706f2543Smrg M.x86.R_ECX : M.x86.R_CX); 2539706f2543Smrg switch (size) { 2540706f2543Smrg case 1: 2541706f2543Smrg while (count--) { 2542706f2543Smrg (*sys_outb)(M.x86.R_DX, 2543706f2543Smrg fetch_data_byte_abs(M.x86.R_ES, M.x86.R_SI)); 2544706f2543Smrg M.x86.R_SI += inc; 2545706f2543Smrg } 2546706f2543Smrg break; 2547706f2543Smrg 2548706f2543Smrg case 2: 2549706f2543Smrg while (count--) { 2550706f2543Smrg (*sys_outw)(M.x86.R_DX, 2551706f2543Smrg fetch_data_word_abs(M.x86.R_ES, M.x86.R_SI)); 2552706f2543Smrg M.x86.R_SI += inc; 2553706f2543Smrg } 2554706f2543Smrg break; 2555706f2543Smrg case 4: 2556706f2543Smrg while (count--) { 2557706f2543Smrg (*sys_outl)(M.x86.R_DX, 2558706f2543Smrg fetch_data_long_abs(M.x86.R_ES, M.x86.R_SI)); 2559706f2543Smrg M.x86.R_SI += inc; 2560706f2543Smrg break; 2561706f2543Smrg } 2562706f2543Smrg } 2563706f2543Smrg M.x86.R_CX = 0; 2564706f2543Smrg if (M.x86.mode & SYSMODE_PREFIX_DATA) { 2565706f2543Smrg M.x86.R_ECX = 0; 2566706f2543Smrg } 2567706f2543Smrg M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); 2568706f2543Smrg } else { 2569706f2543Smrg switch (size) { 2570706f2543Smrg case 1: 2571706f2543Smrg (*sys_outb)(M.x86.R_DX, 2572706f2543Smrg fetch_data_byte_abs(M.x86.R_ES, M.x86.R_SI)); 2573706f2543Smrg break; 2574706f2543Smrg case 2: 2575706f2543Smrg (*sys_outw)(M.x86.R_DX, 2576706f2543Smrg fetch_data_word_abs(M.x86.R_ES, M.x86.R_SI)); 2577706f2543Smrg break; 2578706f2543Smrg case 4: 2579706f2543Smrg (*sys_outl)(M.x86.R_DX, 2580706f2543Smrg fetch_data_long_abs(M.x86.R_ES, M.x86.R_SI)); 2581706f2543Smrg break; 2582706f2543Smrg } 2583706f2543Smrg M.x86.R_SI += inc; 2584706f2543Smrg } 2585706f2543Smrg} 2586706f2543Smrg 2587706f2543Smrg/**************************************************************************** 2588706f2543SmrgPARAMETERS: 2589706f2543Smrgaddr - Address to fetch word from 2590706f2543Smrg 2591706f2543SmrgREMARKS: 2592706f2543SmrgFetches a word from emulator memory using an absolute address. 2593706f2543Smrg****************************************************************************/ 2594706f2543Smrgu16 mem_access_word(int addr) 2595706f2543Smrg{ 2596706f2543SmrgDB( if (CHECK_MEM_ACCESS()) 2597706f2543Smrg x86emu_check_mem_access(addr);) 2598706f2543Smrg return (*sys_rdw)(addr); 2599706f2543Smrg} 2600706f2543Smrg 2601706f2543Smrg/**************************************************************************** 2602706f2543SmrgREMARKS: 2603706f2543SmrgPushes a word onto the stack. 2604706f2543Smrg 2605706f2543SmrgNOTE: Do not inline this, as (*sys_wrX) is already inline! 2606706f2543Smrg****************************************************************************/ 2607706f2543Smrgvoid push_word(u16 w) 2608706f2543Smrg{ 2609706f2543SmrgDB( if (CHECK_SP_ACCESS()) 2610706f2543Smrg x86emu_check_sp_access();) 2611706f2543Smrg M.x86.R_SP -= 2; 2612706f2543Smrg (*sys_wrw)(((u32)M.x86.R_SS << 4) + M.x86.R_SP, w); 2613706f2543Smrg} 2614706f2543Smrg 2615706f2543Smrg/**************************************************************************** 2616706f2543SmrgREMARKS: 2617706f2543SmrgPushes a long onto the stack. 2618706f2543Smrg 2619706f2543SmrgNOTE: Do not inline this, as (*sys_wrX) is already inline! 2620706f2543Smrg****************************************************************************/ 2621706f2543Smrgvoid push_long(u32 w) 2622706f2543Smrg{ 2623706f2543SmrgDB( if (CHECK_SP_ACCESS()) 2624706f2543Smrg x86emu_check_sp_access();) 2625706f2543Smrg M.x86.R_SP -= 4; 2626706f2543Smrg (*sys_wrl)(((u32)M.x86.R_SS << 4) + M.x86.R_SP, w); 2627706f2543Smrg} 2628706f2543Smrg 2629706f2543Smrg/**************************************************************************** 2630706f2543SmrgREMARKS: 2631706f2543SmrgPops a word from the stack. 2632706f2543Smrg 2633706f2543SmrgNOTE: Do not inline this, as (*sys_rdX) is already inline! 2634706f2543Smrg****************************************************************************/ 2635706f2543Smrgu16 pop_word(void) 2636706f2543Smrg{ 2637706f2543Smrg register u16 res; 2638706f2543Smrg 2639706f2543SmrgDB( if (CHECK_SP_ACCESS()) 2640706f2543Smrg x86emu_check_sp_access();) 2641706f2543Smrg res = (*sys_rdw)(((u32)M.x86.R_SS << 4) + M.x86.R_SP); 2642706f2543Smrg M.x86.R_SP += 2; 2643706f2543Smrg return res; 2644706f2543Smrg} 2645706f2543Smrg 2646706f2543Smrg/**************************************************************************** 2647706f2543SmrgREMARKS: 2648706f2543SmrgPops a long from the stack. 2649706f2543Smrg 2650706f2543SmrgNOTE: Do not inline this, as (*sys_rdX) is already inline! 2651706f2543Smrg****************************************************************************/ 2652706f2543Smrgu32 pop_long(void) 2653706f2543Smrg{ 2654706f2543Smrg register u32 res; 2655706f2543Smrg 2656706f2543SmrgDB( if (CHECK_SP_ACCESS()) 2657706f2543Smrg x86emu_check_sp_access();) 2658706f2543Smrg res = (*sys_rdl)(((u32)M.x86.R_SS << 4) + M.x86.R_SP); 2659706f2543Smrg M.x86.R_SP += 4; 2660706f2543Smrg return res; 2661706f2543Smrg} 2662706f2543Smrg 2663706f2543Smrg/**************************************************************************** 2664706f2543SmrgREMARKS: 2665706f2543SmrgCPUID takes EAX/ECX as inputs, writes EAX/EBX/ECX/EDX as output 2666706f2543Smrg****************************************************************************/ 2667706f2543Smrgvoid cpuid (void) 2668706f2543Smrg{ 2669706f2543Smrg u32 feature = M.x86.R_EAX; 2670706f2543Smrg 2671706f2543Smrg#ifdef X86EMU_HAS_HW_CPUID 2672706f2543Smrg /* If the platform allows it, we will base our values on the real 2673706f2543Smrg * results from the CPUID instruction. We limit support to the 2674706f2543Smrg * first two features, and the results of those are sanitized. 2675706f2543Smrg */ 2676706f2543Smrg if (feature <= 1) 2677706f2543Smrg hw_cpuid(&M.x86.R_EAX, &M.x86.R_EBX, &M.x86.R_ECX, &M.x86.R_EDX); 2678706f2543Smrg#endif 2679706f2543Smrg 2680706f2543Smrg switch (feature) { 2681706f2543Smrg case 0: 2682706f2543Smrg /* Regardless if we have real data from the hardware, the emulator 2683706f2543Smrg * will only support upto feature 1, which we set in register EAX. 2684706f2543Smrg * Registers EBX:EDX:ECX contain a string identifying the CPU. 2685706f2543Smrg */ 2686706f2543Smrg M.x86.R_EAX = 1; 2687706f2543Smrg#ifndef X86EMU_HAS_HW_CPUID 2688706f2543Smrg /* EBX:EDX:ECX = "GenuineIntel" */ 2689706f2543Smrg M.x86.R_EBX = 0x756e6547; 2690706f2543Smrg M.x86.R_EDX = 0x49656e69; 2691706f2543Smrg M.x86.R_ECX = 0x6c65746e; 2692706f2543Smrg#endif 2693706f2543Smrg break; 2694706f2543Smrg case 1: 2695706f2543Smrg#ifndef X86EMU_HAS_HW_CPUID 2696706f2543Smrg /* If we don't have x86 compatible hardware, we return values from an 2697706f2543Smrg * Intel 486dx4; which was one of the first processors to have CPUID. 2698706f2543Smrg */ 2699706f2543Smrg M.x86.R_EAX = 0x00000480; 2700706f2543Smrg M.x86.R_EBX = 0x00000000; 2701706f2543Smrg M.x86.R_ECX = 0x00000000; 2702706f2543Smrg M.x86.R_EDX = 0x00000002; /* VME */ 2703706f2543Smrg#else 2704706f2543Smrg /* In the case that we have hardware CPUID instruction, we make sure 2705706f2543Smrg * that the features reported are limited to TSC and VME. 2706706f2543Smrg */ 2707706f2543Smrg M.x86.R_EDX &= 0x00000012; 2708706f2543Smrg#endif 2709706f2543Smrg break; 2710706f2543Smrg default: 2711706f2543Smrg /* Finally, we don't support any additional features. Most CPUs 2712706f2543Smrg * return all zeros when queried for invalid or unsupported feature 2713706f2543Smrg * numbers. 2714706f2543Smrg */ 2715706f2543Smrg M.x86.R_EAX = 0; 2716706f2543Smrg M.x86.R_EBX = 0; 2717706f2543Smrg M.x86.R_ECX = 0; 2718706f2543Smrg M.x86.R_EDX = 0; 2719706f2543Smrg break; 2720706f2543Smrg } 2721706f2543Smrg} 2722706f2543Smrg 2723