📄 m68hc11.md
字号:
;;- Machine description file for Motorola 68HC11 and 68HC12.;;- Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.;;- Contributed by Stephane Carrez (stcarrez@nerim.fr);; This file is part of GNU CC.;; GNU CC 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.;; GNU CC 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 GNU CC; see the file COPYING. If not, write to;; the Free Software Foundation, 59 Temple Place - Suite 330,;; Boston, MA 02111-1307, USA.;; Note:;; A first 68HC11 port was made by Otto Lind (otto@coactive.com);; on gcc 2.6.3. I have used it as a starting point for this port.;; However, this new port is a complete re-write. Its internal;; design is completely different. The generated code is not;; compatible with the gcc 2.6.3 port.;;;; The gcc 2.6.3 port is available at:;;;; ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz;;;;- Instruction patterns. When multiple patterns apply,;;- the first one in the file is chosen.;;-;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.;;-;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code;;- updates for most instructions.;;;; The following constraints are used:;;;; Single pair registers:;; a register 'a' 8-bit;; b register 'b' 8-bit;; d register 'd' 16-bit;; t pseudo soft register 'TMP' 16-bit;; v register 'd' for 68hc11, 16-bit;; NO_REG for 68hc12;; (used for scratch register);; w register 'sp' 16-bit ;; x register 'x' 16-bit;; y register 'y' 16-bit;; z register 'z' 16-bit (fake r for 68HC11 and 68HC12);; D register 'd+x' 32-bit ;;;; Group of registers:;; q register 'a' or 'b' or 'd' 8-bit;; u pseudo soft register 16-bit;; A register 'x', 'y', 'z' 16-bit;; B register 'x', 'y' 16-bit;; h register 'd', 'x', 'y', 'z' 16-bit;;;; Other constraints:;;;; Q an operand which is in memory but whose address is constant;; (ie, a (MEM (SYMBOL_REF x))). This constraint is used by;; bset/bclr instructions together with linker relaxation. The;; operand can be translated to a page0 addressing mode if the;; symbol address is in page0 (0..255).;;;; R an operand which is in memory and whose address is expressed;; with 68HC11/68HC12 indexed addressing mode. In general this;; is any valid (MEM) except a (MEM (SYMBOL_REF x)).;;;; U an operand which is in memory and if it uses the 68HC12 indexed;; addressing mode, the offset is in the range -16..+15. This is;; used by 68HC12 movb/movw instructions since they do not accept;; the full 16-bit offset range (as other insn do).;;;;;; Immediate integer operand constraints:;; `L' is for range -65536 to 65536;; `M' is for values whose 16-bit low part is 0;; 'N' is for +1 or -1.;; 'O' is for 16 (for rotate using swap).;; 'P' is for range -8 to 2 (used by addhi_sp);;;; In many cases, it's not possible to use the 'g' or 'r' constraints.;;;; Operands modifiers:;;;; %b Get the low part of the operand (to obtain a QImode);; This modified must always be used for QImode operations;; because a correction must be applied when the operand;; is a soft register (ex: *ZD1). Otherwise, we generate;; *ZD1 and this is the high part of the register. For other;; kinds of operands, if the operand is already QImode, no;; additional correction is made.;; %h Get the high part of the operand (to obtain a QImode);; %t Represents the temporary/scratch register *_.tmp;; The scratch register is used in some cases when GCC puts;; some values in bad registers. ;;;; 32/64-bit Patterns:;; The 68HC11 does not support 32/64-bit operations. Most of the;; 32/64-bit patterns are defined to split the instruction in;; 16-bits patterns. Providing split patterns generates better code;; than letting GCC implement the 32/64-bit operation itself.;;;;;; Notes:;;;; o For iorqi3, andqi3, xorqi3 patterns, we must accept the 'A' constraint;; otherwise some insn are not satisfied.;;;; o Split patterns that create a swap_areg pattern (xgdx or xgdy) must;; be valid only when z_replacement_completed == 2 because once these;; swap instructions are generated, a flow/cse pass fails to handle;; them correctly (it would treat the X, Y or D register as dead sometimes).;;;; o Some split pattern generate instructions that operate on 'a' or 'b';; register directly (high part and low part of D respectively).;; Such split pattern must also be valid when z_replacement_completed == 2;; because flow/cse is not aware that D is composed of {a, b}.;;;; o Split patterns that generate a (mem:QI (symbol_reg _.dx)) to access;; the high part of a soft register must be expanded after z_replacement;; pass.;;;;---------------------------------------------------------------------------;; Constants(define_constants [ ;; Register numbers (X_REGNUM 0) ; Index X register (D_REGNUM 1) ; Data register (Y_REGNUM 2) ; Index Y register (SP_REGNUM 3) ; Stack pointer (PC_REGNUM 4) ; Program counter (A_REGNUM 5) ; A (high part of D) (B_REGNUM 6) ; B (low part of D) (CC_REGNUM 7) ; Condition code register (SOFT_Z_REGNUM 11) ; Z soft register]);;--------------------------------------------------------------------;;- Test;;--------------------------------------------------------------------;;;; The test and compare insn must not accept a memory operand with;; an auto-inc mode. If we do this, the reload can emit move insns;; after the test or compare. Such move will set the flags and therefore;; break the comparison. This can happen if the auto-inc register;; does not happen to be a hard register (ie, reloading occurs).;; An offsetable memory operand should be ok. The 'tst_operand' and;; 'cmp_operand' predicates take care of this rule.;;(define_expand "tstsi" [(set (cc0) (match_operand:SI 0 "tst_operand" ""))] "" "{ m68hc11_compare_op0 = operands[0]; m68hc11_compare_op1 = const0_rtx; DONE;}")(define_expand "tsthi" [(set (cc0) (match_operand:HI 0 "tst_operand" ""))] "" "{ m68hc11_compare_op0 = operands[0]; m68hc11_compare_op1 = const0_rtx; DONE;}")(define_insn "tsthi_1" [(set (cc0) (match_operand:HI 0 "tst_operand" "dx,*y"))] "" "*{ if (D_REG_P (operands[0]) && !TARGET_M6812) return \"std\\t%t0\"; else return \"cp%0\\t#0\";}")(define_expand "tstqi" [(set (cc0) (match_operand:QI 0 "tst_operand" ""))] "" "{ m68hc11_compare_op0 = operands[0]; m68hc11_compare_op1 = const0_rtx; DONE;}");;;; Split pattern for (tst:QI) on an address register.;;(define_split [(set (cc0) (match_operand:QI 0 "hard_addr_reg_operand" ""))] "z_replacement_completed == 2 && GET_MODE (operands[0]) == QImode" [(parallel [(set (reg:HI D_REGNUM) (match_dup 1)) (set (match_dup 1) (reg:HI D_REGNUM))]) (set (cc0) (reg:QI D_REGNUM)) (parallel [(set (reg:HI D_REGNUM) (match_dup 1)) (set (match_dup 1) (reg:HI D_REGNUM))])] "operands[1] = gen_rtx (REG, HImode, REGNO (operands[0]));")(define_insn "tstqi_1" [(set (cc0) (match_operand:QI 0 "tst_operand" "m,d,*A,!u"))] "" "*{ if (A_REG_P (operands[0])) return \"#\"; else if (D_REG_P (operands[0])) return \"tstb\"; else if (dead_register_here (insn, d_reg)) return \"ldab\\t%b0\"; else return \"tst\\t%b0\";}");;;; tstqi_z_used, cmpqi_z_used and cmphi_z_used are patterns generated ;; during the Z register replacement. They are used when an operand;; uses the Z register as an index register (ie, (MEM:QI (REG:HI Z))).;; In that case, we have to preserve the values of the replacement;; register (as well as the CC0 since the insns are compare insns).;; To do this, the replacement register is pushed on the stack and;; restored after the real compare. A pattern+split is defined to;; avoid problems with the flow+cse register pass which are made;; after Z register replacement.;;(define_insn "tstqi_z_used" [(set (cc0) (match_operand:QI 0 "tst_operand" "m")) (use (match_operand:HI 1 "hard_reg_operand" "dxy")) (use (reg:HI 11))] "" "#")(define_split /* "tstqi_z_used" */ [(set (cc0) (match_operand:QI 0 "tst_operand" "")) (use (match_operand:HI 1 "hard_reg_operand" "")) (use (reg:HI SOFT_Z_REGNUM))] "z_replacement_completed == 2" [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) (match_dup 1)) (set (match_dup 1) (match_dup 2)) (set (cc0) (match_dup 0)) (set (match_dup 1) (mem:HI (post_inc:HI (reg:HI SP_REGNUM))))] "operands[2] = gen_rtx (REG, HImode, SOFT_Z_REGNUM);");;--------------------------------------------------------------------;;- Compare;;--------------------------------------------------------------------(define_expand "cmpsi" [(set (cc0) (compare (match_operand:SI 0 "tst_operand" "") (match_operand:SI 1 "cmp_operand" "")))] "" "{ if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) operands[0] = force_reg (SImode, operands[0]); m68hc11_compare_op0 = operands[0]; m68hc11_compare_op1 = operands[1]; DONE;}");;;; Comparison of a hard register with another one is provided because;; it helps GCC to avoid to spill a pseudo hard register.;; We use a temporary in page 0, this is equivalent to a pseudo hard reg.;; (except that we loose the information that the value is saved in it).;;;; The split pattern transforms the comparison into a save of one hard;; register and a comparison with the temporary.;;(define_split [(set (cc0) (compare (match_operand:HI 0 "hard_reg_operand" "") (match_operand:HI 1 "hard_reg_operand" "")))] "reload_completed" [(set (match_dup 2) (match_dup 1)) (set (cc0) (compare (match_dup 0) (match_dup 2)))] "operands[2] = gen_rtx (REG, HImode, SOFT_TMP_REGNUM);")(define_expand "cmphi" [(set (cc0) (compare (match_operand:HI 0 "tst_operand" "") (match_operand:HI 1 "cmp_operand" "")))] "" "{ if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) operands[0] = force_reg (HImode, operands[0]); m68hc11_compare_op0 = operands[0]; m68hc11_compare_op1 = operands[1]; DONE;}")(define_insn "cmphi_1_hc12" [(set (cc0) (compare (match_operand:HI 0 "tst_operand" "d,?xy,xyd,?xy,d,m,!u,dxy,dxy") (match_operand:HI 1 "cmp_operand" "i,i,!u,m,m,dxy,dxy,?*d*A,!*w")))] "TARGET_M6812" "*{ if (H_REG_P (operands[1]) && !H_REG_P (operands[0])) { cc_status.flags |= CC_REVERSED; return \"cp%1\\t%0\"; } else if (H_REG_P (operands[1])) return \"#\"; else return \"cp%0\\t%1\";}")(define_insn "cmphi_1_hc11" [(set (cc0) (compare (match_operand:HI 0 "tst_operand" "dx,y,xyd,?xy,d,m,!u,dxy,dxy") (match_operand:HI 1 "cmp_operand" "i,i,!u,m,m,dxy,dxy,?*d*A,!*w")))] "TARGET_M6811" "*{ if (H_REG_P (operands[1]) && !H_REG_P (operands[0])) { cc_status.flags |= CC_REVERSED; return \"cp%1\\t%0\"; } else if (H_REG_P (operands[1])) return \"#\"; else return \"cp%0\\t%1\";}")(define_insn "cmphi_z_used" [(set (cc0) (compare (match_operand:HI 0 "tst_operand" "dxy,m") (match_operand:HI 1 "cmp_operand" "m,dxy"))) (use (match_operand:HI 2 "hard_reg_operand" "dxy,dxy")) (use (reg:HI SOFT_Z_REGNUM))] "" "#") (define_split /* "cmphi_z_used" */ [(set (cc0) (compare (match_operand:HI 0 "tst_operand" "") (match_operand:HI 1 "cmp_operand" ""))) (use (match_operand:HI 2 "hard_reg_operand" "")) (use (reg:HI SOFT_Z_REGNUM))] "z_replacement_completed == 2" [(set (mem:HI (pre_dec:HI (reg:HI SP_REGNUM))) (match_dup 2)) (set (match_dup 2) (match_dup 3)) (set (cc0) (compare (match_dup 0) (match_dup 1))) (set (match_dup 2) (mem:HI (post_inc:HI (reg:HI SP_REGNUM))))] "operands[3] = gen_rtx (REG, HImode, SOFT_Z_REGNUM);");;;; 8-bit comparison with address register.;; There is no such comparison instruction, we have to temporarily switch;; the address register and the D register and do the comparison with D.;; The xgdx and xgdy instructions preserve the flags.;;(define_split [(set (cc0) (compare (match_operand:QI 0 "hard_addr_reg_operand" "") (match_operand:QI 1 "cmp_operand" "")))] "z_replacement_completed == 2 && GET_MODE (operands[0]) == QImode" [(parallel [(set (reg:HI D_REGNUM) (match_dup 3)) (set (match_dup 3) (reg:HI D_REGNUM))]) (set (cc0) (compare (reg:QI D_REGNUM) (match_dup 1))) (parallel [(set (reg:HI D_REGNUM) (match_dup 3)) (set (match_dup 3) (reg:HI D_REGNUM))])] "operands[3] = gen_rtx (REG, HImode, REGNO (operands[0]));")(define_split [(set (cc0) (compare (match_operand:QI 0 "hard_reg_operand" "") (match_operand:QI 1 "hard_reg_operand" "")))] "reload_completed" [(set (match_dup 3) (match_dup 4)) (set (cc0) (compare (match_dup 0) (match_dup 2)))] "operands[2] = gen_rtx (REG, QImode, SOFT_TMP_REGNUM); operands[3] = gen_rtx (REG, HImode, SOFT_TMP_REGNUM); operands[4] = gen_rtx (REG, HImode, REGNO (operands[1]));")(define_expand "cmpqi" [(set (cc0) (compare (match_operand:QI 0 "tst_operand" "") (match_operand:QI 1 "cmp_operand" "")))] "" "{ if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) operands[0] = force_reg (QImode, operands[0]); m68hc11_compare_op0 = operands[0]; m68hc11_compare_op1 = operands[1]; DONE;}")(define_insn "bitcmpqi" [(set (cc0) (and:QI (match_operand:QI 0 "tst_operand" "d,d,d,m,!u") (match_operand:QI 1 "cmp_operand" "im,*B,u,d,d")))] "" "@ bitb\\t%b1 # bitb\\t%b1 bitb\\t%b0 bitb\\t%b0")
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -