108 lines
		
	
	
	
		
			2.5 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
		
		
			
		
	
	
			108 lines
		
	
	
	
		
			2.5 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
|   | /* | ||
|  |  * arch/alpha/lib/ev67-strlen_user.S | ||
|  |  * 21264 version contributed by Rick Gorton <rick.gorton@api-networks.com>
 | ||
|  |  * | ||
|  |  * Return the length of the string including the NULL terminator | ||
|  |  * (strlen+1) or zero if an error occurred. | ||
|  |  * | ||
|  |  * In places where it is critical to limit the processing time, | ||
|  |  * and the data is not trusted, strnlen_user() should be used. | ||
|  |  * It will return a value greater than its second argument if | ||
|  |  * that limit would be exceeded. This implementation is allowed | ||
|  |  * to access memory beyond the limit, but will not cross a page | ||
|  |  * boundary when doing so. | ||
|  |  * | ||
|  |  * Much of the information about 21264 scheduling/coding comes from: | ||
|  |  *      Compiler Writer's Guide for the Alpha 21264 | ||
|  |  *      abbreviated as 'CWG' in other comments here | ||
|  |  *      ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html | ||
|  |  * Scheduling notation: | ||
|  |  *      E       - either cluster | ||
|  |  *      U       - upper subcluster; U0 - subcluster U0; U1 - subcluster U1
 | ||
|  |  *      L       - lower subcluster; L0 - subcluster L0; L1 - subcluster L1
 | ||
|  |  * Try not to change the actual algorithm if possible for consistency. | ||
|  |  */ | ||
|  | 
 | ||
|  | #include <asm/regdef.h> | ||
|  | 
 | ||
|  | 
 | ||
|  | /* Allow an exception for an insn; exit if we get one.  */ | ||
|  | #define EX(x,y...)			\ | ||
|  | 	99: x,##y;			\ | ||
|  | 	.section __ex_table,"a";	\
 | ||
|  | 	.long 99b - .;			\
 | ||
|  | 	lda v0, $exception-99b(zero);	\
 | ||
|  | 	.previous | ||
|  | 
 | ||
|  | 
 | ||
|  | 	.set noreorder
 | ||
|  | 	.set noat
 | ||
|  | 	.text | ||
|  | 
 | ||
|  | 	.globl __strlen_user
 | ||
|  | 	.ent __strlen_user
 | ||
|  | 	.frame sp, 0, ra | ||
|  | 
 | ||
|  | 	.align 4
 | ||
|  | __strlen_user: | ||
|  | 	ldah	a1, 32767(zero)	# do not use plain strlen_user() for strings | ||
|  | 				# that might be almost 2 GB long; you should
 | ||
|  | 				# be using strnlen_user() instead | ||
|  | 	nop | ||
|  | 	nop | ||
|  | 	nop | ||
|  | 
 | ||
|  | 	.globl __strnlen_user
 | ||
|  | 
 | ||
|  | 	.align 4
 | ||
|  | __strnlen_user: | ||
|  | 	.prologue 0
 | ||
|  | 	EX( ldq_u t0, 0(a0) )	# L : load first quadword (a0 may be misaligned) | ||
|  | 	lda     t1, -1(zero)	# E : | ||
|  | 
 | ||
|  | 	insqh   t1, a0, t1	# U : | ||
|  | 	andnot  a0, 7, v0	# E : | ||
|  | 	or      t1, t0, t0	# E : | ||
|  | 	subq	a0, 1, a0	# E : get our +1 for the return  | ||
|  | 
 | ||
|  | 	cmpbge  zero, t0, t1	# E : t1 <- bitmask: bit i == 1 <==> i-th byte == 0 | ||
|  | 	subq	a1, 7, t2	# E : | ||
|  | 	subq	a0, v0, t0	# E : | ||
|  | 	bne     t1, $found	# U : | ||
|  | 
 | ||
|  | 	addq	t2, t0, t2	# E : | ||
|  | 	addq	a1, 1, a1	# E : | ||
|  | 	nop			# E : | ||
|  | 	nop			# E : | ||
|  | 
 | ||
|  | 	.align 4
 | ||
|  | $loop:	ble	t2, $limit	# U : | ||
|  | 	EX( ldq t0, 8(v0) )	# L : | ||
|  | 	nop			# E : | ||
|  | 	nop			# E : | ||
|  | 
 | ||
|  | 	cmpbge  zero, t0, t1	# E : | ||
|  | 	subq	t2, 8, t2	# E : | ||
|  | 	addq    v0, 8, v0	# E : addr += 8 | ||
|  | 	beq     t1, $loop	# U : | ||
|  | 
 | ||
|  | $found: cttz	t1, t2		# U0 : | ||
|  | 	addq	v0, t2, v0	# E : | ||
|  | 	subq    v0, a0, v0	# E : | ||
|  | 	ret			# L0 : | ||
|  | 
 | ||
|  | $exception: | ||
|  | 	nop | ||
|  | 	nop | ||
|  | 	nop | ||
|  | 	ret | ||
|  | 
 | ||
|  | 	.align 4		# currently redundant | ||
|  | $limit: | ||
|  | 	nop | ||
|  | 	nop | ||
|  | 	subq	a1, t2, v0 | ||
|  | 	ret | ||
|  | 
 | ||
|  | 	.end __strlen_user
 |