void md_assemble (char *str) { xc16x_insn insn; char *errmsg; /* Initialize GAS's cgen interface for a new instruction. */ gas_cgen_init_parse (); insn.insn = xc16x_cgen_assemble_insn (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg); if (!insn.insn) { as_bad ("%s", errmsg); return; } /* Doesn't really matter what we pass for RELAX_P here. */ gas_cgen_finish_insn (insn.insn, insn.buffer, CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL); }
void md_assemble (char *str) { frv_insn insn; char *errmsg; int packing_constraint; finished_insnS finished_insn; fragS *double_nop_frag = NULL; fragS *single_nop_frag = NULL; struct vliw_insn_list *vliw_insn_list_entry = NULL; /* Initialize GAS's cgen interface for a new instruction. */ gas_cgen_init_parse (); memset (&insn, 0, sizeof (insn)); insn.insn = frv_cgen_assemble_insn (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, &errmsg); if (!insn.insn) { as_bad ("%s", errmsg); return; } /* If the cpu is tomcat, then we need to insert nops to workaround hardware limitations. We need to keep track of each vliw unit and examine the length of the unit and the individual insns within the unit to determine the number and location of the required nops. */ if (frv_mach == bfd_mach_frvtomcat) { /* If we've just finished a VLIW insn OR this is a branch, then start up a new frag. Fill it with nops. We will get rid of those that are not required after we've seen all of the instructions but before we start resolving fixups. */ if ( !FRV_IS_NOP (insn) && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack)) { char *buffer; frag_wane (frag_now); frag_new (0); double_nop_frag = frag_now; buffer = frag_var (rs_machine_dependent, 8, 8, NOP_DELETE, NULL, 0, 0); md_number_to_chars (buffer, FRV_NOP_PACK, 4); md_number_to_chars (buffer+4, FRV_NOP_NOPACK, 4); frag_wane (frag_now); frag_new (0); single_nop_frag = frag_now; buffer = frag_var (rs_machine_dependent, 4, 4, NOP_DELETE, NULL, 0, 0); md_number_to_chars (buffer, FRV_NOP_NOPACK, 4); } vliw_insn_list_entry = frv_insert_vliw_insn (DO_COUNT); vliw_insn_list_entry->insn = insn.insn; if (frv_is_branch_insn (insn.insn)) vliw_insn_list_entry->type = VLIW_BRANCH_TYPE; if ( !FRV_IS_NOP (insn) && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack)) { vliw_insn_list_entry->snop_frag = single_nop_frag; vliw_insn_list_entry->dnop_frag = double_nop_frag; } } /* Make sure that this insn does not violate the VLIW packing constraints. */ /* -mno-pack disallows any packing whatsoever. */ if (frv_flags & EF_FRV_NOPACK) { if (! insn.fields.f_pack) { as_bad (_("VLIW packing used for -mno-pack")); return; } } /* -mcpu=FRV is an idealized FR-V implementation that supports all of the instructions, don't do vliw checking. */ else if (frv_mach != bfd_mach_frv) { if (!target_implements_insn_p (insn.insn)) { as_bad (_("Instruction not supported by this architecture")); return; } packing_constraint = frv_vliw_add_insn (& vliw, insn.insn); if (frv_mach == bfd_mach_fr550 && ! packing_constraint) packing_constraint = fr550_check_acc_range (& vliw, & insn); if (insn.fields.f_pack) frv_vliw_reset (& vliw, frv_mach, frv_flags); if (packing_constraint) { as_bad (_("VLIW packing constraint violation")); return; } } /* Doesn't really matter what we pass for RELAX_P here. */ gas_cgen_finish_insn (insn.insn, insn.buffer, CGEN_FIELDS_BITSIZE (& insn.fields), 1, &finished_insn); /* If the cpu is tomcat, then we need to insert nops to workaround hardware limitations. We need to keep track of each vliw unit and examine the length of the unit and the individual insns within the unit to determine the number and location of the required nops. */ if (frv_mach == bfd_mach_frvtomcat) { if (vliw_insn_list_entry) vliw_insn_list_entry->address = finished_insn.addr; else abort(); if (insn.fields.f_pack) { /* We've completed a VLIW insn. */ previous_vliw_chain = current_vliw_chain; current_vliw_chain = NULL; current_vliw_insn = NULL; } } }
void md_assemble (char * str) { static long delayed_load_register = 0; static long prev_delayed_load_register = 0; static int last_insn_had_delay_slot = 0; static int last_insn_in_noncond_delay_slot = 0; static int last_insn_has_load_delay = 0; static int last_insn_was_memory_access = 0; static int last_insn_was_io_insn = 0; static int last_insn_was_arithmetic_or_logic = 0; static int last_insn_was_branch_insn = 0; static int last_insn_was_conditional_branch_insn = 0; mt_insn insn; char * errmsg; /* Initialize GAS's cgen interface for a new instruction. */ gas_cgen_init_parse (); insn.insn = mt_cgen_assemble_insn (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg); if (!insn.insn) { as_bad ("%s", errmsg); return; } /* Doesn't really matter what we pass for RELAX_P here. */ gas_cgen_finish_insn (insn.insn, insn.buffer, CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL); /* Handle Scheduling Restrictions. */ if (!no_scheduling_restrictions) { /* Detect consecutive Memory Accesses. */ if (last_insn_was_memory_access && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS) && mt_mach == ms1_64_001) as_warn (_("instruction %s may not follow another memory access instruction."), CGEN_INSN_NAME (insn.insn)); /* Detect consecutive I/O Instructions. */ else if (last_insn_was_io_insn && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN)) as_warn (_("instruction %s may not follow another I/O instruction."), CGEN_INSN_NAME (insn.insn)); /* Detect consecutive branch instructions. */ else if (last_insn_was_branch_insn && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN)) as_warn (_("%s may not occupy the delay slot of another branch insn."), CGEN_INSN_NAME (insn.insn)); /* Detect data dependencies on delayed loads: memory and input insns. */ if (last_insn_has_load_delay && delayed_load_register) { if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1) && insn.fields.f_sr1 == delayed_load_register) as_warn (_("operand references R%ld of previous load."), insn.fields.f_sr1); if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2) && insn.fields.f_sr2 == delayed_load_register) as_warn (_("operand references R%ld of previous load."), insn.fields.f_sr2); } /* Detect JAL/RETI hazard */ if (mt_mach == ms2 && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_JAL_HAZARD)) { if ((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1) && insn.fields.f_sr1 == delayed_load_register) || (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2) && insn.fields.f_sr2 == delayed_load_register)) as_warn (_("operand references R%ld of previous instruction."), delayed_load_register); else if ((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1) && insn.fields.f_sr1 == prev_delayed_load_register) || (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2) && insn.fields.f_sr2 == prev_delayed_load_register)) as_warn (_("operand references R%ld of instruction before previous."), prev_delayed_load_register); } /* Detect data dependency between conditional branch instruction and an immediately preceding arithmetic or logical instruction. */ if (last_insn_was_arithmetic_or_logic && !last_insn_in_noncond_delay_slot && (delayed_load_register != 0) && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN) && mt_arch == ms1_64_001) { if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1) && insn.fields.f_sr1 == delayed_load_register) as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."), insn.fields.f_sr1); if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2) && insn.fields.f_sr2 == delayed_load_register) as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."), insn.fields.f_sr2); } } /* Keep track of details of this insn for processing next insn. */ last_insn_in_noncond_delay_slot = last_insn_was_branch_insn && !last_insn_was_conditional_branch_insn; last_insn_had_delay_slot = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT); (void) last_insn_had_delay_slot; last_insn_has_load_delay = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_LOAD_DELAY); last_insn_was_memory_access = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS); last_insn_was_io_insn = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN); last_insn_was_arithmetic_or_logic = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_AL_INSN); last_insn_was_branch_insn = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN); last_insn_was_conditional_branch_insn = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN) && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2); prev_delayed_load_register = delayed_load_register; if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDR)) delayed_load_register = insn.fields.f_dr; else if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDRRR)) delayed_load_register = insn.fields.f_drrr; else /* Insns has no destination register. */ delayed_load_register = 0; /* Generate dwarf2 line numbers. */ dwarf2_emit_insn (4); }