1/******************************************************************************* 2 * 3 * Copyright (c) 1993 Intel Corporation 4 * 5 * Intel hereby grants you permission to copy, modify, and distribute this 6 * software and its documentation. Intel grants this permission provided 7 * that the above copyright notice appears in all copies and that both the 8 * copyright notice and this permission notice appear in supporting 9 * documentation. In addition, Intel grants this permission provided that 10 * you prominently mark as "not part of the original" any modifications 11 * made to this software or documentation, and that the name of Intel 12 * Corporation not be used in advertising or publicity pertaining to 13 * distribution of the software or the documentation without specific, 14 * written prior permission. 15 * 16 * Intel Corporation provides this AS IS, WITHOUT ANY WARRANTY, EXPRESS OR 17 * IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY 18 * OR FITNESS FOR A PARTICULAR PURPOSE. Intel makes no guarantee or 19 * representations regarding the use of, or the results of the use of, 20 * the software and documentation in terms of correctness, accuracy, 21 * reliability, currentness, or otherwise; and you rely on the software, 22 * documentation and results solely at your own risk. 23 * 24 * IN NO EVENT SHALL INTEL BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS, 25 * LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES 26 * OF ANY KIND. IN NO EVENT SHALL INTEL'S TOTAL LIABILITY EXCEED THE SUM 27 * PAID TO INTEL FOR THE PRODUCT LICENSED HEREUNDER. 28 * 29 ******************************************************************************/ 30 31 .file "sncat_ca.s" 32#ifdef __PIC 33 .pic 34#endif 35#ifdef __PID 36 .pid 37#endif 38/* 39 * (c) copyright 1988,1993 Intel Corp., all rights reserved 40 */ 41 42/* 43 procedure strncat (optimized assembler version for the CA) 44 45 dest_addr = strncat (dest_addr, src_addr, max_bytes) 46 47 append the null terminated string pointed to by src_addr to the null 48 terminated string pointed to by dest_addr. Return the original 49 dest_addr. If the source string is longer than max_bytes, then 50 append only max_bytes bytes, and tack on a null byte on the end 51 52 This routine will fail if the source and destination string 53 overlap (in particular, if the end of the source is overlapped 54 by the beginning of the destination). The behavior is undefined. 55 This is acceptable according to the draft C standard. 56 57 Undefined behavior will also occur if the end of the source string 58 (i.e. the terminating null byte) is in the last word of the program's 59 allocated memory space. This is so because, in several cases, strncat 60 will fetch ahead one word. Disallowing the fetch ahead would impose 61 a severe performance penalty. 62 63 This program handles five cases: 64 65 1) both arguments start on a word boundary 66 2) neither are word aligned, but they are offset by the same amount 67 3) source is word aligned, destination is not 68 4) destination is word aligned, source is not 69 5) neither is word aligned, and they are offset by differing amounts 70 71 At the time of this writing, only g0 thru g7 and g13 are available 72 for use in this leafproc; other registers would have to be saved and 73 restored. These nine registers, plus tricky use of g14 are sufficient 74 to implement the routine. The registers are used as follows: 75 76 g0 original dest ptr; not modified, so that it may be returned. 77 g1 src ptr; shift count 78 g2 max_bytes 79 g3 src ptr (word aligned) 80 g4 dest ptr (word aligned) 81 g5 0xff -- byte extraction mask 82 Little endian: 83 g6 lsw of double word for extraction of 4 bytes 84 g7 msw of double word for extraction of 4 bytes 85 Big endian: 86 g6 msw of double word for extraction of 4 bytes 87 g7 lsw of double word for extraction of 4 bytes 88 g13 return address 89 g14 byte extracted. 90*/ 91 92#if __i960_BIG_ENDIAN__ 93#define MSW g6 94#define LSW g7 95#else 96#define LSW g6 97#define MSW g7 98#endif 99 100 .globl _strncat 101 .globl __strncat 102 .leafproc _strncat, __strncat 103 .align 2 104_strncat: 105#ifndef __PIC 106 lda Lrett,g14 107#else 108 lda Lrett-(.+8)(ip),g14 109#endif 110__strncat: 111 notand g0,3,g4 # extract word addr of start of dest 112 lda (g14),g13 # preserve return address 113 cmpibge.f 0,g2,Lexit_code # Lexit if number of bytes to move is <= zero. 114 and g0,3,LSW # extract byte offset of dest 115 ld (g4),MSW # fetch word containing at least first byte 116 shlo 3,LSW,g14 # get shift count for making mask for first word 117 subi 1,0,LSW # mask initially all ones 118#if __i960_BIG_ENDIAN__ 119 shro g14,LSW,LSW # get mask for bytes needed from first word 120#else 121 shlo g14,LSW,LSW # get mask for bytes needed from first word 122#endif 123 notor MSW,LSW,MSW # set unneeded bytes to all ones 124 lda 0xff,g5 # byte extraction mask 125Lsearch_for_word_with_null: 126 scanbyte 0,MSW # check for null byte 127 lda 4(g4),g4 # post-increment dest word pointer 128 mov MSW,LSW # keep a copy of current word 129 ld (g4),MSW # fetch next word of dest 130 bno.t Lsearch_for_word_with_null # branch if null not found yet 131#if __i960_BIG_ENDIAN__ 132 shro 24,LSW,g14 # extract byte 133#else 134 and g5,LSW,g14 # extract byte 135#endif 136 cmpo 0,g14 # branch if null is first byte of word 137 subo 4,g4,g4 # move dest word ptr to word with null 138 notand g1,3,g3 # extract word addr of start of src 139 bne.t Lsearch_for_null 140 141Lcase_14: 142 cmpo g1,g3 # check alignment of source 143 ld (g3),LSW # fetch first word of source 144 shlo 3,g1,g14 # compute shift count 145 lda 4(g3),g3 # post-increment src addr 146 bne.f Lcase_4 # branch if source is unaligned 147Lcase_1: 148Lcase_1_wloop: # word copying loop 149 cmpi g2,4 # check for fewer than four bytes to move 150 lda (LSW),g1 # keep a copy of the src word 151 bl.f Lcase_1_cloop # branch if fewer than four bytes to copy 152 scanbyte 0,g1 # check for null byte in src word 153 ld (g3),LSW # pre-fetch next word of src 154 addo 4,g3,g3 # post-increment src addr 155 bo.f Lcase_1_cloop # branch if word contains null byte 156 subi 4,g2,g2 # decrease max_byte count by the 4 bytes moved 157 st g1,(g4) # store word in dest string 158 addo 4,g4,g4 # post-increment dest addr 159 b Lcase_1_wloop 160 161Lcase_3_cloop: 162Lcase_1_cloop: # character copying loop (max_bytes <= 3) 163 cmpdeci 0,g2,g2 # is max_bytes exhausted? 164#if __i960_BIG_ENDIAN__ 165 rotate 8,g1,g1 # move next byte into position for extraction 166#endif 167 and g5,g1,g14 # extract next char 168 be.f Lstore_null # if max_bytes is exhausted, store null and quit 169 cmpo 0,g14 # check for null byte 170 stob g14,(g4) # store the byte in dest 171#if ! __i960_BIG_ENDIAN__ 172 shro 8,g1,g1 # move next byte into position for extraction 173#endif 174 lda 1(g4),g4 # post-increment dest byte addr 175 bne.t Lcase_1_cloop # branch if null not reached 176 bx (g13) # Lexit (g14 == 0) 177 178Lstore_null: 179 mov 0,g14 # store null, and set g14 to zero 180 stob g14,(g4) 181 bx (g13) 182 183 184Lsearch_for_null: 185#if __i960_BIG_ENDIAN__ 186 shlo 8,LSW,LSW # check next byte 187 shro 24,LSW,g14 188#else 189 shlo 8,g5,g5 # move mask up to next byte 190 and g5,LSW,g14 # extract byte 191#endif 192 lda 1(g4),g4 # move dest byte ptr to next byte 193 cmpobne.t 0,g14,Lsearch_for_null # branch if null is not yet found 194 195Lcase_235: 196 cmpo g1,g3 # check alignment of src 197 ld (g3),LSW # pre-fetch word with start of src 198 and 3,g1,g1 # compute shift count 199 lda 0xff,g5 # load mask for byte extraction 200 shlo 3,g1,g14 201 lda 4(g3),g3 # post-increment src word counter 202 be.t Lcase_3 # branch if src is word aligned 203 and g4,3,MSW # extract byte offset for dest string 204 cmpo MSW,g1 # < indicates first word of dest has more bytes 205 /* than first word of source. */ 206 ld (g3),MSW # fetch second word of src 207#if __i960_BIG_ENDIAN__ 208 subo g14,0,g14 # adjust shift count for big endian 209#endif 210 eshro g14,g6,g5 # extract four bytes 211#if __i960_BIG_ENDIAN__ 212 bge.f 1f 213#else 214 bg.f 1f 215#endif 216 mov MSW,LSW 217 lda 4(g3),g3 # move src word addr to second word boundary 2181: 219 mov g5,MSW 220 lda 0xff,g5 221 b Lcase_25 222 223Lcase_3: # src is word aligned; dest is not 224 mov LSW,MSW # make copy of first word of src 225 lda 32,g14 # initialize shift count to zero (mod 32) 226Lcase_25: 227 228Lcase_3_cloop_at_start: # character copying loop for start of dest str 229 cmpdeci 0,g2,g2 # is max_bytes exhausted? 230#if __i960_BIG_ENDIAN__ 231 shro 24,MSW,g5 # extract next char 232#else 233 and g5,MSW,g5 # extract next char 234#endif 235 be.f Lstore_null # Lexit if max_bytes is exhausted 236 cmpo 0,g5 # check for null byte 237 stob g5,(g4) # store the byte in dest 238 addo 1,g4,g4 # post-increment dest ptr 239 lda 0xff,g5 # re-initialize byte extraction mask 240 notand g4,3,g1 # extract word address 241 be.t Lexit_code # Lexit if null byte reached 242 cmpo g1,g4 # have we reached word boundary in dest yet? 243#if __i960_BIG_ENDIAN__ 244 lda -8(g14),g14 # augment the shift counter 245 rotate 8,MSW,MSW # move next byte into position for extraction 246#else 247 lda 8(g14),g14 # augment the shift counter 248 shro 8,MSW,MSW # move next byte into position for extraction 249#endif 250 bne.t Lcase_3_cloop_at_start # branch if reached word boundary? 251 252#if __i960_BIG_ENDIAN__ 253 cmpo 0,g14 254 ld (g3),MSW # fetch msw of operand for double shift 255 bne Lcase_3_wloop # branch if src is still unaligned. 256 257Lcase_3_wloop2: 258 cmpi g2,4 # less than four bytes to move? 259 mov LSW,g1 # extract 4 bytes of src 260 lda 4(g3),g3 # post-increment src word addr 261 bl.f Lcase_3_cloop # branch if < four bytes left to move 262 scanbyte 0,g1 # check for null byte 263 mov MSW,LSW # move msw to lsw 264 ld (g3),MSW # pre-fetch msw of operand for double shift 265 bo.f Lcase_3_cloop # branch if word contains null byte 266 subi 4,g2,g2 # decrease max_byte count by the 4 bytes moved 267 st g1,(g4) # store 4 bytes to dest 268 addo 4,g4,g4 # post-increment dest ptr 269 b Lcase_3_wloop2 270Lcase_4: 271 subo g14,0,g14 # adjust shift count for big endian 272#else 273Lcase_4: 274#endif 275 276 ld (g3),MSW # fetch msw of operand for double shift 277 278Lcase_3_wloop: 279 cmpi g2,4 # less than four bytes to move? 280 eshro g14,g6,g1 # extract 4 bytes of src 281 lda 4(g3),g3 # post-increment src word addr 282 bl.f Lcase_3_cloop # branch if < four bytes left to move 283 scanbyte 0,g1 # check for null byte 284 mov MSW,LSW # move msw to lsw 285 ld (g3),MSW # pre-fetch msw of operand for double shift 286 bo.f Lcase_3_cloop # branch if word contains null byte 287 subi 4,g2,g2 # decrease max_byte count by the 4 bytes moved 288 st g1,(g4) # store 4 bytes to dest 289 addo 4,g4,g4 # post-increment dest ptr 290 b Lcase_3_wloop 291 292 293Lexit_code: 294 mov 0,g14 # conform to register conventions 295 bx (g13) # g0 = addr of dest; g14 = 0 296Lrett: 297 ret 298 299/* end of strncat */ 300 301