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; } }