static int parse_defined(struct _asm_context *asm_context) { char token[TOKENLEN]; int token_type; int param_count; // throw away int ret; token_type=get_token(asm_context, token, TOKENLEN); if (IS_NOT_TOKEN(token,'(')) { print_error_unexp(token, asm_context); return -1; } token_type=get_token(asm_context, token, TOKENLEN); if (defines_heap_lookup(&asm_context->defines_heap, token, ¶m_count)!=NULL) { ret=1; } else { ret=0; } token_type=get_token(asm_context, token, TOKENLEN); if (IS_NOT_TOKEN(token,')')) { print_error_unexp(token, asm_context); return -1; } return ret; }
static int parse_unary(struct _asm_context *asm_context, int64_t *num, int operation) { char token[TOKENLEN]; int token_type; int64_t temp; struct _var var; var_set_int(&var, 0); token_type = tokens_get(asm_context, token, TOKENLEN); //printf("parse_unary: %s token_type=%d(%d)\n", token, token_type, TOKEN_NUMBER); if (IS_TOKEN(token,'-')) { if (parse_unary(asm_context, &temp, OPER_MINUS) == -1) { return -1; } } else if (IS_TOKEN(token,'~')) { if (parse_unary(asm_context, &temp, OPER_NOT) != 0) { return -1; } } else if (token_type == TOKEN_NUMBER) { temp = atoll(token); } else if (IS_TOKEN(token, '(')) { if (eval_expression_ex(asm_context, &var) != 0) { return -1; } if (var.type != VAR_INT) { print_error("Non-integer number in expression", asm_context); return -1; } temp = var_get_int64(&var); token_type = tokens_get(asm_context, token, TOKENLEN); if (IS_NOT_TOKEN(token,')')) { print_error_unexp(token, asm_context); return -1; } } else { print_error_unexp(token, asm_context); return -1; } if (operation == OPER_NOT) { *num = ~temp; } else if (operation == OPER_MINUS) { *num = -temp; } else { print_error_internal(NULL, __FILE__, __LINE__); return -1; } return 0; }
int parse_db(struct _asm_context *asm_context, int null_term_flag) { char token[TOKENLEN]; int token_type; int data32; if (asm_context->segment == SEGMENT_BSS) { printf("Error: .bss segment doesn't support initialized data at %s:%d\n", asm_context->filename, asm_context->line); return -1; } while(1) { token_type = tokens_get(asm_context, token, TOKENLEN); if (token_type == TOKEN_EOL || token_type == TOKEN_EOF) break; if (token_type == TOKEN_QUOTED) { uint8_t *s = (uint8_t *)token; while(*s != 0) { if (*s == '\\') { int e = tokens_escape_char(asm_context, s); if (e == 0) { return -1; } s = s + e; } memory_write_inc(asm_context, *s, DL_DATA); asm_context->data_count++; s++; } if (null_term_flag == 1) { memory_write_inc(asm_context, 0, DL_DATA); asm_context->data_count++; } } else { tokens_push(asm_context, token, token_type); if (eval_expression(asm_context, &data32) != 0) { if (asm_context->pass == 2) { return -1; } eat_operand(asm_context); data32 = 0; } if (data32 < -128 || data32 > 0xff) { print_error_range("db", -128, 0xff, asm_context); return -1; } memory_write_inc(asm_context, (uint8_t)data32, DL_DATA); asm_context->data_count++; } token_type = tokens_get(asm_context, token, TOKENLEN); if (token_type == TOKEN_EOL || token_type == TOKEN_EOF) { break; } if (IS_NOT_TOKEN(token,',')) { print_error_expecting(",", token, asm_context); return -1; } } asm_context->line++; return 0; }
int parse_instruction_mips(struct _asm_context *asm_context, char *instr) { struct _operand operands[3]; int operand_count = 0; char token[TOKENLEN]; int token_type; char instr_case[TOKENLEN]; int paren_flag; int num,n,r; int opcode; #if 0 int n,cond,s=0; int opcode=0; #endif lower_copy(instr_case, instr); memset(operands, 0, sizeof(operands)); //printf("%s %s\n", instr_case, instr); while(1) { token_type = tokens_get(asm_context, token, TOKENLEN); if (token_type == TOKEN_EOL) { break; } //printf("token=%s token_type=%d\n", token, token_type); if (operand_count == 0 && IS_TOKEN(token,'.')) { strcat(instr_case, "."); strcat(instr, "."); token_type = tokens_get(asm_context, token, TOKENLEN); strcat(instr, token); n = 0; while(token[n] != 0) { token[n]=tolower(token[n]); n++; } strcat(instr_case, token); continue; } do { paren_flag = 0; if (IS_TOKEN(token,'(')) { token_type = tokens_get(asm_context, token, TOKENLEN); paren_flag = 1; } num = get_register_mips(token, 't'); if (num != -1) { operands[operand_count].value = num; operands[operand_count].type = OPERAND_TREG; if (paren_flag == 0) { break; } } else if (paren_flag == 0) { num = get_register_mips(token, 'f'); if (num != -1) { operands[operand_count].value = num; operands[operand_count].type = OPERAND_FREG; break; } } if (paren_flag == 1) { token_type = tokens_get(asm_context, token, TOKENLEN); if (IS_NOT_TOKEN(token,')')) { print_error_unexp(token, asm_context); return -1; } operands[operand_count].reg2 = operands[operand_count].value; operands[operand_count].value = 0; operands[operand_count].type = OPERAND_IMMEDIATE_RS;; break; } operands[operand_count].type = OPERAND_IMMEDIATE; if (asm_context->pass == 1) { eat_operand(asm_context); break; } tokens_push(asm_context, token, token_type); if (eval_expression(asm_context, &num) != 0) { print_error_unexp(token, asm_context); return -1; } operands[operand_count].value = num; token_type = tokens_get(asm_context, token, TOKENLEN); if (IS_TOKEN(token,'(')) { token_type = tokens_get(asm_context, token, TOKENLEN); num = get_register_mips(token, 't'); if (num == -1) { print_error_unexp(token, asm_context); return -1; } operands[operand_count].reg2 = num; operands[operand_count].type = OPERAND_IMMEDIATE_RS;; token_type = tokens_get(asm_context, token, TOKENLEN); if (IS_NOT_TOKEN(token,')')) { print_error_unexp(token, asm_context); return -1; } } else { tokens_push(asm_context, token, token_type); } } while(0); operand_count++; token_type = tokens_get(asm_context, token, TOKENLEN); if (token_type == TOKEN_EOL) { break; } if (IS_NOT_TOKEN(token,',')) { print_error_unexp(token, asm_context); return -1; } if (operand_count == 3) { print_error_unexp(token, asm_context); return -1; } } if (asm_context->pass == 1) { add_bin32(asm_context, 0, IS_OPCODE); return 4; } // Check pseudo-instructions if (strcmp(instr_case, "move") == 0 && operand_count == 2) { strcpy(instr_case, "add"); operands[operand_count].value = 0; operands[operand_count].type = OPERAND_TREG;; operand_count++; } else #if 0 if (strcmp(instr_case, "li") == 0 && operand_count == 2) { strcpy(instr_case, "addi"); memcpy(&operands[operand_count], &operands[operand_count-1], sizeof(struct _operand)); operands[operand_count-1].value = 0; operands[operand_count-1].reg2 = 0; operands[operand_count-1].type = OPERAND_TREG;; operand_count++; } else #endif if (strcmp(instr_case, "nop") == 0 && operand_count == 0) { strcpy(instr_case, "add"); operand_count = 3; } else if (strcmp(instr_case, "neg") == 0 && operand_count == 1) { strcpy(instr_case, "subu"); memcpy(&operands[1], &operands[0], sizeof(struct _operand)); operand_count = 3; } // R-Type Instruction [ op 6, rs 5, rt 5, rd 5, sa 5, function 6 ] n = 0; while(mips_r_table[n].instr != NULL) { if (strcmp(instr_case, mips_r_table[n].instr) == 0) { char shift_table[] = { 0, 11, 21, 16, 6 }; if (mips_r_table[n].operand_count != operand_count) { print_error_illegal_operands(instr, asm_context); return -1; } opcode = mips_r_table[n].function; for (r = 0; r < operand_count; r++) { if (operands[r].type != OPERAND_TREG) { //printf("%s %s %s\n", instr_case, mips_r_table[n].instr, instr); printf("Error: '%s' expects registers at %s:%d\n", instr, asm_context->filename, asm_context->line); return -1; } //printf("%s %d<<%d\n", instr, operands[r].value, shift_table[(int)mips_r_table[n].operand[r]]); opcode |= operands[r].value << shift_table[(int)mips_r_table[n].operand[r]]; } add_bin32(asm_context, opcode, IS_OPCODE); return 4; } n++; } // J-Type Instruction [ op 6, target 26 ] if (strcmp(instr_case, "ja") == 0 || strcmp(instr_case, "jal") == 0) { // FIXME - what to do with this //unsigned int upper = (address + 4) & 0xf0000000; if (operand_count != 1) { print_error_illegal_operands(instr, asm_context); return -1; } if (operands[0].type != OPERAND_IMMEDIATE) { printf("Error: Expecting address for '%s' at %s:%d\n", instr, asm_context->filename, asm_context->line); return -1; } if (instr_case[2] == 'l') { opcode = 2 << 26; } else { opcode = 3 << 26; } add_bin32(asm_context, opcode | operands[0].value >> 2, IS_OPCODE); return 4; } // Coprocessor Instruction [ op 6, format 5, ft 5, fs 5, fd 5, funct 6 ] n = 0; while(mips_cop_table[n].instr != NULL) { if (strcmp(instr_case, mips_cop_table[n].instr) == 0) { char shift_table[] = { 0, 5, 11, 16 }; if (mips_cop_table[n].operand_count != operand_count) { print_error_illegal_operands(instr, asm_context); return -1; } opcode = (0x11 << 26) | (mips_cop_table[n].format << 21) | mips_cop_table[n].function; for (r = 0; r < operand_count; r++) { if (operands[r].type != OPERAND_FREG) { printf("Error: '%s' expects registers at %s:%d\n", instr, asm_context->filename, asm_context->line); return -1; } opcode |= operands[r].value << shift_table[(int)mips_cop_table[n].operand[r]]; } add_bin32(asm_context, opcode, IS_OPCODE); return 4; } n++; } // I-Type? [ op 6, rs 5, rt 5, imm 16 ] n = 0; while(mips_i_table[n].instr != NULL) { if (strcmp(instr_case, mips_i_table[n].instr) == 0) { char shift_table[] = { 0, 0, 21, 16 }; if (mips_i_table[n].operand_count != operand_count) { print_error_opcount(instr, asm_context); return -1; } opcode = mips_i_table[n].function << 26; for (r = 0; r < mips_i_table[n].operand_count; r++) { if ((mips_i_table[n].operand[r] == MIPS_OP_RT || mips_i_table[n].operand[r] == MIPS_OP_RS) && operands[r].type == OPERAND_TREG) { opcode |= operands[r].value << shift_table[(int)mips_i_table[n].operand[r]]; } else if (mips_i_table[n].operand[r] == MIPS_OP_LABEL) { // FIXME - Calculate address //if (operands[r].value > 65535 || operands[r].value < -32768) //{ // print_error("Constant larger than 16 bit.", asm_context); // return -1; //} opcode |= operands[r].value; } else if (mips_i_table[n].operand[r] == MIPS_OP_IMMEDIATE) { if (operands[r].value > 65535 || operands[r].value < -32768) { print_error("Constant larger than 16 bit.", asm_context); return -1; } opcode |= operands[r].value; } else if (mips_i_table[n].operand[r] == MIPS_OP_IMMEDIATE_RS) { if (operands[r].value > 65535 || operands[r].value < -32768) { print_error("Constant larger than 16 bit.", asm_context); return -1; } opcode |= operands[r].value; opcode |= operands[r].reg2 << 21; } else if (mips_i_table[n].operand[r] == MIPS_OP_RT_IS_0) { // Derr } else if (mips_i_table[n].operand[r] == MIPS_OP_RT_IS_1) { opcode |= 1 << 16; } else { print_error_illegal_operands(instr, asm_context); return -1; } opcode |= operands[r].value << shift_table[(int)mips_i_table[n].operand[r]]; } add_bin32(asm_context, opcode, IS_OPCODE); return 4; } n++; } print_error_unknown_instr(instr, asm_context); return -1; }
int parse_db(struct _asm_context *asm_context, int null_term_flag) { char token[TOKENLEN]; int token_type; int data32; if (asm_context->segment==SEGMENT_BSS) { printf("Error: .bss segment doesn't support initialized data at %s:%d\n", asm_context->filename, asm_context->line); return -1; } while(1) { token_type=get_token(asm_context, token, TOKENLEN); if (token_type==TOKEN_EOL || token_type==TOKEN_EOF) break; if (token_type==TOKEN_QUOTED) { unsigned char *s=(unsigned char *)token; while(*s!=0) { if (*s=='\\') { int e=escape_char(asm_context, s); if (e==0) { return -1; } s=s+e; } memory_write_inc(asm_context, *s, DL_DATA); asm_context->data_count++; s++; } if (null_term_flag==1) { memory_write_inc(asm_context, 0, DL_DATA); asm_context->data_count++; } } else { pushback(asm_context, token, token_type); if (eval_expression(asm_context, &data32)==-1) { eat_operand(asm_context); } memory_write_inc(asm_context, (unsigned char)data32, DL_DATA); asm_context->data_count++; } token_type=get_token(asm_context, token, TOKENLEN); if (token_type==TOKEN_EOL || token_type==TOKEN_EOF) break; if (IS_NOT_TOKEN(token,',')) { printf("Parse error: expecting a ',' on line %d.\n", asm_context->line); return -1; } } asm_context->line++; return 0; }
int parse_instruction_65xx(struct _asm_context *asm_context, char *instr) { char token[TOKENLEN]; char instr_case[TOKENLEN]; char temp[80]; int token_type; int opcode; int mode; int num; int index; int i; // make lower case lower_copy(instr_case, instr); // get instruction index index = -1; for(i = 0; i < 56; i++) { if(strcmp(instr_case, opcodes_65xx[i].name) == 0) { index = i; break; } } // no instruction found if(index == -1) { print_error_unexp(token, asm_context); return -1; } // default mode = MODE_IMPLIED; // begin parsing token_type=get_token(asm_context, token, TOKENLEN); if (token_type==TOKEN_EOL) { goto skip; } if(IS_TOKEN(token, '#')) { mode = MODE_IMMEDIATE; if(eval_expression(asm_context, &num) != 0) { if(asm_context->pass == 1) { eat_operand(asm_context); } else { print_error_unexp(token, asm_context); return -1; } } num = (unsigned char)num; if(num < 0 || num > 0xFF) print_error_unexp(token, asm_context); } else if(IS_TOKEN(token, '(')) { mode = MODE_INDIRECT; if(eval_expression(asm_context, &num) != 0) { if(asm_context->pass == 1) { eat_operand(asm_context); } else { print_error_unexp(token, asm_context); return -1; } } token_type = get_token(asm_context, token, TOKENLEN); if (token_type==TOKEN_EOL) { goto skip; } if(IS_TOKEN(token, ',')) { if(num < 0 || num > 0xFF) { print_error("X-Indexed Indirect value out of range", asm_context); return -1; } mode = MODE_X_INDEXED_INDIRECT; token_type = get_token(asm_context, token, TOKENLEN); if (token_type==TOKEN_EOL) { goto skip; } if(IS_NOT_TOKEN(token, 'x') && IS_NOT_TOKEN(token, 'X')) { print_error_unexp(token, asm_context); return -1; } token_type = get_token(asm_context, token, TOKENLEN); if (token_type==TOKEN_EOL) { goto skip; } if(IS_NOT_TOKEN(token, ')')) { print_error_unexp(token, asm_context); return -1; } } else if(IS_TOKEN(token, ')')) { mode = MODE_INDIRECT; token_type = get_token(asm_context, token, TOKENLEN); if (token_type==TOKEN_EOL) { goto skip; } if(IS_TOKEN(token, ',')) { if(num < 0 || num > 0xFF) { print_error("Indirect Y-Indexed value out of range", asm_context); return -1; } mode = MODE_INDIRECT_Y_INDEXED; token_type = get_token(asm_context, token, TOKENLEN); if (token_type==TOKEN_EOL) { goto skip; } if(IS_NOT_TOKEN(token, 'y') && IS_NOT_TOKEN(token, 'Y')) { print_error_unexp(token, asm_context); return -1; } token_type = get_token(asm_context, token, TOKENLEN); } } } else { pushback(asm_context, token, token_type); if(eval_expression(asm_context, &num) != 0) { if(asm_context->pass == 1) { eat_operand(asm_context); } else { print_error_unexp(token, asm_context); return -1; } } // try zero page if((num >= 0x01 && num <= 0xFF) && opcodes_65xx[index].opcode[MODE_ZEROPAGE] != 0xFF) { mode = MODE_ZEROPAGE; } else { mode = MODE_ABSOLUTE; } token_type = get_token(asm_context, token, TOKENLEN); if (token_type==TOKEN_EOL) { goto skip; } if(IS_TOKEN(token, ',')) { token_type = get_token(asm_context, token, TOKENLEN); if (token_type==TOKEN_EOL) { goto skip; } if(IS_TOKEN(token, 'x') || IS_TOKEN(token, 'X')) { if((num >= 0x00 && num <= 0xFF) && opcodes_65xx[index].opcode[MODE_ZEROPAGE_X_INDEXED] != 0xFF) { mode = MODE_ZEROPAGE_X_INDEXED; } else { mode = MODE_ABSOLUTE_X_INDEXED; } } else if(IS_TOKEN(token, 'y') || IS_TOKEN(token, 'Y')) { if((num >= 0x00 && num <= 0xFF) && opcodes_65xx[index].opcode[MODE_ZEROPAGE_Y_INDEXED] != 0xFF) { mode = MODE_ZEROPAGE_Y_INDEXED; } else { mode = MODE_ABSOLUTE_Y_INDEXED; } } else { print_error_unexp(token, asm_context); return -1; } } if(num < 0 || num > 0xFFFF) { print_error("Address out of range", asm_context); return -1; } } skip: // branches are in table positions 3 - 10 if(index >= 3 && index <= 10) { if(mode == MODE_IMMEDIATE) { mode = MODE_RELATIVE; num = (unsigned char)num; } else { mode = MODE_RELATIVE; if(asm_context->pass == 2) { // calculate branch offset, need to add 2 to current // address, since thats where the program counter would be num -= (asm_context->address + 2); if(num < -128 || num > 127) { print_error("Branch out of range", asm_context); return -1; } num = (unsigned char)num; } } } // see if theres an opcode for this instruction and mode opcode = opcodes_65xx[index].opcode[mode]; if(asm_context->pass == 2 && opcode == 0xFF) { sprintf(temp, "No instruction found for addressing mode %d", mode); print_error(temp, asm_context); return -1; } // warn if indirect JMP bug will happen if((opcode == 0x6C) && ((num & 0xFF) == 0xFF)) { print_error("Warning: Indirect JMP to upper page boundary (6502 bug)", asm_context); } //printf("address=%04x, num=%04x\n", asm_context->address, num); // write opcode //printf("%04x, %02x\n", asm_context->address, opcode & 0xFF); add_bin8(asm_context, opcode & 0xFF, IS_OPCODE); // write low byte first, if any if(mode_bytes[mode] > 1) { //printf("%04x, %02x\n", asm_context->address, num & 0xFF); add_bin8(asm_context, num & 0xFF, IS_OPCODE); } // then high byte, if any if(mode_bytes[mode] > 2) { //printf("%04x, %02x\n", asm_context->address, (num >> 8) & 0xFF); add_bin8(asm_context, (num >> 8) & 0xFF, IS_OPCODE); }
int parse_instruction_6800(struct _asm_context *asm_context, char *instr) { char token[TOKENLEN]; int token_type; char instr_case[TOKENLEN]; int operand_type; int operand_value; int address_size = 0; int opcode = -1; int n; lower_copy(instr_case, instr); do { token_type = tokens_get(asm_context, token, TOKENLEN); if (token_type == TOKEN_EOL || token_type == TOKEN_EOF) { operand_type = OPERAND_NONE; break; } if (token_type == TOKEN_POUND) { operand_type = OPERAND_NUMBER; if (eval_expression(asm_context, &operand_value) != 0) { if (asm_context->pass == 2) { print_error_illegal_expression(instr, asm_context); return -1; } eat_operand(asm_context); operand_value = 0xffff; } } else { operand_type = OPERAND_ADDRESS; tokens_push(asm_context, token, token_type); if (eval_expression(asm_context, &operand_value) != 0) { if (asm_context->pass == 2) { print_error_illegal_expression(instr, asm_context); return -1; } eat_operand(asm_context); operand_value = 0xffff; } token_type = tokens_get(asm_context, token, TOKENLEN); if (token_type == TOKEN_EOL || token_type == TOKEN_EOF) { break; } if (IS_NOT_TOKEN(token, ',')) { print_error_unexp(token, asm_context); return -1; } if (expect_token_s(asm_context, "x") != 0) { return -1; } operand_type = OPERAND_ADDRESS_COMMA_X; } } while(0); for (n = 0; n < 256; n++) { if (table_6800[n].instr == NULL) { continue; } if (strcmp(instr_case, table_6800[n].instr) == 0) { if (table_6800[n].operand_type == M6800_OP_NONE && operand_type == OPERAND_NONE) { add_bin8(asm_context, n, IS_OPCODE); return 1; } else if (table_6800[n].operand_type == M6800_OP_REL_OFFSET && operand_type == OPERAND_ADDRESS) { int offset = operand_value - (asm_context->address + 2); if (asm_context->pass != 1) { if (offset < -128 || offset > 127) { print_error_range("Offset", -128, 127, asm_context); return -1; } } add_bin8(asm_context, n, IS_OPCODE); add_bin8(asm_context, offset & 0xff, IS_OPCODE); return 1; } else if (table_6800[n].operand_type == M6800_OP_IMM16 && operand_type == OPERAND_NUMBER) { add_bin8(asm_context, n, IS_OPCODE); add_bin8(asm_context, operand_value >> 8, IS_OPCODE); add_bin8(asm_context, operand_value & 0xff, IS_OPCODE); return 3; } else if (table_6800[n].operand_type == M6800_OP_IMM8 && operand_type == OPERAND_NUMBER) { if (asm_context->pass != 1) { if (operand_value < -128 || operand_value > 255) { print_error_range("Offset", -128, 255, asm_context); return -1; } } add_bin8(asm_context, n, IS_OPCODE); add_bin8(asm_context, operand_value & 0xff, IS_OPCODE); return 2; } else if (table_6800[n].operand_type == M6800_OP_NN_X && operand_type == OPERAND_ADDRESS_COMMA_X) { int offset = operand_value-(asm_context->address + 2); if (asm_context->pass != 1) { if (offset < -128 || offset > 127) { print_error_range("Offset", -128, 127, asm_context); return -1; } } add_bin8(asm_context, n, IS_OPCODE); add_bin8(asm_context, offset & 0xff, IS_OPCODE); return 2; } else if (table_6800[n].operand_type == M6800_OP_DIR_PAGE_8 && operand_type == OPERAND_ADDRESS) { if (asm_context->pass == 1) { if (address_size == 0 && (operand_value >= 0 && operand_value <= 255)) { address_size = 1; opcode = n; } } if (memory_read_m(&asm_context->memory, asm_context->address) == 1) { add_bin8(asm_context, n, IS_OPCODE); add_bin8(asm_context, operand_value, IS_OPCODE); return 2; } } else if (table_6800[n].operand_type == M6800_OP_ABSOLUTE_16 && operand_type == OPERAND_ADDRESS) { if (asm_context->pass == 1) { if (address_size == 0) { address_size = 2; opcode=n; } } if (memory_read_m(&asm_context->memory, asm_context->address)==2) { add_bin8(asm_context, n, IS_OPCODE); add_bin8(asm_context, operand_value >> 8, IS_OPCODE); add_bin8(asm_context, operand_value & 0xff, IS_OPCODE); return 2; } }
int parse_instruction_thumb(struct _asm_context *asm_context, char *instr) { char token[TOKENLEN]; int token_type; char instr_case[TOKENLEN]; struct _operand operands[3]; int operand_count=0; int matched=0; int num; int n; lower_copy(instr_case, instr); memset(&operands, 0, sizeof(operands)); while(1) { token_type=tokens_get(asm_context, token, TOKENLEN); if (token_type==TOKEN_EOL || token_type==TOKEN_EOF) { break; } if (operand_count>=3) { print_error_opcount(instr, asm_context); return -1; } if ((num=get_register_thumb(token))!=-1) { operands[operand_count].type=OPERAND_REGISTER; operands[operand_count].value=num; token_type=tokens_get(asm_context, token, TOKENLEN); if (IS_TOKEN(token,'!')) { operands[operand_count].type=OPERAND_REGISTER_INC; } else { tokens_push(asm_context, token, token_type); } } else if ((num=get_h_register_thumb(token))!=-1) { operands[operand_count].type=OPERAND_H_REGISTER; operands[operand_count].value=num; } else if (token_type==TOKEN_POUND) { if (eval_expression(asm_context, &num)!=0) { if (asm_context->pass==1) { eat_operand(asm_context); } else { print_error_illegal_expression(instr, asm_context); return -1; } } operands[operand_count].type=OPERAND_NUMBER; operands[operand_count].value=num; } else if (IS_TOKEN(token,'[')) { token_type=tokens_get(asm_context, token, TOKENLEN); if (strcasecmp(token,"pc")==0 || strcasecmp(token,"r15")==0) { operands[operand_count].type=OPERAND_PC_AND_REG_IN_BRACKETS; } else if (strcasecmp(token,"sp")==0 || strcasecmp(token,"r13")==0) { operands[operand_count].type=OPERAND_SP_AND_REG_IN_BRACKETS; } else if ((num=get_register_thumb(token))!=-1) { operands[operand_count].type=OPERAND_TWO_REG_IN_BRACKETS; operands[operand_count].value=num; } else { print_error_unexp(token, asm_context); return -1; } if (expect_token_s(asm_context,",")!=0) { return -1; } token_type=tokens_get(asm_context, token, TOKENLEN); if ((num=get_register_thumb(token))!=-1) { operands[operand_count].second_value=num; if (operands[operand_count].type==OPERAND_PC_AND_NUM_IN_BRACKETS) { operands[operand_count].type=OPERAND_PC_AND_REG_IN_BRACKETS; } } else if (token_type==TOKEN_POUND) { if (eval_expression(asm_context, &num)!=0) { if (asm_context->pass==1) { eat_operand(asm_context); } else { print_error_illegal_expression(instr, asm_context); return -1; } } operands[operand_count].second_value=num; operands[operand_count].type++; } else { print_error_unexp(token, asm_context); return -1; } if (expect_token_s(asm_context,"]")!=0) { return -1; } } else if (IS_TOKEN(token,'{')) { operands[operand_count].type=OPERAND_REGISTER_LIST; if (read_register_list(asm_context, &operands[operand_count])==-1) { return -1; } } else { tokens_push(asm_context, token, token_type); if (eval_expression(asm_context, &num)!=0) { if (asm_context->pass==1) { eat_operand(asm_context); } else { print_error_illegal_expression(instr, asm_context); return -1; } } operands[operand_count].value=num; operands[operand_count].type=OPERAND_ADDRESS; } operand_count++; token_type=tokens_get(asm_context, token, TOKENLEN); if (token_type==TOKEN_EOL) break; if (IS_NOT_TOKEN(token,',') || operand_count==3) { print_error_unexp(token, asm_context); return -1; } } n=0; while(table_thumb[n].instr!=NULL) { if (strcmp(table_thumb[n].instr,instr_case)==0) { matched=1; switch(table_thumb[n].type) { case OP_SHIFT: if (operand_count==3 && operands[0].type==OPERAND_REGISTER && operands[1].type==OPERAND_REGISTER && operands[2].type==OPERAND_NUMBER) { if (check_reg_lower(asm_context, operands[0].value)==-1) { return -1; } if (check_reg_lower(asm_context, operands[1].value)==-1) { return -1; } if (check_range(asm_context, "Offset", operands[2].value, 0, 31)==-1) { return -1; } #if 0 if (operands[2].value<0 || operands[2].value>31) { print_error_range("Offset", 0, 31, asm_context); return -1; } #endif add_bin16(asm_context, table_thumb[n].opcode|(operands[2].value<<6)|(operands[1].value<<3)|(operands[0].value), IS_OPCODE); return 2; } break; case OP_ADD_SUB: if (operand_count==3 && operands[0].type==OPERAND_REGISTER && operands[1].type==OPERAND_REGISTER && operands[2].type==OPERAND_REGISTER) { add_bin16(asm_context, table_thumb[n].opcode|(operands[2].value<<6)|(operands[1].value<<3)|(operands[0].value), IS_OPCODE); return 2; } else if (operand_count==3 && operands[0].type==OPERAND_REGISTER && operands[1].type==OPERAND_REGISTER && operands[2].type==OPERAND_NUMBER) { add_bin16(asm_context, table_thumb[n].opcode|(1<<10)|(operands[2].value<<6)|(operands[1].value<<3)|(operands[0].value), IS_OPCODE); return 2; } break; case OP_IMM: if (operand_count==2 && operands[0].type==OPERAND_REGISTER && operands[1].type==OPERAND_NUMBER) { add_bin16(asm_context, table_thumb[n].opcode|(operands[0].value<<8)|(operands[1].value), IS_OPCODE); return 2; } break; case OP_ALU: if (operand_count==2 && operands[0].type==OPERAND_REGISTER && operands[1].type==OPERAND_REGISTER) { add_bin16(asm_context, table_thumb[n].opcode|(operands[1].value<<3)|(operands[0].value), IS_OPCODE); return 2; } break; case OP_HI: if (operand_count==2) { if (operands[0].type==OPERAND_H_REGISTER && operands[1].type==OPERAND_REGISTER) { add_bin16(asm_context, table_thumb[n].opcode|(1<<7)|(operands[1].value<<3)|(operands[0].value), IS_OPCODE); return 2; } else if (operands[0].type==OPERAND_REGISTER && operands[1].type==OPERAND_H_REGISTER) { add_bin16(asm_context, table_thumb[n].opcode|(1<<6)|(operands[1].value<<3)|(operands[0].value), IS_OPCODE); return 2; } else if (operands[0].type==OPERAND_H_REGISTER && operands[1].type==OPERAND_H_REGISTER) { add_bin16(asm_context, table_thumb[n].opcode|(1<<7)|(1<<6)|(operands[1].value<<3)|(operands[0].value), IS_OPCODE); return 2; } } break; case OP_HI_BX: if (operand_count==1 && operands[0].type==OPERAND_REGISTER) { add_bin16(asm_context, table_thumb[n].opcode|(operands[0].value<<3), IS_OPCODE); return 2; } else if (operand_count==1 && operands[0].type==OPERAND_H_REGISTER) { add_bin16(asm_context, table_thumb[n].opcode|(1<<6)|(operands[0].value<<3), IS_OPCODE); return 2; } break; case OP_PC_RELATIVE_LOAD: // REVIEW - Docs say this is a 10 bit, 4 byte aligned number // and it seems unsigned. Why isn't this signed? if (operand_count==2 && operands[0].type==OPERAND_REGISTER && operands[1].type==OPERAND_PC_AND_NUM_IN_BRACKETS) { if (check_range(asm_context, "Offset", operands[1].second_value, 0, 1020)==-1) { return -1; } if (is_4_byte_aligned(asm_context, operands[1].second_value)==-1) { return -1; } #if 0 if ((operands[1].second_value&0x3)!=0) { print_error("Offset not 4 byte aligned", asm_context); return -1; } #endif add_bin16(asm_context, table_thumb[n].opcode|(operands[0].value<<8)|(operands[1].second_value>>2), IS_OPCODE); return 2; } if (operand_count==2 && operands[0].type==OPERAND_REGISTER && operands[1].type==OPERAND_ADDRESS) { // REVIEW: This looks so odd. Docs say: The value of the PC will // be 4 bytes greater than the address of this instruction, but bit // 1 of the PC is forced to 0 to ensure it is word aligned. if (is_4_byte_aligned(asm_context, operands[1].value)==-1) { return -1; } #if 0 if ((operands[1].value&0x3)!=0) { print_error("Offset not 4 byte aligned", asm_context); return -1; } #endif int offset=operands[1].value-((asm_context->address+4)&0xfffffffc); if (asm_context->pass==1) { offset=0; } if (check_range(asm_context, "Offset", offset, 0, 1020)==-1) { return -1; } #if 0 if (offset<0 || offset>1020) { print_error_range("Offset", 0, 1020, asm_context); return -1; } #endif add_bin16(asm_context, table_thumb[n].opcode|(operands[0].value<<8)|(offset>>2), IS_OPCODE); return 2; } break; case OP_LOAD_STORE: if (operand_count==2 && operands[0].type==OPERAND_REGISTER && operands[1].type==OPERAND_TWO_REG_IN_BRACKETS) { add_bin16(asm_context, table_thumb[n].opcode|(operands[1].second_value<<6)|(operands[1].value<<3)|(operands[0].value), IS_OPCODE); return 2; } break; case OP_LOAD_STORE_SIGN_EXT_HALF_WORD: if (operand_count==2 && operands[0].type==OPERAND_REGISTER && operands[1].type==OPERAND_TWO_REG_IN_BRACKETS) { add_bin16(asm_context, table_thumb[n].opcode|(operands[1].second_value<<6)|(operands[1].value<<3)|(operands[0].value), IS_OPCODE); return 2; } break; case OP_LOAD_STORE_IMM_OFFSET_WORD: if (operand_count==2 && operands[0].type==OPERAND_REGISTER && operands[1].type==OPERAND_REG_AND_NUM_IN_BRACKETS) { int offset=operands[1].second_value; if (check_range(asm_context, "Offset", offset, 0, 124)==-1) { return -1; } if (is_4_byte_aligned(asm_context, offset)==-1) { return -1; } #if 0 if ((offset&0x3)!=0) { print_error("Offset not 4 byte aligned", asm_context); return -1; } #endif offset=offset>>2; add_bin16(asm_context, table_thumb[n].opcode|(offset<<6)|(operands[1].value<<3)|(operands[0].value), IS_OPCODE); return 2; } break; case OP_LOAD_STORE_IMM_OFFSET: if (operand_count==2 && operands[0].type==OPERAND_REGISTER && operands[1].type==OPERAND_REG_AND_NUM_IN_BRACKETS) { if (check_range(asm_context, "Offset", operands[1].second_value, 0, 31)==-1) { return -1; } add_bin16(asm_context, table_thumb[n].opcode|(operands[1].second_value<<6)|(operands[1].value<<3)|(operands[0].value), IS_OPCODE); return 2; } break; case OP_LOAD_STORE_IMM_OFFSET_HALF_WORD: if (operand_count==2 && operands[0].type==OPERAND_REGISTER && operands[1].type==OPERAND_REG_AND_NUM_IN_BRACKETS) { int offset=operands[1].second_value; if (check_range(asm_context, "Offset", offset, 0, 60)==-1) { return -1; } if (is_2_byte_aligned(asm_context, offset)==-1) { return -1; } #if 0 if ((offset&0x1)!=0) { print_error("Offset not 2 byte aligned", asm_context); return -1; } #endif offset=offset>>1; add_bin16(asm_context, table_thumb[n].opcode|(offset<<6)|(operands[1].value<<3)|(operands[0].value), IS_OPCODE); return 2; } break; case OP_LOAD_STORE_SP_RELATIVE: if (operand_count==2 && operands[0].type==OPERAND_REGISTER && operands[1].type==OPERAND_SP_AND_NUM_IN_BRACKETS) { if (check_range(asm_context, "Offset", operands[1].value, 0, 1020)==-1) { return -1; } if (is_4_byte_aligned(asm_context, operands[1].value)==-1) { return -1; } add_bin16(asm_context, table_thumb[n].opcode|(operands[0].value<<8)|(operands[1].second_value>>2), IS_OPCODE); return 2; } break; case OP_LOAD_ADDRESS: if (operand_count==3 && operands[0].type==OPERAND_REGISTER && operands[1].type==OPERAND_H_REGISTER && operands[2].type==OPERAND_NUMBER) { if (check_range(asm_context, "Offset", operands[2].value, 0, 1020)==-1) { return -1; } if (is_4_byte_aligned(asm_context, operands[2].value)==-1) { return -1; } if (operands[1].value==7) { add_bin16(asm_context, table_thumb[n].opcode|(operands[0].value<<8)|(operands[2].value>>2), IS_OPCODE); return 2; } else if (operands[1].value==5)
static int read_register_list(struct _asm_context *asm_context, struct _operand *operand) { int token_type; char token[TOKENLEN]; int reg_start,reg_end; while(1) { tokens_get(asm_context, token, TOKENLEN); if ((strcasecmp(token,"lr")==0 || strcasecmp(token,"r14")==0) && operand->second_value==0) { operand->second_value=1; } else if ((strcasecmp(token,"pc")==0 || strcasecmp(token,"r15")==0) && operand->second_value==0) { operand->second_value=2; } else if ((reg_start=get_register_thumb(token))!=-1) { token_type=tokens_get(asm_context, token, TOKENLEN); if (IS_TOKEN(token,'-')) { tokens_get(asm_context, token, TOKENLEN); if ((reg_end=get_register_thumb(token))==-1 || reg_end<reg_start) { print_error_unexp(token, asm_context); return -1; } while(reg_start<=reg_end) { operand->value|=1<<reg_start; reg_start++; } } else { operand->value|=1<<reg_start; tokens_push(asm_context, token, token_type); } } else { print_error_unexp(token, asm_context); return -1; } tokens_get(asm_context, token, TOKENLEN); if (IS_TOKEN(token,'}')) { break; } else if (IS_NOT_TOKEN(token,',')) { print_error_unexp(token, asm_context); return -1; } } return 0; }