;   Copyright (C) 2011-2020 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
