コード例 #1
0
ファイル: 6800.c プロジェクト: mikeakohn/naken_asm
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;
        }
      }
コード例 #2
0
ファイル: thumb.c プロジェクト: asteadman/naken_asm
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)