1/* $NetBSD: emulate.S,v 1.2 2002/02/24 01:04:26 matt Exp $ */ 2/* 3 * Copyright (c) 1986, 1987 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * Mt. Xinu. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)emulate.s 7.5 (Berkeley) 6/28/90 38 */ 39 40#include <machine/asm.h> 41 42/* 43 * String instruction emulation - MicroVAX only. These routines are called 44 * from locore.s when an "emulate" fault occurs on the MicroVAX. They are 45 * called with the stack set up as follows: 46 * 47 * (%sp): Return address of trap handler 48 * 4(%sp): Instruction Opcode (also holds PSL result from emulator) 49 * 8(%sp): Instruction PC 50 * 12(%sp): Operand 1 51 * 16(%sp): Operand 2 52 * 20(%sp): Operand 3 53 * 24(%sp): Operand 4 54 * 28(%sp): Operand 5 55 * 32(%sp): Operand 6 56 * 36(%sp): old Register 11 57 * 40(%sp): old Register 10 58 * 44(%sp): Return PC 59 * 48(%sp): Return PSL 60 * 52(%sp): TOS before instruction 61 * 62 * R11 and %r10 are available for use. If any routine needs to use %r9-%r1 63 * they need to save them first (unless those registers are SUPPOSED to be 64 * messed with by the "instruction"). These routines leave their results 65 * in registers 0-5 explicitly, as needed, and use the macros defined below 66 * to link up with calling routine. 67 */ 68 69#define return rsb 70#define savepsl movpsl 4(%sp) 71#define setpsl(reg) movl reg,4(%sp) 72#define overflowpsl movl $2,4(%sp) 73#define arg1 12(%sp) 74#define arg2 16(%sp) 75#define arg3 20(%sp) 76#define arg4 24(%sp) 77#define arg5 28(%sp) 78#define arg6 32(%sp) 79#define argub(num,reg) movzbl 8+4*num(%sp),reg 80#define arguw(num,reg) movzwl 8+4*num(%sp),reg 81#define argul(num,reg) movl 8+4*num(%sp),reg 82#define argb(num,reg) cvtbl 8+4*num(%sp),reg 83#define argw(num,reg) cvtwl 8+4*num(%sp),reg 84#define argl(num,reg) movl 8+4*num(%sp),reg 85#define toarg(reg,num) movl reg,8+4*num(%sp) 86 87 88 .text 89 .align 1 90ALTENTRY(EMcrc) 91 argl(1,%r11) # (1) table address == %r11 92 argl(2,%r0) # (2) initial crc == %r0 93 argl(4,%r3) # (4) source address == %r3 94 arguw(3,%r2) # (3) source length == %r2 95 jeql Lcrc_out 96Lcrc_loop: 97 xorb2 (%r3)+,%r0 98 extzv $0,$4,%r0,%r10 99 extzv $4,$28,%r0,%r1 100 xorl3 %r1,(%r11)[%r10],%r0 101 extzv $0,$4,%r0,%r10 102 extzv $4,$28,%r0,%r1 103 xorl3 %r1,(%r11)[%r10],%r0 104 sobgtr %r2,Lcrc_loop 105 tstl %r0 106Lcrc_out: 107 savepsl 108 clrl %r1 109 return 110 111 112 .align 1 113ALTENTRY(EMmovtc) 114 arguw(1,%r0) # (1) source length == %r0 115 argl(2,%r1) # (2) source address == %r1 116 argub(3,%r11) # (3) fill character == %r11 117 argl(4,%r3) # (4) table address == %r3 118 argl(6,%r5) # (6) destination address == %r5 119 arguw(5,%r4) # (5) destination length == %r4 120 jeql Lmovtc_out 121Lmovtc_loop: 122 tstl %r0 123 jeql Lmovtc_2loop 124 movzbl (%r1)+,%r2 125 movb (%r3)[%r2],(%r5)+ 126 decl %r0 127 sobgtr %r4,Lmovtc_loop 128 jbr Lmovtc_out 129Lmovtc_2loop: 130 movb %r11,(%r5)+ 131 sobgtr %r4,Lmovtc_2loop 132Lmovtc_out: 133 cmpl %r4,%r0 134 savepsl 135 clrl %r2 136 return 137 138 139 .align 1 140ALTENTRY(EMmovtuc) 141 arguw(1,%r0) # (1) source length == %r0 142 argl(2,%r1) # (2) source address == %r1 143 argub(3,%r11) # (3) escape character == %r11 144 argl(4,%r3) # (4) table address == %r3 145 argl(6,%r5) # (6) destination address == %r5 146 arguw(5,%r4) # (5) destination length == %r4 147 jeql Lmovtuc_out 148Lmovtuc_loop: 149 tstl %r0 150 jeql Lmovtuc_out 151 movzbl (%r1),%r2 152 movzbl (%r3)[%r2],%r2 153 cmpl %r2,%r11 154 jeql Lmovtuc_out 155 movzbl (%r1)+,%r2 156 movb (%r3)[%r2],(%r5)+ 157 decl %r0 158 sobgtr %r4,Lmovtuc_loop 159Lmovtuc_out: 160 cmpl %r4,%r0 161 savepsl 162 clrl %r2 163 return 164 165 166 .align 1 167ALTENTRY(EMmatchc) 168 argl(2,%r10) # (2) substring address == %r10 169 arguw(3,%r2) # (3) source length == %r2 170 argl(4,%r3) # (4) source address == %r3 171 arguw(1,%r11) # (1) substring length == %r11 172 jeql Lmatchc_out # temp source address == %r1 173 addl2 %r10,%r11 # temp substring address == %r0 174 tstl %r2 175 jeql Lmatchc_out 176Lmatchc_loop: 177 cmpb (%r10),(%r3) 178 jneq Lmatchc_fail 179 movl %r3,%r1 180 movl %r10,%r0 181Lmatchc_2loop: 182 cmpl %r0,%r11 183 jeql Lmatchc_succ 184 cmpb (%r0)+,(%r1)+ 185 jeql Lmatchc_2loop 186Lmatchc_fail: 187 incl %r3 188 sobgtr %r2,Lmatchc_loop 189 movl %r10,%r1 190 subl3 %r10,%r11,%r0 191 jbr Lmatchc_out 192Lmatchc_succ: 193 movl %r1,%r3 194 movl %r11,%r1 195 clrl %r0 196Lmatchc_out: 197 savepsl 198 return 199 200 201 .align 1 202ALTENTRY(EMspanc) 203 argl(2,%r1) # (2) string address == %r1 204 argub(4,%r2) # (4) character-mask == %r2 205 argl(3,%r3) # (3) table address == %r3 206 arguw(1,%r0) # (1) string length == %r0 207 jeql Lspanc_out 208Lspanc_loop: 209 movzbl (%r1),%r11 210 mcomb (%r3)[%r11],%r11 211 bicb3 %r11,%r2,%r11 212 jeql Lspanc_out 213 incl %r1 214 sobgtr %r0,Lspanc_loop 215Lspanc_out: 216 savepsl 217 clrl %r2 218 return 219 220 221 .align 1 222ALTENTRY(EMscanc) 223 argl(2,%r1) # (2) string address == %r1 224 argub(4,%r2) # (4) character-mask == %r2 225 argl(3,%r3) # (3) table address == %r3 226 arguw(1,%r0) # (1) string length == %r0 227 jeql Lscanc_out 228Lscanc_loop: 229 movzbl (%r1),%r11 230 mcomb (%r3)[%r11],%r11 231 bicb3 %r11,%r2,%r11 232 jneq Lscanc_out 233 incl %r1 234 sobgtr %r0,Lscanc_loop 235Lscanc_out: 236 savepsl 237 clrl %r2 238 return 239 240 241 .align 1 242ALTENTRY(EMskpc) 243 argub(1,%r11) # (1) character == %r11 244 argl(3,%r1) # (3) string address == %r1 245 arguw(2,%r0) # (2) string length == %r0 246 jeql Lskpc_out # forget zero length strings 247Lskpc_loop: 248 cmpb (%r1),%r11 249 jneq Lskpc_out 250 incl %r1 251 sobgtr %r0,Lskpc_loop 252Lskpc_out: 253 tstl %r0 # be sure of condition codes 254 savepsl 255 return 256 257 258 .align 1 259ALTENTRY(EMlocc) 260 argub(1,%r11) # (1) character == %r11 261 argl(3,%r1) # (3) string address == %r1 262 arguw(2,%r0) # (2) string length == %r0 263 jeql Lskpc_out # forget zero length strings 264Llocc_loop: 265 cmpb (%r1),%r11 266 jeql Llocc_out 267 incl %r1 268 sobgtr %r0,Llocc_loop 269Llocc_out: 270 tstl %r0 # be sure of condition codes 271 savepsl 272 return 273 274 275 .align 1 276ALTENTRY(EMcmpc3) 277 argl(2,%r1) # (2) string1 address == %r1 278 argl(3,%r3) # (3) string2 address == %r3 279 arguw(1,%r0) # (1) strings length == %r0 280 jeql Lcmpc3_out 281Lcmpc3_loop: 282 cmpb (%r1),(%r3) 283 jneq Lcmpc3_out 284 incl %r1 285 incl %r3 286 sobgtr %r0,Lcmpc3_loop 287Lcmpc3_out: 288 savepsl 289 movl %r0,%r2 290 return 291 292 293 .align 1 294ALTENTRY(EMcmpc5) 295 argl(2,%r1) # (2) string1 address == %r1 296 argub(3,%r11) # (1) fill character == %r11 297 arguw(4,%r2) # (1) string2 length == %r2 298 argl(5,%r3) # (3) string2 address == %r3 299 arguw(1,%r0) # (1) string1 length == %r0 300 jeql Lcmpc5_str2 301Lcmpc5_loop: 302 tstl %r2 303 jeql Lcmpc5_str1loop 304 cmpb (%r1),(%r3) 305 jneq Lcmpc5_out 306 incl %r1 307 incl %r3 308 decl %r2 309 sobgtr %r0,Lcmpc5_loop 310Lcmpc5_str2: 311 tstl %r2 312 jeql Lcmpc5_out 313Lcmpc5_str2loop: 314 cmpb %r11,(%r3) 315 jneq Lcmpc5_out 316 incl %r3 317 sobgtr %r2,Lcmpc5_str2loop 318 jbr Lcmpc5_out 319Lcmpc5_str1loop: 320 cmpb (%r1),%r11 321 jneq Lcmpc5_out 322 incl %r1 323 sobgtr %r0,Lcmpc5_str1loop 324Lcmpc5_out: 325 savepsl 326 return 327 328 329/* 330 * Packed Decimal string operations 331 */ 332 333#define POSITIVE $12 334#define NEGATIVE $13 335#define NEGATIVEalt $11 336 337 338 .align 1 339ALTENTRY(EMaddp4) 340 toarg(%r9,6) # save register %r9 in arg6 spot 341 arguw(1,%r11) # (1) source length == %r11 342 argl(2,%r10) # (2) source address == %r10 343 arguw(3,%r9) # (3) destination length == %r9 344 argl(4,%r3) # (4) destination address == %r3 345 ashl $-1,%r11,%r11 346 addl2 %r11,%r10 # source address of LSNibble 347 incl %r11 # source length is in bytes 348 ashl $-1,%r9,%r9 349 addl2 %r9,%r3 # %r3 = destination address of LSNibble 350 incl %r9 # destination length is in bytes 351 toarg(%r3,5) 352 extzv $0,$4,(%r3),%r2 # set standard +/- indicators in destination 353 cmpl %r2,NEGATIVE 354 jeql L112 355 cmpl %r2,NEGATIVEalt 356 jeql L111 357 insv POSITIVE,$0,$4,(%r3) 358 jbr L112 359L111: 360 insv NEGATIVE,$0,$4,(%r3) 361L112: 362 extzv $0,$4,(%r10),%r2 # %r2 = standard +/- of source 363 cmpl %r2,NEGATIVE 364 jeql L114 365 cmpl %r2,NEGATIVEalt 366 jeql L113 367 movl POSITIVE,%r2 368 jbr L114 369L113: 370 movl NEGATIVE,%r2 371L114: 372 cmpl %r11,%r9 # if source is longer than destination 373 jleq L115 374 movl %r9,%r11 # set source length == destination length 375L115: 376 extzv $4,$4,(%r3),%r9 # %r9 = LSDigit of destination 377 extzv $4,$4,(%r10),%r1 # %r1 = LSDigit of source 378 extzv $0,$4,(%r3),%r0 379 cmpl %r0,%r2 # if signs of operands are not equal 380 jeql Laddp4_same # do a subtraction 381 clrl %r2 # %r2 is non-zero if result is non-zero 382 subl2 %r1,%r9 # %r9 = "addition" of operands high nibble 383 jbr L119 # jump into addition loop 384Laddp4_diff_loop: 385 decl %r3 386 extzv $0,$4,(%r3),%r0 387 addl2 %r0,%r1 # %r1 = carry + next (low) nibble of source 388 decl %r10 389 extzv $0,$4,(%r10),%r0 390 subl2 %r0,%r1 # %r1 -= next (low) nibble of destination 391 jgeq L121 # if negative result 392 mnegl $1,%r9 # %r9 == carry = -1 393 addl2 $10,%r1 # %r1 == result += 10 394 jbr L122 # else 395L121: 396 clrl %r9 # %r9 == carry = 0 397L122: 398 insv %r1,$0,$4,(%r3) # store result low nibble 399 bisl2 %r1,%r2 400 extzv $4,$4,(%r3),%r0 401 addl2 %r0,%r9 # %r9 = carry + next (high) nibble of source 402 extzv $4,$4,(%r10),%r0 403 subl2 %r0,%r9 # %r9 -= next (high) nibble of destination 404L119: 405 jgeq L117 # if negative result 406 mnegl $1,%r1 # %r1 == carry = -1 407 addl2 $10,%r9 # %r9 == result += 10 408 jbr L118 # else 409L117: 410 clrl %r1 # %r1 == carry = 0 411L118: 412 insv %r9,$4,$4,(%r3) # store result high nibble 413 bisl2 %r9,%r2 # %r2 is non-zero if result is non-zero 414 decl %r11 # while (--source length) 415 jneq Laddp4_diff_loop 416 argl(4,%r10) # %r10 = address of destination MSNibble 417 jbr Laddp4_diff_carry 418Laddp4_diff_carlop: 419 decl %r3 420 extzv $0,$4,(%r3),%r0 421 addl2 %r0,%r1 # %r1 == carry += next (low) nibble 422 jgeq L127 # if less than zero 423 movl %r1,%r9 # %r9 == carry (must be -1) 424 movl $9,%r1 # %r1 == result = 9 425 jbr L128 426L127: # else 427 clrl %r9 # %r9 == carry = 0 428L128: 429 insv %r1,$0,$4,(%r3) # store result 430 bisl2 %r1,%r2 431 extzv $4,$4,(%r3),%r0 432 addl2 %r0,%r9 # %r9 == carry += next (high) nibble 433 jgeq L129 # if less than zero 434 movl %r9,%r1 # %r1 == carry (must be -1) 435 movl $9,%r9 # %r9 == result = 9 436 jbr L130 437L129: 438 clrl %r1 439L130: 440 insv %r9,$4,$4,(%r3) # store result 441 bisl2 %r9,%r2 442Laddp4_diff_carry: 443 cmpl %r3,%r10 444 jneq Laddp4_diff_carlop 445 tstl %r1 # if carry out of MSN then fix up result 446 jeql Laddp4_add_done 447 argl(5,%r3) # %r3 == address of LSN of destination 448 extzv $0,$4,(%r3),%r0 449 cmpl %r0,NEGATIVE # switch sign of result 450 jneq L132 451 insv POSITIVE,$0,$4,(%r3) 452 jbr L133 453L132: 454 insv NEGATIVE,$0,$4,(%r3) 455L133: 456 extzv $4,$4,(%r3),%r0 # normalize result (carry out of MSN into LSN) 457 subl3 %r0,$10,%r9 # %r9 = 10 - destination LSNibble 458 jbr L134 459L137: 460 movl $9,%r1 461Laddp4_diff_norm: 462 insv %r9,$4,$4,(%r3) 463 cmpl %r3,%r10 # while (not at MSNibble) 464 jeql Laddp4_add_done 465 decl %r3 466 extzv $0,$4,(%r3),%r0 # low nibble = (9 + carry) - low nibble 467 subl2 %r0,%r1 468 cmpl %r1,$9 469 jleq L135 470 clrl %r1 471 movl $10,%r9 472 jbr L136 473L135: 474 movl $9,%r9 475L136: 476 insv %r1,$0,$4,(%r3) 477 extzv $4,$4,(%r3),%r0 # high nibble = (9 + carry) - high nibble 478 subl2 %r0,%r9 479L134: 480 cmpl %r9,$9 481 jleq L137 482 clrl %r9 483 movl $10,%r1 484 jbr Laddp4_diff_norm 485 486Laddp4_same: # operands are of the same sign 487 clrl %r2 488 addl2 %r1,%r9 489 jbr L139 490Laddp4_same_loop: 491 decl %r3 492 extzv $0,$4,(%r3),%r0 493 addl2 %r0,%r1 # %r1 == carry += next (low) nibble of dest 494 decl %r10 495 extzv $0,$4,(%r10),%r0 496 addl2 %r0,%r1 # %r1 += next (low) nibble of source 497 cmpl %r1,$9 # if result > 9 498 jleq L141 499 movl $1,%r9 # %r9 == carry = 1 500 subl2 $10,%r1 # %r1 == result -= 10 501 jbr L142 502L141: # else 503 clrl %r9 # %r9 == carry = 0 504L142: 505 insv %r1,$0,$4,(%r3) # store result 506 bisl2 %r1,%r2 507 extzv $4,$4,(%r10),%r0 508 addl2 %r0,%r9 # ditto for high nibble 509 extzv $4,$4,(%r3),%r0 510 addl2 %r0,%r9 511L139: 512 cmpl %r9,$9 513 jleq L143 514 movl $1,%r1 515 subl2 $10,%r9 516 jbr L144 517L143: 518 clrl %r1 519L144: 520 insv %r9,$4,$4,(%r3) 521 bisl2 %r9,%r2 522 sobgtr %r11,Laddp4_same_loop # while (--source length) 523 argl(4,%r10) # %r10 = destination address of MSNibble 524 jbr Laddp4_same_carry 525Laddp4_same_cloop: 526 decl %r3 527 extzv $0,$4,(%r3),%r0 # propagate carry up to MSNibble of destination 528 addl2 %r0,%r1 529 cmpl %r1,$10 530 jneq L147 531 movl $1,%r9 532 clrl %r1 533 jbr L148 534L147: 535 clrl %r9 536L148: 537 insv %r1,$0,$4,(%r3) 538 bisl2 %r1,%r2 539 extzv $4,$4,(%r3),%r0 540 addl2 %r0,%r9 541 cmpl %r9,$10 542 jneq L149 543 movl $1,%r1 544 clrl %r9 545 jbr L150 546L149: 547 clrl %r1 548L150: 549 insv %r9,$4,$4,(%r3) 550 bisl2 %r9,%r2 551Laddp4_same_carry: 552 cmpl %r3,%r10 553 jneq Laddp4_same_cloop 554 555Laddp4_add_done: 556 argl(5,%r3) # %r3 = destination address of LSNibble 557 tstl %r2 # if zero result 558 jneq L151 559 savepsl # remember that for condition codes 560 insv POSITIVE,$0,$4,(%r3) # make sure sign of result is positive 561 jbr Laddp4_out 562L151: # else 563 extzv $0,$4,(%r3),%r0 564 cmpl %r0,NEGATIVE # if result is negative 565 jneq Laddp4_out 566 mnegl %r2,%r2 # remember THAT in Cond Codes 567 savepsl 568Laddp4_out: 569 argl(4,%r3) 570 argl(2,%r1) 571 clrl %r0 572 clrl %r2 573 argl(6,%r9) # restore %r9 from stack 574 return 575 576 577 .align 1 578ALTENTRY(EMmovp) 579 arguw(1,%r11) # (1) string length == %r11 580 argl(2,%r10) # (1) source address == %r10 581 argl(3,%r3) # (1) destination address == %r3 582 # we will need arg2 and arg3 later 583 clrl %r2 # %r2 == non-zero if source is non-zero 584 ashl $-1,%r11,%r11 # length is number of bytes, not nibbles 585 jeql Lmovp_zlen 586Lmovp_copy: 587 bisb2 (%r10),%r2 # keep track of non-zero source 588 movb (%r10)+,(%r3)+ # move two nibbles 589 sobgtr %r11,Lmovp_copy # loop for length of source 590Lmovp_zlen: 591 extzv $4,$4,(%r10),%r0 # look at least significant nibble 592 bisl2 %r0,%r2 593 extzv $0,$4,(%r10),%r0 # check sign nibble 594 cmpl %r0,NEGATIVEalt 595 jeql Lmovp_neg 596 cmpl %r0,NEGATIVE 597 jneq Lmovp_pos 598Lmovp_neg: # source was negative 599 mnegl %r2,%r2 600Lmovp_pos: 601 tstl %r2 # set condition codes 602 savepsl 603 jeql Lmovp_zero 604 movb (%r10),(%r3) # move last byte if non-zero result 605 jbr Lmovp_out 606Lmovp_zero: 607 movb POSITIVE,(%r3) # otherwise, make result zero and positive 608Lmovp_out: 609 clrl %r0 610 argl(2,%r1) 611 clrl %r2 612 argl(3,%r3) 613 return 614 615 616/* 617 * Definitions for Editpc instruction 618 * 619 * Here are the commands and their corresponding hex values: 620 * 621 * EPend 0x00 622 * EPend_float 0x01 623 * EPclear_signif 0x02 624 * EPset_signif 0x03 625 * EPstore_sign 0x04 626 * EPload_fill 0x40 627 * EPload_sign 0x41 628 * EPload_plus 0x42 629 * EPload_minus 0x43 630 * EPinsert 0x44 631 * EPblank_zero 0x45 632 * EPreplace_sign 0x46 633 * EPadjust_input 0x47 634 * EPfill 0x80 635 * EPmove 0x90 636 * EPfloat 0xa0 637 * 638 * 639 * %r4 is carved up as follows: 640 * 641 * ------------------------------------------- 642 * | N Z V C | 643 * ------------------------------------------- 644 * 645 * fill character is stuffed into arg5 space 646 * sign character is stuffed into arg6 space 647 */ 648 649#define SIGNIFBIT $0 650#define setsignif bisl2 $1,%r4 651#define clsignif bicl2 $1,%r4 652#define OVERFLOWBIT $1 653#define setoverflow bisl2 $2,%r4 654#define cloverflow bicl2 $2,%r4 655#define ZEROBIT $2 656#define setzero bisl2 $4,%r4 657#define clzero bicl2 $4,%r4 658#define NEGATIVEBIT $3 659#define setnegative bisl2 $8,%r4 660#define clnegative bicl2 $8,%r4 661#define putfill movb arg5,(%r5)+ 662#define setfill(reg) movb reg,arg5 663#define putsign movb arg6,(%r5)+ 664#define setsign(reg) movb reg,arg6 665 666 667 .align 1 668ALTENTRY(EMeditpc) 669 arguw(1,%r11) # (1) source length == %r11 670 argl(2,%r10) # (2) source address == %r10 671 argl(3,%r3) # (3) pattern address == %r3 672 argl(4,%r5) # (4) destination address == %r5 673/* # we will need arg1 and arg2 later */ 674/* # arg5 and arg6 are used for fill and sign - %r0 is free */ 675 setfill($32) # fill character is ' ' 676 setsign($32) # sign character is ' ' 677 clrl %r4 # clear flags 678 ashl $-1,%r11,%r11 # source length / 2 679 addl3 %r11,%r10,%r2 680 extzv $4,$4,(%r2),%r1 # %r1 == least significant nibble of source 681L169: 682 cmpl %r2,%r10 683 jeql L170 684 tstb -(%r2) # loop over source packed decimal number 685 jeql L169 686 incl %r1 # %r1 is non-zero if source is non-zero 687L170: 688 addl3 %r11,%r10,%r2 689 tstl %r1 690 jeql L172 # source is zero - set flags 691 extzv $0,$4,(%r2),%r11 692 cmpl %r11,NEGATIVEalt 693 jeql L9998 # source is negative - set sign and flags 694 cmpl %r11,NEGATIVE 695 jneq L175 696L9998: 697 setnegative 698 setsign($45) # sign character is '-' 699 jbr L175 700L172: 701 setzero 702L175: 703 arguw(1,%r2) # (1) source length == %r2 704Ledit_case: 705 movzbl (%r3)+,%r11 # get next edit command (pattern) 706 cmpl %r11,$128 707 jlss L180 708 extzv $0,$4,%r11,%r1 # command has a "count" arg - into %r1 709 ashl $-4,%r11,%r11 # and shift over 710L180: 711 jbc $6,%r11,L181 # "shift" those commands > 64 to 16 and up 712 subl2 $48,%r11 713L181: 714 caseb %r11,$0,$0x18 # "do" the command 715 # %r11 is available for use, %r1 has "count" in it 716Lcaseb_label: 717 .word Le_end - Lcaseb_label # 00 718 .word Le_end_float - Lcaseb_label # 01 719 .word Le_clear_signif - Lcaseb_label # 02 720 .word Le_set_signif - Lcaseb_label # 03 721 .word Le_store_sign - Lcaseb_label # 04 722 .word Le_end - Lcaseb_label # 05 723 .word Le_end - Lcaseb_label # 06 724 .word Le_end - Lcaseb_label # 07 725 .word Le_fill - Lcaseb_label # 80 726 .word Le_move - Lcaseb_label # 90 727 .word Le_float - Lcaseb_label # a0 728 .word Le_end - Lcaseb_label # b0 729 .word Le_end - Lcaseb_label # c0 730 .word Le_end - Lcaseb_label # d0 731 .word Le_end - Lcaseb_label # e0 732 .word Le_end - Lcaseb_label # f0 733 .word Le_load_fill - Lcaseb_label # 40 734 .word Le_load_sign - Lcaseb_label # 41 735 .word Le_load_plus - Lcaseb_label # 42 736 .word Le_load_minus - Lcaseb_label # 43 737 .word Le_insert - Lcaseb_label # 44 738 .word Le_blank_zero - Lcaseb_label # 45 739 .word Le_replace_sign - Lcaseb_label # 46 740 .word Le_adjust_input - Lcaseb_label # 47 741Le_end: 742 arguw(1,%r0) 743 argl(2,%r1) 744 clrl %r2 745 decl %r3 746 setpsl(%r4) 747 clrl %r4 748 return 749 750Le_end_float: 751 jbs SIGNIFBIT,%r4,Ledit_case # if significance not set 752 putsign # drop in the sign 753 # fall into... 754Le_set_signif: 755 setsignif 756 jbr Ledit_case 757 758Le_clear_signif: 759 clsignif 760 jbr Ledit_case 761 762Le_store_sign: 763 putsign 764 jbr Ledit_case 765 766Le_load_fill: 767 setfill((%r3)+) 768 jbr Ledit_case 769 770Le_load_plus: 771 jbs NEGATIVEBIT,%r4,Lpattern_inc # if non-negative 772 # fall into... 773Le_load_sign: 774 setsign((%r3)+) 775 jbr Ledit_case 776 777Le_load_minus: 778 jbs NEGATIVEBIT,%r4,Le_load_sign # if negative load the sign 779 incl %r3 # else increment pattern 780 jbr Ledit_case 781 782Le_insert: 783 jbc SIGNIFBIT,%r4,L196 # if significance set, put next byte 784 movb (%r3)+,(%r5)+ 785 jbr Ledit_case 786L196: # else put in fill character 787 putfill 788 # and throw away character in pattern 789Le_replace_sign: # we dont do anything with 790Lpattern_inc: # replace sign cause we dont 791 incl %r3 # get negative zero 792 jbr Ledit_case 793 794Le_blank_zero: 795 jbc ZEROBIT,%r4,Lpattern_inc # if zero 796 movzbl (%r3)+,%r11 # next byte is a count 797 jeql Ledit_case 798 subl2 %r11,%r5 # to back up over output and replace 799L200: 800 putfill # with fill character 801 sobgtr %r11,L200 802 jbr Ledit_case 803 804Le_adjust_input: 805 movzbl (%r3)+,%r0 # get count of nibbles from pattern 806 subl3 %r2,%r0,%r11 807 jgeq Ledit_case # if length of source is > this number 808L204: # discard digits in source 809 jlbc %r2,L206 # use low bit of length to choose nibble 810 bitb $0xf0,(%r10) # high nibble 811 jeql L208 812 setsignif # set significance and overflow if 813 setoverflow # wasted digit is non-zero 814 jbr L208 815L206: 816 bitb $0xf,(%r10) # low nibble 817 jeql L209 818 setsignif 819 setoverflow 820L209: 821 incl %r10 # increment to next byte 822L208: 823 decl %r2 # decrement source length 824 incl %r11 # continue till were out of excess 825 jlss L204 826 jbr Ledit_case 827 828Le_fill: 829 tstl %r1 # put (count in %r1) fill characters 830 jeql Ledit_case 831Le_fill_loop: 832 putfill 833 sobgtr %r1,Le_fill_loop 834 jbr Ledit_case 835 836Le_move: 837 tstl %r1 # move (count in %r1) characters 838 jeql Ledit_case # from source to destination 839L214: 840 jlbc %r2,L215 # read a nibble 841 extzv $4,$4,(%r10),%r11 842 jbr L216 843L215: 844 extzv $0,$4,(%r10),%r11 845 incl %r10 846L216: 847 decl %r2 # source length CAN go negative here... 848 tstl %r11 849 jeql L218 # if non-zero 850 setsignif # set significance 851L218: 852 jbc SIGNIFBIT,%r4,L219 # if significance set 853 addb3 $48,%r11,(%r5)+ # put 0 + digit into destination 854 jbr L220 855L219: # else put fill character 856 putfill 857L220: 858 sobgtr %r1,L214 859 jbr Ledit_case 860 861Le_float: # move with floating sign character 862 tstl %r1 863 jeql Ledit_case 864L221: 865 jlbc %r2,L222 866 extzv $4,$4,(%r10),%r11 867 jbr L223 868L222: 869 extzv $0,$4,(%r10),%r11 870 incl %r10 871L223: 872 decl %r2 # source length CAN go negative here... 873 tstl %r11 874 jeql L225 875 jbs SIGNIFBIT,%r4,L226 876 putsign 877L226: 878 setsignif 879L225: 880 jbc SIGNIFBIT,%r4,L227 881 addb3 $48,%r11,(%r5)+ 882 jbr L228 883L227: 884 putfill 885L228: 886 sobgtr %r1,L221 887 jbr Ledit_case 888 889 890 .align 1 891ALTENTRY(EMashp) 892 argb(1,%r11) # (1) scale (number to shift) == %r11 893 arguw(2,%r10) # (2) source length == %r10 894 argl(3,%r1) # (3) source address == %r1 895 argub(4,%r2) # (4) rounding factor == %r2 896 arguw(5,%r3) # (5) destination length == %r3 897 toarg(%r6,3)/* # arg3 holds register 6 from caller */ 898 argl(6,%r6) # (6) destination address == %r6 899/* 900 # we need arg6 for later 901 # arg1 is used for temporary storage 902 # arg2 holds "even or odd" destination length 903 # arg4 is used as general storage 904 # arg5 is used as general storage 905*/ 906 ashl $-1,%r3,%r0 # destination length is number of bytes 907 addl2 %r0,%r6 # destination address == least sig nibble 908 toarg(%r6,1) # save in arg1 spot for later 909 ashl $-1,%r10,%r0 910 addl2 %r0,%r1 # source address == least sig nibble 911 extzv $0,$4,(%r1),%r0 # determine sign of source 912 cmpl %r0,NEGATIVEalt 913 jeql Lashp_neg 914 cmpl %r0,NEGATIVE 915 jeql Lashp_neg 916 movb POSITIVE,(%r6) 917 jbr L245 918Lashp_neg: 919 movb NEGATIVE,(%r6) 920L245: 921 clrl arg2 # arg2 is 1 if dstlen is even, 0 if odd 922 blbs %r3,L246 923 incl arg2 924 bisl2 $1,%r3 # %r3<0> counts digits going into destination 925L246: # and is flip-flop for which nibble to 926 tstl %r11 # write in destination (1 = high, 0 = low) 927 jgeq Lashp_left # (it must start out odd) 928 addl2 %r11,%r10 # scale is negative (right shift) 929 jgeq Lashp_right 930 clrl %r10 # test for shifting whole number out 931 jbr Lashp_setround 932Lashp_right: 933 divl3 $2,%r11,%r0 934 addl2 %r0,%r1 # source address == MSNibble to be shifted off 935 jlbc %r11,L249 936 extzv $4,$4,(%r1),%r0 937 addl2 %r0,%r2 # round = last nibble to be shifted off + round 938 jbr Lashp_setround 939L249: 940 extzv $0,$4,(%r1),%r0 941 addl2 %r0,%r2 # round = last nibble to be shifted off + round 942Lashp_setround: # %r11<0> now is flip-flop for which nibble to 943 incl %r11 # read from source (1 == high, 0 == low) 944 cmpl %r2,$9 # set rounding factor to one if nibble shifted 945 jleq Lashp_noround # off + round argument was 10 or greater 946 movl $1,%r2 947 jbr Lashp_shift 948Lashp_zloop: 949 jlbs %r3,L257 # dont need to clear high nibble twice 950 clrb -(%r6) # clear low (and high) nib of next byte in dest 951L257: 952 sobgtr %r3,L258 # move to next nibble in destination, but 953 incl %r3 # dont go beyond the end. 954L258: 955 decl %r11 956Lashp_left: # while scale is positive 957 jneq Lashp_zloop 958 incl %r11 # %r11<0> is flip-plop ... (incl sets it to one) 959Lashp_noround: 960 clrl %r2 # no more rounding 961Lashp_shift: 962 clrl arg4 # arg4 will be used for result condition codes 963 tstl %r10 964 jeql Lashp_round 965Lashp_shloop: 966 jlbc %r11,L260 967 extzv $4,$4,(%r1),%r0 968 jbr L261 969L260: 970 decl %r1 971 extzv $0,$4,(%r1),%r0 972L261: 973 incl %r11 # flip the source nibble flip/flop 974 addl2 %r0,%r2 # round += next nibble 975 cmpl %r2,$10 # if round == 10 976 jneq L262 977 clrl arg5 # then result = 0 and round = 1 978 movl $1,%r2 979 jbr L263 980L262: # else 981 movl %r2,arg5 # store result and round = 0 982 clrl %r2 983L263: 984 bisl2 arg5,arg4 # remember if result was nonzero in arg4 985 decl %r3 # move to next nibble early to check 986 cmpl %r3,arg2 # if weve moved passed destination limits 987 jgeq Lashp_noovfl # test the result for possible overflow 988 movl arg2,%r3 # ignore zero nibbles 989 tstl arg5 # if the nibble was non-zero, overflow 990 jeql L265 991 jbr Lashp_overfl 992Lashp_noovfl: # else 993 jlbs %r3,L264 994 insv arg5,$4,$4,(%r6) # put the result into destination (high or low) 995 jbr L265 996L264: 997 movb arg5,-(%r6) 998L265: 999 sobgtr %r10,Lashp_shloop # loop for length of source 1000 1001Lashp_round: 1002 tstl %r2 # take care of round out of high nibble 1003 jeql Lashp_zeroround 1004 decl %r3 1005 cmpl %r3,arg2 # if weve moved passed destination limits 1006 jlss Lashp_overfl # then overflow 1007 jlbs %r3,L266 1008 insv arg5,$4,$4,(%r6) # put the round into destination (high or low) 1009 jbr Lashp_zeroround 1010L266: 1011 movb arg5,-(%r6) 1012 1013Lashp_zeroround: 1014 argl(1,%r10) # %r10 = address of destination LSNibble 1015 argl(6,%r3) # %r3 = address of destination MSNibble 1016 movl arg4,%r11 # %r11 = non-zero if destination == non-zero 1017 savepsl 1018 jbr L267 1019Lashp_zerofill: 1020 clrb -(%r6) # fill up MSNs of destination with zeros 1021L267: 1022 cmpl %r3,%r6 1023 jneq Lashp_zerofill 1024 extzv $0,$4,(%r10),%r0 # test for negative result 1025 cmpl %r0,NEGATIVE 1026 jneq Lashp_out 1027 mnegl %r11,%r11 1028 savepsl 1029 jneq Lashp_out # turn -0 into 0 1030 insv POSITIVE,$0,$4,(%r10) 1031Lashp_out: 1032 clrl %r0 1033 argl(3,%r6) # restore %r6 from stack 1034 return 1035Lashp_overfl: # do overflow 1036 clrl %r2 1037 overflowpsl 1038 jbr Lashp_out 1039 1040 1041 .align 1 1042ALTENTRY(EMcvtlp) 1043 arguw(2,%r10) # (2) destination length == %r10 1044 argl(3,%r3) # (3) destination address == %r3 1045 ashl $-1,%r10,%r10 1046 addl2 %r10,%r3 # destination address points to Least Sig byte 1047 incl %r10 # length is # of bytes, not nibbles 1048 argl(1,%r11) # (1) source == %r11 1049 savepsl 1050 jgeq Lcvtlp_pos 1051 movb NEGATIVE,(%r3) # source is negative 1052 divl3 $10,%r11,%r0 1053 mull3 $10,%r0,%r1 1054 subl3 %r11,%r1,%r2 # %r2 = source mod 10 1055 mnegl %r0,%r11 # source = -(source / 10) 1056 jbr Lcvtlp_cvt 1057Lcvtlp_pos: 1058 movb POSITIVE,(%r3) # source is non-negative 1059 divl3 $10,%r11,%r0 1060 mull3 $10,%r0,%r1 1061 subl3 %r1,%r11,%r2 # %r2 = source mod 10 1062 movl %r0,%r11 # source = source / 10 1063Lcvtlp_cvt: 1064 insv %r2,$4,$4,(%r3) # store least significant digit 1065 tstl %r11 1066 jeql Lcvtlp_zloop 1067Lcvtlp_loop: # while source is non-zero 1068 decl %r10 # and for length of destination ... 1069 jeql Lcvtlp_over 1070 divl3 $10,%r11,%r1 # %r1 = source / 10 1071 mull3 $10,%r1,%r0 1072 subl2 %r0,%r11 # source = source mod 10 1073 movb %r11,-(%r3) # store low "nibble" in next significant byte 1074 divl3 $10,%r1,%r11 # source = %r1 / 10 1075 mull3 $10,%r11,%r0 1076 subl2 %r0,%r1 # %r1 = source mod 10 1077 insv %r1,$4,$4,(%r3) # store high nibble 1078 tstl %r11 1079 jneq Lcvtlp_loop # quit if source becomes zero 1080Lcvtlp_zloop: # fill any remaining bytes with zeros 1081 decl %r10 1082 jeql Lcvtlp_out 1083 clrb -(%r3) 1084 jbr Lcvtlp_zloop 1085Lcvtlp_over: 1086 overflowpsl 1087Lcvtlp_out: 1088 clrl %r1 # %r0 is already zero 1089 clrl %r2 1090 return 1091 1092 1093 .align 1 1094ALTENTRY(EMcvtpl) 1095 arguw(1,%r11) # (1) source length == %r11 1096 argl(2,%r10) # (2) source address == %r10 1097 clrl %r3 # %r3 == destination 1098 movl %r10,%r1 # %r1 set up now for return 1099 ashl $-1,%r11,%r11 # source length is number of bytes 1100 jeql Lcvtpl_zero 1101Lcvtpl_loop: # for source length 1102 mull2 $10,%r3 # destination *= 10 1103 extzv $4,$4,(%r10),%r0 1104 addl2 %r0,%r3 # destination += high nibble 1105 mull2 $10,%r3 # destination *= 10 1106 extzv $0,$4,(%r10),%r0 1107 addl2 %r0,%r3 # destination += low nibble 1108 incl %r10 1109 sobgtr %r11,Lcvtpl_loop 1110Lcvtpl_zero: # least significant byte 1111 mull2 $10,%r3 1112 extzv $4,$4,(%r10),%r0 1113 addl2 %r0,%r3 # dest = 10 * dest + high nibble 1114 savepsl 1115 extzv $0,$4,(%r10),%r2 # test sign nibble 1116 cmpl %r2,NEGATIVE 1117 jeql Lcvtpl_neg 1118 cmpl %r2,NEGATIVEalt 1119 jneq Lcvtpl_out 1120Lcvtpl_neg: # source was negative - negate destination 1121 mnegl %r3,%r3 1122 savepsl 1123Lcvtpl_out: 1124 toarg(%r3,3) 1125 clrl %r0 1126 clrl %r2 1127 clrl %r3 1128 return 1129 1130 1131 .align 1 1132ALTENTRY(EMcvtps) 1133 return 1134 1135 1136 .align 1 1137ALTENTRY(EMcvtsp) 1138 return 1139 1140 1141 .align 1 1142ALTENTRY(EMaddp6) 1143 return 1144 1145 1146 .align 1 1147ALTENTRY(EMsubp4) 1148 return 1149 1150 1151 .align 1 1152ALTENTRY(EMsubp6) 1153 return 1154 1155 1156 .align 1 1157ALTENTRY(EMcvtpt) 1158 return 1159 1160 1161 .align 1 1162ALTENTRY(EMmulp) 1163 return 1164 1165 1166 .align 1 1167ALTENTRY(EMcvttp) 1168 return 1169 1170 1171 .align 1 1172ALTENTRY(EMdivp) 1173 return 1174 1175 1176 .align 1 1177ALTENTRY(EMcmpp3) 1178 return 1179 1180 1181 .align 1 1182ALTENTRY(EMcmpp4) 1183 return 1184 1185 1186 1187#ifdef notdef 1188/* 1189 * Emulation OpCode jump table: 1190 * ONLY GOES FROM 0xf8 (-8) TO 0x3B (59) 1191 */ 1192#define EMUTABLE 0x43 1193#define NOEMULATE .long noemulate 1194#define EMULATE(a) .long _EM/**/a 1195 .globl _C_LABEL(emJUMPtable) 1196_C_LABEL(emJUMPtable) 1197/* f8 */ EMULATE(ashp); EMULATE(cvtlp); NOEMULATE; NOEMULATE 1198/* fc */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE 1199/* 00 */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE 1200/* 04 */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE 1201/* 08 */ EMULATE(cvtps); EMULATE(cvtsp); NOEMULATE; EMULATE(crc) 1202/* 0c */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE 1203/* 10 */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE 1204/* 14 */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE 1205/* 18 */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE 1206/* 1c */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE 1207/* 20 */ EMULATE(addp4); EMULATE(addp6); EMULATE(subp4); EMULATE(subp6) 1208/* 24 */ EMULATE(cvtpt); EMULATE(mulp); EMULATE(cvttp); EMULATE(divp) 1209/* 28 */ NOEMULATE; EMULATE(cmpc3); EMULATE(scanc); EMULATE(spanc) 1210/* 2c */ NOEMULATE; EMULATE(cmpc5); EMULATE(movtc); EMULATE(movtuc) 1211/* 30 */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE 1212/* 34 */ EMULATE(movp); EMULATE(cmpp3); EMULATE(cvtpl); EMULATE(cmpp4) 1213/* 38 */ EMULATE(editpc); EMULATE(matchc); EMULATE(locc); EMULATE(skpc) 1214 1215/* 1216 * The following is called with the stack set up as follows: 1217 * 1218 * (%sp): Opcode 1219 * 4(%sp): Instruction PC 1220 * 8(%sp): Operand 1 1221 * 12(%sp): Operand 2 1222 * 16(%sp): Operand 3 1223 * 20(%sp): Operand 4 1224 * 24(%sp): Operand 5 1225 * 28(%sp): Operand 6 1226 * 32(%sp): Operand 7 (unused) 1227 * 36(%sp): Operand 8 (unused) 1228 * 40(%sp): Return PC 1229 * 44(%sp): Return PSL 1230 * 48(%sp): TOS before instruction 1231 * 1232 * Each individual routine is called with the stack set up as follows: 1233 * 1234 * (%sp): Return address of trap handler 1235 * 4(%sp): Opcode (will get return PSL) 1236 * 8(%sp): Instruction PC 1237 * 12(%sp): Operand 1 1238 * 16(%sp): Operand 2 1239 * 20(%sp): Operand 3 1240 * 24(%sp): Operand 4 1241 * 28(%sp): Operand 5 1242 * 32(%sp): Operand 6 1243 * 36(%sp): saved register 11 1244 * 40(%sp): saved register 10 1245 * 44(%sp): Return PC 1246 * 48(%sp): Return PSL 1247 * 52(%sp): TOS before instruction 1248 */ 1249 1250SCBVEC(emulate): 1251 movl %r11,32(%sp) # save register %r11 in unused operand 1252 movl %r10,36(%sp) # save register %r10 in unused operand 1253 cvtbl (%sp),%r10 # get opcode 1254 addl2 $8,%r10 # shift negative opcodes 1255 subl3 %r10,$EMUTABLE,%r11 # forget it if opcode is out of range 1256 bcs noemulate 1257 movl _C_LABEL(emJUMPtable)[%r10],%r10 1258 # call appropriate emulation routine 1259 jsb (%r10) # routines put return values into regs 0-5 1260 movl 32(%sp),%r11 # restore register %r11 1261 movl 36(%sp),%r10 # restore register %r10 1262 insv (%sp),$0,$4,44(%sp) # and condition codes in Opcode spot 1263 addl2 $40,%sp # adjust stack for return 1264 rei 1265noemulate: 1266 addl2 $48,%sp # adjust stack for 1267 .word 0xffff # "reserved instruction fault" 1268SCBVEC(emulateFPD): 1269 .word 0xffff # "reserved instruction fault" 1270#endif 1271