root/sys/arch/vax/vax/emulate.S
/*      $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 <machine/asm.h>

/*
 * 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