1;;  Machine Description for Renesas RL78 processors
2;;  Copyright (C) 2011-2018 Free Software Foundation, Inc.
3;;  Contributed by Red Hat.
4
5;; This file is part of GCC.
6
7;; GCC is free software; you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation; either version 3, or (at your option)
10;; any later version.
11
12;; GCC is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GCC; see the file COPYING3.  If not see
19;; <http://www.gnu.org/licenses/>.
20
21(define_constants
22  [
23   (AX_REG 0)
24   (X_REG 0)
25   (A_REG 1)
26   (BC_REG 2)
27   (C_REG 2)
28   (B_REG 3)
29   (DE_REG 4)
30   (E_REG 4)
31   (D_REG 5)
32   (HL_REG 6)
33   (L_REG 6)
34   (H_REG 7)
35
36   (FP_REG 22)
37   (SP_REG 32)
38   (CC_REG 34)
39   (ES_REG 35)
40   (CS_REG 36)
41
42   (UNS_PROLOG	1)
43   (UNS_EPILOG	1)
44   (UNS_RETI	2)
45   (UNS_RETB	3)
46
47   (UNS_SET_RB	10)
48   (UNS_ES_ADDR	11)
49
50   (UNS_TRAMPOLINE_INIT		20)
51   (UNS_TRAMPOLINE_UNINIT	21)
52   (UNS_NONLOCAL_GOTO		22)
53
54   ])
55
56(define_insn "nop"
57  [(const_int 0)]
58  ""
59  "nop"
60  )
61
62(define_mode_iterator QHI [QI HI])
63
64(include "predicates.md")
65(include "constraints.md")
66(include "rl78-expand.md")
67(include "rl78-virt.md")
68(include "rl78-real.md")
69
70(define_attr "is_g13_muldiv_insn" "yes,no" (const_string "no"))
71
72;; Function Prologue/Epilogue Instructions
73
74(define_expand "prologue"
75  [(const_int 0)]
76  ""
77  "rl78_expand_prologue (); DONE;"
78)
79
80(define_expand "epilogue"
81  [(const_int 0)]
82  ""
83  "rl78_expand_epilogue (); DONE;"
84)
85
86(define_expand "sibcall_epilogue"
87  [(return)]
88  ""
89  "FAIL;"
90)
91
92(define_insn "rl78_return"
93  [(return)]
94  ""
95  "ret"
96)
97
98(define_insn "interrupt_return"
99  [(unspec_volatile [(return)] UNS_RETI) ]
100  ""
101  "reti"
102)
103
104(define_insn "brk_interrupt_return"
105  [(unspec_volatile [(return)] UNS_RETB) ]
106  ""
107  "retb"
108)
109
110(define_expand "eh_return"
111  [(match_operand:HI 0 "")]
112  ""
113  "rl78_expand_eh_epilogue (operands[0]);
114   emit_barrier ();
115   DONE;"
116)
117
118;; These are used only by prologue/epilogue so it's "safe" to pass
119;; virtual registers.
120(define_insn "push"
121  [(set (reg:HI SP_REG)
122	(plus:HI (reg:HI SP_REG)
123		  (const_int -2)))
124   (set (mem:HI (reg:HI SP_REG))
125	(match_operand:HI 0 "register_operand" "ABDT,vZint"))]
126  ""
127  "@
128   push\t%v0
129   push\t%v0 ; %0"
130)
131
132(define_insn "pop"
133  [(set (match_operand:HI 0 "register_operand" "=ABDT,vZint")
134	(mem:HI (reg:HI SP_REG)))
135   (set (reg:HI SP_REG)
136	(plus:HI (reg:HI SP_REG)
137		    (const_int 2)))]
138  ""
139  "@
140   pop\t%v0
141   pop\t%v0 ; %0"
142)
143
144(define_insn "sel_rb"
145  [(unspec_volatile [(match_operand 0 "immediate_operand" "")] UNS_SET_RB)]
146  "!TARGET_G10"
147  "sel\trb%u0"
148  )
149
150(define_insn "trampoline_init"
151  [(set (match_operand 0 "register_operand" "=Z08W")
152	(unspec_volatile [(match_operand 1 "register_operand" "Z08W")
153			  (match_operand 2 "register_operand" "Z10W")
154			  ] UNS_TRAMPOLINE_INIT))
155   ]
156  ""
157  "call !!___trampoline_init ; %0 <= %1 %2"
158  )
159
160(define_insn "trampoline_uninit"
161  [(unspec_volatile [(const_int 0)] UNS_TRAMPOLINE_UNINIT)
162   ]
163  ""
164  "call !!___trampoline_uninit"
165  )
166
167;; GCC restores $fp *before* using it to access values on the *old*
168;; frame.  So, we do it ourselves, to ensure this is not the case.
169;; Note that while %1 is usually a label_ref, we allow for a
170;; non-immediate as well.
171(define_expand "nonlocal_goto"
172  [(set (pc)
173	(unspec_volatile [(match_operand 0 "") ;; fp (ignore)
174			  (match_operand 1 "") ;; target
175			  (match_operand 2 "") ;; sp
176			  (match_operand 3 "") ;; ?
177			  ] UNS_NONLOCAL_GOTO))
178   ]
179  ""
180  "emit_jump_insn (gen_nonlocal_goto_insn (operands[0], operands[1], operands[2], operands[3]));
181   emit_barrier ();
182   DONE;"
183  )
184
185(define_insn "nonlocal_goto_insn"
186  [(set (pc)
187	(unspec_volatile [(match_operand 0 "" "") ;; fp (ignore)
188			  (match_operand 1 "" "vi") ;; target
189			  (match_operand 2 "" "vi") ;; sp
190			  (match_operand 3 "" "vi") ;; ?
191			  ] UNS_NONLOCAL_GOTO))
192   ]
193  ""
194  "; nonlocal goto
195	movw	ax, %3
196	movw	r22, ax
197	movw	ax, %2
198	movw	sp, ax
199	movw	ax, %1
200	br	ax
201"
202  )
203
204(define_expand "es_addr"
205  [(unspec:SI [(reg:QI ES_REG)
206	       (match_operand:HI 0 "")
207	       ] UNS_ES_ADDR)]
208  ""
209  ""
210)
211
212;;======================================================================
213;;
214;; "macro" insns - cases where inline chunks of code are more
215;; efficient than anything else.
216
217(define_expand "addsi3"
218  [(set (match_operand:SI          0 "nonimmediate_operand" "=&vm")
219	(plus:SI (match_operand:SI 1 "general_operand"      "vim")
220		 (match_operand    2 "general_operand"      "vim")))
221   ]
222  ""
223  "emit_insn (gen_addsi3_internal_virt (operands[0], operands[1], operands[2]));
224   DONE;"
225)
226
227(define_expand "adddi3"
228  [(set (match_operand:DI          0 "nonimmediate_operand" "")
229	(plus:DI (match_operand:DI 1 "general_operand"      "")
230		 (match_operand:DI 2 "general_operand"      "")))
231   ]
232  ""
233  "rl78_emit_libcall (\"__adddi3\", PLUS, DImode, DImode, 3, operands);
234   DONE;"
235)
236
237(define_insn "addsi3_internal_virt"
238  [(set (match_operand:SI          0 "nonimmediate_operand" "=v,&vm, vm")
239	(plus:SI (match_operand:SI 1 "general_operand"      "0, vim, vim")
240		 (match_operand    2 "general_operand"      "vim,vim,vim")))
241   (clobber (reg:HI AX_REG))
242   (clobber (reg:HI BC_REG))
243   ]
244  "rl78_virt_insns_ok ()"
245  ""
246  [(set_attr "valloc" "macax")]
247)
248
249(define_insn "addsi3_internal_real"
250  [(set (match_operand:SI          0 "nonimmediate_operand" "=v,&vU, vU")
251	(plus:SI (match_operand:SI 1 "general_operand"      "+0, viU, viU")
252		 (match_operand    2 "general_operand"      "viWabWhlWh1,viWabWhlWh1,viWabWhlWh1")))
253   (clobber (reg:HI AX_REG))
254   (clobber (reg:HI BC_REG))
255   ]
256  "rl78_real_insns_ok ()"
257  { return rl78_addsi3_internal (operands, which_alternative); }
258  [(set_attr "valloc" "macax")]
259)
260
261(define_expand "subsi3"
262  [(set (match_operand:SI           0 "nonimmediate_operand")
263	(minus:SI (match_operand:SI 1 "general_operand")
264		  (match_operand    2 "general_operand")))
265   ]
266  ""
267  "emit_insn (gen_subsi3_internal_virt (operands[0], operands[1], operands[2]));
268  DONE;"
269)
270
271(define_expand "subdi3"
272 [(set (match_operand:DI          0 "nonimmediate_operand" "")
273    (minus:DI (match_operand:DI 1 "general_operand"      "")
274         (match_operand:DI    2 "general_operand"      "")))
275   ]
276  ""
277  "rl78_emit_libcall (\"__subdi3\", MINUS, DImode, DImode, 3, operands);
278   DONE;"
279)
280
281(define_insn "subsi3_internal_virt"
282  [(set (match_operand:SI           0 "nonimmediate_operand" "=v,&vm, vm")
283	(minus:SI (match_operand:SI 1 "general_operand"      "0, vim, vim")
284		  (match_operand    2 "general_operand"      "vim,vim,vim")))
285   (clobber (reg:HI AX_REG))
286   (clobber (reg:HI BC_REG))
287   ]
288  "rl78_virt_insns_ok ()"
289  ""
290  [(set_attr "valloc" "macax")]
291)
292
293(define_insn "subsi3_internal_real"
294  [(set (match_operand:SI           0 "nonimmediate_operand" "=v,&vU, vU")
295	(minus:SI (match_operand:SI 1 "general_operand"      "+0, viU, viU")
296		  (match_operand    2 "general_operand"      "viWabWhlWh1,viWabWhlWh1,viWabWhlWh1")))
297   (clobber (reg:HI AX_REG))
298   (clobber (reg:HI BC_REG))
299   ]
300  "rl78_real_insns_ok ()"
301  "@
302   movw ax,%h1 \;subw ax,%h2 \;movw %h0, ax \;movw ax,%H1 \;sknc \;decw ax \;subw ax,%H2 \;movw %H0,ax
303   movw ax,%h1 \;subw ax,%h2 \;movw %h0, ax \;movw ax,%H1 \;sknc \;decw ax \;subw ax,%H2 \;movw %H0,ax
304   movw ax,%h1 \;subw ax,%h2 \;movw bc,  ax \;movw ax,%H1 \;sknc \;decw ax \;subw ax,%H2 \;movw %H0,ax \;movw ax,bc \;movw %h0, ax"
305  [(set_attr "valloc" "macax")]
306)
307
308(define_expand "mulqi3"
309  [(parallel
310    [(set (match_operand:QI            0 "register_operand")
311	   (mult:QI  (match_operand:QI 1 "general_operand")
312		     (match_operand:QI 2 "nonmemory_operand")))
313      (clobber (reg:HI AX_REG))
314    ])
315  ]
316  "" ; mulu supported by all targets
317  ""
318)
319
320(define_expand "mulhi3"
321  [(set (match_operand:HI          0 "register_operand")
322	(mult:HI (match_operand:HI 1 "general_operand")
323		 (match_operand:HI 2 "nonmemory_operand")))
324   ]
325  "! RL78_MUL_NONE"
326  {
327    if (RL78_MUL_G14)
328      emit_insn (gen_mulhi3_g14 (operands[0], operands[1], operands[2]));
329    else /* RL78_MUL_G13 */
330      emit_insn (gen_mulhi3_g13 (operands[0], operands[1], operands[2]));
331    DONE;
332  }
333)
334
335(define_expand "mulsi3"
336  [(set (match_operand:SI          0 "register_operand")
337	(mult:SI (match_operand:SI 1 "general_operand")
338		 (match_operand:SI 2 "nonmemory_operand")))
339   ]
340  "! RL78_MUL_NONE"
341  {
342    if (RL78_MUL_G14)
343      emit_insn (gen_mulsi3_g14 (operands[0], operands[1], operands[2]));
344    else /* RL78_MUL_G13 */
345      emit_insn (gen_mulsi3_g13 (operands[0], operands[1], operands[2]));
346    DONE;
347  }
348)
349
350(define_insn "*mulqi3_rl78"
351  [(set (match_operand:QI          0 "register_operand" "=&v")
352	(mult:QI (match_operand:QI 1 "general_operand" "viU")
353		 (match_operand:QI 2 "general_operand" "vi")))
354   (clobber (reg:HI AX_REG))
355  ]
356  "" ; mulu supported by all targets
357  "; mulqi macro %0 = %1 * %2
358	mov    a, %h1
359	mov    x, a
360	mov    a, %h2
361	mulu   x ; ax = a * x
362	mov    a, x
363	mov    %h0, a
364	; end of mulqi macro"
365  [(set_attr "valloc" "macax")]
366)
367
368(define_insn "mulhi3_g14"
369  [(set (match_operand:HI          0 "register_operand" "=&v")
370	(mult:HI (match_operand:HI 1 "general_operand" "viU")
371		 (match_operand:HI 2 "general_operand" "vi")))
372   (clobber (reg:HI AX_REG))
373   (clobber (reg:HI BC_REG))
374  ]
375  "RL78_MUL_G14"
376  "; G14 mulhi macro %0 = %1 * %2
377	movw    ax, %h1
378	movw    bc, %h2
379	mulhu   ; bcax = bc * ax
380	movw    %h0, ax
381	; end of mulhi macro"
382  [(set_attr "valloc" "macax")]
383)
384
385(define_insn "mulhi3_g13"
386  [(set (match_operand:HI          0 "register_operand" "=&v")
387	(mult:HI (match_operand:HI 1 "general_operand" "viU")
388		 (match_operand:HI 2 "general_operand" "vi")))
389   (clobber (reg:HI AX_REG))
390  ]
391  "RL78_MUL_G13"
392  "; G13 mulhi macro %0 = %1 * %2
393	mov     a, #0x00
394	mov     !0xf00e8, a     ; MDUC
395	movw    ax, %h1
396	movw    0xffff0, ax     ; MDAL
397	movw    ax, %h2
398	movw    0xffff2, ax     ; MDAH
399	nop     ; mdb = mdal * mdah
400	movw    ax, 0xffff6     ; MDBL
401	movw    %h0, ax
402        ; end of mulhi macro"
403  [(set_attr "valloc" "macax")
404   (set_attr "is_g13_muldiv_insn" "yes")]
405)
406
407;; 0xFFFF0 is MACR(L).  0xFFFF2 is MACR(H) but we don't care about it
408;; because we're only using the lower 16 bits (which is the upper 16
409;; bits of the result).
410(define_insn "mulsi3_g14"
411  [(set (match_operand:SI          0 "register_operand" "=&v")
412	(mult:SI (match_operand:SI 1 "general_operand" "viU")
413		 (match_operand:SI 2 "general_operand" "vi")))
414   (clobber (reg:HI AX_REG))
415   (clobber (reg:HI BC_REG))
416  ]
417  "RL78_MUL_G14"
418  "; G14 mulsi macro %0 = %1 * %2
419	movw	ax, %h1
420	movw	bc, %h2
421	MULHU	; bcax = bc * ax
422	movw	%h0, ax
423	movw	ax, bc
424	movw	0xffff0, ax
425	movw	ax, %H1
426	movw	bc, %h2
427	MACHU	; MACR += bc * ax
428	movw	ax, %h1
429	movw	bc, %H2
430	MACHU	; MACR += bc * ax
431	movw	ax, 0xffff0
432	movw	%H0, ax
433	; end of mulsi macro"
434  [(set_attr "valloc" "macax")]
435  )
436
437;; 0xFFFF0 is MDAL.  0xFFFF2 is MDAH.
438;; 0xFFFF6 is MDBL.  0xFFFF4 is MDBH.
439;; 0xF00E0 is MDCL.  0xF00E2 is MDCH.
440;; 0xF00E8 is MDUC.
441;; Warning: this matches the silicon not the documentation.
442(define_insn "mulsi3_g13"
443  [(set (match_operand:SI          0 "register_operand" "=&v")
444	(mult:SI (match_operand:SI 1 "general_operand" "viU")
445		 (match_operand:SI 2 "general_operand" "viU")))
446   (clobber (reg:HI AX_REG))
447   (clobber (reg:HI BC_REG))
448  ]
449  "RL78_MUL_G13"
450  "; G13 mulsi macro %0 = %1 * %2
451	mov	a, #0x00
452	mov	!0xf00e8, a	; MDUC
453	movw	ax, %h1
454	movw	0xffff0, ax	; MDAL
455	movw	ax, %h2
456	movw	0xffff2, ax	; MDAH
457	nop	; mdb = mdal * mdah
458	movw	ax, 0xffff6	; MDBL
459	movw	%h0, ax
460
461	mov	a, #0x40
462	mov	!0xf00e8, a	; MDUC
463	movw	ax, 0xffff4	; MDBH
464	movw	!0xf00e0, ax	; MDCL
465	movw	ax, #0
466	movw	!0xf00e2, ax	; MDCL
467	movw	ax, %H1
468	movw	0xffff0, ax	; MDAL
469	movw	ax, %h2
470	movw	0xffff2, ax	; MDAH
471	nop	; mdc += mdal * mdah
472
473	mov	a, #0x40
474	mov	!0xf00e8, a	; MDUC
475	movw	ax, %h1
476	movw	0xffff0, ax	; MDAL
477	movw	ax, %H2
478	movw	0xffff2, ax	; MDAH
479	nop	; mdc += mdal * mdah
480	nop	; Additional nop for MAC
481	movw	ax, !0xf00e0	; MDCL
482	movw	%H0, ax
483	; end of mulsi macro"
484  [(set_attr "valloc" "macax")
485   (set_attr "is_g13_muldiv_insn" "yes")]
486)
487
488(define_expand "udivmodhi4"
489  [(parallel
490    [(set (match_operand:HI          0 "register_operand")
491          (udiv:HI (match_operand:HI 1 "register_operand")
492                   (match_operand:HI 2 "register_operand")))
493     (set (match_operand:HI          3 "register_operand")
494          (umod:HI (match_dup 1) (match_dup 2)))
495     (clobber (reg:HI AX_REG))
496     (clobber (reg:HI DE_REG))
497    ])
498   ]
499  "RL78_MUL_G14"
500  ""
501)
502
503(define_insn "*udivmodhi4_g14"
504  [(set (match_operand:HI          0 "register_operand" "=v")
505	(udiv:HI (match_operand:HI 1 "register_operand" "v")
506		 (match_operand:HI 2 "register_operand" "v")))
507   (set (match_operand:HI          3 "register_operand" "=v")
508	(umod:HI (match_dup 1) (match_dup 2)))
509   (clobber (reg:HI AX_REG))
510   (clobber (reg:HI DE_REG))
511  ]
512  "RL78_MUL_G14"
513  {
514    if (find_reg_note (insn, REG_UNUSED, operands[3]))
515      return "; G14 udivhi macro %0 = %1 / %2 \n\
516	movw    ax, %h1 \n\
517	movw    de, %h2 \n\
518	push	psw	; Save the current interrupt status \n\
519	di		; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
520	divhu   	; ax = ax / de \n\
521	pop	psw	; Restore saved interrupt status \n\
522	movw    %h0, ax \n\
523	; end of udivhi macro";
524    else if (find_reg_note (insn, REG_UNUSED, operands[0]))
525      return "; G14 umodhi macro %3 = %1 %% %2 \n\
526	movw    ax, %h1 \n\
527	movw    de, %h2 \n\
528	push	psw	; Save the current interrupt status \n\
529	di		; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
530	divhu   	; de = ax %% de \n\
531	pop	psw	; Restore saved interrupt status \n\
532	movw	ax, de \n\
533	movw    %h3, ax \n\
534	; end of umodhi macro";
535    else
536      return "; G14 udivmodhi macro %0 = %1 / %2 and %3 = %1 %% %2 \n\
537	movw    ax, %h1 \n\
538	movw    de, %h2 \n\
539	push	psw	; Save the current interrupt status \n\
540	di		; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
541	divhu   	; ax = ax / de, de = ax %% de \n\
542	pop	psw	; Restore saved interrupt status \n\
543	movw    %h0, ax \n\
544	movw	ax, de \n\
545	movw    %h3, ax \n\
546	; end of udivmodhi macro";
547  }
548  [(set_attr "valloc" "divhi")]
549)
550
551(define_expand "udivmodsi4"
552  [(parallel
553    [(set (match_operand:SI          0 "register_operand")
554          (udiv:SI (match_operand:SI 1 "register_operand")
555                   (match_operand:SI 2 "register_operand")))
556     (set (match_operand:SI          3 "register_operand")
557          (umod:SI (match_dup 1) (match_dup 2)))
558    ])
559   ]
560  "! RL78_MUL_NONE && ! optimize_size"
561  {
562    if (RL78_MUL_G14)
563      emit_insn (gen_udivmodsi4_g14 (operands[0], operands[1], operands[2], operands[3]));
564    else /* RL78_MUL_G13 */
565      emit_insn (gen_udivmodsi4_g13 (operands[0], operands[1], operands[2], operands[3]));
566    DONE;
567  }
568)
569
570(define_insn "udivmodsi4_g14"
571  [(set (match_operand:SI          0 "register_operand" "=v")
572	(udiv:SI (match_operand:SI 1 "register_operand" "v")
573		 (match_operand:SI 2 "register_operand" "v")))
574   (set (match_operand:SI          3 "register_operand" "=v")
575	(umod:SI (match_dup 1) (match_dup 2)))
576   (clobber (reg:HI AX_REG))
577   (clobber (reg:HI BC_REG))
578   (clobber (reg:HI DE_REG))
579   (clobber (reg:HI HL_REG))
580  ]
581  "RL78_MUL_G14"
582  {
583    if (find_reg_note (insn, REG_UNUSED, operands[3]))
584      return "; G14 udivsi macro %0 = %1 / %2 \n\
585	movw    ax, %h1 \n\
586	movw    bc, %H1 \n\
587	movw    de, %h2 \n\
588	movw    hl, %H2 \n\
589	push	psw	; Save the current interrupt status \n\
590	di		; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
591	divwu   	; bcax = bcax / hlde \n\
592	pop	psw	; Restore saved interrupt status \n\
593	movw    %h0, ax \n\
594	movw	ax, bc \n\
595	movw    %H0, ax \n\
596	; end of udivsi macro";
597    else if (find_reg_note (insn, REG_UNUSED, operands[0]))
598      return "; G14 umodsi macro %3 = %1 %% %2 \n\
599	movw    ax, %h1 \n\
600	movw    bc, %H1 \n\
601	movw    de, %h2 \n\
602	movw    hl, %H2 \n\
603	push	psw	; Save the current interrupt status \n\
604	di		; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
605	divwu   	; hlde = bcax %% hlde \n\
606	pop	psw	; Restore saved interrupt status \n\
607	movw	ax, de \n\
608	movw    %h3, ax \n\
609	movw	ax, hl \n\
610	movw    %H3, ax \n\
611	; end of umodsi macro";
612    else
613      return "; G14 udivmodsi macro %0 = %1 / %2 and %3 = %1 %% %2 \n\
614	movw    ax, %h1 \n\
615	movw    bc, %H1 \n\
616	movw    de, %h2 \n\
617	movw    hl, %H2 \n\
618	push	psw	; Save the current interrupt status \n\
619	di		; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
620	divwu   	; bcax = bcax / hlde, hlde = bcax %% hlde \n\
621	pop	psw	; Restore saved interrupt status \n\
622	movw    %h0, ax \n\
623	movw	ax, bc \n\
624	movw    %H0, ax \n\
625	movw	ax, de \n\
626	movw    %h3, ax \n\
627	movw	ax, hl \n\
628	movw    %H3, ax \n\
629	; end of udivmodsi macro";
630  }
631  [(set_attr "valloc" "divsi")]
632)
633
634;; Warning: these values match the silicon not the documentation.
635;; 0xFFFF0 is MDAL.  0xFFFF2 is MDAH.
636;; 0xFFFF6 is MDBL.  0xFFFF4 is MDBH.
637;; 0xF00E0 is MDCL.  0xF00E2 is MDCH.
638;; 0xF00E8 is MDUC.
639
640(define_insn "udivmodsi4_g13"
641  [(set (match_operand:SI          0 "register_operand" "=v")
642	(udiv:SI (match_operand:SI 1 "register_operand" "v")
643		 (match_operand:SI 2 "register_operand" "v")))
644   (set (match_operand:SI          3 "register_operand" "=v")
645	(umod:SI (match_dup 1) (match_dup 2)))
646   (clobber (reg:HI AX_REG))
647  ]
648  "RL78_MUL_G13"
649  {
650    if (find_reg_note (insn, REG_UNUSED, operands[3]))
651      return "; G13 udivsi macro %0 = %1 / %2 \n\
652	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1 \n\
653	mov	!0xf00e8, a	; This preps the peripheral for division without interrupt generation \n\
654	movw	ax, %H1		\n\
655	movw	0xffff2, ax	; MDAH \n\
656	movw	ax, %h1		\n\
657	movw	0xffff0, ax	; MDAL \n\
658	movw	ax, %H2		\n\
659	movw	0xffff4, ax	; MDBH \n\
660	movw	ax, %h2		\n\
661	movw	0xffff6, ax	; MDBL \n\
662	mov	a, #0xC1	; Set the DIVST bit in MDUC \n\
663	mov	!0xf00e8, a	; This starts the division op \n\
6641:	mov	a, !0xf00e8	; Wait 16 clocks or until DIVST is clear \n\
665	bt	a.0, $1b	\n\
666	movw    ax, 0xffff0	; Read the quotient \n\
667	movw	%h0, ax		\n\
668	movw    ax, 0xffff2	\n\
669	movw	%H0, ax		\n\
670	; end of udivsi macro";
671    else if (find_reg_note (insn, REG_UNUSED, operands[0]))
672      return "; G13 umodsi macro %3 = %1 %% %2 \n\
673	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1 \n\
674	mov	!0xf00e8, a	; This preps the peripheral for division without interrupt generation \n\
675	movw	ax, %H1		\n\
676	movw	0xffff2, ax	; MDAH \n\
677	movw	ax, %h1		\n\
678	movw	0xffff0, ax	; MDAL \n\
679	movw	ax, %H2		\n\
680	movw	0xffff4, ax	; MDBH \n\
681	movw	ax, %h2		\n\
682	movw	0xffff6, ax	; MDBL \n\
683	mov	a, #0xC1	; Set the DIVST bit in MDUC \n\
684	mov	!0xf00e8, a	; This starts the division op \n\
6851:	mov	a, !0xf00e8	; Wait 16 clocks or until DIVST is clear \n\
686	bt	a.0, $1b	\n\
687  	movw	ax, !0xf00e0	; Read the remainder \n\
688	movw	%h3, ax		\n\
689	movw	ax, !0xf00e2	\n\
690	movw	%H3, ax		\n\
691	; end of umodsi macro";
692    else
693      return "; G13 udivmodsi macro %0 = %1 / %2 and %3 = %1 %% %2 \n\
694	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1 \n\
695	mov	!0xf00e8, a	; This preps the peripheral for division without interrupt generation \n\
696	movw	ax, %H1		\n\
697	movw	0xffff2, ax	; MDAH \n\
698	movw	ax, %h1		\n\
699	movw	0xffff0, ax	; MDAL \n\
700	movw	ax, %H2		\n\
701	movw	0xffff4, ax	; MDBH \n\
702	movw	ax, %h2		\n\
703	movw	0xffff6, ax	; MDBL \n\
704	mov	a, #0xC1	; Set the DIVST bit in MDUC \n\
705	mov	!0xf00e8, a	; This starts the division op \n\
7061:	mov	a, !0xf00e8	; Wait 16 clocks or until DIVST is clear \n\
707	bt	a.0, $1b	\n\
708	movw    ax, 0xffff0	; Read the quotient \n\
709	movw	%h0, ax		\n\
710	movw    ax, 0xffff2	\n\
711	movw	%H0, ax		\n\
712  	movw	ax, !0xf00e0	; Read the remainder \n\
713	movw	%h3, ax		\n\
714	movw	ax, !0xf00e2	\n\
715	movw	%H3, ax		\n\
716	; end of udivmodsi macro";
717      }
718  [(set_attr "valloc" "macax")
719   (set_attr "is_g13_muldiv_insn" "yes")]
720)
721
722(define_expand "movdi"
723  [(set (match_operand:DI 0 "nonimmediate_operand" "")
724        (match_operand:DI 1 "general_operand"      ""))]
725  ""
726  "rl78_split_movdi(operands, DImode);
727  DONE;"
728)
729
730(define_expand "movdf"
731  [(set (match_operand:DF 0 "nonimmediate_operand" "")
732        (match_operand:DF 1 "general_operand" ""))]
733  ""
734  "rl78_split_movdi(operands, DFmode);
735  DONE;"
736)
737
738(define_expand "umindi3"
739 [(set (match_operand:DI          0 "nonimmediate_operand" "")
740	(umin:DI (match_operand:DI 1 "general_operand"      "")
741		 (match_operand:DI    2 "general_operand"      "")))
742   ]
743  "optimize_size"
744  "rl78_emit_libcall (\"__umindi3\", UMIN, DImode, DImode, 3, operands);
745   DONE;"
746)
747
748(define_expand "umaxdi3"
749 [(set (match_operand:DI          0 "nonimmediate_operand" "")
750	(umax:DI (match_operand:DI 1 "general_operand"      "")
751		 (match_operand:DI    2 "general_operand"      "")))
752   ]
753  "optimize_size"
754  "rl78_emit_libcall (\"__umaxdi3\", UMAX, DImode, DImode, 3, operands);
755   DONE;"
756)
757
758(define_expand "smindi3"
759 [(set (match_operand:DI          0 "nonimmediate_operand" "")
760	(smin:DI (match_operand:DI 1 "general_operand"      "")
761		 (match_operand:DI    2 "general_operand"      "")))
762   ]
763  "optimize_size"
764  "rl78_emit_libcall (\"__smindi3\", SMIN, DImode, DImode, 3, operands);
765   DONE;"
766)
767
768(define_expand "smaxdi3"
769 [(set (match_operand:DI          0 "nonimmediate_operand" "")
770	(smax:DI (match_operand:DI 1 "general_operand"      "")
771		 (match_operand:DI    2 "general_operand"      "")))
772   ]
773  "optimize_size"
774  "rl78_emit_libcall (\"__smaxdi3\", SMAX, DImode, DImode, 3, operands);
775   DONE;"
776)
777
778(define_expand "anddi3"
779 [(set (match_operand:DI          0 "nonimmediate_operand" "")
780	(and:DI (match_operand:DI 1 "general_operand"      "")
781		 (match_operand:DI    2 "general_operand"      "")))
782   ]
783  "optimize_size"
784  "rl78_emit_libcall (\"__anddi3\", AND, DImode, DImode, 3, operands);
785   DONE;"
786)
787