📄 avr.md
字号:
;; -*- Mode: Scheme -*-;; Machine description for GNU compiler,;; for ATMEL AVR micro controllers.;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005;; Free Software Foundation, Inc.;; Contributed by Denis Chertykov (denisc@overta.ru);; 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 2, 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 COPYING. If not, write to;; the Free Software Foundation, 59 Temple Place - Suite 330,;; Boston, MA 02111-1307, USA.;; Special characters after '%':;; A No effect (add 0).;; B Add 1 to REG number, MEM address or CONST_INT.;; C Add 2.;; D Add 3.;; j Branch condition.;; k Reverse branch condition.;; o Displacement for (mem (plus (reg) (const_int))) operands.;; p POST_INC or PRE_DEC address as a pointer (X, Y, Z);; r POST_INC or PRE_DEC address as a register (r26, r28, r30);; ~ Output 'r' if not AVR_MEGA.;; UNSPEC usage:;; 0 Length of a string, see "strlenhi".;; 1 Read from a word address in program memory, see "casesi".;; Condition code settings.(define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber" (const_string "none"))(define_attr "type" "branch,branch1,arith,xcall" (const_string "arith"))(define_attr "mcu_enhanced" "yes,no" (const (if_then_else (symbol_ref "AVR_ENHANCED") (const_string "yes") (const_string "no"))))(define_attr "mcu_mega" "yes,no" (const (if_then_else (symbol_ref "AVR_MEGA") (const_string "yes") (const_string "no")))) ;; The size of instructions in bytes.;; XXX may depend from "cc"(define_attr "length" "" (cond [(eq_attr "type" "branch") (if_then_else (and (ge (minus (pc) (match_dup 0)) (const_int -63)) (le (minus (pc) (match_dup 0)) (const_int 62))) (const_int 1) (if_then_else (and (ge (minus (pc) (match_dup 0)) (const_int -2045)) (le (minus (pc) (match_dup 0)) (const_int 2045))) (const_int 2) (const_int 3))) (eq_attr "type" "branch1") (if_then_else (and (ge (minus (pc) (match_dup 0)) (const_int -62)) (le (minus (pc) (match_dup 0)) (const_int 61))) (const_int 2) (if_then_else (and (ge (minus (pc) (match_dup 0)) (const_int -2044)) (le (minus (pc) (match_dup 0)) (const_int 2043))) (const_int 3) (const_int 4))) (eq_attr "type" "xcall") (if_then_else (eq_attr "mcu_mega" "no") (const_int 1) (const_int 2))] (const_int 2)))(define_insn "*pop1" [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 1)))] "" "pop __tmp_reg__" [(set_attr "length" "1")])(define_insn "*pop2" [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 2)))] "" "pop __tmp_reg__ pop __tmp_reg__" [(set_attr "length" "2")])(define_insn "*pop3" [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 3)))] "" "pop __tmp_reg__ pop __tmp_reg__ pop __tmp_reg__" [(set_attr "length" "3")])(define_insn "*pop4" [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 4)))] "" "pop __tmp_reg__ pop __tmp_reg__ pop __tmp_reg__ pop __tmp_reg__" [(set_attr "length" "4")])(define_insn "*pop5" [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 5)))] "" "pop __tmp_reg__ pop __tmp_reg__ pop __tmp_reg__ pop __tmp_reg__ pop __tmp_reg__" [(set_attr "length" "5")])(define_insn "*pushqi" [(set (mem:QI (post_dec (reg:HI 32))) (match_operand:QI 0 "nonmemory_operand" "r,L"))] "(operands[0] == const0_rtx || register_operand (operands[0], QImode))" "@ push %0 push __zero_reg__" [(set_attr "length" "1,1")])(define_insn "*pushhi" [(set (mem:HI (post_dec (reg:HI 32))) (match_operand:HI 0 "nonmemory_operand" "r,L"))] "(operands[0] == const0_rtx || register_operand (operands[0], HImode))" "@ push %B0\;push %A0 push __zero_reg__\;push __zero_reg__" [(set_attr "length" "2,2")])(define_insn "*pushsi" [(set (mem:SI (post_dec (reg:HI 32))) (match_operand:SI 0 "nonmemory_operand" "r,L"))] "(operands[0] == const0_rtx || register_operand (operands[0], SImode))" "@ push %D0\;push %C0\;push %B0\;push %A0 push __zero_reg__\;push __zero_reg__\;push __zero_reg__\;push __zero_reg__" [(set_attr "length" "4,4")])(define_insn "*pushsf" [(set (mem:SF (post_dec (reg:HI 32))) (match_operand:SF 0 "register_operand" "r"))] "" "push %D0 push %C0 push %B0 push %A0" [(set_attr "length" "4")]);;========================================================================;; move byte;; The last alternative (any immediate constant to any register) is;; very expensive. It should be optimized by peephole2 if a scratch;; register is available, but then that register could just as well be;; allocated for the variable we are loading. But, most of NO_LD_REGS;; are call-saved registers, and most of LD_REGS are call-used registers,;; so this may still be a win for registers live across function calls.(define_expand "movqi" [(set (match_operand:QI 0 "nonimmediate_operand" "") (match_operand:QI 1 "general_operand" ""))] "" "/* One of the ops has to be in a register. */ if (!register_operand(operand0, QImode) && ! (register_operand(operand1, QImode) || const0_rtx == operand1)) operands[1] = copy_to_mode_reg(QImode, operand1); ")(define_insn "*movqi" [(set (match_operand:QI 0 "nonimmediate_operand" "=r,d,Qm,r,q,r,*r") (match_operand:QI 1 "general_operand" "r,i,rL,Qm,r,q,i"))] "(register_operand (operands[0],QImode) || register_operand (operands[1], QImode) || const0_rtx == operands[1])" "* return output_movqi (insn, operands, NULL);" [(set_attr "length" "1,1,5,5,1,1,4") (set_attr "cc" "none,none,clobber,clobber,none,none,clobber")]);; This is used in peephole2 to optimize loading immediate constants;; if a scratch register from LD_REGS happens to be available.(define_insn "*reload_inqi" [(set (match_operand:QI 0 "register_operand" "=l") (match_operand:QI 1 "immediate_operand" "i")) (clobber (match_operand:QI 2 "register_operand" "=&d"))] "reload_completed" "ldi %2,lo8(%1) mov %0,%2" [(set_attr "length" "2") (set_attr "cc" "none")])(define_peephole2 [(match_scratch:QI 2 "d") (set (match_operand:QI 0 "register_operand" "") (match_operand:QI 1 "immediate_operand" ""))] "(operands[1] != const0_rtx && test_hard_reg_class (NO_LD_REGS, operands[0]))" [(parallel [(set (match_dup 0) (match_dup 1)) (clobber (match_dup 2))])] "if (!avr_peep2_scratch_safe (operands[2])) FAIL;");;============================================================================;; move word (16 bit)(define_expand "movhi" [(set (match_operand:HI 0 "nonimmediate_operand" "") (match_operand:HI 1 "general_operand" ""))] "" "{ /* One of the ops has to be in a register. */ if (!register_operand(operand0, HImode) && !(register_operand(operand1, HImode) || const0_rtx == operands[1])) { operands[1] = copy_to_mode_reg(HImode, operand1); }}")(define_peephole2 [(match_scratch:QI 2 "d") (set (match_operand:HI 0 "register_operand" "") (match_operand:HI 1 "immediate_operand" ""))] "(operands[1] != const0_rtx && test_hard_reg_class (NO_LD_REGS, operands[0]))" [(parallel [(set (match_dup 0) (match_dup 1)) (clobber (match_dup 2))])] "if (!avr_peep2_scratch_safe (operands[2])) FAIL;");; '*' because it is not used in rtl generation, only in above peephole(define_insn "*reload_inhi" [(set (match_operand:HI 0 "register_operand" "=r") (match_operand:HI 1 "immediate_operand" "i")) (clobber (match_operand:QI 2 "register_operand" "=&d"))] "reload_completed" "* return output_reload_inhi (insn, operands, NULL);" [(set_attr "length" "4") (set_attr "cc" "none")])(define_insn "*movhi" [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,d,*r,q,r") (match_operand:HI 1 "general_operand" "r,m,rL,i,i,r,q"))] "(register_operand (operands[0],HImode) || register_operand (operands[1],HImode) || const0_rtx == operands[1])" "* return output_movhi (insn, operands, NULL);" [(set_attr "length" "2,6,7,2,6,5,2") (set_attr "cc" "none,clobber,clobber,none,clobber,none,none")]);;==========================================================================;; move double word (32 bit)(define_expand "movsi" [(set (match_operand:SI 0 "nonimmediate_operand" "") (match_operand:SI 1 "general_operand" ""))] "" "{ /* One of the ops has to be in a register. */ if (!register_operand (operand0, SImode) && !(register_operand (operand1, SImode) || const0_rtx == operand1)) { operands[1] = copy_to_mode_reg (SImode, operand1); }}")(define_peephole2 [(match_scratch:QI 2 "d") (set (match_operand:SI 0 "register_operand" "") (match_operand:SI 1 "immediate_operand" ""))] "(operands[1] != const0_rtx && test_hard_reg_class (NO_LD_REGS, operands[0]))" [(parallel [(set (match_dup 0) (match_dup 1)) (clobber (match_dup 2))])] "if (!avr_peep2_scratch_safe (operands[2])) FAIL;");; '*' because it is not used in rtl generation.(define_insn "*reload_insi" [(set (match_operand:SI 0 "register_operand" "=r") (match_operand:SI 1 "immediate_operand" "i")) (clobber (match_operand:QI 2 "register_operand" "=&d"))] "reload_completed" "* return output_reload_insisf (insn, operands, NULL);" [(set_attr "length" "8") (set_attr "cc" "none")])(define_insn "*movsi" [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,Qm,!d,r") (match_operand:SI 1 "general_operand" "r,L,Qm,rL,i,i"))] "(register_operand (operands[0],SImode) || register_operand (operands[1],SImode) || const0_rtx == operands[1])" "* return output_movsisf (insn, operands, NULL);" [(set_attr "length" "4,4,8,9,4,10") (set_attr "cc" "none,set_zn,clobber,clobber,none,clobber")]);; fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;; move floating point numbers (32 bit)(define_expand "movsf" [(set (match_operand:SF 0 "nonimmediate_operand" "") (match_operand:SF 1 "general_operand" ""))] "" "{ /* One of the ops has to be in a register. */ if (!register_operand (operand1, SFmode) && !register_operand (operand0, SFmode)) { operands[1] = copy_to_mode_reg (SFmode, operand1); }}")(define_insn "*movsf" [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r,Qm,!d,r") (match_operand:SF 1 "general_operand" "r,G,Qm,r,F,F"))] "register_operand (operands[0], SFmode) || register_operand (operands[1], SFmode)" "* return output_movsisf (insn, operands, NULL);" [(set_attr "length" "4,4,8,9,4,10") (set_attr "cc" "none,set_zn,clobber,clobber,none,clobber")]);;=========================================================================;; move string (like memcpy);; implement as RTL loop(define_expand "movmemhi" [(parallel [(set (match_operand:BLK 0 "memory_operand" "") (match_operand:BLK 1 "memory_operand" "")) (use (match_operand:HI 2 "const_int_operand" "")) (use (match_operand:HI 3 "const_int_operand" ""))])] "" "{ int prob; HOST_WIDE_INT count; enum machine_mode mode; rtx label = gen_label_rtx (); rtx loop_reg; rtx jump; /* Copy pointers into new psuedos - they will be changed. */ rtx addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0)); rtx addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); /* Create rtx for tmp register - we use this as scratch. */ rtx tmp_reg_rtx = gen_rtx_REG (QImode, TMP_REGNO); if (GET_CODE (operands[2]) != CONST_INT) FAIL; count = INTVAL (operands[2]); if (count <= 0) FAIL; /* Work out branch probability for latter use. */ prob = REG_BR_PROB_BASE - REG_BR_PROB_BASE / count; /* See if constant fit 8 bits. */ mode = (count < 0x100) ? QImode : HImode; /* Create loop counter register. */ loop_reg = copy_to_mode_reg (mode, gen_int_mode (count, mode)); /* Now create RTL code for move loop. */ /* Label at top of loop. */ emit_label (label); /* Move one byte into scratch and inc pointer. */ emit_move_insn (tmp_reg_rtx, gen_rtx_MEM (QImode, addr1)); emit_move_insn (addr1, gen_rtx_PLUS (Pmode, addr1, const1_rtx)); /* Move to mem and inc pointer. */ emit_move_insn (gen_rtx_MEM (QImode, addr0), tmp_reg_rtx); emit_move_insn (addr0, gen_rtx_PLUS (Pmode, addr0, const1_rtx)); /* Decrement count. */ emit_move_insn (loop_reg, gen_rtx_PLUS (mode, loop_reg, constm1_rtx)); /* Compare with zero and jump if not equal. */ emit_cmp_and_jump_insns (loop_reg, const0_rtx, NE, NULL_RTX, mode, 1, label);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -