Ejemplo n.º 1
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);
  }
Ejemplo n.º 2
0
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;
        }
      }