;;  Machine Description for Renesas RL78 processors
;;  Copyright (C) 2011-2024 Free Software Foundation, Inc.
;;  Contributed by Red Hat.

;; This file is part of GCC.

;; GCC 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.

;; GCC 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.

;; You should have received a copy of the GNU General Public License
;; along with GCC; see the file COPYING3.  If not see
;; <http://www.gnu.org/licenses/>.

(define_constants
  [
   (AX_REG 0)
   (X_REG 0)
   (A_REG 1)
   (BC_REG 2)
   (C_REG 2)
   (B_REG 3)
   (DE_REG 4)
   (E_REG 4)
   (D_REG 5)
   (HL_REG 6)
   (L_REG 6)
   (H_REG 7)

   (FP_REG 22)
   (SP_REG 32)
   (CC_REG 34)
   (ES_REG 35)
   (CS_REG 36)

   (UNS_PROLOG	1)
   (UNS_EPILOG	1)
   (UNS_RETI	2)
   (UNS_RETB	3)

   (UNS_SET_RB	10)
   (UNS_ES_ADDR	11)

   (UNS_TRAMPOLINE_INIT		20)
   (UNS_TRAMPOLINE_UNINIT	21)
   (UNS_NONLOCAL_GOTO		22)

   ])

(define_insn "nop"
  [(const_int 0)]
  ""
  "nop"
  )

(define_mode_iterator QHI [QI HI])

(include "predicates.md")
(include "constraints.md")
(include "rl78-expand.md")
(include "rl78-virt.md")
(include "rl78-real.md")

(define_attr "is_g13_muldiv_insn" "yes,no" (const_string "no"))

;; Function Prologue/Epilogue Instructions

(define_expand "prologue"
  [(const_int 0)]
  ""
  "rl78_expand_prologue (); DONE;"
)

(define_expand "epilogue"
  [(const_int 0)]
  ""
  "rl78_expand_epilogue (); DONE;"
)

(define_expand "sibcall_epilogue"
  [(return)]
  ""
  "FAIL;"
)

(define_insn "rl78_return"
  [(return)]
  ""
  "ret"
)

(define_insn "interrupt_return"
  [(unspec_volatile [(return)] UNS_RETI) ]
  ""
  "reti"
)

(define_insn "brk_interrupt_return"
  [(unspec_volatile [(return)] UNS_RETB) ]
  ""
  "retb"
)

(define_expand "eh_return"
  [(match_operand:HI 0 "")]
  ""
  "rl78_expand_eh_epilogue (operands[0]);
   emit_barrier ();
   DONE;"
)

;; These are used only by prologue/epilogue so it's "safe" to pass
;; virtual registers.
(define_insn "push"
  [(set (reg:HI SP_REG)
	(plus:HI (reg:HI SP_REG)
		  (const_int -2)))
   (set (mem:HI (reg:HI SP_REG))
	(match_operand:HI 0 "register_operand" "ABDT,vZint"))]
  ""
  "@
   push\t%v0
   push\t%v0 ; %0"
)

(define_insn "pop"
  [(set (match_operand:HI 0 "register_operand" "=ABDT,vZint")
	(mem:HI (reg:HI SP_REG)))
   (set (reg:HI SP_REG)
	(plus:HI (reg:HI SP_REG)
		    (const_int 2)))]
  ""
  "@
   pop\t%v0
   pop\t%v0 ; %0"
)

(define_insn "sel_rb"
  [(unspec_volatile [(match_operand 0 "immediate_operand" "")] UNS_SET_RB)]
  "!TARGET_G10"
  "sel\trb%u0"
  )

(define_insn "trampoline_init"
  [(set (match_operand 0 "register_operand" "=Z08W")
	(unspec_volatile [(match_operand 1 "register_operand" "Z08W")
			  (match_operand 2 "register_operand" "Z10W")
			  ] UNS_TRAMPOLINE_INIT))
   ]
  ""
  "call !!___trampoline_init ; %0 <= %1 %2"
  )

(define_insn "trampoline_uninit"
  [(unspec_volatile [(const_int 0)] UNS_TRAMPOLINE_UNINIT)
   ]
  ""
  "call !!___trampoline_uninit"
  )

