if cond == "" {
return true
}
- bits, ok := parseARMCondition(cond)
+ bits, ok := ParseARMCondition(cond)
if !ok {
return false
}
return true
}
-// parseARMCondition parses the conditions attached to an ARM instruction.
+// ParseARMCondition parses the conditions attached to an ARM instruction.
// The input is a single string consisting of period-separated condition
// codes, such as ".P.W". An initial period is ignored.
-func parseARMCondition(cond string) (uint8, bool) {
+func ParseARMCondition(cond string) (uint8, bool) {
if strings.HasPrefix(cond, ".") {
cond = cond[1:]
}
// Strange special case: MCR, MRC.
// TODO: Move this to arch? (It will be hard to disentangle.)
prog.To.Type = obj.TYPE_CONST
+ bits, ok := uint8(0), false
if cond != "" {
- p.errorf("TODO: can't handle ARM condition code for instruction %s", p.arch.Aconv(op))
+ // Cond is handled specially for this instruction.
+ bits, ok = arch.ParseARMCondition(cond)
+ if !ok {
+ p.errorf("unrecognized condition code .%q", cond)
+ }
+ cond = ""
}
- cond = ""
// First argument is a condition code as a constant.
x0 := p.getConstant(prog, op, &a[0])
x1 := p.getConstant(prog, op, &a[1])
prog.To.Offset =
(0xe << 24) | // opcode
(op1 << 20) | // MCR/MRC
- ((0 ^ arm.C_SCOND_XOR) << 28) | // scond TODO; should use cond.
+ ((int64(bits) ^ arm.C_SCOND_XOR) << 28) | // scond
((x0 & 15) << 8) | //coprocessor number
((x1 & 7) << 21) | // coprocessor operation
((x2 & 15) << 12) | // ARM register
// Register: R1
if tok.ScanToken == scanner.Ident && p.atStartOfRegister(name) {
- if lex.IsRegisterShift(p.peek()) {
+ if p.atRegisterShift() {
// ARM shifted register such as R1<<R2 or R1>>2.
a.Type = obj.TYPE_SHIFT
a.Offset = p.registerShift(tok.String(), prefix)
return p.arch.RegisterPrefix[name] && p.peek() == '('
}
+// atRegisterShift reports whether we are at the start of an ARM shifted register.
+// We have consumed the register or R prefix.
+func (p *Parser) atRegisterShift() bool {
+ // ARM only.
+ if p.arch.Thechar != '5' {
+ return false
+ }
+ // R1<<...
+ if lex.IsRegisterShift(p.peek()) {
+ return true
+ }
+ // R(1)<<... Ugly check. TODO: Rethink how we handle ARM register shifts to be
+ // less special.
+ if p.peek() != '(' || len(p.input)-p.inputPos < 4 {
+ return false
+ }
+ return p.at('(', scanner.Int, ')') && lex.IsRegisterShift(p.input[p.inputPos+3].ScanToken)
+}
+
// registerReference parses a register given either the name, R10, or a parenthesized form, SPR(10).
func (p *Parser) registerReference(name string) (int16, bool) {
r, present := p.arch.Register[name]
// registerList parses an ARM register list expression, a list of registers in [].
// There may be comma-separated ranges or individual registers, as in
-// [R1,R3-R5,R7]. Only R0 through R15 may appear.
+// [R1,R3-R5]. Only R0 through R15 may appear.
// The opening bracket has been consumed.
func (p *Parser) registerList(a *obj.Addr) {
// One range per loop.
}
return false
}
+
+// at reports whether the next tokens are as requested.
+func (p *Parser) at(next ...lex.ScanToken) bool {
+ if len(p.input)-p.inputPos < len(next) {
+ return false
+ }
+ for i, r := range next {
+ if p.input[p.inputPos+i].ScanToken != r {
+ return false
+ }
+ }
+ return true
+}