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#include <picolibc.h> 32 33 .file "sncpy_ca.s" 34#ifdef __PIC 35 .pic 36#endif 37#ifdef __PID 38 .pid 39#endif 40/* 41 * (c) copyright 1988,1993 Intel Corp., all rights reserved 42 */ 43 44/* 45 procedure strncpy (optimized assembler version for the CA) 46 47 dest_addr = strncpy (dest_addr, src_addr, max_bytes) 48 49 copy the null terminated string pointed to by src_addr to 50 the string space pointed to by dest_addr. Return the original 51 dest_addr. If the source string is shorter than max_bytes, 52 then null-pad the destination string. 53 54 This routine will fail if the source and destination string 55 overlap (in particular, if the end of the source is overlapped 56 by the beginning of the destination). The behavior is undefined. 57 This is acceptable according to the draft C standard. 58 59 Undefined behavior will also occur if the end of the source string 60 (i.e. the terminating null byte) is in the last word of the program's 61 allocated memory space. This is so because, in several cases, strcpy 62 will fetch ahead one word. Disallowing the fetch ahead would impose 63 a severe performance penalty. 64 65 This program handles five cases: 66 67 1) both arguments start on a word boundary 68 2) neither are word aligned, but they are offset by the same amount 69 3) source is word aligned, destination is not 70 4) destination is word aligned, source is not 71 5) neither is word aligned, and they are offset by differing amounts 72 73 At the time of this writing, only g0 thru g7 and g13 are available 74 for use in this leafproc; other registers would have to be saved and 75 restored. These nine registers, plus tricky use of g14 are sufficient 76 to implement the routine. The registers are used as follows: 77 78 g0 original dest ptr; not modified, so that it may be returned. 79 g1 src ptr; shift count 80 g2 max_bytes 81 g3 src ptr (word aligned) 82 g4 dest ptr (word aligned) 83 g5 0xff -- byte extraction mask 84 Little endian: 85 g6 lsw of double word for extraction of 4 bytes 86 g7 msw of double word for extraction of 4 bytes 87 Big endian: 88 g6 msw of double word for extraction of 4 bytes 89 g7 lsw of double word for extraction of 4 bytes 90 g13 return address 91 g14 byte extracted. 92*/ 93 94#if __i960_BIG_ENDIAN__ 95#define MSW g6 96#define LSW g7 97#else 98#define LSW g6 99#define MSW g7 100#endif 101 102 .globl _strncpy 103 .globl __strncpy 104 .leafproc _strncpy, __strncpy 105 .align 2 106_strncpy: 107#ifndef __PIC 108 lda Lrett,g14 109#else 110 lda Lrett-(.+8)(ip),g14 111#endif 112__strncpy: 113 notand g1,3,g3 # extract word addr of start of src 114 lda (g14),g13 # preserve return address 115 cmpibge.f 0,g2,Lexit_code # Lexit if number of bytes to move is <= zero. 116 cmpo g3,g1 # check alignment of src 117 ld (g3),LSW # fetch word containing at least first byte 118 notand g0,3,g4 # extract word addr of start of dest 119 lda 4(g3),g3 # advance src word addr 120 bne.f Lcase_245 # branch if src is NOT word aligned 121 122Lcase_13: 123 cmpo g0,g4 # check alignment of dest 124 lda 0xff,g5 # load mask for byte extraction 125 subo 4,g4,g4 # store is pre-incrementing; back up dest addr 126 bne.f Lcase_3 # branch if dest not word aligned 127 128Lcase_1: # src and dest are word aligned 129Lcase_1_wloop: # word copying loop 130 cmpi g2,4 # check for fewer than four bytes to move 131 lda (LSW),g1 # keep a copy of the src word 132 addo 4,g4,g4 # pre-increment dest addr 133 bl.f Lcase_1_cloop.a # branch if fewer than four bytes to copy 134 scanbyte 0,g1 # check for null byte in src word 135 ld (g3),LSW # pre-fetch next word of src 136 subi 4,g2,g2 # decrease max_byte count by the 4 bytes moved 137 bo.f Lcase_1_cloop.c # branch if word contains null byte 138 addo 4,g3,g3 # post-increment src addr 139 st g1,(g4) # store word in dest string 140 b Lcase_1_wloop 141 142Lcase_3_cloop.a: 143Lcase_1_cloop.a: # character copying loop (max_bytes <= 3) 144#if __i960_BIG_ENDIAN__ 145 rotate 8,g1,g1 # move next byte into position for extraction 146#endif 147 and g5,g1,g14 # extract next char 148Lcase_1_cloop.b: 149 cmpdeci 0,g2,g2 # is max_bytes exhausted? 150 be.f Lexit_code # Lexit if max_bytes is exhausted 151 cmpo 0,g14 # check for null byte 152 stob g14,(g4) # store the byte in dest 153#if ! __i960_BIG_ENDIAN__ 154 shro 8,g1,g1 # move next byte into position for extraction 155#endif 156 lda 1(g4),g4 # post-increment dest byte addr 157 bne.t Lcase_1_cloop.a # branch if null not reached 158 b Lcase_1_cloop.b 159 160Lexit_code: 161 mov 0,g14 # conform to register conventions 162 bx (g13) # g0 = addr of dest; g14 = 0 163Lrett: 164 ret 165 166Lcase_1_cloop.c: 167Lcase_3_cloop.c: 168#if __i960_BIG_ENDIAN__ 169 rotate 24,g5,g5 # move mask into position for testing next byte 170#endif 171 and g5,g1,g14 # extract next char 172 cmpo 0,g14 # check for null byte 173#if ! __i960_BIG_ENDIAN__ 174 lda (g5),LSW # keep a copy of the current mask 175 shlo 8,g5,g5 # move mask into position for testing next byte 176#endif 177 bne.t Lcase_1_cloop.c # branch if null not reached 178#if __i960_BIG_ENDIAN__ 179 subo 1,g5,g5 # null pad. 180 andnot g5,g1,g1 # last bytes to copy, and null pad rest of word 181#else 182 subo 1,LSW,g5 # mask to get last bytes to copy, and null pad 183 and g5,g1,g1 # last bytes to copy, and null pad rest of word 184#endif 185 st g1,(g4) 186 187Lcase_1_zwloop: # zero word loop 188 cmpi g2,4 # check for fewer than four bytes to move 189 addo 4,g4,g4 # pre-increment dest addr 190 bl.f Lcase_1_cloop.b # branch if fewer than four bytes to copy 191 subo 4,g2,g2 # decrease max_byte count by the 4 bytes moved 192 st g14,(g4) # store word in dest string 193 b Lcase_1_zwloop 194 195Lcase_3: # src is word aligned; dest is not 196 addo 8,g4,g4 # move dest word ptr to first word boundary 197 lda (g0),g1 # copy dest byte ptr 198 mov LSW,MSW # make copy of first word of src 199 lda 32,g14 # initialize shift count to zero (mod 32) 200 201Lcase_25: 202Lcase_3_cloop_at_start: # character copying loop for start of dest str 203 cmpdeci 0,g2,g2 # is max_bytes exhausted? 204#if __i960_BIG_ENDIAN__ 205 shro 24,MSW,g5 # extract next char 206#else 207 and g5,MSW,g5 # extract next char 208#endif 209 be.f Lexit_code # Lexit if max_bytes is exhausted 210 cmpo 0,g5 # check for null byte 211 stob g5,(g1) # store the byte in dest 212 addo 1,g1,g1 # post-increment dest ptr 213 lda 0xff,g5 # re-initialize byte extraction mask 214 bne.t 1f # drop thru if null byte reached (to pad) 215 movl 0,g6 # blank out remainder of input buffer 2161: 217 cmpo g1,g4 # have we reached word boundary in dest yet? 218#if __i960_BIG_ENDIAN__ 219 lda -8(g14),g14 # augment the shift counter 220 rotate 8,MSW,MSW # move next byte into position for extraction 221#else 222 lda 8(g14),g14 # augment the shift counter 223 shro 8,MSW,MSW # move next byte into position for extraction 224#endif 225 bne.t Lcase_3_cloop_at_start # branch if reached word boundary? 226 227 ld (g3),MSW # fetch msw of operand for double shift 228 229Lcase_4: 230 231#if __i960_BIG_ENDIAN__ 232 cmpobne 0,g14,Lcase_3_wloop # branch if src is still unaligned. 233 234Lcase_3_wloop2: 235 cmpi g2,4 # less than four bytes to move? 236 lda (LSW),g1 # extract 4 bytes of src 237 lda 4(g3),g3 # post-increment src word addr 238 bl.f Lcase_3_cloop.a # branch if < four bytes left to move 239 scanbyte 0,g1 # check for null byte 240 lda (MSW),LSW # move msw to lsw 241 subi 4,g2,g2 # decrease max_byte count by the 4 bytes moved 242 ld (g3),MSW # pre-fetch msw of operand for double shift 243 bo.f Lcase_3_cloop.c # branch if word contains null byte 244 st g1,(g4) # store 4 bytes to dest 245 addo 4,g4,g4 # post-increment dest ptr 246 b Lcase_3_wloop2 247 248#endif 249 250Lcase_3_wloop: 251 cmpi g2,4 # less than four bytes to move? 252 eshro g14,g6,g1 # extract 4 bytes of src 253 lda 4(g3),g3 # post-increment src word addr 254 bl.f Lcase_3_cloop.a # branch if < four bytes left to move 255 scanbyte 0,g1 # check for null byte 256 lda (MSW),LSW # move msw to lsw 257 subi 4,g2,g2 # decrease max_byte count by the 4 bytes moved 258 ld (g3),MSW # pre-fetch msw of operand for double shift 259 bo.f Lcase_3_cloop.c # branch if word contains null byte 260 st g1,(g4) # store 4 bytes to dest 261 addo 4,g4,g4 # post-increment dest ptr 262 b Lcase_3_wloop 263 264Lcase_245: 265 cmpo g0,g4 # check alignment of dest 266 ld (g3),MSW # pre-fetch second half 267 and 3,g1,g1 # compute shift count 268 lda 0xff,g5 # load mask for byte extraction 269#if __i960_BIG_ENDIAN__ 270 subo g1,4,g14 # adjust shift count for big endian. 271 shlo 3,g14,g14 272#else 273 shlo 3,g1,g14 274#endif 275 be.t Lcase_4 # branch if dest is word aligned 276 or g4,g1,g1 # is src earlier in word, later, or sync w/ dst 277 cmpo g0,g1 # < indicates first word of dest has more bytes 278 /* than first word of source. */ 279 lda 4(g4),g4 # move dest word addr to first word boundary 280 eshro g14,g6,g5 # extract four bytes 281 lda (g0),g1 282 bg.f 1f 283 mov MSW,LSW 284 lda 4(g3),g3 # move src word addr to second word boundary 2851: 286 mov g5,MSW 287 lda 0xff,g5 288 b Lcase_25 289 290/* end of strncpy */ 291 292