;; GCC restores $fp *before* using it to access values on the *old*
;; frame.  So, we do it ourselves, to ensure this is not the case.
;; Note that while %1 is usually a label_ref, we allow for a
;; non-immediate as well.
(define_expand "nonlocal_goto"
  [(set (pc)
	(unspec_volatile [(match_operand 0 "") ;; fp (ignore)
			  (match_operand 1 "") ;; target
			  (match_operand 2 "") ;; sp
			  (match_operand 3 "") ;; ?
			  ] UNS_NONLOCAL_GOTO))
   ]
  ""
  "emit_jump_insn (gen_nonlocal_goto_insn (operands[0], operands[1], operands[2], operands[3]));
   emit_barrier ();
   DONE;"
  )

(define_insn "nonlocal_goto_insn"
  [(set (pc)
	(unspec_volatile [(match_operand 0 "" "") ;; fp (ignore)
			  (match_operand 1 "" "vi") ;; target
			  (match_operand 2 "" "vi") ;; sp
			  (match_operand 3 "" "vi") ;; ?
			  ] UNS_NONLOCAL_GOTO))
   ]
  ""
  "; nonlocal goto
	movw	ax, %3
	movw	r22, ax
	movw	ax, %2
	movw	sp, ax
	movw	ax, %1
	br	ax
"
  )

(define_expand "es_addr"
  [(unspec:SI [(reg:QI ES_REG)
	       (match_operand:HI 0 "")
	       ] UNS_ES_ADDR)]
  ""
  ""
)

;;======================================================================
;;
;; "macro" insns - cases where inline chunks of code are more
;; efficient than anything else.

(define_expand "addsi3"
  [(set (match_operand:SI          0 "nonimmediate_operand" "=&vm")
	(plus:SI (match_operand:SI 1 "general_operand"      "vim")
		 (match_operand    2 "general_operand"      "vim")))
   ]
  ""
  "emit_insn (gen_addsi3_internal_virt (operands[0], operands[1], operands[2]));
   DONE;"
)

(define_expand "adddi3"
  [(set (match_operand:DI          0 "nonimmediate_operand" "")
	(plus:DI (match_operand:DI 1 "general_operand"      "")
		 (match_operand:DI 2 "general_operand"      "")))
   ]
  ""
  "rl78_emit_libcall (\"__adddi3\", PLUS, DImode, DImode, 3, operands);
   DONE;"
)

(define_insn "addsi3_internal_virt"
  [(set (match_operand:SI          0 "nonimmediate_operand" "=v,&vm, vm")
	(plus:SI (match_operand:SI 1 "general_operand"      "0, vim, vim")
		 (match_operand    2 "general_operand"      "vim,vim,vim")))
   (clobber (reg:HI AX_REG))
   (clobber (reg:HI BC_REG))
   ]
  "rl78_virt_insns_ok ()"
  ""
  [(set_attr "valloc" "macax")]
)

(define_insn "addsi3_internal_real"
  [(set (match_operand:SI          0 "nonimmediate_operand" "=v,&vU, vU")
	(plus:SI (match_operand:SI 1 "general_operand"      "+0, viU, viU")
		 (match_operand    2 "general_operand"      "viWabWhlWh1,viWabWhlWh1,viWabWhlWh1")))
   (clobber (reg:HI AX_REG))
   (clobber (reg:HI BC_REG))
   ]
  "rl78_real_insns_ok ()"
  { return rl78_addsi3_internal (operands, which_alternative); }
  [(set_attr "valloc" "macax")]
)

(define_expand "subsi3"
  [(set (match_operand:SI           0 "nonimmediate_operand")
	(minus:SI (match_operand:SI 1 "general_operand")
		  (match_operand    2 "general_operand")))
   ]
  ""
  "emit_insn (gen_subsi3_internal_virt (operands[0], operands[1], operands[2]));
  DONE;"
)

(define_expand "subdi3"
 [(set (match_operand:DI          0 "nonimmediate_operand" "")
    (minus:DI (match_operand:DI 1 "general_operand"      "")
         (match_operand:DI    2 "general_operand"      "")))
   ]
  ""
  "rl78_emit_libcall (\"__subdi3\", MINUS, DImode, DImode, 3, operands);
   DONE;"
)

