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