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 "strcp_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 strcpy (optimized assembler version for the CA) 46 47 dest_addr = strcpy (dest_addr, src_addr) 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. 52 53 This routine will fail if the source and destination string 54 overlap (in particular, if the end of the source is overlapped 55 by the beginning of the destination). The behavior is undefined. 56 This is acceptable according to the draft C standard. 57 58 Undefined behavior will also occur if the end of the source string 59 (i.e. the terminating null byte) is in the last word of the program's 60 allocated memory space. This is so because, in several cases, strcpy 61 will fetch ahead one word. Disallowing the fetch ahead would impose 62 a severe performance penalty. 63 64 This program handles five cases: 65 66 1) both arguments start on a word boundary 67 2) neither are word aligned, but they are offset by the same amount 68 3) source is word aligned, destination is not 69 4) destination is word aligned, source is not 70 5) neither is word aligned, and they are offset by differing amounts 71 72 At the time of this writing, only g0 thru g7 and g13 are available 73 for use in this leafproc; other registers would have to be saved and 74 restored. These nine registers, plus tricky use of g14 are sufficient 75 to implement the routine. The registers are used as follows: 76 77 g0 original dest ptr; not modified, so that it may be returned. 78 g1 src ptr; shift count 79 g2 dest ptr; 4 bytes of src 80 g3 src ptr (word aligned) 81 g4 dest ptr (word aligned) 82 g5 0xff -- byte extraction mask 83 g6 lsw of double word for extraction of 4 bytes (little endian) 84 msw of double word for extraction of 4 bytes (big endian) 85 g7 msw of double word for extraction of 4 bytes (little endian) 86 lsw of double word for extraction of 4 bytes (big endian) 87 g13 return address 88 g14 byte extracted. When reaches null byte, which is zero, we will 89 be in conformance with register conventions, and can return to 90 the caller with a clear conscience. 91 92 procedure strcat 93 94 dest_addr = strcat (dest_addr, src_addr) 95 96 Appends the string pointed to by src_addr to the string pointed 97 to by dest_addr. The first character of the source string is 98 copied to the location initially occupied by the trailing null 99 byte of the destination string. Thereafter, characters are copied 100 from the source to the destination up thru the null byte that 101 trails the source string. 102*/ 103 104#if __i960_BIG_ENDIAN__ 105#define MSW g6 106#define LSW g7 107#else 108#define LSW g6 109#define MSW g7 110#endif 111 112 .globl _strcpy, _strcat 113 .globl __strcpy, __strcat 114 .leafproc _strcpy, __strcpy 115 .leafproc _strcat, __strcat 116 .align 2 117_strcat: 118#ifndef __PIC 119 lda Lrett,g14 120#else 121 lda Lrett-(.+8)(ip),g14 122#endif 123__strcat: 124 notand g0,3,g4 # extract word addr of start of dest 125 lda (g14),g13 # preserve return address 126 and g0,3,LSW # extract byte offset of dest 127 ld (g4),MSW # fetch word containing at least first byte 128 shlo 3,LSW,g14 # get shift count for making mask for first word 129 subi 1,0,LSW # mask initially all ones 130#if __i960_BIG_ENDIAN__ 131 shro g14,LSW,LSW # get mask for bytes needed from first word 132 lda 0xff000000,g5 # byte extraction mask 133#else 134 shlo g14,LSW,LSW # get mask for bytes needed from first word 135 lda 0xff,g5 # byte extraction mask 136#endif 137 notor MSW,LSW,MSW # set unneeded bytes to all ones 138Lsearch_for_word_with_null: 139 scanbyte 0,MSW # check for null byte 140 lda 4(g4),g4 # post-increment dest word pointer 141 mov MSW,LSW # keep a copy of current word 142 ld (g4),MSW # fetch next word of dest 143 bno.t Lsearch_for_word_with_null # branch if null not found yet 144 and g5,LSW,g14 # extract byte 145 cmpo 0,g14 # branch if null is first byte of word 146 subo 4,g4,g4 # move dest word ptr back to word with null 147 notand g1,3,g3 # extract word addr of start of src 148 lda (g4),g2 # set dest byte ptr to 1st byte of word w/ null 149 be.f Lcase_14 150Lsearch_for_null: 151#if __i960_BIG_ENDIAN__ 152 shro 8,g5,g5 # move mask down to next byte 153#else 154 shlo 8,g5,g5 # move mask up to next byte 155#endif 156 lda 1(g2),g2 # move dest byte ptr to next byte 157 and g5,LSW,g14 # extract byte 158 cmpobne.t 0,g14,Lsearch_for_null # branch if null is not yet found 159 lda 0xff,g5 # byte extraction mask 160 b Lcase_235.a 161 162 163_strcpy: 164#ifndef __PIC 165 lda Lrett,g14 166#else 167 lda Lrett-(.+8)(ip),g14 168#endif 169__strcpy: 170 notand g0,3,g4 # extract word addr of start of dest 171 lda (g14),g13 # preserve return address 172 cmpo g0,g4 # check alignment of dest 173 lda 0xff,g5 # load mask for byte extraction 174 notand g1,3,g3 # extract word addr of start of src 175 bne.f Lcase_235 # branch if dest is NOT word aligned 176 177Lcase_14: 178 cmpo g3,g1 # check alignment of src 179 ld (g3),LSW # fetch word containing at least first byte 180 shlo 3,g1,g1 # compute shift count 181 lda 4(g3),g3 # advance src word addr 182#if __i960_BIG_ENDIAN__ 183 lda 0xff,g5 # byte extraction mask 184#endif 185 bne.f Lcase_4 # branch if src is NOT word aligned 186 187Lcase_1: # src and dest are word aligned 188 subo 4,g4,g4 # store is pre-incrementing; back up dest addr 189Lcase_1_wloop: # word copying loop 190 scanbyte 0,LSW # check for null byte in src word 191 lda (LSW),g2 # keep a copy of the src word 192 addo 4,g4,g4 # pre-increment dest addr 193 ld (g3),LSW # pre-fetch next word of src 194 addo 4,g3,g3 # post-increment src addr 195 bo.f Lcase_1_cloop # branch if word contains null byte 196 st g2,(g4) # store word in dest string 197 b Lcase_1_wloop 198 199Lcase_3_cloop: 200Lcase_1_cloop: # character copying loop 201#if __i960_BIG_ENDIAN__ 202 rotate 8,g2,g2 # move next byte into position for extraction 203 and g5,g2,g14 # extract next char 204#else 205 and g5,g2,g14 # extract next char 206 shro 8,g2,g2 # move next byte into position for extraction 207#endif 208 cmpo 0,g14 # check for null byte 209 stob g14,(g4) # store the byte in dest 210 lda 1(g4),g4 # post-increment dest byte addr 211 bne.t Lcase_1_cloop # branch if null not reached 212 213Lexit_code: 214 bx (g13) # g0 = addr of dest; g14 = 0 215Lrett: 216 ret 217 218Lcase_3: # src is word aligned; dest is not 219 addo 4,g4,g4 # move dest word ptr to first word boundary 220 mov LSW,MSW # make copy of first word of src 221 lda 0,g1 # initialize shift count to zero 222 223Lcase_25: 224Lcase_3_cloop_at_start: # character copying loop for start of dest str 225#if __i960_BIG_ENDIAN__ 226 rotate 8,MSW,MSW # move next byte into position for extraction 227 and g5,MSW,g14 # extract next char 228#else 229 and g5,MSW,g14 # extract next char 230 shro 8,MSW,MSW # move next byte into position for extraction 231#endif 232 cmpo 0,g14 # check for null byte 233 stob g14,(g2) # store the byte in dest 234 lda 1(g2),g2 # post-increment dest ptr 235 be.f Lexit_code # branch if null byte reached 236 cmpo g2,g4 # have we reached word boundary in dest? 237 lda 8(g1),g1 # augment the shift counter 238 bne.t Lcase_3_cloop_at_start 239 240Lcase_4: 241 ld (g3),MSW # fetch msw of operand for double shift 242#if __i960_BIG_ENDIAN__ 243 subo g1,0,g1 # Adjust shift count for big endian. 244#endif 245 246Lcase_3_wloop: 247 eshro g1,g6,g2 # extract 4 bytes of src 248 lda 4(g3),g3 # post-increment src word addr 249 scanbyte 0,g2 # check for null byte 250 lda (MSW),LSW # move msw to lsw 251 ld (g3),MSW # pre-fetch msw of operand for double shift 252 bo.f Lcase_3_cloop # branch if word contains null byte 253 st g2,(g4) # store 4 bytes to dest 254 addo 4,g4,g4 # post-increment dest ptr 255 b Lcase_3_wloop 256 257Lcase_235: 258 lda (g0),g2 # copy dest ptr 259Lcase_235.a: 260 cmpo g3,g1 # check alignment of src 261 ld (g3),LSW # fetch word containing at least first byte 262 and 3,g1,g14 # compute shift count 263 lda 4(g3),g3 # advance src word addr 264 shlo 3,g14,g1 265 be.t Lcase_3 # branch if dest is word aligned 266 or g4,g14,g14 # is src earlier in word, later, or sync w/ dst 267 ld (g3),MSW # pre-fetch second half 268 cmpo g2,g14 # < indicates first word of dest has more bytes 269 lda 4(g4),g4 # move dest word addr to first word boundary 270 /* than first word of source. */ 271#if __i960_BIG_ENDIAN__ 272 subo g1,0,g14 # Adjust shift count for big endian. 273 eshro g14,g6,g14 # extract four bytes 274 bge.f 1f 275#else 276 eshro g1,g6,g14 # extract four bytes 277 bg.f 1f 278#endif 279 mov MSW,LSW 280 lda 4(g3),g3 # move src word addr to second word boundary 2811: 282 mov g14,MSW 283 b Lcase_25 284 285/* end of strcpy */ 286 287