(define_insn "subsi3_internal_virt"
  [(set (match_operand:SI           0 "nonimmediate_operand" "=v,&vm, vm")
	(minus:SI (match_operand:SI 1 "general_operand"      "0, vim, vim")
		  (match_operand    2 "general_operand"      "vim,vim,vim")))
   (clobber (reg:HI AX_REG))
   (clobber (reg:HI BC_REG))
   ]
  "rl78_virt_insns_ok ()"
  ""
  [(set_attr "valloc" "macax")]
)

(define_insn "subsi3_internal_real"
  [(set (match_operand:SI           0 "nonimmediate_operand" "=v,&vU, vU")
	(minus:SI (match_operand:SI 1 "general_operand"      "+0, viU, viU")
		  (match_operand    2 "general_operand"      "viWabWhlWh1,viWabWhlWh1,viWabWhlWh1")))
   (clobber (reg:HI AX_REG))
   (clobber (reg:HI BC_REG))
   ]
  "rl78_real_insns_ok ()"
  "@
   movw ax,%h1 \;subw ax,%h2 \;movw %h0, ax \;movw ax,%H1 \;sknc \;decw ax \;subw ax,%H2 \;movw %H0,ax
   movw ax,%h1 \;subw ax,%h2 \;movw %h0, ax \;movw ax,%H1 \;sknc \;decw ax \;subw ax,%H2 \;movw %H0,ax
   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"
  [(set_attr "valloc" "macax")]
)

(define_expand "mulqi3"
  [(parallel
    [(set (match_operand:QI            0 "register_operand")
	   (mult:QI  (match_operand:QI 1 "general_operand")
		     (match_operand:QI 2 "nonmemory_operand")))
      (clobber (reg:HI AX_REG))
    ])
  ]
  "" ; mulu supported by all targets
  ""
)

(define_expand "mulhi3"
  [(set (match_operand:HI          0 "register_operand")
	(mult:HI (match_operand:HI 1 "general_operand")
		 (match_operand:HI 2 "nonmemory_operand")))
   ]
  "! RL78_MUL_NONE"
  {
    if (RL78_MUL_G14)
      emit_insn (gen_mulhi3_g14 (operands[0], operands[1], operands[2]));
    else /* RL78_MUL_G13 */
      emit_insn (gen_mulhi3_g13 (operands[0], operands[1], operands[2]));
    DONE;
  }
)

(define_expand "mulsi3"
  [(set (match_operand:SI          0 "register_operand")
	(mult:SI (match_operand:SI 1 "general_operand")
		 (match_operand:SI 2 "nonmemory_operand")))
   ]
  "! RL78_MUL_NONE"
  {
    if (RL78_MUL_G14)
      emit_insn (gen_mulsi3_g14 (operands[0], operands[1], operands[2]));
    else /* RL78_MUL_G13 */
      emit_insn (gen_mulsi3_g13 (operands[0], operands[1], operands[2]));
    DONE;
  }
)

(define_insn "*mulqi3_rl78"
  [(set (match_operand:QI          0 "register_operand" "=&v")
	(mult:QI (match_operand:QI 1 "general_operand" "viU")
		 (match_operand:QI 2 "general_operand" "vi")))
   (clobber (reg:HI AX_REG))
  ]
  "" ; mulu supported by all targets
  "; mulqi macro %0 = %1 * %2
	mov    a, %h1
	mov    x, a
	mov    a, %h2
	mulu   x ; ax = a * x
	mov    a, x
	mov    %h0, a
	; end of mulqi macro"
  [(set_attr "valloc" "macax")]
)

(define_insn "mulhi3_g14"
  [(set (match_operand:HI          0 "register_operand" "=&v")
	(mult:HI (match_operand:HI 1 "general_operand" "viU")
		 (match_operand:HI 2 "general_operand" "vi")))
   (clobber (reg:HI AX_REG))
   (clobber (reg:HI BC_REG))
  ]
  "RL78_MUL_G14"
  "; G14 mulhi macro %0 = %1 * %2
	movw    ax, %h1
	movw    bc, %h2
	mulhu   ; bcax = bc * ax
	movw    %h0, ax
	; end of mulhi macro"
  [(set_attr "valloc" "macax")]
)

(define_insn "mulhi3_g13"
  [(set (match_operand:HI          0 "register_operand" "=&v")
	(mult:HI (match_operand:HI 1 "general_operand" "viU")
		 (match_operand:HI 2 "general_operand" "vi")))
   (clobber (reg:HI AX_REG))
  ]
  "RL78_MUL_G13"
  "; G13 mulhi macro %0 = %1 * %2
	mov     a, #0x00
	mov     !0xf00e8, a     ; MDUC
	movw    ax, %h1
	movw    0xffff0, ax     ; MDAL
	movw    ax, %h2
	movw    0xffff2, ax     ; MDAH
	nop     ; mdb = mdal * mdah
	movw    ax, 0xffff6     ; MDBL
	movw    %h0, ax
        ; end of mulhi macro"
  [(set_attr "valloc" "macax")
   (set_attr "is_g13_muldiv_insn" "yes")]
)

;; 0xFFFF0 is MACR(L).  0xFFFF2 is MACR(H) but we don't care about it
;; because we're only using the lower 16 bits (which is the upper 16
;; bits of the result).
(define_insn "mulsi3_g14"
  [(set (match_operand:SI          0 "register_operand" "=&v")
	(mult:SI (match_operand:SI 1 "general_operand" "viU")
		 (match_operand:SI 2 "general_operand" "vi")))
   (clobber (reg:HI AX_REG))
   (clobber (reg:HI BC_REG))
  ]
  "RL78_MUL_G14"
  "; G14 mulsi macro %0 = %1 * %2
	movw	ax, %h1
	movw	bc, %h2
	MULHU	; bcax = bc * ax
	movw	%h0, ax
	movw	ax, bc
	movw	0xffff0, ax
	movw	ax, %H1
	movw	bc, %h2
	MACHU	; MACR += bc * ax
	movw	ax, %h1
	movw	bc, %H2
	MACHU	; MACR += bc * ax
	movw	ax, 0xffff0
	movw	%H0, ax
	; end of mulsi macro"
  [(set_attr "valloc" "macax")]
  )

;; 0xFFFF0 is MDAL.  0xFFFF2 is MDAH.
;; 0xFFFF6 is MDBL.  0xFFFF4 is MDBH.
;; 0xF00E0 is MDCL.  0xF00E2 is MDCH.
;; 0xF00E8 is MDUC.
;; Warning: this matches the silicon not the documentation.
(define_insn "mulsi3_g13"
  [(set (match_operand:SI          0 "register_operand" "=&v")
	(mult:SI (match_operand:SI 1 "general_operand" "viU")
		 (match_operand:SI 2 "general_operand" "viU")))
   (clobber (reg:HI AX_REG))
   (clobber (reg:HI BC_REG))
  ]
  "RL78_MUL_G13"
  "; G13 mulsi macro %0 = %1 * %2
	mov	a, #0x00
	mov	!0xf00e8, a	; MDUC
	movw	ax, %h1
	movw	0xffff0, ax	; MDAL
	movw	ax, %h2
	movw	0xffff2, ax	; MDAH
	nop	; mdb = mdal * mdah
	movw	ax, 0xffff6	; MDBL
	movw	%h0, ax

	mov	a, #0x40
	mov	!0xf00e8, a	; MDUC
	movw	ax, 0xffff4	; MDBH
	movw	!0xf00e0, ax	; MDCL
	movw	ax, #0
	movw	!0xf00e2, ax	; MDCL
	movw	ax, %H1
	movw	0xffff0, ax	; MDAL
	movw	ax, %h2
	movw	0xffff2, ax	; MDAH
	nop	; mdc += mdal * mdah

	mov	a, #0x40
	mov	!0xf00e8, a	; MDUC
	movw	ax, %h1
	movw	0xffff0, ax	; MDAL
	movw	ax, %H2
	movw	0xffff2, ax	; MDAH
	nop	; mdc += mdal * mdah
	nop	; Additional nop for MAC
	movw	ax, !0xf00e0	; MDCL
	movw	%H0, ax
	; end of mulsi macro"
  [(set_attr "valloc" "macax")
   (set_attr "is_g13_muldiv_insn" "yes")]
)

