summaryrefslogtreecommitdiff
path: root/libgcc/config/rl78/cmpsi2.S
blob: 20899973cc08a37e90a2af6a65d6a2cb8e2b86d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
;   Copyright (C) 2011-2017 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