/* * @(#)emulate.s 7.1 (Berkeley) 6/5/86 */ #ifdef VAX630 /* * 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 .globl _EMcrc _EMcrc: argl(1,r11) # (1) table address == r11 argl(2,r0) # (2) initial crc == r0 toarg(r8,1) # save r8 in arg1 spot argl(4,r8) # (4) source address == r8 toarg(r1,4) # save r1 in arg4 spot tstl arg3 # (3) source length == "arg3" jeql Lcrc_out Lcrc_loop: xorb2 (r8)+,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 decl arg3 jneq Lcrc_loop tstl r0 Lcrc_out: savepsl argl(1,r8) argl(4,r1) return .align 1 .globl _EMmovtc _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 decl r4 jeql Lmovtc_out jbr Lmovtc_loop Lmovtc_2loop: movb r11,(r5)+ decl r4 jneq Lmovtc_2loop Lmovtc_out: cmpl r4,r0 savepsl clrl r2 return .align 1 .globl _EMmovtuc _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_out Lmovtuc_loop: tstl r0 jeql Lmovtuc_out movzbl (r1),r2 movzbl (r3)[r2],r2 cmpl r2,r11 jeql Lmovtuc_out movzbl (r1)+,r2 movb (r3)[r2],(r5)+ decl r0 decl r4 jneq Lmovtuc_loop Lmovtuc_out: cmpl r4,r0 savepsl clrl r2 return .align 1 .globl _EMmatchc _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 decl r2 jneq Lmatchc_loop movl r10,r1 subl3 r10,r11,r0 jbr Lmatchc_out Lmatchc_succ: movl r11,r1 clrl r0 Lmatchc_out: savepsl return .align 1 .globl _EMspanc _EMspanc: argl(2,r1) # (2) string address == r1 argl(3,r3) # (3) table address == r3 argub(4,r2) # (4) character-mask == r2 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 decl r0 jneq Lspanc_loop Lspanc_out: savepsl clrl r2 return .align 1 .globl _EMscanc _EMscanc: argl(2,r1) # (2) string address == r1 argl(3,r3) # (3) table address == r3 argub(4,r2) # (4) character-mask == r2 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 decl r0 jneq Lscanc_loop Lscanc_out: savepsl clrl r2 return .align 1 .globl _EMskpc _EMskpc: argub(1,r11) # (1) character == r11 argl(3,r1) # (3) string address == r1 arguw(2,r0) # (2) string length == r0 incl r0 Lskpc_loop: decl r0 jeql Lskpc_out cmpb (r1)+,r11 jeql Lskpc_loop decl r1 tstl r0 Lskpc_out: savepsl return .align 1 .globl _EMlocc _EMlocc: argub(1,r11) # (1) character == r11 argl(3,r1) # (3) string address == r1 arguw(2,r0) # (2) string length == r0 incl r0 Llocc_loop: decl r0 jeql Llocc_out cmpb (r1)+,r11 jneq Llocc_loop decl r1 tstl r0 Llocc_out: savepsl return .align 1 .globl _EMcmpc3 _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 decl r0 jneq Lcmpc3_loop Lcmpc3_out: savepsl movl r0,r2 return .align 1 .globl _EMcmpc5 _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 decl r0 jneq Lcmpc5_loop Lcmpc5_str2: tstl r2 jeql Lcmpc5_out Lcmpc5_str2loop: cmpb r11,(r3) jneq Lcmpc5_out incl r3 decl r2 jneq Lcmpc5_str2loop jbr Lcmpc5_out Lcmpc5_str1loop: cmpb (r1),r11 jneq Lcmpc5_out incl r1 decl r0 jneq Lcmpc5_str1loop Lcmpc5_out: savepsl return /* * Packed Decimal string operations */ #define POSITIVE $12 #define NEGATIVE $13 #define NEGATIVEalt $11 .align 1 .globl _EMaddp4 _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 # arg4 will be needed later # arg5 holds destination address of LSNibble temporarily 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) # stored in arg5 spot 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 decl r11 # while (--source length) jneq Laddp4_same_loop 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 .globl _EMmovp _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 decl r11 # loop for length of source jneq Lmovp_copy 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 .globl _EMeditpc _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 don't do anything with Lpattern_inc: # replace sign `cause we don't 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 decl r11 jneq 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 we're 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 decl r1 jneq 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: decl r1 jneq 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: decl r1 jneq L221 jbr Ledit_case .align 1 .globl _EMashp _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 # 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: # r3<0> counts digits going into destination bisl2 $1,r3 # 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 # don't need to clear high nibble twice clrb -(r6) # clear low (and high) nib of next byte in dest L257: decl r3 # move to next nibble in destination, but jneq L258 # don't go beyond the end. incl r3 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_sethigh 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 jgeq Lashp_noovfl # if we've moved passed destination limits clrl r3 # test the result for possible overflow tstl arg5 # ignore zero nibbles jeql L265 # if the nibble was non-zero, overflow 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: decl r6 insv arg5,$0,$4,(r6) L265: decl r10 # loop for length of source jneq Lashp_shloop Lashp_sethigh: jlbc r3,L266 # if we haven't set the high nibble, insv r2,$4,$4,(r6) # carry the round into the high nibble clrl r2 L266: 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: cvtlb r2,-(r6) # fill up MSNs of destination with carry or zero clrl r2 L267: cmpl r3,r6 jneq Lashp_zerofill tstl r2 # if carry beyond destination, overflow jneq Lashp_overfl 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 .globl _EMcvtlp _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 .globl _EMcvtpl _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 decl r11 jneq 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 .globl _EMcvtps _EMcvtps: return .align 1 .globl _EMcvtsp _EMcvtsp: return .align 1 .globl _EMaddp6 _EMaddp6: return .align 1 .globl _EMsubp4 _EMsubp4: return .align 1 .globl _EMsubp6 _EMsubp6: return .align 1 .globl _EMcvtpt _EMcvtpt: return .align 1 .globl _EMmulp _EMmulp: return .align 1 .globl _EMcvttp _EMcvttp: return .align 1 .globl _EMdivp _EMdivp: return .align 1 .globl _EMcmpp3 _EMcmpp3: return .align 1 .globl _EMcmpp4 _EMcmpp4: return #endif UVAXII #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 _emJUMPtable _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 _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