arm.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // Copyright 2015 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // This file encapsulates some of the odd characteristics of the ARM
  5. // instruction set, to minimize its interaction with the core of the
  6. // assembler.
  7. package arch
  8. import (
  9. "strings"
  10. "github.com/twitchyliquid64/golang-asm/obj"
  11. "github.com/twitchyliquid64/golang-asm/obj/arm"
  12. )
  13. var armLS = map[string]uint8{
  14. "U": arm.C_UBIT,
  15. "S": arm.C_SBIT,
  16. "W": arm.C_WBIT,
  17. "P": arm.C_PBIT,
  18. "PW": arm.C_WBIT | arm.C_PBIT,
  19. "WP": arm.C_WBIT | arm.C_PBIT,
  20. }
  21. var armSCOND = map[string]uint8{
  22. "EQ": arm.C_SCOND_EQ,
  23. "NE": arm.C_SCOND_NE,
  24. "CS": arm.C_SCOND_HS,
  25. "HS": arm.C_SCOND_HS,
  26. "CC": arm.C_SCOND_LO,
  27. "LO": arm.C_SCOND_LO,
  28. "MI": arm.C_SCOND_MI,
  29. "PL": arm.C_SCOND_PL,
  30. "VS": arm.C_SCOND_VS,
  31. "VC": arm.C_SCOND_VC,
  32. "HI": arm.C_SCOND_HI,
  33. "LS": arm.C_SCOND_LS,
  34. "GE": arm.C_SCOND_GE,
  35. "LT": arm.C_SCOND_LT,
  36. "GT": arm.C_SCOND_GT,
  37. "LE": arm.C_SCOND_LE,
  38. "AL": arm.C_SCOND_NONE,
  39. "U": arm.C_UBIT,
  40. "S": arm.C_SBIT,
  41. "W": arm.C_WBIT,
  42. "P": arm.C_PBIT,
  43. "PW": arm.C_WBIT | arm.C_PBIT,
  44. "WP": arm.C_WBIT | arm.C_PBIT,
  45. "F": arm.C_FBIT,
  46. "IBW": arm.C_WBIT | arm.C_PBIT | arm.C_UBIT,
  47. "IAW": arm.C_WBIT | arm.C_UBIT,
  48. "DBW": arm.C_WBIT | arm.C_PBIT,
  49. "DAW": arm.C_WBIT,
  50. "IB": arm.C_PBIT | arm.C_UBIT,
  51. "IA": arm.C_UBIT,
  52. "DB": arm.C_PBIT,
  53. "DA": 0,
  54. }
  55. var armJump = map[string]bool{
  56. "B": true,
  57. "BL": true,
  58. "BX": true,
  59. "BEQ": true,
  60. "BNE": true,
  61. "BCS": true,
  62. "BHS": true,
  63. "BCC": true,
  64. "BLO": true,
  65. "BMI": true,
  66. "BPL": true,
  67. "BVS": true,
  68. "BVC": true,
  69. "BHI": true,
  70. "BLS": true,
  71. "BGE": true,
  72. "BLT": true,
  73. "BGT": true,
  74. "BLE": true,
  75. "CALL": true,
  76. "JMP": true,
  77. }
  78. func jumpArm(word string) bool {
  79. return armJump[word]
  80. }
  81. // IsARMCMP reports whether the op (as defined by an arm.A* constant) is
  82. // one of the comparison instructions that require special handling.
  83. func IsARMCMP(op obj.As) bool {
  84. switch op {
  85. case arm.ACMN, arm.ACMP, arm.ATEQ, arm.ATST:
  86. return true
  87. }
  88. return false
  89. }
  90. // IsARMSTREX reports whether the op (as defined by an arm.A* constant) is
  91. // one of the STREX-like instructions that require special handling.
  92. func IsARMSTREX(op obj.As) bool {
  93. switch op {
  94. case arm.ASTREX, arm.ASTREXD, arm.ASWPW, arm.ASWPBU:
  95. return true
  96. }
  97. return false
  98. }
  99. // MCR is not defined by the obj/arm; instead we define it privately here.
  100. // It is encoded as an MRC with a bit inside the instruction word,
  101. // passed to arch.ARMMRCOffset.
  102. const aMCR = arm.ALAST + 1
  103. // IsARMMRC reports whether the op (as defined by an arm.A* constant) is
  104. // MRC or MCR
  105. func IsARMMRC(op obj.As) bool {
  106. switch op {
  107. case arm.AMRC, aMCR: // Note: aMCR is defined in this package.
  108. return true
  109. }
  110. return false
  111. }
  112. // IsARMBFX reports whether the op (as defined by an arm.A* constant) is one the
  113. // BFX-like instructions which are in the form of "op $width, $LSB, (Reg,) Reg".
  114. func IsARMBFX(op obj.As) bool {
  115. switch op {
  116. case arm.ABFX, arm.ABFXU, arm.ABFC, arm.ABFI:
  117. return true
  118. }
  119. return false
  120. }
  121. // IsARMFloatCmp reports whether the op is a floating comparison instruction.
  122. func IsARMFloatCmp(op obj.As) bool {
  123. switch op {
  124. case arm.ACMPF, arm.ACMPD:
  125. return true
  126. }
  127. return false
  128. }
  129. // ARMMRCOffset implements the peculiar encoding of the MRC and MCR instructions.
  130. // The difference between MRC and MCR is represented by a bit high in the word, not
  131. // in the usual way by the opcode itself. Asm must use AMRC for both instructions, so
  132. // we return the opcode for MRC so that asm doesn't need to import obj/arm.
  133. func ARMMRCOffset(op obj.As, cond string, x0, x1, x2, x3, x4, x5 int64) (offset int64, op0 obj.As, ok bool) {
  134. op1 := int64(0)
  135. if op == arm.AMRC {
  136. op1 = 1
  137. }
  138. bits, ok := ParseARMCondition(cond)
  139. if !ok {
  140. return
  141. }
  142. offset = (0xe << 24) | // opcode
  143. (op1 << 20) | // MCR/MRC
  144. ((int64(bits) ^ arm.C_SCOND_XOR) << 28) | // scond
  145. ((x0 & 15) << 8) | //coprocessor number
  146. ((x1 & 7) << 21) | // coprocessor operation
  147. ((x2 & 15) << 12) | // ARM register
  148. ((x3 & 15) << 16) | // Crn
  149. ((x4 & 15) << 0) | // Crm
  150. ((x5 & 7) << 5) | // coprocessor information
  151. (1 << 4) /* must be set */
  152. return offset, arm.AMRC, true
  153. }
  154. // IsARMMULA reports whether the op (as defined by an arm.A* constant) is
  155. // MULA, MULS, MMULA, MMULS, MULABB, MULAWB or MULAWT, the 4-operand instructions.
  156. func IsARMMULA(op obj.As) bool {
  157. switch op {
  158. case arm.AMULA, arm.AMULS, arm.AMMULA, arm.AMMULS, arm.AMULABB, arm.AMULAWB, arm.AMULAWT:
  159. return true
  160. }
  161. return false
  162. }
  163. var bcode = []obj.As{
  164. arm.ABEQ,
  165. arm.ABNE,
  166. arm.ABCS,
  167. arm.ABCC,
  168. arm.ABMI,
  169. arm.ABPL,
  170. arm.ABVS,
  171. arm.ABVC,
  172. arm.ABHI,
  173. arm.ABLS,
  174. arm.ABGE,
  175. arm.ABLT,
  176. arm.ABGT,
  177. arm.ABLE,
  178. arm.AB,
  179. obj.ANOP,
  180. }
  181. // ARMConditionCodes handles the special condition code situation for the ARM.
  182. // It returns a boolean to indicate success; failure means cond was unrecognized.
  183. func ARMConditionCodes(prog *obj.Prog, cond string) bool {
  184. if cond == "" {
  185. return true
  186. }
  187. bits, ok := ParseARMCondition(cond)
  188. if !ok {
  189. return false
  190. }
  191. /* hack to make B.NE etc. work: turn it into the corresponding conditional */
  192. if prog.As == arm.AB {
  193. prog.As = bcode[(bits^arm.C_SCOND_XOR)&0xf]
  194. bits = (bits &^ 0xf) | arm.C_SCOND_NONE
  195. }
  196. prog.Scond = bits
  197. return true
  198. }
  199. // ParseARMCondition parses the conditions attached to an ARM instruction.
  200. // The input is a single string consisting of period-separated condition
  201. // codes, such as ".P.W". An initial period is ignored.
  202. func ParseARMCondition(cond string) (uint8, bool) {
  203. return parseARMCondition(cond, armLS, armSCOND)
  204. }
  205. func parseARMCondition(cond string, ls, scond map[string]uint8) (uint8, bool) {
  206. cond = strings.TrimPrefix(cond, ".")
  207. if cond == "" {
  208. return arm.C_SCOND_NONE, true
  209. }
  210. names := strings.Split(cond, ".")
  211. bits := uint8(0)
  212. for _, name := range names {
  213. if b, present := ls[name]; present {
  214. bits |= b
  215. continue
  216. }
  217. if b, present := scond[name]; present {
  218. bits = (bits &^ arm.C_SCOND) | b
  219. continue
  220. }
  221. return 0, false
  222. }
  223. return bits, true
  224. }
  225. func armRegisterNumber(name string, n int16) (int16, bool) {
  226. if n < 0 || 15 < n {
  227. return 0, false
  228. }
  229. switch name {
  230. case "R":
  231. return arm.REG_R0 + n, true
  232. case "F":
  233. return arm.REG_F0 + n, true
  234. }
  235. return 0, false
  236. }