(define_expand "udivmodhi4"
  [(parallel
    [(set (match_operand:HI          0 "register_operand")
          (udiv:HI (match_operand:HI 1 "register_operand")
                   (match_operand:HI 2 "register_operand")))
     (set (match_operand:HI          3 "register_operand")
          (umod:HI (match_dup 1) (match_dup 2)))
     (clobber (reg:HI AX_REG))
     (clobber (reg:HI DE_REG))
    ])
   ]
  "RL78_MUL_G14"
  ""
)

(define_insn "*udivmodhi4_g14"
  [(set (match_operand:HI          0 "register_operand" "=v")
	(udiv:HI (match_operand:HI 1 "register_operand" "v")
		 (match_operand:HI 2 "register_operand" "v")))
   (set (match_operand:HI          3 "register_operand" "=v")
	(umod:HI (match_dup 1) (match_dup 2)))
   (clobber (reg:HI AX_REG))
   (clobber (reg:HI DE_REG))
  ]
  "RL78_MUL_G14"
  {
    if (find_reg_note (insn, REG_UNUSED, operands[3]))
      return "; G14 udivhi macro %0 = %1 / %2 \n\
	movw    ax, %h1 \n\
	movw    de, %h2 \n\
	push	psw	; Save the current interrupt status \n\
	di		; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
	divhu   	; ax = ax / de \n\
	pop	psw	; Restore saved interrupt status \n\
	movw    %h0, ax \n\
	; end of udivhi macro";
    else if (find_reg_note (insn, REG_UNUSED, operands[0]))
      return "; G14 umodhi macro %3 = %1 %% %2 \n\
	movw    ax, %h1 \n\
	movw    de, %h2 \n\
	push	psw	; Save the current interrupt status \n\
	di		; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
	divhu   	; de = ax %% de \n\
	pop	psw	; Restore saved interrupt status \n\
	movw	ax, de \n\
	movw    %h3, ax \n\
	; end of umodhi macro";
    else
      return "; G14 udivmodhi macro %0 = %1 / %2 and %3 = %1 %% %2 \n\
	movw    ax, %h1 \n\
	movw    de, %h2 \n\
	push	psw	; Save the current interrupt status \n\
	di		; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
	divhu   	; ax = ax / de, de = ax %% de \n\
	pop	psw	; Restore saved interrupt status \n\
	movw    %h0, ax \n\
	movw	ax, de \n\
	movw    %h3, ax \n\
	; end of udivmodhi macro";
  }
  [(set_attr "valloc" "divhi")]
)

(define_expand "udivmodsi4"
  [(parallel
    [(set (match_operand:SI          0 "register_operand")
          (udiv:SI (match_operand:SI 1 "register_operand")
                   (match_operand:SI 2 "register_operand")))
     (set (match_operand:SI          3 "register_operand")
          (umod:SI (match_dup 1) (match_dup 2)))
    ])
   ]
  "! RL78_MUL_NONE && ! optimize_size"
  {
    if (RL78_MUL_G14)
      emit_insn (gen_udivmodsi4_g14 (operands[0], operands[1], operands[2], operands[3]));
    else /* RL78_MUL_G13 */
      emit_insn (gen_udivmodsi4_g13 (operands[0], operands[1], operands[2], operands[3]));
    DONE;
  }
)

(define_insn "udivmodsi4_g14"
  [(set (match_operand:SI          0 "register_operand" "=v")
	(udiv:SI (match_operand:SI 1 "register_operand" "v")
		 (match_operand:SI 2 "register_operand" "v")))
   (set (match_operand:SI          3 "register_operand" "=v")
	(umod:SI (match_dup 1) (match_dup 2)))
   (clobber (reg:HI AX_REG))
   (clobber (reg:HI BC_REG))
   (clobber (reg:HI DE_REG))
   (clobber (reg:HI HL_REG))
  ]
  "RL78_MUL_G14"
  {
    if (find_reg_note (insn, REG_UNUSED, operands[3]))
      return "; G14 udivsi macro %0 = %1 / %2 \n\
	movw    ax, %h1 \n\
	movw    bc, %H1 \n\
	movw    de, %h2 \n\
	movw    hl, %H2 \n\
	push	psw	; Save the current interrupt status \n\
	di		; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
	divwu   	; bcax = bcax / hlde \n\
	pop	psw	; Restore saved interrupt status \n\
	movw    %h0, ax \n\
	movw	ax, bc \n\
	movw    %H0, ax \n\
	; end of udivsi macro";
    else if (find_reg_note (insn, REG_UNUSED, operands[0]))
      return "; G14 umodsi macro %3 = %1 %% %2 \n\
	movw    ax, %h1 \n\
	movw    bc, %H1 \n\
	movw    de, %h2 \n\
	movw    hl, %H2 \n\
	push	psw	; Save the current interrupt status \n\
	di		; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
	divwu   	; hlde = bcax %% hlde \n\
	pop	psw	; Restore saved interrupt status \n\
	movw	ax, de \n\
	movw    %h3, ax \n\
	movw	ax, hl \n\
	movw    %H3, ax \n\
	; end of umodsi macro";
    else
      return "; G14 udivmodsi macro %0 = %1 / %2 and %3 = %1 %% %2 \n\
	movw    ax, %h1 \n\
	movw    bc, %H1 \n\
	movw    de, %h2 \n\
	movw    hl, %H2 \n\
	push	psw	; Save the current interrupt status \n\
	di		; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E \n\
	divwu   	; bcax = bcax / hlde, hlde = bcax %% hlde \n\
	pop	psw	; Restore saved interrupt status \n\
	movw    %h0, ax \n\
	movw	ax, bc \n\
	movw    %H0, ax \n\
	movw	ax, de \n\
	movw    %h3, ax \n\
	movw	ax, hl \n\
	movw    %H3, ax \n\
	; end of udivmodsi macro";
  }
  [(set_attr "valloc" "divsi")]
)

;; Warning: these values match the silicon not the documentation.
;; 0xFFFF0 is MDAL.  0xFFFF2 is MDAH.
;; 0xFFFF6 is MDBL.  0xFFFF4 is MDBH.
;; 0xF00E0 is MDCL.  0xF00E2 is MDCH.
;; 0xF00E8 is MDUC.

(define_insn "udivmodsi4_g13"
  [(set (match_operand:SI          0 "register_operand" "=v")
	(udiv:SI (match_operand:SI 1 "register_operand" "v")
		 (match_operand:SI 2 "register_operand" "v")))
   (set (match_operand:SI          3 "register_operand" "=v")
	(umod:SI (match_dup 1) (match_dup 2)))
   (clobber (reg:HI AX_REG))
  ]
  "RL78_MUL_G13"
  {
    if (find_reg_note (insn, REG_UNUSED, operands[3]))
      return "; G13 udivsi macro %0 = %1 / %2 \n\
	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1 \n\
	mov	!0xf00e8, a	; This preps the peripheral for division without interrupt generation \n\
	movw	ax, %H1		\n\
	movw	0xffff2, ax	; MDAH \n\
	movw	ax, %h1		\n\
	movw	0xffff0, ax	; MDAL \n\
	movw	ax, %H2		\n\
	movw	0xffff4, ax	; MDBH \n\
	movw	ax, %h2		\n\
	movw	0xffff6, ax	; MDBL \n\
	mov	a, #0xC1	; Set the DIVST bit in MDUC \n\
	mov	!0xf00e8, a	; This starts the division op \n\
1:	mov	a, !0xf00e8	; Wait 16 clocks or until DIVST is clear \n\
	bt	a.0, $1b	\n\
	movw    ax, 0xffff0	; Read the quotient \n\
	movw	%h0, ax		\n\
	movw    ax, 0xffff2	\n\
	movw	%H0, ax		\n\
	; end of udivsi macro";
    else if (find_reg_note (insn, REG_UNUSED, operands[0]))
      return "; G13 umodsi macro %3 = %1 %% %2 \n\
	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1 \n\
	mov	!0xf00e8, a	; This preps the peripheral for division without interrupt generation \n\
	movw	ax, %H1		\n\
	movw	0xffff2, ax	; MDAH \n\
	movw	ax, %h1		\n\
	movw	0xffff0, ax	; MDAL \n\
	movw	ax, %H2		\n\
	movw	0xffff4, ax	; MDBH \n\
	movw	ax, %h2		\n\
	movw	0xffff6, ax	; MDBL \n\
	mov	a, #0xC1	; Set the DIVST bit in MDUC \n\
	mov	!0xf00e8, a	; This starts the division op \n\
1:	mov	a, !0xf00e8	; Wait 16 clocks or until DIVST is clear \n\
	bt	a.0, $1b	\n\
  	movw	ax, !0xf00e0	; Read the remainder \n\
	movw	%h3, ax		\n\
	movw	ax, !0xf00e2	\n\
	movw	%H3, ax		\n\
	; end of umodsi macro";
    else
      return "; G13 udivmodsi macro %0 = %1 / %2 and %3 = %1 %% %2 \n\
	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1 \n\
	mov	!0xf00e8, a	; This preps the peripheral for division without interrupt generation \n\
	movw	ax, %H1		\n\
	movw	0xffff2, ax	; MDAH \n\
	movw	ax, %h1		\n\
	movw	0xffff0, ax	; MDAL \n\
	movw	ax, %H2		\n\
	movw	0xffff4, ax	; MDBH \n\
	movw	ax, %h2		\n\
	movw	0xffff6, ax	; MDBL \n\
	mov	a, #0xC1	; Set the DIVST bit in MDUC \n\
	mov	!0xf00e8, a	; This starts the division op \n\
1:	mov	a, !0xf00e8	; Wait 16 clocks or until DIVST is clear \n\
	bt	a.0, $1b	\n\
	movw    ax, 0xffff0	; Read the quotient \n\
	movw	%h0, ax		\n\
	movw    ax, 0xffff2	\n\
	movw	%H0, ax		\n\
  	movw	ax, !0xf00e0	; Read the remainder \n\
	movw	%h3, ax		\n\
	movw	ax, !0xf00e2	\n\
	movw	%H3, ax		\n\
	; end of udivmodsi macro";
      }
  [(set_attr "valloc" "macax")
   (set_attr "is_g13_muldiv_insn" "yes")]
)

