|
|
1.1 root 1: ;; libgcc1 routines for the Hitachi h8/300 cpu.
2: ;; Contributed by Steve Chamberlain.
3: ;; [email protected]
4:
5: /* Copyright (C) 1994 Free Software Foundation, Inc.
6:
7: This file is free software; you can redistribute it and/or modify it
8: under the terms of the GNU General Public License as published by the
9: Free Software Foundation; either version 2, or (at your option) any
10: later version.
11:
12: In addition to the permissions in the GNU General Public License, the
13: Free Software Foundation gives you unlimited permission to link the
14: compiled version of this file with other programs, and to distribute
15: those programs without any restriction coming from the use of this
16: file. (The General Public License restrictions do apply in other
17: respects; for example, they cover modification of the file, and
18: distribution when not linked into another program.)
19:
20: This file is distributed in the hope that it will be useful, but
21: WITHOUT ANY WARRANTY; without even the implied warranty of
22: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23: General Public License for more details.
24:
25: You should have received a copy of the GNU General Public License
26: along with this program; see the file COPYING. If not, write to
27: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
28:
29: /* As a special exception, if you link this library with other files,
30: some of which are compiled with GCC, to produce an executable,
31: this library does not by itself cause the resulting executable
32: to be covered by the GNU General Public License.
33: This exception does not however invalidate any other reasons why
34: the executable file might be covered by the GNU General Public License. */
35:
36: /* Assembler register definitions. */
37:
38: #define A0 r0
39: #define A0L r0l
40: #define A0H r0h
41:
42: #define A1 r1
43: #define A1L r1l
44: #define A1H r1h
45:
46: #define A2 r2
47: #define A2L r2l
48: #define A2H r2h
49:
50: #define A3 r3
51: #define A3L r3l
52: #define A3H r3h
53:
54: #define S0 r4
55: #define S0L r4l
56: #define S0H r4h
57:
58: #define S1 r5
59: #define S1L r5l
60: #define S1H r5h
61:
62: #define S2 r6
63: #define S2L r6l
64: #define S2H r6h
65:
66: #ifdef __H8300__
67: #define MOVP mov.w /* pointers are 16 bits */
68: #define ADDP add.w
69: #define CMPP cmp.w
70: #define PUSHP push
71: #define POPP pop
72:
73: #define A0P r0
74: #define A1P r1
75: #define A2P r2
76: #define A3P r3
77: #define S0P r4
78: #define S1P r5
79: #define S2P r6
80: #endif
81:
82: #ifdef __H8300H__
83: #define MOVP mov.l /* pointers are 32 bits */
84: #define ADDP add.l
85: #define CMPP cmp.l
86: #define PUSHP push.l
87: #define POPP pop.l
88:
89: #define A0P er0
90: #define A1P er1
91: #define A2P er2
92: #define A3P er3
93: #define S0P er4
94: #define S1P er5
95: #define S2P er6
96:
97: #define A0E e0
98: #define A1E e1
99: #define A2E e2
100: #define A3E e3
101: #endif
102:
103: #ifdef L_cmpsi2
104: #ifdef __H8300__
105: .section .text
106: .align 2
107: .global ___cmpsi2
108: ___cmpsi2:
109: cmp.w A2,A0
110: bne .L2
111: cmp.w A3,A1
112: bne .L2
113: mov.w #1,A0
114: rts
115: .L2:
116: cmp.w A0,A2
117: bgt .L4
118: bne .L3
119: cmp.w A1,A3
120: bls .L3
121: .L4:
122: sub.w A0,A0
123: rts
124: .L3:
125: mov.w #2,A0
126: .L5:
127: rts
128: .end
129: #endif
130: #endif /* L_cmpsi2 */
131:
132: #ifdef L_ucmpsi2
133: #ifdef __H8300__
134: .section .text
135: .align 2
136: .global ___ucmpsi2
137: ___ucmpsi2:
138: cmp.w A2,A0
139: bne .L2
140: cmp.w A3,A1
141: bne .L2
142: mov.w #1,A0
143: rts
144: .L2:
145: cmp.w A0,A2
146: bhi .L4
147: bne .L3
148: cmp.w A1,A3
149: bls .L3
150: .L4:
151: sub.w A0,A0
152: rts
153: .L3:
154: mov.w #2,A0
155: .L5:
156: rts
157: .end
158: #endif
159: #endif /* L_ucmpsi2 */
160:
161: #ifdef L_divhi3
162:
163: ;; HImode divides for the H8/300.
164: ;; We bunch all of this into one object file since there are several
165: ;; "supporting routines".
166:
167: ; general purpose normalize routine
168: ;
169: ; divisor in A0
170: ; dividend in A1
171: ; turns both into +ve numbers, and leaves what the answer sign
172: ; should be in A2L
173:
174: #ifdef __H8300__
175: .section .text
176: .align 2
177: divnorm:
178: mov.b #0x0,A2L
179: or A0H,A0H ; is divisor > 0
180: bge _lab1
181: not A0H ; no - then make it +ve
182: not A0L
183: adds #1,A0
184: xor #0x1,A2L ; and remember that in A2L
185: _lab1: or A1H,A1H ; look at dividend
186: bge _lab2
187: not A1H ; it is -ve, make it positive
188: not A1L
189: adds #1,A1
190: xor #0x1,A2L; and toggle sign of result
191: _lab2: rts
192:
193: ; A0=A0/A1 signed
194:
195: .global ___divhi3
196: ___divhi3:
197: bsr divnorm
198: bsr ___udivhi3
199: negans: or A2L,A2L ; should answer be negative ?
200: beq _lab4
201: not A0H ; yes, so make it so
202: not A0L
203: adds #1,A0
204: _lab4: rts
205:
206: ; A0=A0%A1 signed
207:
208: .global ___modhi3
209: ___modhi3:
210: bsr divnorm
211: bsr ___udivhi3
212: mov A3,A0
213: bra negans
214:
215: ; A0=A0%A1 unsigned
216:
217: .global ___umodhi3
218: ___umodhi3:
219: bsr ___udivhi3
220: mov A3,A0
221: rts
222:
223: ; A0=A0/A1 unsigned
224: ; A3=A0%A1 unsigned
225: ; A2H trashed
226: ; D high 8 bits of denom
227: ; d low 8 bits of denom
228: ; N high 8 bits of num
229: ; n low 8 bits of num
230: ; M high 8 bits of mod
231: ; m low 8 bits of mod
232: ; Q high 8 bits of quot
233: ; q low 8 bits of quot
234: ; P preserve
235:
236: ; The h8 only has a 16/8 bit divide, so we look at the incoming and
237: ; see how to partition up the expression.
238:
239: .global ___udivhi3
240: ___udivhi3:
241: ; A0 A1 A2 A3
242: ; Nn Dd P
243: sub.w A3,A3 ; Nn Dd xP 00
244: or A1H,A1H
245: bne divlongway
246: or A0H,A0H
247: beq _lab6
248:
249: ; we know that D == 0 and N is != 0
250: mov.b A0H,A3L ; Nn Dd xP 0N
251: divxu A1L,A3 ; MQ
252: mov.b A3L,A0H ; Q
253: ; dealt with N, do n
254: _lab6: mov.b A0L,A3L ; n
255: divxu A1L,A3 ; mq
256: mov.b A3L,A0L ; Qq
257: mov.b A3H,A3L ; m
258: mov.b #0x0,A3H ; Qq 0m
259: rts
260:
261: ; D != 0 - which means the denominator is
262: ; loop around to get the result.
263:
264: divlongway:
265: mov.b A0H,A3L ; Nn Dd xP 0N
266: mov.b #0x0,A0H ; high byte of answer has to be zero
267: mov.b #0x8,A2H ; 8
268: div8: add.b A0L,A0L ; n*=2
269: rotxl A3L ; Make remainder bigger
270: rotxl A3H
271: sub.w A1,A3 ; Q-=N
272: bhs setbit ; set a bit ?
273: add.w A1,A3 ; no : too far , Q+=N
274:
275: dec A2H
276: bne div8 ; next bit
277: rts
278:
279: setbit: inc A0L ; do insert bit
280: dec A2H
281: bne div8 ; next bit
282: rts
283:
284: #endif /* __H8300__ */
285: #endif /* L_divhi3 */
286:
287: #ifdef L_divsi3
288:
289: ;; 4 byte integer divides for the H8/300.
290: ;;
291: ;; We have one routine which does all the work and lots of
292: ;; little ones which prepare the args and massage the sign.
293: ;; We bunch all of this into one object file since there are several
294: ;; "supporting routines".
295:
296: #ifdef __H8300H__
297: .h8300h
298: #endif
299:
300: .section .text
301: .align 2
302:
303: ; Put abs SIs into r0/r1 and r2/r3, and leave a 1 in r6l with sign of rest.
304: ; This function is here to keep branch displacements small.
305:
306: #ifdef __H8300__
307:
308: divnorm:
309: mov.b #0,S2L ; keep the sign in S2
310: mov.b A0H,A0H ; is the numerator -ve
311: bge postive
312:
313: ; negate arg
314: not A0H
315: not A1H
316: not A0L
317: not A1L
318:
319: add #1,A1L
320: addx #0,A1H
321: addx #0,A0H
322: addx #0,A0L
323:
324: mov.b #1,S2L ; the sign will be -ve
325: postive:
326: mov.b A2H,A2H ; is the denominator -ve
327: bge postive2
328: not A2L
329: not A2H
330: not A3L
331: not A3H
332: add.b #1,A3L
333: addx #0,A3H
334: addx #0,A2L
335: addx #0,A2H
336: xor #1,S2L ; toggle result sign
337: postive2:
338: rts
339:
340: #else /* __H8300H__ */
341:
342: divnorm:
343: mov.b #0,S2L ; keep the sign in S2
344: mov.l A0P,A0P ; is the numerator -ve
345: bge postive
346:
347: neg.l A0P ; negate arg
348: mov.b #1,S2L ; the sign will be -ve
349:
350: postive:
351: mov.l A1P,A1P ; is the denominator -ve
352: bge postive2
353:
354: neg.l A1P ; negate arg
355: xor.b #1,S2L ; toggle result sign
356:
357: postive2:
358: rts
359:
360: #endif
361:
362: ; numerator in A0/A1
363: ; denominator in A2/A3
364: .global ___modsi3
365: ___modsi3:
366: PUSHP S2P
367: PUSHP S0P
368: PUSHP S1P
369:
370: bsr divnorm
371: bsr divmodsi4
372: #ifdef __H8300__
373: mov S0,A0
374: mov S1,A1
375: #else
376: mov.l S0P,A0P
377: #endif
378: bra exitdiv
379:
380: .global ___udivsi3
381: ___udivsi3:
382: PUSHP S2P
383: PUSHP S0P
384: PUSHP S1P
385: mov.b #0,S2L ; keep sign low
386: bsr divmodsi4
387: bra exitdiv
388:
389: .global ___umodsi3
390: ___umodsi3:
391: PUSHP S2P
392: PUSHP S0P
393: PUSHP S1P
394: mov.b #0,S2L ; keep sign low
395: bsr divmodsi4
396: #ifdef __H8300__
397: mov S0,A0
398: mov S1,A1
399: #else
400: mov.l S0P,A0P
401: #endif
402: bra exitdiv
403:
404: .global ___divsi3
405: ___divsi3:
406: PUSHP S2P
407: PUSHP S0P
408: PUSHP S1P
409: jsr divnorm
410: jsr divmodsi4
411:
412: ; examine what the sign should be
413: exitdiv:
414: POPP S1P
415: POPP S0P
416:
417: or S2L,S2L
418: beq reti
419:
420: ; should be -ve
421: #ifdef __H8300__
422: not A0H
423: not A1H
424: not A0L
425: not A1L
426:
427: add #1,A1L
428: addx #0,A1H
429: addx #0,A0H
430: addx #0,A0L
431: #else /* __H8300H__ */
432: neg.l A0P
433: #endif
434:
435: reti:
436: POPP S2P
437: rts
438:
439: ; takes A0/A1 numerator (A0P for 300h)
440: ; A2/A3 denominator (A1P for 300h)
441: ; returns A0/A1 quotient (A0P for 300h)
442: ; S0/S1 remainder (S0P for 300h)
443: ; trashes S2
444:
445: #ifdef __H8300__
446:
447: divmodsi4:
448: sub.w S0,S0 ; zero play area
449: mov.w S0,S1
450: mov.b A2H,S2H
451: or A2L,S2H
452: or A3H,S2H
453: bne DenHighZero
454: mov.b A0H,A0H
455: bne NumByte0Zero
456: mov.b A0L,A0L
457: bne NumByte1Zero
458: mov.b A1H,A1H
459: bne NumByte2Zero
460: bra NumByte3Zero
461: NumByte0Zero:
462: mov.b A0H,S1L
463: divxu A3L,S1
464: mov.b S1L,A0H
465: NumByte1Zero:
466: mov.b A0L,S1L
467: divxu A3L,S1
468: mov.b S1L,A0L
469: NumByte2Zero:
470: mov.b A1H,S1L
471: divxu A3L,S1
472: mov.b S1L,A1H
473: NumByte3Zero:
474: mov.b A1L,S1L
475: divxu A3L,S1
476: mov.b S1L,A1L
477:
478: mov.b S1H,S1L
479: mov.b #0x0,S1H
480: rts
481:
482: ; have to do the divide by shift and test
483: DenHighZero:
484: mov.b A0H,S1L
485: mov.b A0L,A0H
486: mov.b A1H,A0L
487: mov.b A1L,A1H
488:
489: mov.b #0,A1L
490: mov.b #24,S2H ; only do 24 iterations
491:
492: nextbit:
493: add.w A1,A1 ; double the answer guess
494: rotxl A0L
495: rotxl A0H
496:
497: rotxl S1L ; double remainder
498: rotxl S1H
499: rotxl S0L
500: rotxl S0H
501: sub.w A3,S1 ; does it all fit
502: subx A2L,S0L
503: subx A2H,S0H
504: bhs setone
505:
506: add.w A3,S1 ; no, restore mistake
507: addx A2L,S0L
508: addx A2H,S0H
509:
510: dec S2H
511: bne nextbit
512: rts
513:
514: setone:
515: inc A1L
516: dec S2H
517: bne nextbit
518: rts
519:
520: #else /* __H8300H__ */
521:
522: divmodsi4:
523: sub.l S0P,S0P ; zero play area
524: mov.w A1E,A1E ; denominator top word 0?
525: bne DenHighZero
526:
527: ; do it the easy way, see page 107 in manual
528: mov.w A0E,A2
529: extu.l A2P
530: divxu.w A1,A2P
531: mov.w A2E,A0E
532: divxu.w A1,A0P
533: mov.w A0E,S0
534: mov.w A2,A0E
535: extu.l S0P
536: rts
537:
538: DenHighZero:
539: mov.w A0E,A2
540: mov.b A2H,S0L
541: mov.b A2L,A2H
542: mov.b A0H,A2L
543: mov.w A2,A0E
544: mov.b A0L,A0H
545: mov.b #0,A0L
546: mov.b #24,S2H ; only do 24 iterations
547:
548: nextbit:
549: shll.l A0P ; double the answer guess
550: rotxl.l S0P ; double remainder
551: sub.l A1P,S0P ; does it all fit?
552: bhs setone
553:
554: add.l A1P,S0P ; no, restore mistake
555: dec S2H
556: bne nextbit
557: rts
558:
559: setone:
560: inc A0L
561: dec S2H
562: bne nextbit
563: rts
564:
565: #endif
566: #endif /* L_divsi3 */
567:
568: #ifdef L_mulhi3
569:
570: ;; HImode multiply.
571: ; The h8 only has an 8*8->16 multiply.
572: ; The answer is the same as:
573: ;
574: ; product = (srca.l * srcb.l) + ((srca.h * srcb.l) + (srcb.h * srca.l)) * 256
575: ; (we can ignore A1.h * A0.h cause that will all off the top)
576: ; A0 in
577: ; A1 in
578: ; A0 answer
579:
580: #ifdef __H8300__
581: .section .text
582: .align 2
583: .global ___mulhi3
584: ___mulhi3:
585: mov.b A1L,A2L ; A2l gets srcb.l
586: mulxu A0L,A2 ; A2 gets first sub product
587:
588: mov.b A0H,A3L ; prepare for
589: mulxu A1L,A3 ; second sub product
590:
591: add.b A3L,A2H ; sum first two terms
592:
593: mov.b A1H,A3L ; third sub product
594: mulxu A0L,A3
595:
596: add.b A3L,A2H ; almost there
597: mov.w A2,A0 ; that is
598: rts
599:
600: #endif
601: #endif /* L_mulhi3 */
602:
603: #ifdef L_mulsi3
604:
605: ;; SImode multiply.
606: ;;
607: ;; I think that shift and add may be sufficient for this. Using the
608: ;; supplied 8x8->16 would need 10 ops of 14 cycles each + overhead. This way
609: ;; the inner loop uses maybe 20 cycles + overhead, but terminates
610: ;; quickly on small args.
611: ;;
612: ;; A0/A1 src_a
613: ;; A2/A3 src_b
614: ;;
615: ;; while (a)
616: ;; {
617: ;; if (a & 1)
618: ;; r += b;
619: ;; a >>= 1;
620: ;; b <<= 1;
621: ;; }
622:
623: .section .text
624: .align 2
625:
626: #ifdef __H8300__
627:
628: .global ___mulsi3
629: ___mulsi3:
630: PUSHP S0P
631: PUSHP S1P
632: PUSHP S2P
633:
634: sub.w S0,S0
635: sub.w S1,S1
636:
637: ; while (a)
638: _top: mov.w A0,A0
639: bne _more
640: mov.w A1,A1
641: beq _done
642: _more: ; if (a & 1)
643: bld #0,A1L
644: bcc _nobit
645: ; r += b
646: add.w A3,S1
647: addx A2L,S0L
648: addx A2H,S0H
649: _nobit:
650: ; a >>= 1
651: shlr A0H
652: rotxr A0L
653: rotxr A1H
654: rotxr A1L
655:
656: ; b <<= 1
657: add.w A3,A3
658: addx A2L,A2L
659: addx A2H,A2H
660: bra _top
661:
662: _done:
663: mov.w S0,A0
664: mov.w S1,A1
665: POPP S2P
666: POPP S1P
667: POPP S0P
668: rts
669:
670: #else /* __H8300H__ */
671:
672: .h8300h
673:
674: .global ___mulsi3
675: ___mulsi3:
676: sub.l A2P,A2P
677:
678: ; while (a)
679: _top: mov.l A0P,A0P
680: beq _done
681:
682: ; if (a & 1)
683: bld #0,A0L
684: bcc _nobit
685:
686: ; r += b
687: add.l A1P,A2P
688:
689: _nobit:
690: ; a >>= 1
691: shlr.l A0P
692:
693: ; b <<= 1
694: shll.l A1P
695: bra _top
696:
697: _done:
698: mov.l A2P,A0P
699: rts
700:
701: #endif
702: #endif /* L_mulsi3 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.