int parse_dc16(struct _asm_context *asm_context) { char token[TOKENLEN]; int token_type; int data32; uint16_t data16; 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) { // if the user has a comma at the end, but no data, this is okay token_type = tokens_get(asm_context, token, TOKENLEN); if (token_type == TOKEN_EOL || token_type == TOKEN_EOF) break; 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 < -32768 || data32 > 0xffff) { print_error_range("dc16", -32768, 0xffff, asm_context); return -1; } data16 = (uint16_t)data32; if (asm_context->memory.endian == ENDIAN_LITTLE) { memory_write_inc(asm_context, data16 & 255, DL_DATA); memory_write_inc(asm_context, data16 >> 8, DL_DATA); } else {
int assemble(struct _asm_context *asm_context) { char token[TOKENLEN]; int token_type; while(1) { token_type = tokens_get(asm_context, token, TOKENLEN); #ifdef DEBUG printf("%d: <%d> %s\n", asm_context->line, token_type, token); #endif if (token_type == TOKEN_EOF) break; if (token_type == TOKEN_EOL) { if (asm_context->macros.stack_ptr == 0) { asm_context->line++; } } else if (token_type == TOKEN_LABEL) { int param_count_temp; if (macros_lookup(&asm_context->macros, token, ¶m_count_temp) != NULL) { print_already_defined(asm_context, token); return -1; } if (symbols_append(&asm_context->symbols, token, asm_context->address / asm_context->bytes_per_address) == -1) { return -1; } } else if (token_type == TOKEN_POUND || IS_TOKEN(token,'.')) { token_type = tokens_get(asm_context, token, TOKENLEN); #ifdef DEBUG printf("%d: <%d> %s\n", asm_context->line, token_type, token); #endif if (token_type == TOKEN_EOF) break; if (strcasecmp(token, "define") == 0) { if (macros_parse(asm_context, IS_DEFINE) != 0) return -1; } else if (strcasecmp(token, "ifdef") == 0) { parse_ifdef(asm_context, 0); } else if (strcasecmp(token, "ifndef") == 0) { parse_ifdef(asm_context, 1); } else if (strcasecmp(token, "if") == 0) { parse_if(asm_context); } else if (strcasecmp(token, "endif") == 0) { if (asm_context->ifdef_count < 1) { printf("Error: unmatched .endif at %s:%d\n", asm_context->filename, asm_context->ifdef_count); return -1; } return 0; } else if (strcasecmp(token, "else") == 0) { if (asm_context->ifdef_count < 1) { printf("Error: unmatched .else at %s:%d\n", asm_context->filename, asm_context->ifdef_count); return -1; } return 2; } else if (strcasecmp(token, "include") == 0) { if (parse_include(asm_context) != 0) return -1; } else if (strcasecmp(token, "binfile") == 0) { if (parse_binfile(asm_context) != 0) return -1; } else if (strcasecmp(token, "code") == 0) { asm_context->segment = SEGMENT_CODE; } else if (strcasecmp(token, "bss") == 0) { asm_context->segment = SEGMENT_BSS; } else if (strcasecmp(token, "msp430_cpu4") == 0) { asm_context->msp430_cpu4 = 1; } else if (strcasecmp(token, "macro") == 0) { if (macros_parse(asm_context, IS_MACRO) != 0) return -1; } else if (strcasecmp(token, "pragma") == 0) { if (parse_pragma(asm_context) != 0) return -1; } else if (strcasecmp(token, "device") == 0) { if (parse_device(asm_context) != 0) return -1; } else if (strcasecmp(token, "set") == 0) { if (parse_set(asm_context) != 0) return -1; } else if (strcasecmp(token, "export") == 0) { if (parse_export(asm_context) != 0) return -1; } else if (strcasecmp(token, "equ") == 0 || strcasecmp(token, "def")==0) { if (parse_equ(asm_context) != 0) return -1; } else { int ret = check_for_directive(asm_context, token); if (ret == 2) break; if (ret == -1) return -1; if (ret != 1) { printf("Error: Unknown directive '%s' at %s:%d.\n", token, asm_context->filename, asm_context->line); return -1; } } } else if (token_type == TOKEN_STRING) { int ret = check_for_directive(asm_context, token); if (ret == 2) break; if (ret == -1) return -1; if (ret != 1) { int start_address = asm_context->address; char token2[TOKENLEN]; int token_type2; token_type2 = tokens_get(asm_context, token2, TOKENLEN); if (strcasecmp(token2, "equ") == 0) { //token_type2 = tokens_get(asm_context, token2, TOKENLEN); int ptr = 0; int ch = '\n'; while(1) { ch = tokens_get_char(asm_context); if (ch == EOF || ch == '\n') break; if (ch == '*' && ptr > 0 && token2[ptr-1] == '/') { macros_strip_comment(asm_context); ptr--; continue; } token2[ptr++] = ch; if (ptr == TOKENLEN-1) { printf("Internal Error: token overflow at %s:%d.\n", __FILE__, __LINE__); return -1; } } token2[ptr] = 0; tokens_unget_char(asm_context, ch); macros_strip(token2); macros_append(asm_context, token, token2, 0); } else { tokens_push(asm_context, token2, token_type2); ret = asm_context->parse_instruction(asm_context, token); if (asm_context->pass == 2 && asm_context->list != NULL && asm_context->include_count == 0) { asm_context->list_output(asm_context, start_address); fprintf(asm_context->list, "\n"); } if (ret < 0) return -1; if (asm_context->macros.stack_ptr == 0) { asm_context->line++; } asm_context->instruction_count++; if (asm_context->address > start_address) { asm_context->code_count += (asm_context->address - start_address); } } } } else { print_error_unexp(token, asm_context); return -1; } } if (asm_context->error == 1) { 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; }
static int eval_expression_go(struct _asm_context *asm_context, struct _var *var, struct _operator *last_operator) { char token[TOKENLEN]; int token_type; struct _var var_stack[3]; int var_stack_ptr = 1; struct _operator operator; int last_token_was_op = -1; #ifdef DEBUG printf("Enter eval_expression_go, var=%d/%f/%d\n", var_get_int32(var), var_get_float(var), var_get_type(var)); #endif memcpy(&operator, last_operator, sizeof(struct _operator)); VAR_COPY(&var_stack[0], var); while(1) { #ifdef DEBUG printf("eval_expression> going to grab a token\n"); #endif token_type = tokens_get(asm_context, token, TOKENLEN); #ifdef DEBUG printf("eval_expression> token=%s var_stack_ptr=%d\n", token, var_stack_ptr); #endif // Issue 15: Return an error if a stack is full with noe operator. if (var_stack_ptr == 3 && operator.operation == OPER_UNSET) { return -1; } if (token_type == TOKEN_QUOTED) { if (token[0] == '\\') { int e = tokens_escape_char(asm_context, (unsigned char *)token); if (e == 0) return -1; if (token[e+1] != 0) { print_error("Quoted literal too long.", asm_context); return -1; } sprintf(token, "%d", token[e]); } else { if (token[1]!=0) { print_error("Quoted literal too long.", asm_context); return -1; } sprintf(token, "%d", token[0]); } token_type = TOKEN_NUMBER; } // Open and close parenthesis if (IS_TOKEN(token,'(')) { if (last_token_was_op == 0 && operator.operation != OPER_UNSET) { operate(&var_stack[var_stack_ptr-2], &var_stack[var_stack_ptr-1], last_operator); var_stack_ptr--; operator.operation = OPER_UNSET; VAR_COPY(var, &var_stack[var_stack_ptr-1]); tokens_push(asm_context, token, token_type); return 0; } if (operator.operation == OPER_UNSET && var_stack_ptr == 2) { // This is probably the x(r12) case.. so this is actually okay VAR_COPY(var, &var_stack[var_stack_ptr-1]); tokens_push(asm_context, token, token_type); return 0; } struct _var paren_var; struct _operator paren_operator; paren_operator.precedence = PREC_UNSET; paren_operator.operation = OPER_UNSET; memset(&paren_var, 0, sizeof(struct _var)); if (eval_expression_go(asm_context, &paren_var, &paren_operator) != 0) { return -1; } last_token_was_op = 0; #ifdef DEBUG printf("Paren got back %d/%f/%d\n", var_get_int32(&paren_var), var_get_float(&paren_var), var_get_type(&paren_var)); #endif VAR_COPY(&var_stack[var_stack_ptr++], &paren_var); token_type = tokens_get(asm_context, token, TOKENLEN); if (!(token[1] == 0 && token[0] == ')')) { print_error("No matching ')'", asm_context); return -1; } continue; } if (IS_TOKEN(token,')')) { tokens_push(asm_context, token, token_type); break; } // End of expression if (IS_TOKEN(token,',') || IS_TOKEN(token,']') || token_type == TOKEN_EOF || IS_TOKEN(token,'.')) { tokens_push(asm_context, token, token_type); break; } if (token_type == TOKEN_EOL) { //asm_context->tokens.line++; tokens_push(asm_context, token, token_type); break; } // Read number if (token_type == TOKEN_NUMBER) { last_token_was_op = 0; if (var_stack_ptr == 3) { print_error_unexp(token, asm_context); return -1; } var_set_int(&var_stack[var_stack_ptr++], atoll(token)); } else if (token_type == TOKEN_FLOAT) { if (var_stack_ptr == 3) { print_error_unexp(token, asm_context); return -1; } var_set_float(&var_stack[var_stack_ptr++], atof(token)); } else if (token_type == TOKEN_SYMBOL) { last_token_was_op = 1; struct _operator operator_prev; memcpy(&operator_prev, &operator, sizeof(struct _operator)); if (get_operator(token, &operator) == -1) { print_error_unexp(token, asm_context); return -1; } // Issue 15: 2015-July-21 mkohn - If operator is ~ then reverse // the next number. if (operator.operation == OPER_NOT) { int64_t num; if (parse_unary(asm_context, &num, OPER_NOT) != 0) { return -1; } if (var_stack_ptr == 3) { print_error_unexp(token, asm_context); return -1; } var_set_int(&var_stack[var_stack_ptr++], num); memcpy(&operator, &operator_prev, sizeof(struct _operator)); last_token_was_op = 0; continue; } // Stack pointer probably shouldn't be less than 2 if (var_stack_ptr == 0) { printf("Error: Unexpected operator '%s' at %s:%d\n", token, asm_context->tokens.filename, asm_context->tokens.line); return -1; } #ifdef DEBUG printf("TOKEN %s: precedence %d %d\n", token, last_operator->precedence, operator.precedence); #endif if (last_operator->precedence == PREC_UNSET) { memcpy(last_operator, &operator, sizeof(struct _operator)); } else if (last_operator->precedence > operator.precedence) { if (eval_expression_go(asm_context, &var_stack[var_stack_ptr-1], &operator) == -1) { return -1; } } else { operate(&var_stack[var_stack_ptr-2], &var_stack[var_stack_ptr-1], last_operator); var_stack_ptr--; memcpy(last_operator, &operator, sizeof(struct _operator)); } } else { if (asm_context->pass != 1) { print_error_unexp(token, asm_context); } return -1; } } #ifdef DEBUG printf("going to leave operation=%d\n", last_operator->operation); PRINT_STACK() #endif if (last_operator->operation != OPER_UNSET) { operate(&var_stack[var_stack_ptr-2], &var_stack[var_stack_ptr-1], last_operator); var_stack_ptr--; } VAR_COPY(var, &var_stack[var_stack_ptr-1]); 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_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; }