(define_expand "movdi"
  [(set (match_operand:DI 0 "nonimmediate_operand" "")
        (match_operand:DI 1 "general_operand"      ""))]
  ""
  "rl78_split_movdi(operands, DImode);
  DONE;"
)

(define_expand "movdf"
  [(set (match_operand:DF 0 "nonimmediate_operand" "")
        (match_operand:DF 1 "general_operand" ""))]
  ""
  "rl78_split_movdi(operands, DFmode);
  DONE;"
)

(define_expand "umindi3"
 [(set (match_operand:DI          0 "nonimmediate_operand" "")
	(umin:DI (match_operand:DI 1 "general_operand"      "")
		 (match_operand:DI    2 "general_operand"      "")))
   ]
  "optimize_size"
  "rl78_emit_libcall (\"__umindi3\", UMIN, DImode, DImode, 3, operands);
   DONE;"
)

(define_expand "umaxdi3"
 [(set (match_operand:DI          0 "nonimmediate_operand" "")
	(umax:DI (match_operand:DI 1 "general_operand"      "")
		 (match_operand:DI    2 "general_operand"      "")))
   ]
  "optimize_size"
  "rl78_emit_libcall (\"__umaxdi3\", UMAX, DImode, DImode, 3, operands);
   DONE;"
)

(define_expand "smindi3"
 [(set (match_operand:DI          0 "nonimmediate_operand" "")
	(smin:DI (match_operand:DI 1 "general_operand"      "")
		 (match_operand:DI    2 "general_operand"      "")))
   ]
  "optimize_size"
  "rl78_emit_libcall (\"__smindi3\", SMIN, DImode, DImode, 3, operands);
   DONE;"
)

(define_expand "smaxdi3"
 [(set (match_operand:DI          0 "nonimmediate_operand" "")
	(smax:DI (match_operand:DI 1 "general_operand"      "")
		 (match_operand:DI    2 "general_operand"      "")))
   ]
  "optimize_size"
  "rl78_emit_libcall (\"__smaxdi3\", SMAX, DImode, DImode, 3, operands);
   DONE;"
)

(define_expand "anddi3"
 [(set (match_operand:DI          0 "nonimmediate_operand" "")
	(and:DI (match_operand:DI 1 "general_operand"      "")
		 (match_operand:DI    2 "general_operand"      "")))
   ]
  "optimize_size"
  "rl78_emit_libcall (\"__anddi3\", AND, DImode, DImode, 3, operands);
   DONE;"
)
