| ;   Copyright (C) 2011-2021 Free Software Foundation, Inc. | 
 | ;   Contributed by Red Hat. | 
 | ;  | 
 | ; This file is free software; you can redistribute it and/or modify it | 
 | ; under the terms of the GNU General Public License as published by the | 
 | ; Free Software Foundation; either version 3, or (at your option) any | 
 | ; later version. | 
 | ;  | 
 | ; This file is distributed in the hope that it will be useful, but | 
 | ; WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 | ; General Public License for more details. | 
 | ;  | 
 | ; Under Section 7 of GPL version 3, you are granted additional | 
 | ; permissions described in the GCC Runtime Library Exception, version | 
 | ; 3.1, as published by the Free Software Foundation. | 
 | ; | 
 | ; You should have received a copy of the GNU General Public License and | 
 | ; a copy of the GCC Runtime Library Exception along with this program; | 
 | ; see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see | 
 | ; <http://www.gnu.org/licenses/>. | 
 |  | 
 |  | 
 | #include "vregs.h" | 
 |  | 
 | 	.text | 
 |  | 
 | 	;;   int __cmpsi2 (signed long A, signed long B) | 
 | 	;; | 
 | 	;; Performs a signed comparison of A and B. | 
 | 	;; If A is less than B it returns 0.  If A is greater | 
 | 	;; than B it returns 2.  If they are equal it returns 1. | 
 |  | 
 | START_FUNC ___cmpsi2 | 
 |  | 
 | 	;; A is at [sp+4] | 
 | 	;; B is at [sp+8] | 
 | 	;; Result put in R8 | 
 |  | 
 | 	;; Initialise default return value. | 
 | 	onew	bc | 
 | 	 | 
 | 	;;  Compare the high words. | 
 | 	movw	ax, [sp + 10] | 
 | 	movw	de, ax | 
 | 	movw	ax, [sp + 6] | 
 | 	cmpw	ax, de | 
 | 	skz | 
 | 	br	!!.Lconvert_to_signed | 
 |  | 
 | .Lcompare_bottom_words:	 | 
 | 	;; The top words are equal - compare the bottom words. | 
 | 	;; Note - code from __ucmpsi2 branches into here. | 
 | 	movw   ax, [sp + 8] | 
 | 	movw   de, ax | 
 | 	movw   ax, [sp + 4] | 
 | 	cmpw   ax, de | 
 | 	sknz | 
 | 	br	!!.Lless_than_or_greater_than | 
 | 	;; The words are equal - return 1. | 
 | 	;; Note - we could branch to the return code at the end of the | 
 | 	;; function but a branch instruction takes 4 bytes, and the | 
 | 	;; return sequence itself is only 4 bytes long... | 
 | 	movw	ax, bc | 
 | 	movw	r8, ax | 
 | 	ret | 
 |  | 
 | .Lconvert_to_signed:	 | 
 | 	;; The top words are different.  Unfortunately the comparison | 
 | 	;; is always unsigned, so to get a signed result we XOR the CY | 
 | 	;; flag with the top bits of AX and DE. | 
 | 	xor1	cy, a.7 | 
 | 	mov	a, d | 
 | 	xor1	cy, a.7 | 
 | 	;; Fall through. | 
 |  | 
 | .Lless_than_or_greater_than: | 
 | 	;; We now have a signed less than/greater than result in CY. | 
 | 	;; Return 0 for less than, 2 for greater than. | 
 | 	;; Note - code from __ucmpsi2 branches into here. | 
 | 	incw	bc | 
 | 	sknc | 
 | 	clrw	bc | 
 |  | 
 | 	;; Get the result value, currently in BC, into r8 | 
 | 	movw	ax, bc | 
 | 	movw	r8, ax | 
 | 	ret | 
 |  | 
 | END_FUNC ___cmpsi2 | 
 |  | 
 | ;; ------------------------------------------------------ | 
 |  | 
 | 	;;   int __ucmpsi2 (unsigned long A, unsigned long B) | 
 | 	;; | 
 | 	;; Performs an unsigned comparison of A and B. | 
 | 	;; If A is less than B it returns 0.  If A is greater | 
 | 	;; than B it returns 2.  If they are equal it returns 1. | 
 |  | 
 | START_FUNC ___ucmpsi2 | 
 |  | 
 | 	;; A is at [sp+4] | 
 | 	;; B is at [sp+8] | 
 | 	;; Result put in R8..R9 | 
 |  | 
 | 	;; Initialise default return value. | 
 | 	onew	bc | 
 |  | 
 | 	;;  Compare the high words. | 
 | 	movw	ax, [sp + 10] | 
 | 	movw	de, ax | 
 | 	movw	ax, [sp + 6] | 
 | 	cmpw	ax, de | 
 | 	skz | 
 | 	;; Note: These branches go into the __cmpsi2 code! | 
 | 	br	!!.Lless_than_or_greater_than | 
 | 	br	!!.Lcompare_bottom_words | 
 |  | 
 | END_FUNC ___ucmpsi2 | 
 |  | 
 | ;; ------------------------------------------------------ | 
 | 	 | 
 | 	;;   signed int __gcc_bcmp (const unsigned char *s1, const unsigned char *s2, size_t size) | 
 | 	;;   Result is negative if S1 is less than S2, | 
 | 	;;   positive if S1 is greater, 0 if S1 and S2 are equal. | 
 |  | 
 | START_FUNC __gcc_bcmp | 
 |  | 
 | 	;; S1 is at [sp+4] | 
 | 	;; S2 is at [sp+6] | 
 | 	;; SIZE is at [sp+8] | 
 | 	;; Result in r8/r9 | 
 | 	 | 
 |         movw	r10, #0 | 
 | 1: | 
 | 	;; Compare R10 against the SIZE parameter | 
 |         movw	ax, [sp+8] | 
 |         subw	ax, r10 | 
 |         sknz | 
 |         br	!!1f | 
 |  | 
 | 	;; Load S2[r10] into R8 | 
 |         movw	ax, [sp+6] | 
 |         addw	ax, r10 | 
 |         movw	hl, ax | 
 |         mov	a, [hl] | 
 |         mov	r8, a | 
 |  | 
 | 	;; Load S1[r10] into A | 
 |         movw	ax, [sp+4] | 
 |         addw	ax, r10 | 
 |         movw	hl, ax | 
 |         mov	a, [hl] | 
 |  | 
 | 	;; Increment offset | 
 |         incw	r10 | 
 |  | 
 | 	;; Compare loaded bytes | 
 |         cmp	a, r8 | 
 |         sknz | 
 |         br	!!1b | 
 |  | 
 | 	;; They differ.  Subtract *S2 from *S1 and return as the result. | 
 | 	mov	x, a | 
 | 	mov	a, #0 | 
 | 	mov	r9, #0 | 
 | 	subw	ax, r8 | 
 | 1: | 
 | 	movw	r8, ax | 
 |         ret | 
 |  | 
 | END_FUNC __gcc_bcmp |