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 "mccpy_ca.s" 34#ifdef __PIC 35 .pic 36#endif 37#ifdef __PID 38 .pid 39#endif 40/* 41 * (c) copyright 1989,1993 Intel Corp., all rights reserved 42 */ 43 44/* 45 procedure memccpy (optimized assembler version for the 80960CA) 46 47 dest_addr = memccpy (dest_addr, src_addr, char, len) 48 49 copy len bytes pointed to by src_addr to the space pointed to by 50 dest_addr, stopping if char is copied. If char is copied, 51 return address of byte after char in dest string; else null. 52 53 Undefined behavior will occur if the end of the source array is in 54 the last two words of the program's allocated memory space. This 55 is so because the routine fetches ahead. Disallowing the fetch 56 ahead would impose a severe performance penalty. 57 58 Undefined behavior will also occur if the source and destination 59 strings overlap. 60 61 62 This program handles five cases: 63 64 1) both arguments start on a word boundary 65 2) neither are word aligned, but they are offset by the same amount 66 3) source is word aligned, destination is not 67 4) destination is word aligned, source is not 68 5) neither is word aligned, and they are offset by differing amounts 69 70 At the time of this writing, only g0 thru g7 and g13 are available 71 for use in this leafproc; other registers would have to be saved and 72 restored. These nine registers, plus tricky use of g14 are sufficient 73 to implement the routine. 74*/ 75 76#if __i960_BIG_ENDIAN__ 77#define MSW g6 78#define LSW g7 79#else 80#define LSW g6 81#define MSW g7 82#endif 83 84 .globl _memccpy 85 .leafproc _memccpy, __memccpy 86 .align 2 87_memccpy: 88#ifndef __PIC 89 lda Lrett,g14 90#else 91 lda Lrett-(.+8)(ip),g14 92#endif 93__memccpy: 94 notand g1,3,g5 # extract word addr of start of src 95 lda (g14),g13 # preserve return address 96 cmpibge.f 0,g3,Lexit_char_not_found # Lexit if # of bytes to move is <= 0 97 cmpo g5,g1 # check alignment of src 98 ld (g5),LSW # fetch word containing at least first byte 99 notand g0,3,g4 # extract word addr of start of dest 100 lda 4(g5),g5 # advance src word addr 101 shlo 24,g2,g2 # reduce char to single byte 102 bne.f Lcase_245 # branch if src is NOT word aligned 103 104Lcase_13: 105 cmpobe.t g0,g4,Lcase_1_setup # branch if dest word aligned 106 107Lcase_3: # src is word aligned; dest is not 108 mov LSW,MSW # make copy of first word of src 109 addo 4,g4,g1 # move dest word ptr to first word boundary 110 lda 32,g14 # initialize shift count to zero 111 112Lcase_25: 113Lcase_3_cloop_at_start: # character copying loop for start of dest str 114 cmpdeci 0,g3,g3 # is max_bytes exhausted? 115#if __i960_BIG_ENDIAN__ 116 lda -8(g14),g14 # augment the shift counter 117#else 118 lda 8(g14),g14 # augment the shift counter 119#endif 120 be.f Lexit_char_not_found # Lexit if max_bytes is exhausted 121#if __i960_BIG_ENDIAN__ 122 rotate 8,MSW,MSW # move next byte into position for extraction 123#endif 124 shlo 24,MSW,g4 125 stob MSW,(g0) # store the byte in dest 126 cmpo g4,g2 127 lda 1(g0),g0 # post-increment dest ptr 128#if ! __i960_BIG_ENDIAN__ 129 shro 8,MSW,MSW # move next byte into position for extraction 130#endif 131 be.f Lexit_char_found # Lexit if char found 132 cmpobne.t g1,g0,Lcase_3_cloop_at_start # branch if reached word boundary 133 134 ld (g5),MSW # fetch msw of operand for double shift 135 136Lcase_4: 137 shro 8,g2,g4 138 or g4,g2,g1 139 shro 16,g1,g4 140 or g4,g1,g4 141 142#if __i960_BIG_ENDIAN__ 143 cmpobne 0,g14,Lcase_3_wloop 144 145Lcase_3_wloop2: 146 cmpi g3,4 # less than four bytes to move? 147 lda 4(g5),g5 # post-increment src word addr 148 mov LSW,g1 # extract 4 bytes of src 149 bl.f Lcase_13_cloop_setup # branch if < four bytes left to move 150 scanbyte g4,g1 # branch if word has char in it 151 bo.f Lcase_13_cloop_setup 152 mov MSW,LSW # move msw to lsw 153 ld (g5),MSW # pre-fetch msw of operand for double shift 154 subi 4,g3,g3 # decrease max_byte count by the 4 bytes moved 155 st g1,(g0) # store 4 bytes to dest 156 addo 4,g0,g0 # post-increment dest ptr 157 b Lcase_3_wloop2 158#endif 159 160Lcase_3_wloop: 161 cmpi g3,4 # less than four bytes to move? 162 lda 4(g5),g5 # post-increment src word addr 163 eshro g14,g6,g1 # extract 4 bytes of src 164 bl.f Lcase_13_cloop_setup # branch if < four bytes left to move 165 scanbyte g4,g1 # branch if word has char in it 166 bo.f Lcase_13_cloop_setup 167 mov MSW,LSW # move msw to lsw 168 ld (g5),MSW # pre-fetch msw of operand for double shift 169 subi 4,g3,g3 # decrease max_byte count by the 4 bytes moved 170 st g1,(g0) # store 4 bytes to dest 171 addo 4,g0,g0 # post-increment dest ptr 172 b Lcase_3_wloop 173 174Lcase_1_setup: 175 subo 4,g0,g0 # store is pre-incrementing; back up dest addr 176 shro 8,g2,g4 177 or g4,g2,MSW 178 shro 16,MSW,g4 179 or g4,MSW,g4 180 b Lcase_1 181Lcase_1_wloop: # word copying loop 182 subi 4,g3,g3 # decrease max_byte count by the 4 bytes moved 183 ld (g5),LSW # pre-fetch next word of src 184 addo 4,g5,g5 # post-increment src addr 185 st g1,(g0) # store word in dest string 186Lcase_1: # src and dest are word aligned 187 cmpi g3,4 # check for fewer than four bytes to move 188 addo 4,g0,g0 # pre-increment dest addr 189 lda (LSW),g1 # keep a copy of the src word 190 bl.f Lcase_13_cloop_setup # branch if less than four bytes to copy 191 scanbyte LSW,g4 # branch if char is not in foursome 192 bno.t Lcase_1_wloop 193Lcase_13_cloop_setup: 194 cmpibe.f 0,g3,Lexit_char_not_found # Lexit if max_bytes is exhausted 195 196Lcase_1_cloop: 197#if __i960_BIG_ENDIAN__ 198 rotate 8,g1,g1 # move next byte into position for extraction 199#endif 200 shlo 24,g1,g4 201 stob g1,(g0) # store the byte in dest 202 cmpo g4,g2 203 lda 1(g0),g0 # post-increment dest byte addr 204 subi 1,g3,g3 205 be.f Lexit_char_found # Lexit if char reached 206 cmpi 0,g3 207#if ! __i960_BIG_ENDIAN__ 208 shro 8,g1,g1 # move next byte into position for extraction 209#endif 210 bne.t Lcase_1_cloop # continue if len not exhausted 211 212Lexit_char_not_found: 213 mov 0,g0 214Lexit_char_found: 215 lda 0,g14 216 bx (g13) # g0 = dest array address; g14 = 0 217Lrett: 218 ret 219 220 221Lcase_245: 222 cmpo g0,g4 # check alignment of dest 223 ld (g5),MSW # pre-fetch second half 224 and 3,g1,g1 # compute shift count 225 shlo 3,g1,g14 226#if __i960_BIG_ENDIAN__ 227 subo g14,0,g14 # adjust shift count for big endian 228#endif 229 be.t Lcase_4 # branch if dest is word aligned 230 or g4,g1,g1 # is src earlier in word, later, or sync w/ dst 231 cmpo g0,g1 # < indicates first word of dest has more bytes 232 /* than first word of source. */ 233 eshro g14,g6,g4 # extract four bytes 234 lda 4(g0),g1 # move dest word addr to first word boundary 235#if __i960_BIG_ENDIAN__ 236 bge.f 1f 237#else 238 bg.f 1f 239#endif 240 mov MSW,LSW 241 lda 4(g5),g5 # move src word addr to second word boundary 2421: 243 notand g1,3,g1 244 mov g4,MSW 245 b Lcase_25 246 247/* end of memccpy */ 248