/* SPIM S20 MIPS simulator. Parser for instructions and assembler directives. Copyright (C) 1990 by James Larus (larus@cs.wisc.edu). SAL assembler Copyright (C) 1992 by Scott Kempf (scottk@cs.wisc.edu). SPIM is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. SPIM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to James R. Larus, Computer Sciences Department, University of Wisconsin--Madison, 1210 West Dayton Street, Madison, WI 53706, USA or to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* $Header: /home/aa/projects/spim/public_html/cvsroot/spimsal/parser.y,v 1.3 2001/06/04 22:24:10 spim Exp $ */ %start LINE %token Y_EOF 0 %token Y_NL %token Y_INT %token Y_ID %token Y_REG %token Y_FP_REG %token Y_STR %token Y_FP /* MIPS instructions op codes: */ %token Y_ABS_D_OP %token Y_ABS_S_OP %token Y_ADDIU_OP %token Y_ADDI_OP %token Y_ADDU_OP %token Y_ADD_D_OP %token Y_ADD_OP %token Y_ADD_S_OP %token Y_ANDI_OP %token Y_AND_OP %token Y_BC0F_OP %token Y_BC0T_OP %token Y_BC1F_OP %token Y_BC1T_OP %token Y_BC2F_OP %token Y_BC2T_OP %token Y_BC3F_OP %token Y_BC3T_OP %token Y_BEQ_OP %token Y_BGEZAL_OP %token Y_BGEZ_OP %token Y_BGTZ_OP %token Y_BLEZ_OP %token Y_BLTZAL_OP %token Y_BLTZ_OP %token Y_BNE_OP %token Y_BREAK_OP %token Y_CALL_POP %token Y_CFC0_OP %token Y_CFC1_OP %token Y_CFC2_OP %token Y_CFC3_OP %token Y_COP0_OP %token Y_COP1_OP %token Y_COP2_OP %token Y_COP3_OP %token Y_CTC0_OP %token Y_CTC1_OP %token Y_CTC2_OP %token Y_CTC3_OP %token Y_CVT_POP %token Y_CVT_D_S_OP %token Y_CVT_D_W_OP %token Y_CVT_S_D_OP %token Y_CVT_S_W_OP %token Y_CVT_W_D_OP %token Y_CVT_W_S_OP %token Y_C_EQ_D_OP %token Y_C_EQ_S_OP %token Y_C_F_D_OP %token Y_C_F_S_OP %token Y_C_LE_D_OP %token Y_C_LE_S_OP %token Y_C_LT_D_OP %token Y_C_LT_S_OP %token Y_C_NGE_D_OP %token Y_C_NGE_S_OP %token Y_C_NGLE_D_OP %token Y_C_NGLE_S_OP %token Y_C_NGL_D_OP %token Y_C_NGL_S_OP %token Y_C_NGT_D_OP %token Y_C_NGT_S_OP %token Y_C_OLE_D_OP %token Y_C_OLE_S_OP %token Y_C_SEQ_D_OP %token Y_C_SEQ_S_OP %token Y_C_SF_D_OP %token Y_C_SF_S_OP %token Y_C_UEQ_D_OP %token Y_C_UEQ_S_OP %token Y_C_ULE_D_OP %token Y_C_ULE_S_OP %token Y_C_UN_D_OP %token Y_C_UN_S_OP %token Y_DIVU_OP %token Y_DIV_D_OP %token Y_DIV_OP %token Y_DIV_S_OP %token Y_DONE_POP %token Y_GET_POP %token Y_GETC_POP %token Y_GETI_POP %token Y_GIFEQ_POP %token Y_GIFNE_POP %token Y_GIFGT_POP %token Y_GIFGE_POP %token Y_GIFLT_POP %token Y_GIFLE_POP %token Y_GOTO_POP %token Y_JALR_OP %token Y_JAL_OP %token Y_JR_OP %token Y_J_OP %token Y_LBU_OP %token Y_LB_OP %token Y_LHU_OP %token Y_LH_OP %token Y_LUI_OP %token Y_LWC0_OP %token Y_LWC1_OP %token Y_LWC2_OP %token Y_LWC3_OP %token Y_LWL_OP %token Y_LWR_OP %token Y_LW_OP %token Y_MFC0_OP %token Y_MFC1_OP %token Y_MFC2_OP %token Y_MFC3_OP %token Y_MFHI_OP %token Y_MFLO_OP %token Y_MOV_D_OP %token Y_MOV_S_OP %token Y_MTC0_OP %token Y_MTC1_OP %token Y_MTC2_OP %token Y_MTC3_OP %token Y_MTHI_OP %token Y_MTLO_OP %token Y_MULTU_OP %token Y_MULT_OP %token Y_MUL_D_OP %token Y_MUL_S_OP %token Y_NEG_D_OP %token Y_NEG_S_OP %token Y_NOR_OP %token Y_ORI_OP %token Y_OR_OP %token Y_RFE_OP %token Y_SB_OP %token Y_SH_OP %token Y_SLLV_OP %token Y_SLL_OP %token Y_SLTIU_OP %token Y_SLTI_OP %token Y_SLTU_OP %token Y_SLT_OP %token Y_SRAV_OP %token Y_SRA_OP %token Y_SRLV_OP %token Y_SRL_OP %token Y_SUBU_OP %token Y_SUB_D_OP %token Y_SUB_OP %token Y_SUB_S_OP %token Y_SWC0_OP %token Y_SWC1_OP %token Y_SWC2_OP %token Y_SWC3_OP %token Y_SWL_OP %token Y_SWR_OP %token Y_SW_OP %token Y_SYSCALL_OP %token Y_TLBP_OP %token Y_TLBR_OP %token Y_TLBWI_OP %token Y_TLBWR_OP %token Y_XORI_OP %token Y_XOR_OP /* Assembler pseudo operations op codes: */ %token Y_ABS_POP %token Y_BAL_POP %token Y_BEQZ_POP %token Y_BGEU_POP %token Y_BGE_POP %token Y_BGTU_POP %token Y_BGT_POP %token Y_BLEU_POP %token Y_BLE_POP %token Y_BLTU_POP %token Y_BLT_POP %token Y_BNEZ_POP %token Y_B_POP %token Y_LA_POP %token Y_LD_POP %token Y_LP_POP %token Y_LI_POP %token Y_LI_D_POP %token Y_LI_S_POP %token Y_L_D_POP %token Y_L_S_POP %token Y_MFC1_D_POP %token Y_MTC1_D_POP %token Y_MOVE_POP %token Y_MULOU_POP %token Y_MULO_POP %token Y_MUL_POP %token Y_NEGU_POP %token Y_NEG_POP %token Y_NOP_POP %token Y_NOT_POP %token Y_PUT_POP %token Y_PUTC_POP %token Y_PUTI_POP %token Y_PUTS_POP %token Y_REMU_POP %token Y_RETURN_POP %token Y_REM_POP %token Y_ROL_POP %token Y_ROR_POP %token Y_SD_POP %token Y_SEQ_POP %token Y_SGEU_POP %token Y_SGE_POP %token Y_SGTU_POP %token Y_SGT_POP %token Y_SLEU_POP %token Y_SLE_POP %token Y_SNE_POP %token Y_S_D_POP %token Y_S_S_POP %token Y_ULHU_POP %token Y_ULH_POP %token Y_ULW_POP %token Y_USH_POP %token Y_USW_POP /* Assembler directives: */ %token Y_ALIAS_DIR %token Y_ALIGN_DIR %token Y_ASCII_DIR %token Y_ASCIIZ_DIR %token Y_ASM0_DIR %token Y_BGNB_DIR %token Y_BYTE_DIR %token Y_COMM_DIR %token Y_DATA_DIR %token Y_DOUBLE_DIR %token Y_ENDB_DIR %token Y_ENDR_DIR %token Y_END_DIR %token Y_ENT_DIR %token Y_EQ_DIR %token Y_ERR_DIR %token Y_EXTERN_DIR %token Y_FILE_DIR %token Y_FLOAT_DIR %token Y_FMASK_DIR %token Y_FRAME_DIR %token Y_GLOBAL_DIR %token Y_HALF_DIR %token Y_K_TEXT_DIR %token Y_K_DATA_DIR %token Y_LABEL_DIR %token Y_LCOMM_DIR %token Y_LIVEREG_DIR %token Y_LOC_DIR %token Y_MASK_DIR %token Y_NOALIAS_DIR %token Y_OPTIONS_DIR %token Y_RDATA_DIR %token Y_REPEAT_DIR %token Y_SDATA_DIR %token Y_SET_DIR %token Y_SPACE_DIR %token Y_STRUCT_DIR %token Y_TEXT_DIR %token Y_VERSTAMP_DIR %token Y_VREG_DIR %token Y_WORD_DIR %{ #include #include "endian.h" #include "spim.h" #include "inst.h" #include "data.h" #include "mem.h" #include "reg.h" #include "sym_tbl.h" typedef struct ll { label *head; struct ll *tail; } label_list; /* NOTE: defines for *_RMUM should not be changes lightly. */ /* These must match with the registers used by SYSCALL and */ /* The destination must match src2 so that move works. -SK */ #define A_SRC1_RNUM 4 #define A_SRC2_RNUM 2 #define A_DEST_RNUM 2 #define A_SUB_RNUM 3 #define A_DSUB_RNUM 5 #define AF_SRC1_RNUM 12 #define AF_SRC2_RNUM 0 #define AF_DEST_RNUM 0 /* Local functions: */ static void clear_labels(); static label_list * cons_label (label *head, label_list *tail); static void div_inst (int, int, int, int, int); static void mult_inst (int, int, int, int); static void nop_inst (void); static void set_eq_inst (int, int, int, int); static void set_ge_inst (int, int, int, int); static void set_gt_inst (int, int, int, int); static void set_le_inst (int, int, int, int); static void store_word_data (int); static void trap_inst (void); void Store(char *xlabel, int reg); int op_to_float_op(int); int op_to_double_op(int); int BadTypes(int, int, int); char *input_file_name; extern int y_str_length; static int null_term; /* Non-zero means string terminate by \0 */ static void (*store_op) (); /* Function to store items in an EXPR_LST */ int data_dir = 0; /* Non-zero means item in data segment */ int text_dir = 1; /* Non-zero means item in text segment */ static label_list *this_line_labels = NULL; /* List of label for curent line */ extern int in_kernel; /* Non-zero means kernel segment */ static label *abstract_line_label; /* Label for curent line or NULL */ static int noat_flag = 0; /* Non-zero means program can use $1 */ %} /* Define types for parser. */ %union { int ival; char *cptr; addr_expr *aeptr; imm_expr *ieptr; double *dptr; } %type Y_ID A_DEST Y_STR OPT_ID %type LOAD_OP REGISTER SOURCE REG SRC1 SRC2 DEST_REG ABS_ADDR %type ABS_ADDR COP_REG LOAD_COP LOAD_IMM_OP OPT_DSUB %type F_DEST ULOADH_POP STORE_OP FP_REGISTER F_SRC1 F_SRC2 F_DEST %type DIV_POP UNARY_BR_POP A_SRC1 A_SRC2 LOADF_OP STORE_COP STOREF_OP %type SYS_OP BINARY_OP_I BINARY_OPR_I BINARY_IMM_OP SHIFT_OP %type DIV_POP BINARY_OP_NOI MUL_POP SET_LE_POP SET_GT_POP SET_EQ_POP %type MULT_OP NULLARY_BR_OP UNARY_BR_OP UNARY_BR_POP BINARY_BR_OP %type BR_GT_POP BR_GE_POP BR_LT_POP BR_LE_POP J_OPS B_OP MOVE_COP_OP %type MOV_FROM_HILO_OP MOV_TO_HILO_OP MOV_COP_OP CTL_COP_OP FP_ABS_OP %type FP_BINARY_OP FP_CONVERT_OP FP_NEG_OP FP_CMP_OP EXPR Y_BREAK_OP %type SET_GE_POP DEST OPT_SUB ASM_DIRECTIVE %type ADDRESS %type IMM LABEL %type Y_FP %% LINE : {scanner_start_line ();} OPT_LBL CMD Y_NL; OPT_LBL : Y_ID ':' { label *tmp; abstract_line_label = tmp = record_label ($1, (text_dir ? current_text_pc () : current_data_pc ())); this_line_labels = cons_label(tmp, this_line_labels); } | { abstract_line_label = NULL; } ; CMD : ASM_CODE Y_NL { clear_labels (); return (1); } | ASM_DIRECTIVE Y_NL { clear_labels (); return (1); } | Y_NL { return (1); } | Y_EOF { clear_labels (); return (0); } ; ASM_CODE: LOAD_OP DEST_REG ADDRESS { i_type_inst ($1 == Y_LD_POP ? Y_LW_OP : $1, $2, addr_expr_reg ($3), addr_expr_imm ($3)); if ($1 == Y_LD_POP) { i_type_inst (Y_LW_OP, $2 + 1, addr_expr_reg($3), incr_expr_offset(addr_expr_imm($3), 4)); } free ($3); } | LOAD_COP COP_REG ADDRESS { i_type_inst ($1, $2, addr_expr_reg ($3), addr_expr_imm ($3)); free ($3); } | LOAD_IMM_OP DEST_REG IMM { i_type_inst ($1, $2, 0, $3); } | Y_LA_POP DEST_REG ADDRESS { if (addr_expr_reg ($3)) i_type_inst (Y_ADDI_OP, $2, addr_expr_reg($3), addr_expr_imm ($3)); else i_type_inst (Y_LUI_OP, $2, 0, addr_expr_imm ($3)); free ($3); } | Y_LP_POP A_DEST OPT_DSUB Y_ID { i_type_inst (Y_ADDI_OP, A_DEST_RNUM, 0, addr_expr_imm(make_addr_expr(0, $4, 0))); Store($2, $3); } | Y_LA_POP A_DEST OPT_DSUB Y_ID { i_type_inst (Y_ADDI_OP, A_DEST_RNUM, 0, addr_expr_imm(make_addr_expr(0, $4, 0))); Store($2, $3); } | Y_LI_POP DEST_REG IMM { i_type_inst (Y_ORI_OP, $2, 0, $3); } | Y_LI_D_POP F_DEST Y_FP { int *x = (int *) $3; i_type_inst (Y_ORI_OP, 1, 0, const_imm_expr (*x)); r_type_inst (Y_MTC1_OP, $2, 0, 1); i_type_inst (Y_ORI_OP, 1, 0, const_imm_expr (*(x+1))); r_type_inst (Y_MTC1_OP, $2 + 1, 0, 1); } | Y_LI_S_POP F_DEST Y_FP { float x = *$3; int *y = (int *) &x; i_type_inst (Y_ORI_OP, 1, 0, const_imm_expr (*y)); r_type_inst (Y_MTC1_OP, $2, 0, 1); } | Y_ULW_POP DEST_REG ADDRESS { if (IS_BIG_ENDIAN) { i_type_inst (Y_LWL_OP, $2, addr_expr_reg ($3), addr_expr_imm ($3)); i_type_inst (Y_LWR_OP, $2, addr_expr_reg ($3), incr_expr_offset (addr_expr_imm ($3), 3)); } else { i_type_inst (Y_LWL_OP, $2, addr_expr_reg ($3), incr_expr_offset (addr_expr_imm ($3), 3)); i_type_inst (Y_LWR_OP, $2, addr_expr_reg ($3), addr_expr_imm ($3)); } free ($3); } | ULOADH_POP DEST_REG ADDRESS { if (IS_BIG_ENDIAN) { i_type_inst (($1 == Y_ULH_POP ? Y_LB_OP : Y_LBU_OP), $2, addr_expr_reg ($3), addr_expr_imm ($3)); i_type_inst (Y_LBU_OP, 1, addr_expr_reg ($3), incr_expr_offset (addr_expr_imm ($3), 1)); } else { i_type_inst (($1 == Y_ULH_POP ? Y_LB_OP : Y_LBU_OP), $2, addr_expr_reg ($3), incr_expr_offset (addr_expr_imm ($3), 1)); i_type_inst (Y_LBU_OP, 1, addr_expr_reg ($3), addr_expr_imm ($3)); } r_sh_type_inst (Y_SLL_OP, $2, $2, 8); r_type_inst (Y_OR_OP, $2, $2, 1); free ($3); } | LOADF_OP F_DEST ADDRESS { i_type_inst (Y_LWC1_OP, $2, addr_expr_reg ($3), addr_expr_imm ($3)); if ($1 == Y_L_D_POP) { i_type_inst (Y_LWC1_OP, $2 + 1, addr_expr_reg ($3), incr_expr_offset (addr_expr_imm ($3), 4)); } free ($3); } | STORE_OP SOURCE ADDRESS { i_type_inst ($1 == Y_SD_POP ? Y_SW_OP : $1, $2, addr_expr_reg ($3), addr_expr_imm ($3)); if ($1 == Y_SD_POP) { i_type_inst (Y_SW_OP, $2 + 1, addr_expr_reg ($3), incr_expr_offset (addr_expr_imm ($3), 4)); } free ($3); } | STORE_COP COP_REG ADDRESS { i_type_inst ($1, $2, addr_expr_reg ($3), addr_expr_imm ($3)); free ($3); } | Y_USW_POP SOURCE ADDRESS { if (IS_BIG_ENDIAN) { i_type_inst (Y_SWL_OP, $2, addr_expr_reg ($3), addr_expr_imm ($3)); i_type_inst (Y_SWR_OP, $2, addr_expr_reg ($3), incr_expr_offset (addr_expr_imm ($3), 3)); } else { i_type_inst (Y_SWL_OP, $2, addr_expr_reg ($3), incr_expr_offset (addr_expr_imm ($3), 3)); i_type_inst (Y_SWR_OP, $2, addr_expr_reg ($3), addr_expr_imm ($3)); } free ($3); } | Y_USH_POP SOURCE ADDRESS { i_type_inst (Y_SB_OP, $2, addr_expr_reg ($3), addr_expr_imm ($3)); r_sh_type_inst (Y_SRL_OP, 1, $2, 8); i_type_inst (Y_SB_OP, 1, addr_expr_reg ($3), incr_expr_offset (addr_expr_imm ($3), 1)); free ($3); } | STOREF_OP F_SRC1 ADDRESS { i_type_inst (Y_SWC1_OP, $2, addr_expr_reg ($3), addr_expr_imm ($3)); if ($1 == Y_S_D_POP) { i_type_inst (Y_SWC1_OP, $2 + 1, addr_expr_reg ($3), incr_expr_offset (addr_expr_imm ($3), 4)); } free ($3); } | SYS_OP { r_type_inst ($1, 0, 0, 0); } | Y_BREAK_OP Y_INT { if ($2 == 1) yyerror ("Breakpoint 1 is reserved for debugger\n"); r_type_inst ($1, $2, 0, 0); } | Y_NOP_POP { nop_inst (); } | Y_ABS_POP DEST_REG SRC1 { if ($2 != $3) r_type_inst (Y_ADDU_OP, $2, 0, $3); i_type_inst (Y_BGEZ_OP, 0, $3, branch_offset (2)); r_type_inst (Y_SUB_OP, $2, 0, $3); } | Y_NEG_POP DEST_REG SRC1 { r_type_inst (Y_SUB_OP, $2, 0, $3); } | Y_NEGU_POP DEST_REG SRC1 { r_type_inst (Y_SUBU_OP, $2, 0, $3); } | Y_NOT_POP DEST_REG SRC1 { r_type_inst (Y_NOR_OP, $2, $3, 0); } | Y_MOVE_POP DEST_REG SRC1 { r_type_inst (Y_ADDU_OP, $2, 0, $3); } | BINARY_OP_I DEST_REG SRC1 SRC2 { r_type_inst ($1, $2, $3, $4); } | BINARY_OP_I DEST_REG SRC1 IMM { i_type_inst (op_to_imm_op ($1), $2, $3, $4); } | BINARY_OP_I DEST_REG IMM { i_type_inst (op_to_imm_op ($1), $2, $2, $3); } | BINARY_OPR_I DEST_REG SRC1 SRC2 { r_type_inst ($1, $2, $4, $3); } | BINARY_OPR_I DEST_REG SRC1 Y_INT { r_sh_type_inst (op_to_imm_op($1), $2, $3, $4); } | BINARY_OPR_I DEST_REG Y_INT { r_sh_type_inst (op_to_imm_op($1), $2, $2, $3); } | BINARY_IMM_OP DEST_REG SRC1 IMM { i_type_inst ($1, $2, $3, $4); } | BINARY_IMM_OP DEST_REG IMM { i_type_inst ($1, $2, $2, $3); } | SHIFT_OP DEST_REG SRC1 Y_INT { r_sh_type_inst ($1, $2, $3, $4); } | SHIFT_OP DEST_REG SRC1 SRC2 { r_type_inst (imm_op_to_op($1), $2, $4, $3); } | BINARY_OP_NOI DEST_REG SRC1 SRC2 { r_type_inst ($1, $2, $3, $4); } | BINARY_OP_NOI DEST_REG SRC1 IMM { if (bare_machine) yyerror ("Immediate form not allowed in bare machine"); else { if (!zero_imm ($4)) i_type_inst (Y_ORI_OP, 1, 0, $4); /* Use $at */ r_type_inst ($1, $2, $3, (zero_imm ($4) ? 0 : 1)); } } | BINARY_OP_NOI DEST_REG IMM { if (bare_machine) yyerror ("Immediate form not allowed in bare machine"); else { if (!zero_imm ($3)) i_type_inst (Y_ORI_OP, 1, 0, $3); /* Use $at */ r_type_inst ($1, $2, $2, (zero_imm ($3) ? 0 : 1)); } } | DIV_POP DEST_REG SRC1 { /* The hardware divide operation (ignore 1st arg) */ if ($1 != Y_DIV_OP && $1 != Y_DIVU_OP) yyerror ("Syntax error"); r_type_inst ($1, 0, $2, $3); } | DIV_POP DEST_REG SRC1 SRC2 { /* Pseudo divide operations */ div_inst ($1, $2, $3, $4, 0); } | DIV_POP DEST_REG SRC1 IMM { if (zero_imm ($4)) yyerror ("Divide by zero"); else { i_type_inst (Y_ORI_OP, 1, 0, $4); /* Use $at */ div_inst ($1, $2, $3, 1, 1); } } | MUL_POP DEST_REG SRC1 SRC2 { mult_inst ($1, $2, $3, $4); } | MUL_POP DEST_REG SRC1 IMM { if (zero_imm ($4)) r_type_inst (Y_ORI_OP, $2, 0, 0); else { i_type_inst (Y_ORI_OP, 1, 0, $4); /* Use $at */ mult_inst ($1, $2, $3, 1); } } | MULT_OP SRC1 SRC2 { r_type_inst ($1, 0, $2, $3); } | Y_ROR_POP DEST_REG SRC1 SRC2 { r_type_inst (Y_SUBU_OP, 1, 0, $4); r_type_inst (Y_SLLV_OP, 1, 1, $3); r_type_inst (Y_SRLV_OP, $2, $4, $3); r_type_inst (Y_OR_OP, $2, $2, 1); } | Y_ROL_POP DEST_REG SRC1 SRC2 { r_type_inst (Y_SUBU_OP, 1, 0, $4); r_type_inst (Y_SRLV_OP, 1, 1, $3); r_type_inst (Y_SLLV_OP, $2, $4, $3); r_type_inst (Y_OR_OP, $2, $2, 1); } | Y_ROR_POP DEST_REG SRC1 IMM { long dist = eval_imm_expr ($4); r_sh_type_inst (Y_SLL_OP, 1, $3, -dist); r_sh_type_inst (Y_SRL_OP, $2, $3, dist); r_type_inst (Y_OR_OP, $2, $2, 1); } | Y_ROL_POP DEST_REG SRC1 IMM { long dist = eval_imm_expr ($4); r_sh_type_inst (Y_SRL_OP, 1, $3, -dist); r_sh_type_inst (Y_SLL_OP, $2, $3, dist); r_type_inst (Y_OR_OP, $2, $2, 1); } | SET_LE_POP DEST_REG SRC1 SRC2 { set_le_inst ($1, $2, $3, $4); } | SET_LE_POP DEST_REG SRC1 IMM { if (!zero_imm ($4)) i_type_inst (Y_ORI_OP, 1, 0, $4); /* Use $at */ set_le_inst ($1, $2, $3, (zero_imm ($4) ? 0 : 1)); } | SET_GT_POP DEST_REG SRC1 SRC2 { set_gt_inst ($1, $2, $3, $4); } | SET_GT_POP DEST_REG SRC1 IMM { if (!zero_imm ($4)) i_type_inst (Y_ORI_OP, 1, 0, $4); /* Use $at */ set_gt_inst ($1, $2, $3, (zero_imm ($4) ? 0 : 1)); } | SET_GE_POP DEST_REG SRC1 SRC2 { set_ge_inst ($1, $2, $3, $4); } | SET_GE_POP DEST_REG SRC1 IMM { if (!zero_imm ($4)) i_type_inst (Y_ORI_OP, 1, 0, $4); /* Use $at */ set_ge_inst ($1, $2, $3, (zero_imm ($4) ? 0 : 1)); } | SET_EQ_POP DEST_REG SRC1 SRC2 { set_eq_inst ($1, $2, $3, $4); } | SET_EQ_POP DEST_REG SRC1 IMM { if (!zero_imm ($4)) i_type_inst (Y_ORI_OP, 1, 0, $4); /* Use $at */ set_eq_inst ($1, $2, $3, (zero_imm ($4) ? 0 : 1)); } | NULLARY_BR_OP LABEL { i_type_inst ($1, 0, 0, $2); } | UNARY_BR_OP SRC1 LABEL { i_type_inst ($1, 0, $2, $3); } | UNARY_BR_POP SRC1 LABEL { i_type_inst ($1 == Y_BEQZ_POP ? Y_BEQ_OP : Y_BNE_OP, 0, $2, $3); } | BINARY_BR_OP SRC1 SRC2 LABEL { i_type_inst ($1, $3, $2, $4); } | BINARY_BR_OP SRC1 IMM LABEL { if (bare_machine) yyerror ("Immediate form not allowed on bare machine"); else { if (zero_imm ($3)) i_type_inst ($1, $2, (zero_imm ($3) ? 0 : 1), $4); else { i_type_inst (Y_ORI_OP, 1, 0, $3); /* Use $at */ i_type_inst ($1, $2, (zero_imm ($3) ? 0 : 1), $4); } } } | BR_GT_POP SRC1 SRC2 LABEL { r_type_inst ($1 == Y_BGT_POP ? Y_SLT_OP : Y_SLTU_OP, 1, $3, $2); /* Use $at */ i_type_inst (Y_BNE_OP, 0, 1, $4); } | BR_GT_POP SRC1 IMM LABEL { if ($1 == Y_BGT_POP) { /* Use $at */ i_type_inst (Y_SLTI_OP, 1, $2, incr_expr_offset ($3, 1)); i_type_inst (Y_BEQ_OP, 0, 1, $4); } else { /* Use $at */ /* Can't add 1 to immediate since 0xffffffff+1 = 0 < 1 */ i_type_inst (Y_ORI_OP, 1, 0, $3); i_type_inst (Y_BEQ_OP, $2, 1, branch_offset (3)); r_type_inst (Y_SLTU_OP, 1, $2, 1); i_type_inst (Y_BEQ_OP, 0, 1, $4); } } | BR_GE_POP SRC1 SRC2 LABEL { r_type_inst ($1 == Y_BGE_POP ? Y_SLT_OP : Y_SLTU_OP, 1, $2, $3); /* Use $at */ i_type_inst (Y_BEQ_OP, 0, 1, $4); } | BR_GE_POP SRC1 IMM LABEL { i_type_inst ($1 == Y_BGE_POP ? Y_SLTI_OP : Y_SLTIU_OP, 1, $2, $3); /* Use $at */ i_type_inst (Y_BEQ_OP, 0, 1, $4); } | BR_LT_POP SRC1 SRC2 LABEL { r_type_inst ($1 == Y_BLT_POP ? Y_SLT_OP : Y_SLTU_OP, 1, $2, $3); /* Use $at */ i_type_inst (Y_BNE_OP, 0, 1, $4); } | BR_LT_POP SRC1 IMM LABEL { i_type_inst ($1 == Y_BLT_POP ? Y_SLTI_OP : Y_SLTIU_OP, 1, $2, $3); /* Use $at */ i_type_inst (Y_BNE_OP, 0, 1, $4); } | BR_LE_POP SRC1 SRC2 LABEL { r_type_inst ($1 == Y_BLE_POP ? Y_SLT_OP : Y_SLTU_OP, 1, $3, $2); /* Use $at */ i_type_inst (Y_BEQ_OP, 0, 1, $4); } | BR_LE_POP SRC1 IMM LABEL { if ($1 == Y_BLE_POP) { /* Use $at */ i_type_inst (Y_SLTI_OP, 1, $2, incr_expr_offset ($3, 1)); i_type_inst (Y_BNE_OP, 0, 1, $4); } else { /* Use $at */ /* Can't add 1 to immediate since 0xffffffff+1 = 0 < 1 */ i_type_inst (Y_ORI_OP, 1, 0, $3); i_type_inst (Y_BEQ_OP, $2, 1, copy_imm_expr ($4)); r_type_inst (Y_SLTU_OP, 1, $2, 1); i_type_inst (Y_BNE_OP, 0, 1, $4); } } | J_OPS LABEL { if (($1 == Y_J_OP) || ($1 == Y_JR_OP)) j_type_inst (Y_J_OP, $2); else if (($1 == Y_JAL_OP) || ($1 == Y_JALR_OP)) j_type_inst (Y_JAL_OP, $2); } | J_OPS SRC1 { if (($1 == Y_J_OP) || ($1 == Y_JR_OP)) r_type_inst (Y_JR_OP, 0, $2, 0); else if (($1 == Y_JAL_OP) || ($1 == Y_JALR_OP)) r_type_inst (Y_JALR_OP, 31, $2, 0); } | J_OPS DEST SRC1 { if (($1 == Y_J_OP) || ($1 == Y_JR_OP)) r_type_inst (Y_JR_OP, 0, $3, 0); else if (($1 == Y_JAL_OP) || ($1 == Y_JALR_OP)) r_type_inst (Y_JALR_OP, $2, $3, 0); } | B_OP LABEL { i_type_inst (($1 == Y_BAL_POP ? Y_BGEZAL_OP : Y_BGEZ_OP), 0, 0, $2); } | MOVE_COP_OP COP_REG COP_REG { r_type_inst ($1, $2, $3, 0); } | MOV_FROM_HILO_OP REG { r_type_inst ($1, $2, 0, 0); } | MOV_TO_HILO_OP REG { r_type_inst ($1, 0, $2, 0); } | MOV_COP_OP REG COP_REG { if ($1 == Y_MFC1_D_POP) { r_type_inst (Y_MFC1_OP, $3, 0, $2); r_type_inst (Y_MFC1_OP, $3 + 1, 0, $2 + 1); } else if ($1 == Y_MTC1_D_POP) { r_type_inst (Y_MTC1_OP, $3, 0, $2); r_type_inst (Y_MTC1_OP, $3 + 1, 0, $2 + 1); } else r_type_inst ($1, $3, 0, $2); } | CTL_COP_OP COP_REG COP_REG { r_type_inst ($1, $3, 0, $2); } | FP_ABS_OP F_DEST F_SRC1 { r_type_inst ($1, $2, $3, 0); } | FP_BINARY_OP F_DEST F_SRC1 F_SRC2 { r_type_inst ($1, $2, $3, $4); } | FP_CONVERT_OP F_DEST F_SRC2 { r_type_inst ($1, $2, $3, 0); } | FP_NEG_OP F_DEST F_SRC2 { r_type_inst ($1, $2, $3, 0); } | FP_CMP_OP F_SRC1 F_SRC2 { r_cond_type_inst ($1, $2, $3); } | Y_ROR_POP A_DEST OPT_DSUB A_SRC1 A_SRC2 { if (((get_label_type($2) != WORD_A_TYPE) && (get_label_type($2) != BYTE_A_TYPE)) || (($4 != WORD_A_TYPE) && ($4 != BYTE_A_TYPE)) || (($5 != WORD_A_TYPE) && ($5 != BYTE_A_TYPE))) yyerror("ROR must use .byte or .word\n"); r_type_inst (Y_SUBU_OP, 1, 0, A_SRC2_RNUM); r_type_inst (Y_SLLV_OP, 1, 1, A_SRC1_RNUM); r_type_inst (Y_SRLV_OP, A_DEST_RNUM, A_SRC2_RNUM,A_SRC1_RNUM); r_type_inst (Y_OR_OP, A_DEST_RNUM, A_DEST_RNUM, 1); Store($2, $3); } | Y_ROL_POP A_DEST OPT_DSUB A_SRC1 A_SRC2 { if (((get_label_type($2) != WORD_A_TYPE) && (get_label_type($2) != BYTE_A_TYPE)) || (($4 != WORD_A_TYPE) && ($4 != BYTE_A_TYPE)) || (($5 != WORD_A_TYPE) && ($5 != BYTE_A_TYPE))) yyerror("ROR must use .byte or .word\n"); r_type_inst (Y_SUBU_OP, 1, 0, A_SRC2_RNUM); r_type_inst (Y_SRLV_OP, 1, 1, A_SRC1_RNUM); r_type_inst (Y_SLLV_OP, A_DEST_RNUM, A_SRC2_RNUM,A_SRC1_RNUM); r_type_inst (Y_OR_OP, A_DEST_RNUM, A_DEST_RNUM, 1); Store($2, $3); } | BINARY_OPR_I A_DEST OPT_DSUB A_SRC1 A_SRC2 { if (((get_label_type($2) != WORD_A_TYPE) && (get_label_type($2) != BYTE_A_TYPE)) || (($4 != WORD_A_TYPE) && ($4 != BYTE_A_TYPE)) || (($5 != WORD_A_TYPE) && ($5 != BYTE_A_TYPE))) yyerror("Shift must use .byte or .word\n"); r_type_inst ($1, A_DEST_RNUM, A_SRC2_RNUM, A_SRC1_RNUM); Store($2, $3); } | SHIFT_OP A_DEST OPT_DSUB A_SRC1 A_SRC2 { if (((get_label_type($2) != WORD_A_TYPE) && (get_label_type($2) != BYTE_A_TYPE)) || (($4 != WORD_A_TYPE) && ($4 != BYTE_A_TYPE)) || (($5 != WORD_A_TYPE) && ($5 != BYTE_A_TYPE))) yyerror("Shift must use .byte or .word\n"); r_type_inst (imm_op_to_op($1), A_DEST_RNUM, A_SRC2_RNUM, A_SRC1_RNUM); Store($2, $3); } | Y_CVT_POP A_DEST OPT_DSUB A_SRC2 { if (get_label_type($2) == FLOAT_A_TYPE) { if (($4 != WORD_A_TYPE) && ($4 != BYTE_A_TYPE)) yyerror("Type mismatch"); r_type_inst(Y_MTC1_OP, AF_DEST_RNUM, 0, A_SRC2_RNUM); r_type_inst(Y_CVT_S_W_OP, AF_SRC2_RNUM, AF_SRC2_RNUM, 0); } else if ((get_label_type($2) == WORD_A_TYPE) || (get_label_type($2) == BYTE_A_TYPE)) { if ($4 != FLOAT_A_TYPE) yyerror("Type mismatch"); r_type_inst(Y_CVT_W_S_OP, AF_SRC2_RNUM, AF_SRC2_RNUM, 0); r_type_inst(Y_MFC1_OP, AF_SRC2_RNUM, 0, A_DEST_RNUM); } else yyerror("Unknown type"); Store($2, $3); } | Y_B_POP '(' A_SRC1 ')' { if ($3 != WORD_A_TYPE) { yyerror("Type mismatch. In b (label), the label must be a .word\n"); } r_type_inst(Y_JR_OP, 0, A_SRC1_RNUM, 0); } | BINARY_OP_NOI A_DEST OPT_DSUB A_SRC1 A_SRC2 { if (BadTypes(get_label_type($2), $4, $5)) yyerror("Type mismatch"); switch (get_label_type($2)) { case WORD_A_TYPE: case BYTE_A_TYPE: r_type_inst ($1, A_DEST_RNUM, A_SRC1_RNUM, A_SRC2_RNUM); break; case FLOAT_A_TYPE: r_type_inst (op_to_float_op($1), AF_DEST_RNUM, AF_SRC1_RNUM, AF_SRC2_RNUM); break; case DOUBLE_A_TYPE: r_type_inst (op_to_double_op($1), AF_DEST_RNUM, AF_SRC1_RNUM, AF_SRC2_RNUM); break; default: yyerror ("Unknown type"); } Store($2, $3); } | BINARY_OP_I A_DEST OPT_DSUB A_SRC1 A_SRC2 { if (BadTypes(get_label_type($2), $4, $5)) yyerror("Type mismatch"); switch (get_label_type($2)) { case WORD_A_TYPE: case BYTE_A_TYPE: r_type_inst ($1, A_DEST_RNUM, A_SRC1_RNUM, A_SRC2_RNUM); break; case FLOAT_A_TYPE: r_type_inst (op_to_float_op($1), AF_DEST_RNUM, AF_SRC1_RNUM, AF_SRC2_RNUM); break; case DOUBLE_A_TYPE: r_type_inst (op_to_double_op($1), AF_DEST_RNUM, AF_SRC1_RNUM, AF_SRC2_RNUM); break; default: yyerror ("Unknown type"); } Store($2, $3); } | Y_MOVE_POP A_DEST OPT_DSUB A_SRC2 { /* Source must be A_SRC2, because A_SRC2_RNUM = A_DEST_RNUM */ switch (get_label_type($2)) { case WORD_A_TYPE: case BYTE_A_TYPE: if ($4 == FLOAT_A_TYPE) r_type_inst(Y_MFC1_OP, AF_SRC2_RNUM, 0, A_DEST_RNUM); else if (($4 != WORD_A_TYPE) && ($4 != BYTE_A_TYPE)) yyerror("Type mismatch"); break; case DOUBLE_A_TYPE: if ($4 != DOUBLE_A_TYPE) yyerror("Type mismatch"); break; case FLOAT_A_TYPE: if (($4 == WORD_A_TYPE) || ($4 == BYTE_A_TYPE)) r_type_inst(Y_MTC1_OP, AF_DEST_RNUM, 0, A_SRC2_RNUM); else if ($4 != FLOAT_A_TYPE) yyerror("Type mismatch"); break; default: yyerror ("Unknown type"); } Store($2, $3); } | DIV_POP A_DEST OPT_DSUB A_SRC1 A_SRC2 { if (BadTypes(get_label_type($2), $4, $5)) yyerror("Type mismatch"); switch (get_label_type($2)) { case WORD_A_TYPE: div_inst ($1, A_DEST_RNUM, A_SRC1_RNUM, A_SRC2_RNUM, 0); break; case BYTE_A_TYPE: div_inst ($1, A_DEST_RNUM, A_SRC1_RNUM, A_SRC2_RNUM, 0); break; case FLOAT_A_TYPE: r_type_inst (op_to_float_op($1), AF_DEST_RNUM, AF_SRC1_RNUM, AF_SRC2_RNUM); break; case DOUBLE_A_TYPE: r_type_inst (op_to_double_op($1), AF_DEST_RNUM, AF_SRC1_RNUM, AF_SRC2_RNUM); break; default: yyerror ("Unknown type"); } Store($2, $3); } | MUL_POP A_DEST OPT_DSUB A_SRC1 A_SRC2 { if (BadTypes(get_label_type($2), $4, $5)) yyerror("Type mismatch"); switch (get_label_type($2)) { case WORD_A_TYPE: mult_inst (Y_MUL_POP, A_DEST_RNUM, A_SRC1_RNUM, A_SRC2_RNUM); break; case BYTE_A_TYPE: mult_inst (Y_MUL_POP, A_DEST_RNUM, A_SRC1_RNUM, A_SRC2_RNUM); break; case FLOAT_A_TYPE: r_type_inst (op_to_float_op($1), AF_DEST_RNUM, AF_SRC1_RNUM, AF_SRC2_RNUM); break; case DOUBLE_A_TYPE: r_type_inst (op_to_double_op($1), AF_DEST_RNUM, AF_SRC1_RNUM, AF_SRC2_RNUM); break; default: yyerror ("Unknown type"); } Store($2, $3); } | Y_PUT_POP A_SRC1 { switch ($2) { case BYTE_A_TYPE: i_type_inst(Y_ORI_OP, 2, 0, make_imm_expr (11, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; case WORD_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (1, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; case FLOAT_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (2, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; case DOUBLE_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (3, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; default: yyerror ("Unknown type"); } } | Y_PUTC_POP A_SRC1 { switch ($2) { case BYTE_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (11, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; case WORD_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (11, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; case FLOAT_A_TYPE: case DOUBLE_A_TYPE: default: yyerror ("Bad type in putc, must be byte or word."); } } | Y_PUTI_POP A_SRC1 { switch ($2) { case BYTE_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (1, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; case WORD_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (1, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; case FLOAT_A_TYPE: case DOUBLE_A_TYPE: default: yyerror ("Bad type in puti, must be byte or word."); } } | Y_PUTS_POP Y_ID { i_type_inst (Y_ADDI_OP, A_SRC1_RNUM, 0, addr_expr_imm(make_addr_expr(0, $2, 0))); i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (4, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); } | Y_PUTS_POP Y_REG { i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (4, NULL, 0)); r_type_inst (Y_ADD_OP, 4, $2, 0); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); } | Y_PUTC_POP Y_REG { i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (11, NULL, 0)); r_type_inst (Y_ADD_OP, 4, $2, 0); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); } | Y_PUTI_POP Y_REG { i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (1, NULL, 0)); r_type_inst (Y_ADD_OP, 4, $2, 0); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); } | Y_GET_POP A_DEST OPT_DSUB { switch (get_label_type($2)) { case BYTE_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (12, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; case WORD_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (5, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; case FLOAT_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (6, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; case DOUBLE_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (7, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; default: yyerror ("Unknown type"); } Store($2, $3); } | Y_GETC_POP A_DEST OPT_DSUB { switch (get_label_type($2)) { case BYTE_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (12, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; case WORD_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (12, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; case FLOAT_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (6, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; case DOUBLE_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (7, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; default: yyerror ("Unknown type"); } Store($2, $3); } | Y_GETI_POP A_DEST OPT_DSUB { switch (get_label_type($2)) { case BYTE_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (5, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; case WORD_A_TYPE: i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (5, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); break; case FLOAT_A_TYPE: case DOUBLE_A_TYPE: default: yyerror ("Unknown type"); } Store($2, $3); } | Y_GETC_POP Y_REG { i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (12, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); r_type_inst (Y_ADD_OP, $2, 2, 0); break; } | Y_GETI_POP Y_REG { i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (5, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); r_type_inst (Y_ADD_OP, $2, 2, 0); break; } | Y_DONE_POP { i_type_inst (Y_ORI_OP, 2, 0, make_imm_expr (10, NULL, 0)); r_type_inst (Y_SYSCALL_OP, 0, 0, 0); } | UNARY_BR_OP A_SRC1 LABEL { if (($2 != BYTE_A_TYPE) && ($2 != WORD_A_TYPE)) yyerror("Type mismatch"); i_type_inst ($1, 0, A_SRC1_RNUM, $3); } | UNARY_BR_POP A_SRC1 LABEL { if (($2 != BYTE_A_TYPE) && ($2 != WORD_A_TYPE)) yyerror("Type mismatch"); i_type_inst ($1 == Y_BEQZ_POP ? Y_BEQ_OP : Y_BNE_OP, 0, A_SRC1_RNUM, $3); } | BINARY_BR_OP A_SRC1 A_SRC2 LABEL { if ((($2 != BYTE_A_TYPE) && ($2 != WORD_A_TYPE)) || (($3 != BYTE_A_TYPE) && ($3 != WORD_A_TYPE))) yyerror("Type mismatch"); i_type_inst ($1, A_SRC1_RNUM, A_SRC2_RNUM, $4); } | BR_GT_POP A_SRC1 A_SRC2 LABEL { if ((($2 != BYTE_A_TYPE) && ($2 != WORD_A_TYPE)) || (($3 != BYTE_A_TYPE) && ($3 != WORD_A_TYPE))) yyerror("Type mismatch"); r_type_inst ($1 == Y_BGT_POP ? Y_SLT_OP : Y_SLTU_OP, 1, A_SRC2_RNUM, A_SRC1_RNUM); /* Use $at */ i_type_inst (Y_BNE_OP, 0, 1, $4); } | BR_GE_POP A_SRC1 A_SRC2 LABEL { if ((($2 != BYTE_A_TYPE) && ($2 != WORD_A_TYPE)) || (($3 != BYTE_A_TYPE) && ($3 != WORD_A_TYPE))) yyerror("Type mismatch"); r_type_inst ($1 == Y_BGE_POP ? Y_SLT_OP : Y_SLTU_OP, 1, A_SRC1_RNUM, A_SRC2_RNUM); /* Use $at */ i_type_inst (Y_BEQ_OP, 0, 1, $4); } | BR_LT_POP A_SRC1 A_SRC2 LABEL { if ((($2 != BYTE_A_TYPE) && ($2 != WORD_A_TYPE)) || (($3 != BYTE_A_TYPE) && ($3 != WORD_A_TYPE))) yyerror("Type mismatch"); r_type_inst ($1 == Y_BLT_POP ? Y_SLT_OP : Y_SLTU_OP, 1, A_SRC1_RNUM, A_SRC2_RNUM); /* Use $at */ i_type_inst (Y_BNE_OP, 0, 1, $4); } | BR_LE_POP A_SRC1 A_SRC2 LABEL { if ((($2 != BYTE_A_TYPE) && ($2 != WORD_A_TYPE)) || (($3 != BYTE_A_TYPE) && ($3 != WORD_A_TYPE))) yyerror("Type mismatch"); r_type_inst ($1 == Y_BLE_POP ? Y_SLT_OP : Y_SLTU_OP, 1, A_SRC2_RNUM, A_SRC1_RNUM); /* Use $at */ i_type_inst (Y_BEQ_OP, 0, 1, $4); } ; A_DEST: Y_ID; A_SRC1: Y_INT { i_type_inst (Y_ORI_OP, A_SRC1_RNUM, 0, make_imm_expr ($1, NULL, 0)); $$ = WORD_A_TYPE; } | Y_STR { char *c = $1; if (strlen(c) > 1) yyerror("illegal character constant"); i_type_inst (Y_ORI_OP, A_SRC1_RNUM, 0, make_imm_expr ((int)*c, NULL, 0)); $$ = BYTE_A_TYPE; } | Y_FP { /* This does not handle doubles! */ float x = *$1; int *y = (int *) &x; i_type_inst (Y_ORI_OP, 1, 0, const_imm_expr (*y)); r_type_inst (Y_MTC1_OP, AF_SRC1_RNUM, 0, 1); $$ = FLOAT_A_TYPE; } | Y_ID OPT_SUB { if ($2 == 0) { $$ = get_label_type($1); } else if (0 == strcmp($1, "M")) { $$ = WORD_A_TYPE; $1 = NULL; } else if (0 == strcmp ($1, "m")) { $$ = BYTE_A_TYPE; $1 = NULL; } else { $$ = BYTE_A_TYPE; yyerror("Bad array, use M or m.\n"); } switch ($$) { case WORD_A_TYPE: /* if ($2 != 0) r_sh_type_inst (Y_SLL_OP, $2, $2, 2); */ i_type_inst (Y_LW_OP, A_SRC1_RNUM, $2, addr_expr_imm(make_addr_expr(0, $1, 0))); break; case BYTE_A_TYPE: i_type_inst (Y_LB_OP, A_SRC1_RNUM, $2, addr_expr_imm(make_addr_expr(0, $1, 0))); break; case FLOAT_A_TYPE: /* if ($2 != 0) r_sh_type_inst (Y_SLL_OP, $2, $2, 2); */ i_type_inst (Y_LWC1_OP, AF_SRC1_RNUM, $2, addr_expr_imm(make_addr_expr(0, $1, 0))); break; case DOUBLE_A_TYPE: /* if ($2 != 0) r_sh_type_inst (Y_SLL_OP, $2, $2, 3); */ i_type_inst (Y_LWC1_OP, AF_SRC1_RNUM, $2, addr_expr_imm(make_addr_expr(0, $1, 0))); i_type_inst (Y_LWC1_OP, AF_SRC1_RNUM + 1, $2, incr_expr_offset(addr_expr_imm( make_addr_expr(0, $1, 0)), 4)); break; default: yyerror ("Unknown type"); } } ; A_SRC2: Y_INT { i_type_inst (Y_ORI_OP, A_SRC2_RNUM, 0, make_imm_expr ($1, NULL, 0)); $$ = WORD_A_TYPE; } | Y_STR { char *c = $1; if (strlen(c) > 1) yyerror("illegal character constant"); i_type_inst (Y_ORI_OP, A_SRC2_RNUM, 0, make_imm_expr ((int)*c, NULL, 0)); $$ = BYTE_A_TYPE; } | Y_FP { /* This does not handle doubles! */ float x = *$1; int *y = (int *) &x; i_type_inst (Y_ORI_OP, 1, 0, const_imm_expr (*y)); r_type_inst (Y_MTC1_OP, AF_SRC2_RNUM, 0, 1); $$ = FLOAT_A_TYPE; } | Y_ID OPT_SUB { if ($2 == 0) { $$ = get_label_type($1); } else if (0 == strcmp($1, "M")) { $$ = WORD_A_TYPE; $1 = NULL; } else if (0 == strcmp ($1, "m")) { $$ = BYTE_A_TYPE; $1 = NULL; } else { $$ = BYTE_A_TYPE; yyerror("Bad array, use M or m.\n"); } switch ($$) { case WORD_A_TYPE: /* if ($2 != 0) r_sh_type_inst (Y_SLL_OP, $2, $2, 2); */ i_type_inst (Y_LW_OP, A_SRC2_RNUM, $2, addr_expr_imm(make_addr_expr(0, $1, 0))); break; case BYTE_A_TYPE: i_type_inst (Y_LB_OP, A_SRC2_RNUM, $2, addr_expr_imm(make_addr_expr(0, $1, 0))); break; case FLOAT_A_TYPE: /* if ($2 != 0) r_sh_type_inst (Y_SLL_OP, $2, $2, 2); */ i_type_inst (Y_LWC1_OP, AF_SRC2_RNUM, $2, addr_expr_imm(make_addr_expr(0, $1, 0))); break; case DOUBLE_A_TYPE: /* if ($2 != 0) r_sh_type_inst (Y_SLL_OP, $2, $2, 3); */ i_type_inst (Y_LWC1_OP, AF_SRC2_RNUM, $2, addr_expr_imm(make_addr_expr(0, $1, 0))); i_type_inst (Y_LWC1_OP, AF_SRC2_RNUM + 1, $2, incr_expr_offset(addr_expr_imm( make_addr_expr(0, $1, 0)), 4)); break; default: yyerror ("Unknown type"); } } ; OPT_DSUB: { $$ = 0; } | '[' Y_INT ']' { i_type_inst (Y_ORI_OP, A_DSUB_RNUM, 0, make_imm_expr ($2, NULL, 0)); $$ = A_DSUB_RNUM; } | '[' Y_STR ']' { char *c = $2; if (strlen(c) > 1) yyerror("illegal character constant"); i_type_inst (Y_ORI_OP, A_DSUB_RNUM, 0, make_imm_expr ((int)*c, NULL, 0)); $$ = A_DSUB_RNUM; } | '[' Y_ID ']' { switch (get_label_type($2)) { case WORD_A_TYPE: i_type_inst (Y_LW_OP, A_DSUB_RNUM, 0, addr_expr_imm(make_addr_expr(0, $2, 0))); break; case BYTE_A_TYPE: i_type_inst (Y_LB_OP, A_DSUB_RNUM, 0, addr_expr_imm(make_addr_expr(0, $2, 0))); break; case FLOAT_A_TYPE: case DOUBLE_A_TYPE: default: yyerror ("Bad array index."); } $$ = A_DSUB_RNUM; } ; OPT_SUB: { $$ = 0; } | '[' Y_INT ']' { i_type_inst (Y_ORI_OP, A_SUB_RNUM, 0, make_imm_expr ($2, NULL, 0)); $$ = A_SUB_RNUM; } | '[' Y_STR ']' { char *c = $2; if (strlen(c) > 1) yyerror("illegal character constant"); i_type_inst (Y_ORI_OP, A_SUB_RNUM, 0, make_imm_expr ((int)*c, NULL, 0)); $$ = A_SUB_RNUM; } | '[' Y_ID ']' { switch (get_label_type($2)) { case WORD_A_TYPE: i_type_inst (Y_LW_OP, A_SUB_RNUM, 0, addr_expr_imm(make_addr_expr(0, $2, 0))); break; case BYTE_A_TYPE: i_type_inst (Y_LB_OP, A_SUB_RNUM, 0, addr_expr_imm(make_addr_expr(0, $2, 0))); break; case FLOAT_A_TYPE: case DOUBLE_A_TYPE: default: yyerror ("Bad array index."); } $$ = A_SUB_RNUM; } ; LOAD_OP: Y_LB_OP | Y_LBU_OP | Y_LH_OP | Y_LHU_OP | Y_LW_OP | Y_LWL_OP | Y_LWR_OP | Y_LD_POP ; LOAD_COP: Y_LWC0_OP | Y_LWC2_OP | Y_LWC3_OP ; LOAD_IMM_OP: Y_LUI_OP; ULOADH_POP: Y_ULH_POP | Y_ULHU_POP ; LOADF_OP: Y_LWC1_OP | Y_L_S_POP | Y_L_D_POP ; STORE_OP: Y_SB_OP | Y_SH_OP | Y_SW_OP | Y_SWL_OP | Y_SWR_OP | Y_SD_POP ; STORE_COP: Y_SWC0_OP | Y_SWC2_OP | Y_SWC3_OP ; STOREF_OP: Y_SWC1_OP | Y_S_S_POP | Y_S_D_POP ; SYS_OP: Y_RFE_OP | Y_SYSCALL_OP ; /* These binary operations have immediate analogues. */ BINARY_OP_I: Y_ADD_OP | Y_ADDU_OP | Y_AND_OP | Y_XOR_OP | Y_OR_OP | Y_SLT_OP | Y_SLTU_OP ; BINARY_OPR_I: Y_SLLV_OP | Y_SRAV_OP | Y_SRLV_OP ; BINARY_IMM_OP: Y_ADDI_OP | Y_ADDIU_OP | Y_ANDI_OP | Y_ORI_OP | Y_XORI_OP | Y_SLTI_OP | Y_SLTIU_OP ; SHIFT_OP: Y_SLL_OP | Y_SRA_OP | Y_SRL_OP ; /* These binary operations do not have immediate analogues. */ BINARY_OP_NOI: Y_NOR_OP | Y_SUB_OP | Y_SUBU_OP ; DIV_POP : Y_DIV_OP | Y_DIVU_OP | Y_REM_POP | Y_REMU_POP ; MUL_POP : Y_MUL_POP | Y_MULO_POP | Y_MULOU_POP ; SET_LE_POP: Y_SLE_POP | Y_SLEU_POP ; SET_GT_POP: Y_SGT_POP | Y_SGTU_POP ; SET_GE_POP: Y_SGE_POP | Y_SGEU_POP ; SET_EQ_POP: Y_SEQ_POP | Y_SNE_POP ; MULT_OP: Y_MULT_OP | Y_MULTU_OP ; NULLARY_BR_OP: Y_BC0T_OP | Y_BC1T_OP | Y_BC2T_OP | Y_BC3T_OP | Y_BC0F_OP | Y_BC1F_OP | Y_BC2F_OP | Y_BC3F_OP ; UNARY_BR_OP: Y_BGEZ_OP | Y_BGEZAL_OP | Y_BGTZ_OP | Y_BLEZ_OP | Y_BLTZ_OP | Y_BLTZAL_OP ; UNARY_BR_POP: Y_BEQZ_POP | Y_BNEZ_POP ; BINARY_BR_OP: Y_BEQ_OP | Y_BNE_OP ; BR_GT_POP: Y_BGT_POP | Y_BGTU_POP BR_GE_POP: Y_BGE_POP | Y_BGEU_POP BR_LT_POP: Y_BLT_POP | Y_BLTU_POP BR_LE_POP: Y_BLE_POP | Y_BLEU_POP ; J_OPS: Y_J_OP | Y_JAL_OP | Y_JR_OP | Y_JALR_OP ; B_OP: Y_B_POP | Y_BAL_POP ; MOVE_COP_OP: Y_MOV_S_OP | Y_MOV_D_OP ; MOV_FROM_HILO_OP: Y_MFHI_OP | Y_MFLO_OP ; MOV_TO_HILO_OP: Y_MTHI_OP | Y_MTLO_OP ; MOV_COP_OP: Y_MFC0_OP | Y_MFC1_OP | Y_MFC1_D_POP | Y_MFC2_OP | Y_MFC3_OP | Y_MTC0_OP | Y_MTC1_OP | Y_MTC1_D_POP | Y_MTC2_OP | Y_MTC3_OP ; CTL_COP_OP: Y_CFC0_OP | Y_CFC1_OP | Y_CFC2_OP | Y_CFC3_OP | Y_CTC0_OP | Y_CTC1_OP | Y_CTC2_OP | Y_CTC3_OP ; FP_ABS_OP: Y_ABS_S_OP | Y_ABS_D_OP ; FP_BINARY_OP: Y_ADD_S_OP | Y_ADD_D_OP | Y_DIV_S_OP | Y_DIV_D_OP | Y_MUL_S_OP | Y_MUL_D_OP | Y_SUB_S_OP | Y_SUB_D_OP ; FP_CONVERT_OP: Y_CVT_D_S_OP | Y_CVT_D_W_OP | Y_CVT_S_D_OP | Y_CVT_S_W_OP | Y_CVT_W_D_OP | Y_CVT_W_S_OP ; FP_NEG_OP: Y_NEG_S_OP | Y_NEG_D_OP ; FP_CMP_OP: Y_C_F_S_OP | Y_C_UN_S_OP | Y_C_EQ_S_OP | Y_C_UEQ_S_OP | Y_C_OLE_S_OP | Y_C_ULE_S_OP | Y_C_SF_S_OP | Y_C_NGLE_S_OP | Y_C_SEQ_S_OP | Y_C_NGL_S_OP | Y_C_LT_S_OP | Y_C_NGE_S_OP | Y_C_LE_S_OP | Y_C_NGT_S_OP | Y_C_F_D_OP | Y_C_UN_D_OP | Y_C_EQ_D_OP | Y_C_UEQ_D_OP | Y_C_OLE_D_OP | Y_C_ULE_D_OP | Y_C_SF_D_OP | Y_C_NGLE_D_OP | Y_C_SEQ_D_OP | Y_C_NGL_D_OP | Y_C_LT_D_OP | Y_C_NGE_D_OP | Y_C_LE_D_OP | Y_C_NGT_D_OP ; ASM_DIRECTIVE: Y_ALIAS_DIR Y_REG Y_REG | Y_ALIGN_DIR EXPR { align_data ($2); } | Y_ASCII_DIR {null_term = 0;} STR_LST { if (text_dir) yyerror ("Can't put data in text segment\n"); } | Y_ASCIIZ_DIR {null_term = 1;} STR_LST { if (text_dir) yyerror ("Can't put data in text segment\n"); } | Y_ASM0_DIR | Y_BGNB_DIR Y_INT | Y_BYTE_DIR {store_op = store_byte;} EXPR_LST { if (text_dir) yyerror ("Can't put data in text segment\n"); if (abstract_line_label) set_label_type(abstract_line_label, BYTE_A_TYPE); } | Y_COMM_DIR Y_ID EXPR { align_data (2); if (lookup_label ($2)->addr == 0) record_label ($2,current_data_pc ()); increment_data_pc ($3); } | Y_DATA_DIR { user_kernel_data_segment (0); data_dir = 1; text_dir = 0; enable_data_alignment (); } | Y_K_DATA_DIR { user_kernel_data_segment (1); data_dir = 1; text_dir = 0; enable_data_alignment (); } | Y_DOUBLE_DIR {store_op = store_double;} FP_EXPR_LST { if (text_dir) yyerror ("Can't put data in text segment\n"); if (abstract_line_label) set_label_type(abstract_line_label, DOUBLE_A_TYPE); } | Y_END_DIR OPT_ID | Y_ENDB_DIR Y_INT | Y_ENDR_DIR | Y_ENT_DIR Y_ID | Y_ENT_DIR Y_ID Y_INT | Y_EXTERN_DIR Y_ID EXPR { extern_directive ($2, $3); } | Y_EQ_DIR Y_ID Y_INT { record_label ($2, $3); } | Y_ERR_DIR { fatal_error ("File contains an .err directive\n"); } | Y_FILE_DIR Y_INT Y_STR | Y_FLOAT_DIR {store_op = store_float;} FP_EXPR_LST { if (text_dir) yyerror ("Can't put data in text segment\n"); if (abstract_line_label) set_label_type(abstract_line_label, FLOAT_A_TYPE); } | Y_FMASK_DIR Y_INT Y_INT | Y_FRAME_DIR REGISTER Y_INT REGISTER | Y_GLOBAL_DIR Y_ID { make_label_global ($2); } | Y_HALF_DIR {store_op = store_half;} EXPR_LST { if (text_dir) yyerror ("Can't put data in text segment\n"); } | Y_LABEL_DIR Y_ID { record_label ($2, (text_dir ? current_text_pc () : current_data_pc ())); } | Y_LCOMM_DIR Y_ID EXPR { lcomm_directive ($2, $3); } /* Produced by cc 2.10 */ | Y_LIVEREG_DIR Y_INT Y_INT | Y_LOC_DIR Y_INT Y_INT | Y_MASK_DIR Y_INT Y_INT | Y_NOALIAS_DIR Y_REG Y_REG | Y_OPTIONS_DIR Y_ID | Y_REPEAT_DIR EXPR { yyerror ("Warning: repeat directive ignored\n"); } | Y_RDATA_DIR { data_dir = 1; text_dir = 0; enable_data_alignment (); } | Y_SDATA_DIR { data_dir = 1; text_dir = 0; enable_data_alignment (); } | Y_SET_DIR Y_ID { if (streq ($2, "noat")) noat_flag = 1; else if (streq ($2, "at")) noat_flag = 0; } | Y_SPACE_DIR EXPR { if (data_dir) increment_data_pc ($2); else if (text_dir) increment_text_pc ($2); } | Y_STRUCT_DIR EXPR { yyerror ("Warning: struct directive ignored\n"); } | Y_TEXT_DIR { user_kernel_text_segment (0); data_dir = 0; text_dir = 1; enable_data_alignment (); } | Y_TEXT_DIR ABS_ADDR { user_kernel_text_segment (0); data_dir = 0; text_dir = 1; enable_data_alignment (); text_begins_at_point ($2); } | Y_K_TEXT_DIR { user_kernel_text_segment (1); data_dir = 0; text_dir = 1; enable_data_alignment (); } | Y_K_TEXT_DIR ABS_ADDR { user_kernel_text_segment (1); data_dir = 0; text_dir = 1; enable_data_alignment (); k_text_begins_at_point ($2); } | Y_VERSTAMP_DIR Y_INT Y_INT | Y_VREG_DIR REGISTER Y_INT Y_INT | Y_WORD_DIR { store_op = store_word_data; if (abstract_line_label) set_label_type(abstract_line_label, WORD_A_TYPE); } EXPR_LST ; ADDRESS : '(' REGISTER ')' { $$ = make_addr_expr (0, NULL, $2); } | ABS_ADDR { $$ = make_addr_expr ($1, NULL, 0); } | ABS_ADDR '(' REGISTER ')' { $$ = make_addr_expr ($1, NULL, $3); } | Y_ID { $$ = make_addr_expr (0, $1, 0); } | Y_ID '(' REGISTER ')' { $$ = make_addr_expr (0, $1, $3); } | Y_ID '+' ABS_ADDR { $$ = make_addr_expr ($3, $1, 0); } | ABS_ADDR '+' Y_ID { $$ = make_addr_expr ($1, $3, 0); } | Y_ID '-' ABS_ADDR { $$ = make_addr_expr (- $3, $1, 0); } | Y_ID '+' ABS_ADDR '(' REGISTER ')' { $$ = make_addr_expr ($3, $1, $5); } | Y_ID '-' ABS_ADDR '(' REGISTER ')' { $$ = make_addr_expr (- $3, $1, $5); } | error { yyerror("Address expected"); $$ = make_addr_expr (0, "not defined!", 0); } ; IMM : ABS_ADDR { $$ = make_imm_expr ($1, NULL, 0); } | Y_STR { char *c = $1; if (strlen(c) > 1) yyerror("illegal character constant"); $$ = make_imm_expr ((int)*c, NULL, 0); } | Y_ID { $$ = make_imm_expr (0, $1, 0); } | Y_ID '+' ABS_ADDR { $$ = make_imm_expr ($3, $1, 0); } | Y_ID '-' ABS_ADDR { $$ = make_imm_expr (- $3, $1, 0); } ; ABS_ADDR: Y_INT; DEST_REG: REGISTER ; SRC1 : REGISTER ; SRC2 : REGISTER ; DEST : REGISTER ; REG : REGISTER ; SOURCE : REGISTER ; REGISTER: Y_REG { if ($1 < 0 || $1 > 31) yyerror ("Register number out of range"); if ($1 == 1 && !bare_machine && !noat_flag) yyerror ("Register 1 is reserved for assembler"); $$ = $1; } ; F_DEST: FP_REGISTER ; F_SRC1: FP_REGISTER ; F_SRC2: FP_REGISTER ; FP_REGISTER: Y_FP_REG { if ($1 < 0 || $1 > 31) yyerror ("FP register number out of range"); $$ = $1; } | error { yyerror("Floating point register required"); $$ = 0; } ; COP_REG: Y_REG | Y_FP_REG ; LABEL : Y_ID { $$ = make_imm_expr (- current_text_pc (), $1, 1); } | error { $$ = make_imm_expr (0, "Not defined!", 0); yyerror("Label required"); } ; STR_LST : STR_LST Y_STR { store_string ($2, y_str_length, null_term); } | Y_STR { store_string ($1, y_str_length, null_term); } | error { yyerror("String expected"); } ; EXPR : Y_INT | Y_STR { char *c = $1; if (strlen(c) > 1) yyerror("illegal character constant"); $$ = (int)*c; } | Y_ID { label *l = lookup_label ($1); if (! l->addr) { if (store_op == store_double) align_data(3); if (store_op == store_float) align_data(2); if (store_op == store_word_data) align_data(2); if (store_op == store_half) align_data(1); record_data_uses_symbol (current_data_pc (), l); $$ = 0; } else $$ = l->addr; } | error { $$ = 0; yyerror("Expression expected"); } ; EXPR_LST: NMT_EXPR_LST | { store_op(0); } ; NMT_EXPR_LST: NMT_EXPR_LST EXPR { store_op ($2); } | EXPR { store_op ($1); } | EXPR ':' Y_INT { int i; for (i = 0; i < $3; i ++) store_op ($1); } ; FP_EXPR_LST: NMT_FP_EXPR_LST | { double z = 0; store_op(&z); } ; NMT_FP_EXPR_LST: NMT_FP_EXPR_LST Y_FP { store_op ($2); } | Y_FP { store_op ($1); } ; OPT_ID : Y_ID | {$$ = NULL;} ; %% /* Maintain and update the address of labels for the current line. */ void fix_current_label_address (mem_addr new_addr) { label_list *l; for (l = this_line_labels; l != NULL; l = l->tail) l->head->addr = new_addr; clear_labels (); } static label_list * cons_label (label *head, label_list *tail) { label_list *c = (label_list *) malloc (sizeof (label_list)); c->head = head; c->tail = tail; return (c); } static void clear_labels () { label_list *n; for ( ; this_line_labels != NULL; this_line_labels = n) { n = this_line_labels->tail; free (this_line_labels); } } int op_to_imm_op (int opcode) { switch (opcode) { case Y_ADD_OP: return (Y_ADDI_OP); case Y_ADDU_OP: return (Y_ADDIU_OP); case Y_AND_OP: return (Y_ANDI_OP); case Y_OR_OP: return (Y_ORI_OP); case Y_XOR_OP: return (Y_XORI_OP); case Y_SLT_OP: return (Y_SLTI_OP); case Y_SLTU_OP: return (Y_SLTIU_OP); case Y_SLLV_OP: return (Y_SLL_OP); case Y_SRAV_OP: return (Y_SRA_OP); case Y_SRLV_OP: return (Y_SRL_OP); default: fatal_error ("Can't convert op to immediate op\n"); /*NOTREACHED*/ } } int imm_op_to_op (int opcode) { switch (opcode) { case Y_ADDI_OP: return (Y_ADD_OP); case Y_ADDIU_OP: return (Y_ADDU_OP); case Y_ANDI_OP: return (Y_AND_OP); case Y_ORI_OP: return (Y_OR_OP); case Y_XORI_OP: return (Y_XOR_OP); case Y_SLTI_OP: return (Y_SLT_OP); case Y_SLTIU_OP: return (Y_SLTU_OP); case Y_J_OP: return (Y_JR_OP); case Y_LUI_OP: return (Y_ADDU_OP); case Y_SLL_OP: return (Y_SLLV_OP); case Y_SRA_OP: return (Y_SRAV_OP); case Y_SRL_OP: return (Y_SRLV_OP); default: fatal_error ("Can't convert immediate op to op"); /*NOTREACHED*/ } } int op_to_float_op(int opcode) { switch (opcode) { case Y_ADD_OP: return Y_ADD_S_OP; case Y_SUB_OP: return Y_SUB_S_OP; case Y_MULT_OP: return Y_MUL_S_OP; case Y_MUL_POP: return Y_MUL_S_OP; case Y_DIV_OP: return Y_DIV_S_OP; default: yyerror ("No such floating point operation"); return Y_ADD_D_OP; } } int op_to_double_op(int opcode) { switch (opcode) { case Y_ADD_OP: return Y_ADD_D_OP; case Y_SUB_OP: return Y_SUB_D_OP; case Y_MULT_OP: return Y_MUL_D_OP; case Y_DIV_OP: return Y_DIV_D_OP; default: yyerror ("No such floating point operation"); return Y_ADD_D_OP; } } static void nop_inst (void) { r_type_inst (Y_OR_OP, 0, 0, 0); } static void trap_inst (void) { r_type_inst (Y_BREAK_OP, 0, 0, 0); } imm_expr *branch_offset (int n_inst) { return (const_imm_expr ((n_inst << 2) - 4));/* Later shifted right 2 places */ } static void div_inst (int op, int rd, int rs, int rt, int const_divisor) { if (rd != 0 && !const_divisor) { i_type_inst (Y_BNE_OP, 0, rt, branch_offset (2)); trap_inst (); } if (op == Y_DIV_OP || op == Y_REM_POP) r_type_inst (Y_DIV_OP, 0, rs, rt); else r_type_inst (Y_DIVU_OP, 0, rs, rt); if (rd != 0) { if (op == Y_DIV_OP || op == Y_DIVU_OP) r_type_inst (Y_MFLO_OP, rd, 0, 0); else r_type_inst (Y_MFHI_OP, rd, 0, 0); } } static void mult_inst (int op, int rd, int rs, int rt) { if (op == Y_MULOU_POP) r_type_inst (Y_MULTU_OP, 0, rs, rt); else r_type_inst (Y_MULT_OP, 0, rs, rt); if (op == Y_MULOU_POP && rd != 0) { r_type_inst (Y_MFHI_OP, 1, 0, 0); /* Use $at */ i_type_inst (Y_BEQ_OP, 0, 1, branch_offset (2)); trap_inst (); } else if (op == Y_MULO_POP && rd != 0) { r_type_inst (Y_MFHI_OP, 1, 0, 0); /* use $at */ r_type_inst (Y_MFLO_OP, rd, 0, 0); r_sh_type_inst (Y_SRA_OP, rd, rd, 31); i_type_inst (Y_BEQ_OP, rd, 1, branch_offset (2)); trap_inst (); } if (rd != 0) r_type_inst (Y_MFLO_OP, rd, 0, 0); } static void set_le_inst (int op, int rd, int rs, int rt) { i_type_inst (Y_BNE_OP, rs, rt, branch_offset (3)); i_type_inst (Y_ORI_OP, rd, 0, const_imm_expr (1)); i_type_inst (Y_BEQ_OP, 0, 0, branch_offset (2)); r_type_inst ((op == Y_SLE_POP ? Y_SLT_OP : Y_SLTU_OP), rd, rs, rt); } static void set_gt_inst (int op, int rd, int rs, int rt) { r_type_inst (op == Y_SGT_POP ? Y_SLT_OP : Y_SLTU_OP, rd, rt, rs); } static void set_ge_inst (int op, int rd, int rs, int rt) { i_type_inst (Y_BNE_OP, rs, rt, branch_offset (3)); i_type_inst (Y_ORI_OP, rd, 0, const_imm_expr (1)); i_type_inst (Y_BEQ_OP, 0, 0, branch_offset (2)); r_type_inst (op == Y_SGE_POP ? Y_SLT_OP : Y_SLTU_OP, rd, rt, rs); } static void set_eq_inst (int op, int rd, int rs, int rt) { imm_expr *if_eq, *if_neq; if (op == Y_SEQ_POP) if_eq = const_imm_expr (1), if_neq = const_imm_expr (0); else if_eq = const_imm_expr (0), if_neq = const_imm_expr (1); i_type_inst (Y_BEQ_OP, rs, rt, branch_offset (3)); /* RD <- 0 (if not equal) */ i_type_inst (Y_ORI_OP, rd, 0, if_neq); i_type_inst (Y_BEQ_OP, 0, 0, branch_offset (2)); /* Branch always */ /* RD <- 1 */ i_type_inst (Y_ORI_OP, rd, 0, if_eq); } /* Store the value either as a datum or instruction. */ static void store_word_data (int value) { if (data_dir) store_word (value); else if (text_dir) store_instruction (inst_decode (value)); } int BadTypes(int t1, int t2, int t3) { return (((t2 != t3) || (t1 != t2)) && (((t1 != WORD_A_TYPE) && (t1 != BYTE_A_TYPE)) || ((t2 != WORD_A_TYPE) && (t2 != BYTE_A_TYPE)) || ((t3 != WORD_A_TYPE) && (t3 != BYTE_A_TYPE)) )); } /* Old version that allows arrays from all vars */ #ifdef OLDVER void Store(char *xlabel, int reg) { switch (get_label_type((char *) xlabel)) { case WORD_A_TYPE: if (reg != 0) r_sh_type_inst (Y_SLL_OP, reg, reg, 2); i_type_inst (Y_SW_OP, A_DEST_RNUM, reg, addr_expr_imm(make_addr_expr(0, xlabel, 0))); break; case BYTE_A_TYPE: i_type_inst (Y_SB_OP, A_DEST_RNUM, reg, addr_expr_imm(make_addr_expr(0, xlabel, 0))); break; case FLOAT_A_TYPE: if (reg != 0) r_sh_type_inst (Y_SLL_OP, reg, reg, 2); i_type_inst (Y_SWC1_OP, AF_DEST_RNUM, reg, addr_expr_imm(make_addr_expr(0, xlabel, 0))); break; case DOUBLE_A_TYPE: if (reg != 0) r_sh_type_inst (Y_SLL_OP, reg, reg, 3); i_type_inst (Y_SWC1_OP, AF_DEST_RNUM, reg, addr_expr_imm(make_addr_expr(0, xlabel, 0))); i_type_inst (Y_SWC1_OP, AF_DEST_RNUM + 1, reg, incr_expr_offset(addr_expr_imm(make_addr_expr(0, xlabel, 0)), 4)); break; default: yyerror ("Unknown type"); } } #else /* OLDVER */ void Store(char *xlabel, int reg) { if (reg == 0) { switch (get_label_type((char *) xlabel)) { case WORD_A_TYPE: i_type_inst (Y_SW_OP, A_DEST_RNUM, reg, addr_expr_imm(make_addr_expr(0, xlabel, 0))); break; case BYTE_A_TYPE: i_type_inst (Y_SB_OP, A_DEST_RNUM, reg, addr_expr_imm(make_addr_expr(0, xlabel, 0))); break; case FLOAT_A_TYPE: i_type_inst (Y_SWC1_OP, AF_DEST_RNUM, reg, addr_expr_imm(make_addr_expr(0, xlabel, 0))); break; case DOUBLE_A_TYPE: i_type_inst (Y_SWC1_OP, AF_DEST_RNUM, reg, addr_expr_imm(make_addr_expr(0, xlabel, 0))); i_type_inst (Y_SWC1_OP, AF_DEST_RNUM + 1, reg, incr_expr_offset(addr_expr_imm(make_addr_expr(0, xlabel, 0)), 4)); break; default: yyerror ("Unknown type"); } } else if (0 == strcmp(xlabel, "M")) { /* reg = reg x 4 if (reg != 0) r_sh_type_inst (Y_SLL_OP, reg, reg, 2); */ i_type_inst (Y_SW_OP, A_DEST_RNUM, reg, addr_expr_imm(make_addr_expr(0, NULL, 0))); } else if (0 == strcmp(xlabel, "m")) { i_type_inst (Y_SB_OP, A_DEST_RNUM, reg, addr_expr_imm(make_addr_expr(0, NULL, 0))); } else { yyerror("Bad array, use M or m.\n"); } } #endif /* OLDVER */ void yyerror (const char *s) { extern int line_no; extern char *input_file_name; sprintf(mess_buff, "spim: (parser) %s on line %d of file %s\n", s, line_no, input_file_name); error (mess_buff); print_erroneous_line (); }