/* $NetBSD: emulate.S,v 1.5 2005/12/11 12:19:36 christos Exp $ */ /* * Copyright (c) 1986, 1987 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Mt. Xinu. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)emulate.s 7.5 (Berkeley) 6/28/90 */ #include /* * String instruction emulation - MicroVAX only. These routines are called * from locore.s when an "emulate" fault occurs on the MicroVAX. They are * called with the stack set up as follows: * * (%sp): Return address of trap handler * 4(%sp): Instruction Opcode (also holds PSL result from emulator) * 8(%sp): Instruction PC * 12(%sp): Operand 1 * 16(%sp): Operand 2 * 20(%sp): Operand 3 * 24(%sp): Operand 4 * 28(%sp): Operand 5 * 32(%sp): Operand 6 * 36(%sp): old Register 11 * 40(%sp): old Register 10 * 44(%sp): Return PC * 48(%sp): Return PSL * 52(%sp): TOS before instruction * * R11 and %r10 are available for use. If any routine needs to use %r9-%r1 * they need to save them first (unless those registers are SUPPOSED to be * messed with by the "instruction"). These routines leave their results * in registers 0-5 explicitly, as needed, and use the macros defined below * to link up with calling routine. */ #define return rsb #define savepsl movpsl 4(%sp) #define setpsl(reg) movl reg,4(%sp) #define overflowpsl movl $2,4(%sp) #define arg1 12(%sp) #define arg2 16(%sp) #define arg3 20(%sp) #define arg4 24(%sp) #define arg5 28(%sp) #define arg6 32(%sp) #define argub(num,reg) movzbl 8+4*num(%sp),reg #define arguw(num,reg) movzwl 8+4*num(%sp),reg #define argul(num,reg) movl 8+4*num(%sp),reg #define argb(num,reg) cvtbl 8+4*num(%sp),reg #define argw(num,reg) cvtwl 8+4*num(%sp),reg #define argl(num,reg) movl 8+4*num(%sp),reg #define toarg(reg,num) movl reg,8+4*num(%sp) .text .align 1 ALTENTRY(EMcrc) argl(1,%r11) # (1) table address == %r11 argl(2,%r0) # (2) initial crc == %r0 argl(4,%r3) # (4) source address == %r3 arguw(3,%r2) # (3) source length == %r2 jeql Lcrc_out Lcrc_loop: xorb2 (%r3)+,%r0 extzv $0,$4,%r0,%r10 extzv $4,$28,%r0,%r1 xorl3 %r1,(%r11)[%r10],%r0 extzv $0,$4,%r0,%r10 extzv $4,$28,%r0,%r1 xorl3 %r1,(%r11)[%r10],%r0 sobgtr %r2,Lcrc_loop tstl %r0 Lcrc_out: savepsl clrl %r1 return .align 1 ALTENTRY(EMmovtc) arguw(1,%r0) # (1) source length == %r0 argl(2,%r1) # (2) source address == %r1 argub(3,%r11) # (3) fill character == %r11 argl(4,%r3) # (4) table address == %r3 argl(6,%r5) # (6) destination address == %r5 arguw(5,%r4) # (5) destination length == %r4 jeql Lmovtc_out Lmovtc_loop: tstl %r0 jeql Lmovtc_2loop movzbl (%r1)+,%r2 movb (%r3)[%r2],(%r5)+ decl %r0 sobgtr %r4,Lmovtc_loop jbr Lmovtc_out Lmovtc_2loop: movb %r11,(%r5)+ sobgtr %r4,Lmovtc_2loop Lmovtc_out: cmpw arg1,arg5 savepsl clrl %r2 return .align 1 ALTENTRY(EMmovtuc) arguw(1,%r0) # (1) source length == %r0 argl(2,%r1) # (2) source address == %r1 argub(3,%r11) # (3) escape character == %r11 argl(4,%r3) # (4) table address == %r3 argl(6,%r5) # (6) destination address == %r5 arguw(5,%r4) # (5) destination length == %r4 jeql Lmovtuc_out1 Lmovtuc_loop: tstl %r0 jeql Lmovtuc_out1 movzbl (%r1),%r2 movzbl (%r3)[%r2],%r2 cmpl %r2,%r11 jeql Lmovtuc_out2 movzbl (%r1)+,%r2 movb (%r3)[%r2],(%r5)+ decl %r0 sobgtr %r4,Lmovtuc_loop Lmovtuc_out1: clrl %r2 # clear V-bit brb Lmovtuc_out Lmovtuc_out2: movl $2,%r2 # set V-bit Lmovtuc_out: cmpw arg1,arg5 savepsl bisl2 %r2,4(%sp) # merge V-bit into psl clrl %r2 return .align 1 ALTENTRY(EMmatchc) argl(2,%r10) # (2) substring address == %r10 arguw(3,%r2) # (3) source length == %r2 argl(4,%r3) # (4) source address == %r3 arguw(1,%r11) # (1) substring length == %r11 jeql Lmatchc_out # temp source address == %r1 addl2 %r10,%r11 # temp substring address == %r0 tstl %r2 jeql Lmatchc_out Lmatchc_loop: cmpb (%r10),(%r3) jneq Lmatchc_fail movl %r3,%r1 movl %r10,%r0 Lmatchc_2loop: cmpl %r0,%r11 jeql Lmatchc_succ cmpb (%r0)+,(%r1)+ jeql Lmatchc_2loop Lmatchc_fail: incl %r3 sobgtr %r2,Lmatchc_loop movl %r10,%r1 subl3 %r10,%r11,%r0 jbr Lmatchc_out Lmatchc_succ: movl %r1,%r3 movl %r11,%r1 clrl %r0 Lmatchc_out: savepsl return .align 1 ALTENTRY(EMspanc) argl(2,%r1) # (2) string address == %r1 argub(4,%r2) # (4) character-mask == %r2 argl(3,%r3) # (3) table address == %r3 arguw(1,%r0) # (1) string length == %r0 jeql Lspanc_out Lspanc_loop: movzbl (%r1),%r11 mcomb (%r3)[%r11],%r11 bicb3 %r11,%r2,%r11 jeql Lspanc_out incl %r1 sobgtr %r0,Lspanc_loop Lspanc_out: savepsl clrl %r2 return .align 1 ALTENTRY(EMscanc) argl(2,%r1) # (2) string address == %r1 argub(4,%r2) # (4) character-mask == %r2 argl(3,%r3) # (3) table address == %r3 arguw(1,%r0) # (1) string length == %r0 jeql Lscanc_out Lscanc_loop: movzbl (%r1),%r11 mcomb (%r3)[%r11],%r11 bicb3 %r11,%r2,%r11 jneq Lscanc_out incl %r1 sobgtr %r0,Lscanc_loop Lscanc_out: savepsl clrl %r2 return .align 1 ALTENTRY(EMskpc) argub(1,%r11) # (1) character == %r11 argl(3,%r1) # (3) string address == %r1 arguw(2,%r0) # (2) string length == %r0 jeql Lskpc_out # forget zero length strings Lskpc_loop: cmpb (%r1),%r11 jneq Lskpc_out incl %r1 sobgtr %r0,Lskpc_loop Lskpc_out: tstl %r0 # be sure of condition codes savepsl return .align 1 ALTENTRY(EMlocc) argub(1,%r11) # (1) character == %r11 argl(3,%r1) # (3) string address == %r1 arguw(2,%r0) # (2) string length == %r0 jeql Lskpc_out # forget zero length strings Llocc_loop: cmpb (%r1),%r11 jeql Llocc_out incl %r1 sobgtr %r0,Llocc_loop Llocc_out: tstl %r0 # be sure of condition codes savepsl return .align 1 ALTENTRY(EMcmpc3) argl(2,%r1) # (2) string1 address == %r1 argl(3,%r3) # (3) string2 address == %r3 arguw(1,%r0) # (1) strings length == %r0 jeql Lcmpc3_out Lcmpc3_loop: cmpb (%r1),(%r3) jneq Lcmpc3_out incl %r1 incl %r3 sobgtr %r0,Lcmpc3_loop Lcmpc3_out: savepsl movl %r0,%r2 return .align 1 ALTENTRY(EMcmpc5) argl(2,%r1) # (2) string1 address == %r1 argub(3,%r11) # (1) fill character == %r11 arguw(4,%r2) # (1) string2 length == %r2 argl(5,%r3) # (3) string2 address == %r3 arguw(1,%r0) # (1) string1 length == %r0 jeql Lcmpc5_str2 Lcmpc5_loop: tstl %r2 jeql Lcmpc5_str1loop cmpb (%r1),(%r3) jneq Lcmpc5_out incl %r1 incl %r3 decl %r2 sobgtr %r0,Lcmpc5_loop Lcmpc5_str2: tstl %r2 jeql Lcmpc5_out Lcmpc5_str2loop: cmpb %r11,(%r3) jneq Lcmpc5_out incl %r3 sobgtr %r2,Lcmpc5_str2loop jbr Lcmpc5_out Lcmpc5_str1loop: cmpb (%r1),%r11 jneq Lcmpc5_out incl %r1 sobgtr %r0,Lcmpc5_str1loop Lcmpc5_out: savepsl return /* * Packed Decimal string operations */ #define POSITIVE $12 #define NEGATIVE $13 #define NEGATIVEalt $11 .align 1 ALTENTRY(EMaddp4) toarg(%r9,6) # save register %r9 in arg6 spot arguw(1,%r11) # (1) source length == %r11 argl(2,%r10) # (2) source address == %r10 arguw(3,%r9) # (3) destination length == %r9 argl(4,%r3) # (4) destination address == %r3 ashl $-1,%r11,%r11 addl2 %r11,%r10 # source address of LSNibble incl %r11 # source length is in bytes ashl $-1,%r9,%r9 addl2 %r9,%r3 # %r3 = destination address of LSNibble incl %r9 # destination length is in bytes toarg(%r3,5) extzv $0,$4,(%r3),%r2 # set standard +/- indicators in destination cmpl %r2,NEGATIVE jeql L112 cmpl %r2,NEGATIVEalt jeql L111 insv POSITIVE,$0,$4,(%r3) jbr L112 L111: insv NEGATIVE,$0,$4,(%r3) L112: extzv $0,$4,(%r10),%r2 # %r2 = standard +/- of source cmpl %r2,NEGATIVE jeql L114 cmpl %r2,NEGATIVEalt jeql L113 movl POSITIVE,%r2 jbr L114 L113: movl NEGATIVE,%r2 L114: cmpl %r11,%r9 # if source is longer than destination jleq L115 movl %r9,%r11 # set source length == destination length L115: extzv $4,$4,(%r3),%r9 # %r9 = LSDigit of destination extzv $4,$4,(%r10),%r1 # %r1 = LSDigit of source extzv $0,$4,(%r3),%r0 cmpl %r0,%r2 # if signs of operands are not equal jeql Laddp4_same # do a subtraction clrl %r2 # %r2 is non-zero if result is non-zero subl2 %r1,%r9 # %r9 = "addition" of operands high nibble jbr L119 # jump into addition loop Laddp4_diff_loop: decl %r3 extzv $0,$4,(%r3),%r0 addl2 %r0,%r1 # %r1 = carry + next (low) nibble of source decl %r10 extzv $0,$4,(%r10),%r0 subl2 %r0,%r1 # %r1 -= next (low) nibble of destination jgeq L121 # if negative result mnegl $1,%r9 # %r9 == carry = -1 addl2 $10,%r1 # %r1 == result += 10 jbr L122 # else L121: clrl %r9 # %r9 == carry = 0 L122: insv %r1,$0,$4,(%r3) # store result low nibble bisl2 %r1,%r2 extzv $4,$4,(%r3),%r0 addl2 %r0,%r9 # %r9 = carry + next (high) nibble of source extzv $4,$4,(%r10),%r0 subl2 %r0,%r9 # %r9 -= next (high) nibble of destination L119: jgeq L117 # if negative result mnegl $1,%r1 # %r1 == carry = -1 addl2 $10,%r9 # %r9 == result += 10 jbr L118 # else L117: clrl %r1 # %r1 == carry = 0 L118: insv %r9,$4,$4,(%r3) # store result high nibble bisl2 %r9,%r2 # %r2 is non-zero if result is non-zero decl %r11 # while (--source length) jneq Laddp4_diff_loop argl(4,%r10) # %r10 = address of destination MSNibble jbr Laddp4_diff_carry Laddp4_diff_carlop: decl %r3 extzv $0,$4,(%r3),%r0 addl2 %r0,%r1 # %r1 == carry += next (low) nibble jgeq L127 # if less than zero movl %r1,%r9 # %r9 == carry (must be -1) movl $9,%r1 # %r1 == result = 9 jbr L128 L127: # else clrl %r9 # %r9 == carry = 0 L128: insv %r1,$0,$4,(%r3) # store result bisl2 %r1,%r2 extzv $4,$4,(%r3),%r0 addl2 %r0,%r9 # %r9 == carry += next (high) nibble jgeq L129 # if less than zero movl %r9,%r1 # %r1 == carry (must be -1) movl $9,%r9 # %r9 == result = 9 jbr L130 L129: clrl %r1 L130: insv %r9,$4,$4,(%r3) # store result bisl2 %r9,%r2 Laddp4_diff_carry: cmpl %r3,%r10 jneq Laddp4_diff_carlop tstl %r1 # if carry out of MSN then fix up result jeql Laddp4_add_done argl(5,%r3) # %r3 == address of LSN of destination extzv $0,$4,(%r3),%r0 cmpl %r0,NEGATIVE # switch sign of result jneq L132 insv POSITIVE,$0,$4,(%r3) jbr L133 L132: insv NEGATIVE,$0,$4,(%r3) L133: extzv $4,$4,(%r3),%r0 # normalize result (carry out of MSN into LSN) subl3 %r0,$10,%r9 # %r9 = 10 - destination LSNibble jbr L134 L137: movl $9,%r1 Laddp4_diff_norm: insv %r9,$4,$4,(%r3) cmpl %r3,%r10 # while (not at MSNibble) jeql Laddp4_add_done decl %r3 extzv $0,$4,(%r3),%r0 # low nibble = (9 + carry) - low nibble subl2 %r0,%r1 cmpl %r1,$9 jleq L135 clrl %r1 movl $10,%r9 jbr L136 L135: movl $9,%r9 L136: insv %r1,$0,$4,(%r3) extzv $4,$4,(%r3),%r0 # high nibble = (9 + carry) - high nibble subl2 %r0,%r9 L134: cmpl %r9,$9 jleq L137 clrl %r9 movl $10,%r1 jbr Laddp4_diff_norm Laddp4_same: # operands are of the same sign clrl %r2 addl2 %r1,%r9 jbr L139 Laddp4_same_loop: decl %r3 extzv $0,$4,(%r3),%r0 addl2 %r0,%r1 # %r1 == carry += next (low) nibble of dest decl %r10 extzv $0,$4,(%r10),%r0 addl2 %r0,%r1 # %r1 += next (low) nibble of source cmpl %r1,$9 # if result > 9 jleq L141 movl $1,%r9 # %r9 == carry = 1 subl2 $10,%r1 # %r1 == result -= 10 jbr L142 L141: # else clrl %r9 # %r9 == carry = 0 L142: insv %r1,$0,$4,(%r3) # store result bisl2 %r1,%r2 extzv $4,$4,(%r10),%r0 addl2 %r0,%r9 # ditto for high nibble extzv $4,$4,(%r3),%r0 addl2 %r0,%r9 L139: cmpl %r9,$9 jleq L143 movl $1,%r1 subl2 $10,%r9 jbr L144 L143: clrl %r1 L144: insv %r9,$4,$4,(%r3) bisl2 %r9,%r2 sobgtr %r11,Laddp4_same_loop # while (--source length) argl(4,%r10) # %r10 = destination address of MSNibble jbr Laddp4_same_carry Laddp4_same_cloop: decl %r3 extzv $0,$4,(%r3),%r0 # propagate carry up to MSNibble of destination addl2 %r0,%r1 cmpl %r1,$10 jneq L147 movl $1,%r9 clrl %r1 jbr L148 L147: clrl %r9 L148: insv %r1,$0,$4,(%r3) bisl2 %r1,%r2 extzv $4,$4,(%r3),%r0 addl2 %r0,%r9 cmpl %r9,$10 jneq L149 movl $1,%r1 clrl %r9 jbr L150 L149: clrl %r1 L150: insv %r9,$4,$4,(%r3) bisl2 %r9,%r2 Laddp4_same_carry: cmpl %r3,%r10 jneq Laddp4_same_cloop Laddp4_add_done: argl(5,%r3) # %r3 = destination address of LSNibble tstl %r2 # if zero result jneq L151 savepsl # remember that for condition codes insv POSITIVE,$0,$4,(%r3) # make sure sign of result is positive jbr Laddp4_out L151: # else extzv $0,$4,(%r3),%r0 cmpl %r0,NEGATIVE # if result is negative jneq Laddp4_out mnegl %r2,%r2 # remember THAT in Cond Codes savepsl Laddp4_out: argl(4,%r3) argl(2,%r1) clrl %r0 clrl %r2 argl(6,%r9) # restore %r9 from stack return .align 1 ALTENTRY(EMmovp) arguw(1,%r11) # (1) string length == %r11 argl(2,%r10) # (1) source address == %r10 argl(3,%r3) # (1) destination address == %r3 # we will need arg2 and arg3 later clrl %r2 # %r2 == non-zero if source is non-zero ashl $-1,%r11,%r11 # length is number of bytes, not nibbles jeql Lmovp_zlen Lmovp_copy: bisb2 (%r10),%r2 # keep track of non-zero source movb (%r10)+,(%r3)+ # move two nibbles sobgtr %r11,Lmovp_copy # loop for length of source Lmovp_zlen: extzv $4,$4,(%r10),%r0 # look at least significant nibble bisl2 %r0,%r2 extzv $0,$4,(%r10),%r0 # check sign nibble cmpl %r0,NEGATIVEalt jeql Lmovp_neg cmpl %r0,NEGATIVE jneq Lmovp_pos Lmovp_neg: # source was negative mnegl %r2,%r2 Lmovp_pos: tstl %r2 # set condition codes savepsl jeql Lmovp_zero movb (%r10),(%r3) # move last byte if non-zero result jbr Lmovp_out Lmovp_zero: movb POSITIVE,(%r3) # otherwise, make result zero and positive Lmovp_out: clrl %r0 argl(2,%r1) clrl %r2 argl(3,%r3) return /* * Definitions for Editpc instruction * * Here are the commands and their corresponding hex values: * * EPend 0x00 * EPend_float 0x01 * EPclear_signif 0x02 * EPset_signif 0x03 * EPstore_sign 0x04 * EPload_fill 0x40 * EPload_sign 0x41 * EPload_plus 0x42 * EPload_minus 0x43 * EPinsert 0x44 * EPblank_zero 0x45 * EPreplace_sign 0x46 * EPadjust_input 0x47 * EPfill 0x80 * EPmove 0x90 * EPfloat 0xa0 * * * %r4 is carved up as follows: * * ------------------------------------------- * | N Z V C | * ------------------------------------------- * * fill character is stuffed into arg5 space * sign character is stuffed into arg6 space */ #define SIGNIFBIT $0 #define setsignif bisl2 $1,%r4 #define clsignif bicl2 $1,%r4 #define OVERFLOWBIT $1 #define setoverflow bisl2 $2,%r4 #define cloverflow bicl2 $2,%r4 #define ZEROBIT $2 #define setzero bisl2 $4,%r4 #define clzero bicl2 $4,%r4 #define NEGATIVEBIT $3 #define setnegative bisl2 $8,%r4 #define clnegative bicl2 $8,%r4 #define putfill movb arg5,(%r5)+ #define setfill(reg) movb reg,arg5 #define putsign movb arg6,(%r5)+ #define setsign(reg) movb reg,arg6 .align 1 ALTENTRY(EMeditpc) arguw(1,%r11) # (1) source length == %r11 argl(2,%r10) # (2) source address == %r10 argl(3,%r3) # (3) pattern address == %r3 argl(4,%r5) # (4) destination address == %r5 /* # we will need arg1 and arg2 later */ /* # arg5 and arg6 are used for fill and sign - %r0 is free */ setfill($32) # fill character is ' ' setsign($32) # sign character is ' ' clrl %r4 # clear flags ashl $-1,%r11,%r11 # source length / 2 addl3 %r11,%r10,%r2 extzv $4,$4,(%r2),%r1 # %r1 == least significant nibble of source L169: cmpl %r2,%r10 jeql L170 tstb -(%r2) # loop over source packed decimal number jeql L169 incl %r1 # %r1 is non-zero if source is non-zero L170: addl3 %r11,%r10,%r2 tstl %r1 jeql L172 # source is zero - set flags extzv $0,$4,(%r2),%r11 cmpl %r11,NEGATIVEalt jeql L9998 # source is negative - set sign and flags cmpl %r11,NEGATIVE jneq L175 L9998: setnegative setsign($45) # sign character is '-' jbr L175 L172: setzero L175: arguw(1,%r2) # (1) source length == %r2 Ledit_case: movzbl (%r3)+,%r11 # get next edit command (pattern) cmpl %r11,$128 jlss L180 extzv $0,$4,%r11,%r1 # command has a "count" arg - into %r1 ashl $-4,%r11,%r11 # and shift over L180: jbc $6,%r11,L181 # "shift" those commands > 64 to 16 and up subl2 $48,%r11 L181: caseb %r11,$0,$0x18 # "do" the command # %r11 is available for use, %r1 has "count" in it Lcaseb_label: .word Le_end - Lcaseb_label # 00 .word Le_end_float - Lcaseb_label # 01 .word Le_clear_signif - Lcaseb_label # 02 .word Le_set_signif - Lcaseb_label # 03 .word Le_store_sign - Lcaseb_label # 04 .word Le_end - Lcaseb_label # 05 .word Le_end - Lcaseb_label # 06 .word Le_end - Lcaseb_label # 07 .word Le_fill - Lcaseb_label # 80 .word Le_move - Lcaseb_label # 90 .word Le_float - Lcaseb_label # a0 .word Le_end - Lcaseb_label # b0 .word Le_end - Lcaseb_label # c0 .word Le_end - Lcaseb_label # d0 .word Le_end - Lcaseb_label # e0 .word Le_end - Lcaseb_label # f0 .word Le_load_fill - Lcaseb_label # 40 .word Le_load_sign - Lcaseb_label # 41 .word Le_load_plus - Lcaseb_label # 42 .word Le_load_minus - Lcaseb_label # 43 .word Le_insert - Lcaseb_label # 44 .word Le_blank_zero - Lcaseb_label # 45 .word Le_replace_sign - Lcaseb_label # 46 .word Le_adjust_input - Lcaseb_label # 47 Le_end: arguw(1,%r0) argl(2,%r1) clrl %r2 decl %r3 setpsl(%r4) clrl %r4 return Le_end_float: jbs SIGNIFBIT,%r4,Ledit_case # if significance not set putsign # drop in the sign # fall into... Le_set_signif: setsignif jbr Ledit_case Le_clear_signif: clsignif jbr Ledit_case Le_store_sign: putsign jbr Ledit_case Le_load_fill: setfill((%r3)+) jbr Ledit_case Le_load_plus: jbs NEGATIVEBIT,%r4,Lpattern_inc # if non-negative # fall into... Le_load_sign: setsign((%r3)+) jbr Ledit_case Le_load_minus: jbs NEGATIVEBIT,%r4,Le_load_sign # if negative load the sign incl %r3 # else increment pattern jbr Ledit_case Le_insert: jbc SIGNIFBIT,%r4,L196 # if significance set, put next byte movb (%r3)+,(%r5)+ jbr Ledit_case L196: # else put in fill character putfill # and throw away character in pattern Le_replace_sign: # we dont do anything with Lpattern_inc: # replace sign cause we dont incl %r3 # get negative zero jbr Ledit_case Le_blank_zero: jbc ZEROBIT,%r4,Lpattern_inc # if zero movzbl (%r3)+,%r11 # next byte is a count jeql Ledit_case subl2 %r11,%r5 # to back up over output and replace L200: putfill # with fill character sobgtr %r11,L200 jbr Ledit_case Le_adjust_input: movzbl (%r3)+,%r0 # get count of nibbles from pattern subl3 %r2,%r0,%r11 jgeq Ledit_case # if length of source is > this number L204: # discard digits in source jlbc %r2,L206 # use low bit of length to choose nibble bitb $0xf0,(%r10) # high nibble jeql L208 setsignif # set significance and overflow if setoverflow # wasted digit is non-zero jbr L208 L206: bitb $0xf,(%r10) # low nibble jeql L209 setsignif setoverflow L209: incl %r10 # increment to next byte L208: decl %r2 # decrement source length incl %r11 # continue till were out of excess jlss L204 jbr Ledit_case Le_fill: tstl %r1 # put (count in %r1) fill characters jeql Ledit_case Le_fill_loop: putfill sobgtr %r1,Le_fill_loop jbr Ledit_case Le_move: tstl %r1 # move (count in %r1) characters jeql Ledit_case # from source to destination L214: jlbc %r2,L215 # read a nibble extzv $4,$4,(%r10),%r11 jbr L216 L215: extzv $0,$4,(%r10),%r11 incl %r10 L216: decl %r2 # source length CAN go negative here... tstl %r11 jeql L218 # if non-zero setsignif # set significance L218: jbc SIGNIFBIT,%r4,L219 # if significance set addb3 $48,%r11,(%r5)+ # put 0 + digit into destination jbr L220 L219: # else put fill character putfill L220: sobgtr %r1,L214 jbr Ledit_case Le_float: # move with floating sign character tstl %r1 jeql Ledit_case L221: jlbc %r2,L222 extzv $4,$4,(%r10),%r11 jbr L223 L222: extzv $0,$4,(%r10),%r11 incl %r10 L223: decl %r2 # source length CAN go negative here... tstl %r11 jeql L225 jbs SIGNIFBIT,%r4,L226 putsign L226: setsignif L225: jbc SIGNIFBIT,%r4,L227 addb3 $48,%r11,(%r5)+ jbr L228 L227: putfill L228: sobgtr %r1,L221 jbr Ledit_case .align 1 ALTENTRY(EMashp) argb(1,%r11) # (1) scale (number to shift) == %r11 arguw(2,%r10) # (2) source length == %r10 argl(3,%r1) # (3) source address == %r1 argub(4,%r2) # (4) rounding factor == %r2 arguw(5,%r3) # (5) destination length == %r3 toarg(%r6,3)/* # arg3 holds register 6 from caller */ argl(6,%r6) # (6) destination address == %r6 /* # we need arg6 for later # arg1 is used for temporary storage # arg2 holds "even or odd" destination length # arg4 is used as general storage # arg5 is used as general storage */ ashl $-1,%r3,%r0 # destination length is number of bytes addl2 %r0,%r6 # destination address == least sig nibble toarg(%r6,1) # save in arg1 spot for later ashl $-1,%r10,%r0 addl2 %r0,%r1 # source address == least sig nibble extzv $0,$4,(%r1),%r0 # determine sign of source cmpl %r0,NEGATIVEalt jeql Lashp_neg cmpl %r0,NEGATIVE jeql Lashp_neg movb POSITIVE,(%r6) jbr L245 Lashp_neg: movb NEGATIVE,(%r6) L245: clrl arg2 # arg2 is 1 if dstlen is even, 0 if odd blbs %r3,L246 incl arg2 bisl2 $1,%r3 # %r3<0> counts digits going into destination L246: # and is flip-flop for which nibble to tstl %r11 # write in destination (1 = high, 0 = low) jgeq Lashp_left # (it must start out odd) addl2 %r11,%r10 # scale is negative (right shift) jgeq Lashp_right clrl %r10 # test for shifting whole number out jbr Lashp_setround Lashp_right: divl3 $2,%r11,%r0 addl2 %r0,%r1 # source address == MSNibble to be shifted off jlbc %r11,L249 extzv $4,$4,(%r1),%r0 addl2 %r0,%r2 # round = last nibble to be shifted off + round jbr Lashp_setround L249: extzv $0,$4,(%r1),%r0 addl2 %r0,%r2 # round = last nibble to be shifted off + round Lashp_setround: # %r11<0> now is flip-flop for which nibble to incl %r11 # read from source (1 == high, 0 == low) cmpl %r2,$9 # set rounding factor to one if nibble shifted jleq Lashp_noround # off + round argument was 10 or greater movl $1,%r2 jbr Lashp_shift Lashp_zloop: jlbs %r3,L257 # dont need to clear high nibble twice clrb -(%r6) # clear low (and high) nib of next byte in dest L257: sobgtr %r3,L258 # move to next nibble in destination, but incl %r3 # dont go beyond the end. L258: decl %r11 Lashp_left: # while scale is positive jneq Lashp_zloop incl %r11 # %r11<0> is flip-plop ... (incl sets it to one) Lashp_noround: clrl %r2 # no more rounding Lashp_shift: clrl arg4 # arg4 will be used for result condition codes tstl %r10 jeql Lashp_round Lashp_shloop: jlbc %r11,L260 extzv $4,$4,(%r1),%r0 jbr L261 L260: decl %r1 extzv $0,$4,(%r1),%r0 L261: incl %r11 # flip the source nibble flip/flop addl2 %r0,%r2 # round += next nibble cmpl %r2,$10 # if round == 10 jneq L262 clrl arg5 # then result = 0 and round = 1 movl $1,%r2 jbr L263 L262: # else movl %r2,arg5 # store result and round = 0 clrl %r2 L263: bisl2 arg5,arg4 # remember if result was nonzero in arg4 decl %r3 # move to next nibble early to check cmpl %r3,arg2 # if weve moved passed destination limits jgeq Lashp_noovfl # test the result for possible overflow movl arg2,%r3 # ignore zero nibbles tstl arg5 # if the nibble was non-zero, overflow jeql L265 jbr Lashp_overfl Lashp_noovfl: # else jlbs %r3,L264 insv arg5,$4,$4,(%r6) # put the result into destination (high or low) jbr L265 L264: movb arg5,-(%r6) L265: sobgtr %r10,Lashp_shloop # loop for length of source Lashp_round: tstl %r2 # take care of round out of high nibble jeql Lashp_zeroround decl %r3 cmpl %r3,arg2 # if weve moved passed destination limits jlss Lashp_overfl # then overflow jlbs %r3,L266 insv arg5,$4,$4,(%r6) # put the round into destination (high or low) jbr Lashp_zeroround L266: movb arg5,-(%r6) Lashp_zeroround: argl(1,%r10) # %r10 = address of destination LSNibble argl(6,%r3) # %r3 = address of destination MSNibble movl arg4,%r11 # %r11 = non-zero if destination == non-zero savepsl jbr L267 Lashp_zerofill: clrb -(%r6) # fill up MSNs of destination with zeros L267: cmpl %r3,%r6 jneq Lashp_zerofill extzv $0,$4,(%r10),%r0 # test for negative result cmpl %r0,NEGATIVE jneq Lashp_out mnegl %r11,%r11 savepsl jneq Lashp_out # turn -0 into 0 insv POSITIVE,$0,$4,(%r10) Lashp_out: clrl %r0 argl(3,%r6) # restore %r6 from stack return Lashp_overfl: # do overflow clrl %r2 overflowpsl jbr Lashp_out .align 1 ALTENTRY(EMcvtlp) arguw(2,%r10) # (2) destination length == %r10 argl(3,%r3) # (3) destination address == %r3 ashl $-1,%r10,%r10 addl2 %r10,%r3 # destination address points to Least Sig byte incl %r10 # length is # of bytes, not nibbles argl(1,%r11) # (1) source == %r11 savepsl jgeq Lcvtlp_pos movb NEGATIVE,(%r3) # source is negative divl3 $10,%r11,%r0 mull3 $10,%r0,%r1 subl3 %r11,%r1,%r2 # %r2 = source mod 10 mnegl %r0,%r11 # source = -(source / 10) jbr Lcvtlp_cvt Lcvtlp_pos: movb POSITIVE,(%r3) # source is non-negative divl3 $10,%r11,%r0 mull3 $10,%r0,%r1 subl3 %r1,%r11,%r2 # %r2 = source mod 10 movl %r0,%r11 # source = source / 10 Lcvtlp_cvt: insv %r2,$4,$4,(%r3) # store least significant digit tstl %r11 jeql Lcvtlp_zloop Lcvtlp_loop: # while source is non-zero decl %r10 # and for length of destination ... jeql Lcvtlp_over divl3 $10,%r11,%r1 # %r1 = source / 10 mull3 $10,%r1,%r0 subl2 %r0,%r11 # source = source mod 10 movb %r11,-(%r3) # store low "nibble" in next significant byte divl3 $10,%r1,%r11 # source = %r1 / 10 mull3 $10,%r11,%r0 subl2 %r0,%r1 # %r1 = source mod 10 insv %r1,$4,$4,(%r3) # store high nibble tstl %r11 jneq Lcvtlp_loop # quit if source becomes zero Lcvtlp_zloop: # fill any remaining bytes with zeros decl %r10 jeql Lcvtlp_out clrb -(%r3) jbr Lcvtlp_zloop Lcvtlp_over: overflowpsl Lcvtlp_out: clrl %r1 # %r0 is already zero clrl %r2 return .align 1 ALTENTRY(EMcvtpl) arguw(1,%r11) # (1) source length == %r11 argl(2,%r10) # (2) source address == %r10 clrl %r3 # %r3 == destination movl %r10,%r1 # %r1 set up now for return ashl $-1,%r11,%r11 # source length is number of bytes jeql Lcvtpl_zero Lcvtpl_loop: # for source length mull2 $10,%r3 # destination *= 10 extzv $4,$4,(%r10),%r0 addl2 %r0,%r3 # destination += high nibble mull2 $10,%r3 # destination *= 10 extzv $0,$4,(%r10),%r0 addl2 %r0,%r3 # destination += low nibble incl %r10 sobgtr %r11,Lcvtpl_loop Lcvtpl_zero: # least significant byte mull2 $10,%r3 extzv $4,$4,(%r10),%r0 addl2 %r0,%r3 # dest = 10 * dest + high nibble savepsl extzv $0,$4,(%r10),%r2 # test sign nibble cmpl %r2,NEGATIVE jeql Lcvtpl_neg cmpl %r2,NEGATIVEalt jneq Lcvtpl_out Lcvtpl_neg: # source was negative - negate destination mnegl %r3,%r3 savepsl Lcvtpl_out: toarg(%r3,3) clrl %r0 clrl %r2 clrl %r3 return .align 1 ALTENTRY(EMcvtps) return .align 1 ALTENTRY(EMcvtsp) return .align 1 ALTENTRY(EMaddp6) return .align 1 ALTENTRY(EMsubp4) return .align 1 ALTENTRY(EMsubp6) return .align 1 ALTENTRY(EMcvtpt) return .align 1 ALTENTRY(EMmulp) return .align 1 ALTENTRY(EMcvttp) return .align 1 ALTENTRY(EMdivp) return .align 1 ALTENTRY(EMcmpp3) return .align 1 ALTENTRY(EMcmpp4) return #ifdef notdef /* * Emulation OpCode jump table: * ONLY GOES FROM 0xf8 (-8) TO 0x3B (59) */ #define EMUTABLE 0x43 #define NOEMULATE .long noemulate #define EMULATE(a) .long _EM/**/a .globl _C_LABEL(emJUMPtable) _C_LABEL(emJUMPtable) /* f8 */ EMULATE(ashp); EMULATE(cvtlp); NOEMULATE; NOEMULATE /* fc */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE /* 00 */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE /* 04 */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE /* 08 */ EMULATE(cvtps); EMULATE(cvtsp); NOEMULATE; EMULATE(crc) /* 0c */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE /* 10 */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE /* 14 */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE /* 18 */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE /* 1c */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE /* 20 */ EMULATE(addp4); EMULATE(addp6); EMULATE(subp4); EMULATE(subp6) /* 24 */ EMULATE(cvtpt); EMULATE(mulp); EMULATE(cvttp); EMULATE(divp) /* 28 */ NOEMULATE; EMULATE(cmpc3); EMULATE(scanc); EMULATE(spanc) /* 2c */ NOEMULATE; EMULATE(cmpc5); EMULATE(movtc); EMULATE(movtuc) /* 30 */ NOEMULATE; NOEMULATE; NOEMULATE; NOEMULATE /* 34 */ EMULATE(movp); EMULATE(cmpp3); EMULATE(cvtpl); EMULATE(cmpp4) /* 38 */ EMULATE(editpc); EMULATE(matchc); EMULATE(locc); EMULATE(skpc) /* * The following is called with the stack set up as follows: * * (%sp): Opcode * 4(%sp): Instruction PC * 8(%sp): Operand 1 * 12(%sp): Operand 2 * 16(%sp): Operand 3 * 20(%sp): Operand 4 * 24(%sp): Operand 5 * 28(%sp): Operand 6 * 32(%sp): Operand 7 (unused) * 36(%sp): Operand 8 (unused) * 40(%sp): Return PC * 44(%sp): Return PSL * 48(%sp): TOS before instruction * * Each individual routine is called with the stack set up as follows: * * (%sp): Return address of trap handler * 4(%sp): Opcode (will get return PSL) * 8(%sp): Instruction PC * 12(%sp): Operand 1 * 16(%sp): Operand 2 * 20(%sp): Operand 3 * 24(%sp): Operand 4 * 28(%sp): Operand 5 * 32(%sp): Operand 6 * 36(%sp): saved register 11 * 40(%sp): saved register 10 * 44(%sp): Return PC * 48(%sp): Return PSL * 52(%sp): TOS before instruction */ SCBVEC(emulate): movl %r11,32(%sp) # save register %r11 in unused operand movl %r10,36(%sp) # save register %r10 in unused operand cvtbl (%sp),%r10 # get opcode addl2 $8,%r10 # shift negative opcodes subl3 %r10,$EMUTABLE,%r11 # forget it if opcode is out of range bcs noemulate movl _C_LABEL(emJUMPtable)[%r10],%r10 # call appropriate emulation routine jsb (%r10) # routines put return values into regs 0-5 movl 32(%sp),%r11 # restore register %r11 movl 36(%sp),%r10 # restore register %r10 insv (%sp),$0,$4,44(%sp) # and condition codes in Opcode spot addl2 $40,%sp # adjust stack for return rei noemulate: addl2 $48,%sp # adjust stack for .word 0xffff # "reserved instruction fault" SCBVEC(emulateFPD): .word 0xffff # "reserved instruction fault" #endif