From 182f0f4ca1825c00804e9b01d8bbc5c2eff6c0bd Mon Sep 17 00:00:00 2001 From: Martin Meloun Date: Wed, 25 Sep 2013 15:48:27 +0200 Subject: [PATCH] MBTumbl: Implement support for conditional execution This adds pseudo instructions IT, ITT, ITE as a part of CMP and CMPU instructions for conditional execution on MBTumbl Signed-off-by: Martin Meloun --- gas/config/tc-microblaze.c | 107 +++++++++++++++++++++++++++++++++++-- opcodes/microblaze-dis.c | 74 ++++++++++++++++++++++++- opcodes/microblaze-opc.h | 13 +++-- opcodes/microblaze-opcm.h | 33 ++++++++++-- 4 files changed, 215 insertions(+), 12 deletions(-) diff --git a/gas/config/tc-microblaze.c b/gas/config/tc-microblaze.c index 80bfebb0d..560215f93 100644 --- a/gas/config/tc-microblaze.c +++ b/gas/config/tc-microblaze.c @@ -104,6 +104,11 @@ static segT sdata_segment = 0; /* Small data section. */ static segT sdata2_segment = 0; /* Small read-only section. */ static segT rodata_segment = 0; /* read-only section. */ +/* Previous instruction (for pseudo instructions) */ +static char * last_output; +static int last_inst; +static int last_pseudo; + /* Generate a symbol for stabs information. */ void @@ -562,6 +567,53 @@ parse_reg (char * s, unsigned * reg) return s; } +/* Try to parse a cond name. */ + +static char * +parse_cond (char * s, unsigned * cond) +{ + /* Strip leading whitespace. */ + while (ISSPACE (* s)) + ++ s; + + if (strncasecmp (s, "eq", 2) == 0) + { + *cond = COND_EQ; + return s + 2; + } + else if (strncasecmp (s, "ne", 2) == 0) + { + *cond = COND_NE; + return s + 2; + } + else if (strncasecmp (s, "lt", 2) == 0) + { + *cond = COND_LT; + return s + 2; + } + else if (strncasecmp (s, "le", 2) == 0) + { + *cond = COND_LE; + return s + 2; + } + else if (strncasecmp (s, "gt", 2) == 0) + { + *cond = COND_GT; + return s + 2; + } + else if (strncasecmp (s, "ge", 2) == 0) + { + *cond = COND_GE; + return s + 2; + } + else + { + as_bad (_("condition expected, but saw '%.6s'"), s); + *cond = 0; + return s; + } +} + static char * parse_exp (char *s, expressionS *e) { @@ -796,6 +848,7 @@ md_assemble (char * str) struct op_code_struct * opcode, *opcode1; char * output = NULL; int nlen = 0; + int pseudo = 0; int i; unsigned long inst, inst1; unsigned reg1; @@ -1250,6 +1303,45 @@ md_assemble (char * str) inst |= (reg1 << RD_LOW) & RD_MASK; output = frag_more (isize); break; +#else + + case INST_TYPE_COND: + if (strcmp (op_end, "")) + op_end = parse_cond (op_end + 1, ®1); /* Get cond. */ + else + { + as_fatal (_("Error in statement syntax")); + reg1 = 0; + } + + if (last_pseudo != 0 || last_output == NULL) + { + as_fatal (_("IT, ITT, ITE pseudo instructions must follow CMP or CMPU isntructions")); + return; + } + + opcode1 = (struct op_code_struct *) hash_find (opcode_hash_control, "cmp"); + if ((opcode1 == NULL) || ((last_inst & opcode1->opcode_mask) != opcode1->bit_sequence)) + { + opcode1 = (struct op_code_struct *) hash_find (opcode_hash_control, "cmpu"); + if ((opcode1 == NULL) || ((last_inst & opcode1->opcode_mask) != opcode1->bit_sequence)) + { + as_fatal (_("IT, ITT, ITE pseudo instructions must follow CMP or CMPU isntructions")); + return; + } + } + + /* Modify last instruction */ + last_inst |= (reg1 << COND_LOW) & COND_MASK; + last_inst |= opcode->bit_sequence; + last_output[0] = INST_BYTE0 (last_inst); + last_output[1] = INST_BYTE1 (last_inst); + last_output[2] = INST_BYTE2 (last_inst); + last_output[3] = INST_BYTE3 (last_inst); + + /* Only one pseudo instruction follows */ + pseudo = 1; + break; #endif case INST_TYPE_RD_SPECIAL: @@ -1643,10 +1735,17 @@ md_assemble (char * str) if (strcmp (op_end, opcode->name) && strcmp (op_end, "")) as_warn (_("ignoring operands: %s "), op_end); - output[0] = INST_BYTE0 (inst); - output[1] = INST_BYTE1 (inst); - output[2] = INST_BYTE2 (inst); - output[3] = INST_BYTE3 (inst); + if (!pseudo) + { + output[0] = INST_BYTE0 (inst); + output[1] = INST_BYTE1 (inst); + output[2] = INST_BYTE2 (inst); + output[3] = INST_BYTE3 (inst); + + last_output = output; + last_inst = inst; + } + last_pseudo = pseudo; #ifdef OBJ_ELF dwarf2_emit_insn (4); diff --git a/opcodes/microblaze-dis.c b/opcodes/microblaze-dis.c index 49db4d2fa..2ecec054d 100644 --- a/opcodes/microblaze-dis.c +++ b/opcodes/microblaze-dis.c @@ -86,6 +86,63 @@ get_field_imm15 (long instr) return (strdup (tmpstr)); } +#else + +static char * +get_field_itt_cond (long instr) +{ + const char *cond = NULL; + + switch ((instr & COND_MASK) >> COND_LOW) + { + case COND_EQ: + cond = "eq"; + break; + case COND_NE: + cond = "ne"; + break; + case COND_LE: + cond = "le"; + break; + case COND_LT: + cond = "lt"; + break; + case COND_GE: + cond = "ge"; + break; + case COND_GT: + cond = "gt"; + break; + } + + if (cond == NULL) + return NULL; + return (strdup (cond)); +} + +static char * +get_field_itt (long instr) +{ + const char *cond_type = NULL; + + switch ((instr & COND_TYPE_MASK) >> COND_TYPE_LOW) + { + case COND_TYPE_IT: + cond_type = "it"; + break; + case COND_TYPE_ITT: + cond_type = "itt"; + break; + case COND_TYPE_ITE: + cond_type = "ite"; + break; + } + + if (cond_type == NULL) + return NULL; + return (strdup (cond_type)); +} + #endif static char * @@ -186,7 +243,7 @@ read_insn_microblaze (bfd_vma memaddr, /* Just a linear search of the table. */ for (op = opcodes; op->name != 0; op ++) - if (op->bit_sequence == (inst & op->opcode_mask)) + if ((op->bit_sequence == (inst & op->opcode_mask)) && (op->inst_type != pseudo_inst)) break; *opr = op; @@ -206,6 +263,10 @@ print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info) static bfd_vma prev_insn_addr = -1; /* Init the prev insn addr. */ static int prev_insn_vma = -1; /* Init the prev insn vma. */ int curr_insn_vma = info->buffer_vma; +#ifdef ARCH_mbtumbl + char * cmp_cond; + char * cmp_cond_type; +#endif info->bytes_per_chunk = 4; @@ -248,7 +309,18 @@ print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info) case INST_TYPE_RD_R1_R2: print_func (stream, "\t%s, %s, %s", get_field_rd (inst), get_field_r1(inst), get_field_r2 (inst)); + +#ifdef ARCH_mbtumbl + /* Maybe CMP with ITT */ + if (!strcmp(op->name, "cmp") || !strcmp(op->name, "cmpu")) + { + cmp_cond = get_field_itt_cond(inst); + cmp_cond_type = get_field_itt(inst); + if (cmp_cond && cmp_cond_type) + print_func (stream, "\t\t%s\t%s", cmp_cond_type, cmp_cond); + } break; +#endif case INST_TYPE_RD_R1_IMM: print_func (stream, "\t%s, %s, %s", get_field_rd (inst), get_field_r1(inst), get_field_imm (inst)); diff --git a/opcodes/microblaze-opc.h b/opcodes/microblaze-opc.h index b982351b6..3be14a7f9 100644 --- a/opcodes/microblaze-opc.h +++ b/opcodes/microblaze-opc.h @@ -65,9 +65,12 @@ #else -/* Halt instruction type */ +/* Halt instruction is IMM5 */ #define INST_TYPE_IMM5 20 +/* Conditional pseudoinstruction */ +#define INST_TYPE_COND 21 + #endif #define INST_TYPE_NONE 25 @@ -90,6 +93,7 @@ #define OPCODE_MASK_H2 0xFC1F0000 /* High 6 and bits 20-16. */ #define OPCODE_MASK_H12 0xFFFF0000 /* High 16. */ #define OPCODE_MASK_H4 0xFC0007FF /* High 6 and low 11 bits. */ +#define OPCODE_MASK_H4S 0xFC0007E0 /* High 6 and bits 11 - 6. */ #define OPCODE_MASK_H13S 0xFFE0EFF0 /* High 11 and 15:1 bits and last nibble of last byte for spr. */ #define OPCODE_MASK_H23S 0xFC1FC000 /* High 6, 20-16 and 15:1 bits and last @@ -139,9 +143,12 @@ struct op_code_struct {"cmp", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000001, OPCODE_MASK_H4, cmp, arithmetic_inst }, {"cmpu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000003, OPCODE_MASK_H4, cmpu, arithmetic_inst }, #else - {"cmp", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x48000000, OPCODE_MASK_H4, cmp, arithmetic_inst }, - {"cmpu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x48000020, OPCODE_MASK_H4, cmpu, arithmetic_inst }, + {"cmp", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x48000000, OPCODE_MASK_H4S, cmp, arithmetic_inst }, + {"cmpu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x48000020, OPCODE_MASK_H4S, cmpu, arithmetic_inst }, {"cmpi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x68000000, OPCODE_MASK_H, cmpi, arithmetic_inst }, + {"it", INST_TYPE_COND, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x00000008, OPCODE_MASK_H123A, it, pseudo_inst }, + {"itt", INST_TYPE_COND, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x00000010, OPCODE_MASK_H123A, itt, pseudo_inst }, + {"ite", INST_TYPE_COND, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x00000018, OPCODE_MASK_H123A, ite, pseudo_inst }, #endif {"addkc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x18000000, OPCODE_MASK_H4, addkc, arithmetic_inst }, {"rsubkc",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x1C000000, OPCODE_MASK_H4, rsubkc, arithmetic_inst }, diff --git a/opcodes/microblaze-opcm.h b/opcodes/microblaze-opcm.h index 7d4f46330..04688595e 100644 --- a/opcodes/microblaze-opcm.h +++ b/opcodes/microblaze-opcm.h @@ -31,10 +31,11 @@ enum microblaze_instr addi, rsubi, addic, rsubic, addik, rsubik, addikc, rsubikc, mul, muli, bsll, bsra, bsrl, bslli, bsrai, bsrli, or, and, xor, andn, sra, src, srl, sext8, sext16, mts, mfs, br, brd, brl, - bra, bral, beq, bne, bned, blt, ble, bgt, bge, ori, andi, xori, andni, + bra, bral, beq, bne, blt, ble, bgt, bge, ori, andi, xori, andni, imm, rts, rti, bri, brli, brai, brali, beqi, bnei, blti, blei, bgti, bgei, lbu, lhu, lw, lwx, sb, sh, sw, swx, lbui, lhui, lwi, - sbi, shi, swi, halt, invalid_inst + sbi, shi, swi, halt, it, itt, ite, + invalid_inst }; #else @@ -82,9 +83,10 @@ enum microblaze_instr_type return_inst, immediate_inst, special_inst, memory_load_inst, memory_store_inst, barrel_shift_inst, #ifndef ARCH_mbtumbl - anyware_inst, + anyware_inst, #else - halt_inst + halt_inst, + pseudo_inst #endif }; @@ -139,6 +141,29 @@ enum microblaze_instr_type #define REG_TLBHI 36868 /* MMU: TLB High reg. */ #define REG_TLBSX 36869 /* MMU: TLB Search Index reg. */ +#else + +/* Tumbl conditions for it, itt, ite */ + +#define COND_ALL 0 +#define COND_EQ 1 +#define COND_NE 2 +#define COND_LT 3 +#define COND_LE 4 +#define COND_GT 5 +#define COND_GE 6 + +#define COND_LOW 0 +#define COND_MASK 0x7 + +#define COND_TYPE_MASK 0x18 +#define COND_TYPE_LOW 3 + +#define COND_TYPE_ALL 0 +#define COND_TYPE_IT 1 +#define COND_TYPE_ITT 2 +#define COND_TYPE_ITE 3 + #endif /* Alternate names for gen purpose regs. */ -- 2.39.2