kolibrios/contrib/toolchain/avra/src/mnemonic.c

794 lines
29 KiB
C
Raw Normal View History

/***********************************************************************
*
* avra - Assembler for the Atmel AVR microcontroller series
*
* Copyright (C) 1998-2004 Jon Anders Haugum, Tobias Weber
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*
* Authors of avra can be reached at:
* email: jonah@omegav.ntnu.no, tobiw@suprafluid.com
* www: http://sourceforge.net/projects/avra
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "misc.h"
#include "avra.h"
#include "device.h"
#define MAX_MNEMONIC_LEN 8 // Maximum mnemonic length
enum {
MNEMONIC_NOP = 0, // 0000 0000 0000 0000
MNEMONIC_SEC, // 1001 0100 0000 1000
MNEMONIC_CLC, // 1001 0100 1000 1000
MNEMONIC_SEN, // 1001 0100 0010 1000
MNEMONIC_CLN, // 1001 0100 1010 1000
MNEMONIC_SEZ, // 1001 0100 0001 1000
MNEMONIC_CLZ, // 1001 0100 1001 1000
MNEMONIC_SEI, // 1001 0100 0111 1000
MNEMONIC_CLI, // 1001 0100 1111 1000
MNEMONIC_SES, // 1001 0100 0100 1000
MNEMONIC_CLS, // 1001 0100 1100 1000
MNEMONIC_SEV, // 1001 0100 0011 1000
MNEMONIC_CLV, // 1001 0100 1011 1000
MNEMONIC_SET, // 1001 0100 0110 1000
MNEMONIC_CLT, // 1001 0100 1110 1000
MNEMONIC_SEH, // 1001 0100 0101 1000
MNEMONIC_CLH, // 1001 0100 1101 1000
MNEMONIC_SLEEP, // 1001 0101 1000 1000
MNEMONIC_WDR, // 1001 0101 1010 1000
MNEMONIC_IJMP, // 1001 0100 0000 1001
MNEMONIC_EIJMP, // 1001 0100 0001 1001
MNEMONIC_ICALL, // 1001 0101 0000 1001
MNEMONIC_EICALL, // 1001 0101 0001 1001
MNEMONIC_RET, // 1001 0101 0000 1000
MNEMONIC_RETI, // 1001 0101 0001 1000
MNEMONIC_SPM, // 1001 0101 1110 1000
MNEMONIC_ESPM, // 1001 0101 1111 1000
MNEMONIC_BREAK, // 1001 0101 1001 1000
MNEMONIC_LPM, // 1001 0101 1100 1000
MNEMONIC_ELPM, // 1001 0101 1101 1000
MNEMONIC_BSET, // s 1001 0100 0sss 1000
MNEMONIC_BCLR, // s 1001 0100 1sss 1000
MNEMONIC_SER, // Rd 1110 1111 dddd 1111
MNEMONIC_COM, // Rd 1001 010d dddd 0000
MNEMONIC_NEG, // Rd 1001 010d dddd 0001
MNEMONIC_INC, // Rd 1001 010d dddd 0011
MNEMONIC_DEC, // Rd 1001 010d dddd 1010
MNEMONIC_LSR, // Rd 1001 010d dddd 0110
MNEMONIC_ROR, // Rd 1001 010d dddd 0111
MNEMONIC_ASR, // Rd 1001 010d dddd 0101
MNEMONIC_SWAP, // Rd 1001 010d dddd 0010
MNEMONIC_PUSH, // Rr 1001 001r rrrr 1111
MNEMONIC_POP, // Rd 1001 000d dddd 1111
MNEMONIC_TST, // Rd 0010 00dd dddd dddd
MNEMONIC_CLR, // Rd 0010 01dd dddd dddd
MNEMONIC_LSL, // Rd 0000 11dd dddd dddd
MNEMONIC_ROL, // Rd 0001 11dd dddd dddd
MNEMONIC_BREQ, // k 1111 00kk kkkk k001
MNEMONIC_BRNE, // k 1111 01kk kkkk k001
MNEMONIC_BRCS, // k 1111 00kk kkkk k000
MNEMONIC_BRCC, // k 1111 01kk kkkk k000
MNEMONIC_BRSH, // k 1111 01kk kkkk k000
MNEMONIC_BRLO, // k 1111 00kk kkkk k000
MNEMONIC_BRMI, // k 1111 00kk kkkk k010
MNEMONIC_BRPL, // k 1111 01kk kkkk k010
MNEMONIC_BRGE, // k 1111 01kk kkkk k100
MNEMONIC_BRLT, // k 1111 00kk kkkk k100
MNEMONIC_BRHS, // k 1111 00kk kkkk k101
MNEMONIC_BRHC, // k 1111 01kk kkkk k101
MNEMONIC_BRTS, // k 1111 00kk kkkk k110
MNEMONIC_BRTC, // k 1111 01kk kkkk k110
MNEMONIC_BRVS, // k 1111 00kk kkkk k011
MNEMONIC_BRVC, // k 1111 01kk kkkk k011
MNEMONIC_BRIE, // k 1111 00kk kkkk k111
MNEMONIC_BRID, // k 1111 01kk kkkk k111
MNEMONIC_RJMP, // k 1100 kkkk kkkk kkkk
MNEMONIC_RCALL, // k 1101 kkkk kkkk kkkk
MNEMONIC_JMP, // k 1001 010k kkkk 110k + 16k
MNEMONIC_CALL, // k 1001 010k kkkk 111k + 16k
MNEMONIC_BRBS, // s, k 1111 00kk kkkk ksss
MNEMONIC_BRBC, // s, k 1111 01kk kkkk ksss
MNEMONIC_ADD, // Rd, Rr 0000 11rd dddd rrrr
MNEMONIC_ADC, // Rd, Rr 0001 11rd dddd rrrr
MNEMONIC_SUB, // Rd, Rr 0001 10rd dddd rrrr
MNEMONIC_SBC, // Rd, Rr 0000 10rd dddd rrrr
MNEMONIC_AND, // Rd, Rr 0010 00rd dddd rrrr
MNEMONIC_OR, // Rd, Rr 0010 10rd dddd rrrr
MNEMONIC_EOR, // Rd, Rr 0010 01rd dddd rrrr
MNEMONIC_CP, // Rd, Rr 0001 01rd dddd rrrr
MNEMONIC_CPC, // Rd, Rr 0000 01rd dddd rrrr
MNEMONIC_CPSE, // Rd, Rr 0001 00rd dddd rrrr
MNEMONIC_MOV, // Rd, Rr 0010 11rd dddd rrrr
MNEMONIC_MUL, // Rd, Rr 1001 11rd dddd rrrr
MNEMONIC_MOVW, // Rd, Rr 0000 0001 dddd rrrr
MNEMONIC_MULS, // Rd, Rr 0000 0010 dddd rrrr
MNEMONIC_MULSU, // Rd, Rr 0000 0011 0ddd 0rrr
MNEMONIC_FMUL, // Rd, Rr 0000 0011 0ddd 1rrr
MNEMONIC_FMULS, // Rd, Rr 0000 0011 1ddd 0rrr
MNEMONIC_FMULSU, // Rd, Rr 0000 0011 1ddd 1rrr
MNEMONIC_ADIW, // Rd, K 1001 0110 KKdd KKKK
MNEMONIC_SBIW, // Rd, K 1001 0111 KKdd KKKK
MNEMONIC_SUBI, // Rd, K 0101 KKKK dddd KKKK
MNEMONIC_SBCI, // Rd, K 0100 KKKK dddd KKKK
MNEMONIC_ANDI, // Rd, K 0111 KKKK dddd KKKK
MNEMONIC_ORI, // Rd, K 0110 KKKK dddd KKKK
MNEMONIC_SBR, // Rd, K 0110 KKKK dddd KKKK
MNEMONIC_CPI, // Rd, K 0011 KKKK dddd KKKK
MNEMONIC_LDI, // Rd, K 1110 KKKK dddd KKKK
MNEMONIC_CBR, // Rd, K 0111 KKKK dddd KKKK ~K
MNEMONIC_SBRC, // Rr, b 1111 110r rrrr 0bbb
MNEMONIC_SBRS, // Rr, b 1111 111r rrrr 0bbb
MNEMONIC_BST, // Rr, b 1111 101d dddd 0bbb
MNEMONIC_BLD, // Rd, b 1111 100d dddd 0bbb
MNEMONIC_IN, // Rd, P 1011 0PPd dddd PPPP
MNEMONIC_OUT, // P, Rr 1011 1PPr rrrr PPPP
MNEMONIC_SBIC, // P, b 1001 1001 PPPP Pbbb
MNEMONIC_SBIS, // P, b 1001 1011 PPPP Pbbb
MNEMONIC_SBI, // P, b 1001 1010 PPPP Pbbb
MNEMONIC_CBI, // P, b 1001 1000 PPPP Pbbb
MNEMONIC_LDS, // Rd, k 1001 000d dddd 0000 + 16k
MNEMONIC_STS, // k, Rr 1001 001d dddd 0000 + 16k
MNEMONIC_LD, // Rd, __ dummy
MNEMONIC_ST, // __, Rr dummy
MNEMONIC_LDD, // Rd, _+q dummy
MNEMONIC_STD, // _+q, Rr dummy
MNEMONIC_COUNT,
MNEMONIC_LPM_Z, // Rd, Z 1001 000d dddd 0100
MNEMONIC_LPM_ZP, // Rd, Z+ 1001 000d dddd 0101
MNEMONIC_ELPM_Z, // Rd, Z 1001 000d dddd 0110
MNEMONIC_ELPM_ZP, // Rd, Z+ 1001 000d dddd 0111
MNEMONIC_LD_X, // Rd, X 1001 000d dddd 1100
MNEMONIC_LD_XP, // Rd, X+ 1001 000d dddd 1101
MNEMONIC_LD_MX, // Rd, -X 1001 000d dddd 1110
MNEMONIC_LD_Y, // Rd, Y 1000 000d dddd 1000
MNEMONIC_LD_YP, // Rd, Y+ 1001 000d dddd 1001
MNEMONIC_LD_MY, // Rd, -Y 1001 000d dddd 1010
MNEMONIC_LD_Z, // Rd, Z 1000 000d dddd 0000
MNEMONIC_LD_ZP, // Rd, Z+ 1001 000d dddd 0001
MNEMONIC_LD_MZ, // Rd, -Z 1001 000d dddd 0010
MNEMONIC_ST_X, // X, Rr 1001 001d dddd 1100
MNEMONIC_ST_XP, // X+, Rr 1001 001d dddd 1101
MNEMONIC_ST_MX, // -X, Rr 1001 001d dddd 1110
MNEMONIC_ST_Y, // Y, Rr 1000 001d dddd 1000
MNEMONIC_ST_YP, // Y+, Rr 1001 001d dddd 1001
MNEMONIC_ST_MY, // -Y, Rr 1001 001d dddd 1010
MNEMONIC_ST_Z, // Z, Rr 1000 001d dddd 0000
MNEMONIC_ST_ZP, // Z+, Rr 1001 001d dddd 0001
MNEMONIC_ST_MZ, // -Z, Rr 1001 001d dddd 0010
MNEMONIC_LDD_Y, // Rd, Y+q 10q0 qq0d dddd 1qqq
MNEMONIC_LDD_Z, // Rd, Z+q 10q0 qq0d dddd 0qqq
MNEMONIC_STD_Y, // Y+q, Rr 10q0 qq1r rrrr 1qqq
MNEMONIC_STD_Z, // Z+q, Rr 10q0 qq1r rrrr 0qqq
MNEMONIC_END
};
struct instruction {
char *mnemonic;
int opcode;
int flag; /* Device flags meaning the instruction is not
supported */
};
struct instruction instruction_list[] = {
{"nop", 0x0000, 0},
{"sec", 0x9408, 0},
{"clc", 0x9488, 0},
{"sen", 0x9428, 0},
{"cln", 0x94a8, 0},
{"sez", 0x9418, 0},
{"clz", 0x9498, 0},
{"sei", 0x9478, 0},
{"cli", 0x94f8, 0},
{"ses", 0x9448, 0},
{"cls", 0x94c8, 0},
{"sev", 0x9438, 0},
{"clv", 0x94b8, 0},
{"set", 0x9468, 0},
{"clt", 0x94e8, 0},
{"seh", 0x9458, 0},
{"clh", 0x94d8, 0},
{"sleep", 0x9588, 0},
{"wdr", 0x95a8, 0},
{"ijmp", 0x9409, DF_TINY1X},
{"eijmp", 0x9419, DF_NO_EIJMP},
{"icall", 0x9509, DF_TINY1X},
{"eicall",0x9519, DF_NO_EICALL},
{"ret", 0x9508, 0},
{"reti", 0x9518, 0},
{"spm", 0x95e8, DF_NO_SPM},
{"espm", 0x95f8, DF_NO_ESPM},
{"break", 0x9598, DF_NO_BREAK},
{"lpm", 0x95c8, DF_NO_LPM},
{"elpm", 0x95d8, DF_NO_ELPM},
{"bset", 0x9408, 0},
{"bclr", 0x9488, 0},
{"ser", 0xef0f, 0},
{"com", 0x9400, 0},
{"neg", 0x9401, 0},
{"inc", 0x9403, 0},
{"dec", 0x940a, 0},
{"lsr", 0x9406, 0},
{"ror", 0x9407, 0},
{"asr", 0x9405, 0},
{"swap", 0x9402, 0},
{"push", 0x920f, DF_TINY1X},
{"pop", 0x900f, DF_TINY1X},
{"tst", 0x2000, 0},
{"clr", 0x2400, 0},
{"lsl", 0x0c00, 0},
{"rol", 0x1c00, 0},
{"breq", 0xf001, 0},
{"brne", 0xf401, 0},
{"brcs", 0xf000, 0},
{"brcc", 0xf400, 0},
{"brsh", 0xf400, 0},
{"brlo", 0xf000, 0},
{"brmi", 0xf002, 0},
{"brpl", 0xf402, 0},
{"brge", 0xf404, 0},
{"brlt", 0xf004, 0},
{"brhs", 0xf005, 0},
{"brhc", 0xf405, 0},
{"brts", 0xf006, 0},
{"brtc", 0xf406, 0},
{"brvs", 0xf003, 0},
{"brvc", 0xf403, 0},
{"brie", 0xf007, 0},
{"brid", 0xf407, 0},
{"rjmp", 0xc000, 0},
{"rcall", 0xd000, 0},
{"jmp", 0x940c, DF_NO_JMP},
{"call", 0x940e, DF_NO_JMP},
{"brbs", 0xf000, 0},
{"brbc", 0xf400, 0},
{"add", 0x0c00, 0},
{"adc", 0x1c00, 0},
{"sub", 0x1800, 0},
{"sbc", 0x0800, 0},
{"and", 0x2000, 0},
{"or", 0x2800, 0},
{"eor", 0x2400, 0},
{"cp", 0x1400, 0},
{"cpc", 0x0400, 0},
{"cpse", 0x1000, 0},
{"mov", 0x2c00, 0},
{"mul", 0x9c00, DF_NO_MUL},
{"movw", 0x0100, DF_NO_MOVW},
{"muls", 0x0200, DF_NO_MUL},
{"mulsu", 0x0300, DF_NO_MUL},
{"fmul", 0x0308, DF_NO_MUL},
{"fmuls", 0x0380, DF_NO_MUL},
{"fmulsu",0x0388, DF_NO_MUL},
{"adiw", 0x9600, DF_TINY1X},
{"sbiw", 0x9700, DF_TINY1X},
{"subi", 0x5000, 0},
{"sbci", 0x4000, 0},
{"andi", 0x7000, 0},
{"ori", 0x6000, 0},
{"sbr", 0x6000, 0},
{"cpi", 0x3000, 0},
{"ldi", 0xe000, 0},
{"cbr", 0x7000, 0},
{"sbrc", 0xfc00, 0},
{"sbrs", 0xfe00, 0},
{"bst", 0xfa00, 0},
{"bld", 0xf800, 0},
{"in", 0xb000, 0},
{"out", 0xb800, 0},
{"sbic", 0x9900, 0},
{"sbis", 0x9b00, 0},
{"sbi", 0x9a00, 0},
{"cbi", 0x9800, 0},
{"lds", 0x9000, DF_TINY1X},
{"sts", 0x9200, DF_TINY1X},
{"ld", 0, 0},
{"st", 0, 0},
{"ldd", 0, DF_TINY1X},
{"std", 0, DF_TINY1X},
{"count", 0, 0},
{"lpm", 0x9004, DF_NO_LPM|DF_NO_LPM_X},
{"lpm", 0x9005, DF_NO_LPM|DF_NO_LPM_X},
{"elpm", 0x9006, DF_NO_ELPM|DF_NO_ELPM_X},
{"elpm", 0x9007, DF_NO_ELPM|DF_NO_ELPM_X},
{"ld", 0x900c, DF_NO_XREG},
{"ld", 0x900d, DF_NO_XREG},
{"ld", 0x900e, DF_NO_XREG},
{"ld", 0x8008, DF_NO_YREG},
{"ld", 0x9009, DF_NO_YREG},
{"ld", 0x900a, DF_NO_YREG},
{"ld", 0x8000, 0},
{"ld", 0x9001, DF_TINY1X},
{"ld", 0x9002, DF_TINY1X},
{"st", 0x920c, DF_NO_XREG},
{"st", 0x920d, DF_NO_XREG},
{"st", 0x920e, DF_NO_XREG},
{"st", 0x8208, DF_NO_YREG},
{"st", 0x9209, DF_NO_YREG},
{"st", 0x920a, DF_NO_YREG},
{"st", 0x8200, 0},
{"st", 0x9201, DF_TINY1X},
{"st", 0x9202, DF_TINY1X},
{"ldd", 0x8008, DF_TINY1X},
{"ldd", 0x8000, DF_TINY1X},
{"std", 0x8208, DF_TINY1X},
{"std", 0x8200, DF_TINY1X},
{"end", 0, 0}
};
/* We try to parse the command name. Is it a assembler mnemonic or anything else ?
* If so, it may be a macro.
*/
int parse_mnemonic(struct prog_info *pi)
{
int mnemonic;
int i;
int opcode = 0;
int opcode2 = 0;
int instruction_long = False;
char *operand1;
char *operand2;
struct macro *macro;
char temp[MAX_MNEMONIC_LEN + 1];
operand1 = get_next_token(pi->fi->scratch, TERM_SPACE); // we get the first word on line
mnemonic = get_mnemonic_type(my_strlwr(pi->fi->scratch));
if(mnemonic == -1) { // if -1 this must be a macro name
macro = get_macro(pi, pi->fi->scratch); // and so, we try to get the corresponding macro struct.
if(macro) {
return(expand_macro(pi, macro, operand1)); // we expand the macro
} else { // if we cant find a name, this is a unknown word.
print_msg(pi, MSGTYPE_ERROR, "Unknown mnemonic/macro: %s", pi->fi->scratch);
return(True);
}
}
if(pi->pass == PASS_2) {
if(mnemonic <= MNEMONIC_BREAK) {
if(operand1) {
print_msg(pi, MSGTYPE_WARNING, "Garbage after instruction %s: %s", instruction_list[mnemonic].mnemonic, operand1); }
opcode = 0; // No operand
} else if(mnemonic <= MNEMONIC_ELPM) {
if(operand1) {
operand2 = get_next_token(operand1, TERM_COMMA);
if(!operand2) {
print_msg(pi, MSGTYPE_ERROR, "%s needs a second operand", instruction_list[mnemonic].mnemonic);
return(True); }
get_next_token(operand2, TERM_END);
i = get_register(pi, operand1);
opcode = i << 4;
i = get_indirect(pi, operand2);
if(i == 6) { // Means Z
if(mnemonic == MNEMONIC_LPM)
mnemonic = MNEMONIC_LPM_Z;
else if(mnemonic == MNEMONIC_ELPM)
mnemonic = MNEMONIC_ELPM_Z;
} else if(i == 7) { // Means Z+
if(mnemonic == MNEMONIC_LPM)
mnemonic = MNEMONIC_LPM_ZP;
else if(mnemonic == MNEMONIC_ELPM)
mnemonic = MNEMONIC_ELPM_ZP;
} else {
print_msg(pi, MSGTYPE_ERROR, "Unsupported operand: %s", operand2);
return(True);
}
} else
opcode = 0;
} else {
if(!operand1) {
print_msg(pi, MSGTYPE_ERROR, "%s needs an operand", instruction_list[mnemonic].mnemonic);
return(True);
}
operand2 = get_next_token(operand1, TERM_COMMA);
if(mnemonic >= MNEMONIC_BRBS) {
if(!operand2) {
print_msg(pi, MSGTYPE_ERROR, "%s needs a second operand", instruction_list[mnemonic].mnemonic);
return(True);
}
get_next_token(operand2, TERM_END);
}
if(mnemonic <= MNEMONIC_BCLR) {
if(!get_bitnum(pi, operand1, &i))
return(False);
opcode = i << 4;
} else if(mnemonic <= MNEMONIC_ROL) {
i = get_register(pi, operand1);
if((mnemonic == MNEMONIC_SER) && (i < 16)) {
print_msg(pi, MSGTYPE_ERROR, "%s can only use a high register (r16 - r31)", instruction_list[mnemonic].mnemonic);
i &= 0x0f;
}
opcode = i << 4;
if(mnemonic >= MNEMONIC_TST)
opcode |= ((i & 0x10) << 5) | (i & 0x0f);
} else if(mnemonic <= MNEMONIC_RCALL) {
if(!get_expr(pi, operand1, &i))
return(False);
i -= pi->cseg_addr + 1;
if(mnemonic <= MNEMONIC_BRID) {
if((i < -64) || (i > 63))
print_msg(pi, MSGTYPE_ERROR, "Branch out of range (-64 <= k <= 63)");
opcode = (i & 0x7f) << 3;
} else {
if(((i < -2048) || (i > 2047)) && (pi->device->flash_size != 4096))
print_msg(pi, MSGTYPE_ERROR, "Relative address out of range (-2048 <= k <= 2047)");
opcode = i & 0x0fff;
}
} else if(mnemonic <= MNEMONIC_CALL) {
if(!get_expr(pi, operand1, &i))
return(False);
if((i < 0) || (i > 4194303))
print_msg(pi, MSGTYPE_ERROR, "Address out of range (0 <= k <= 4194303)");
opcode = ((i & 0x3e0000) >> 13) | ((i & 0x010000) >> 16);
opcode2 = i & 0xffff;
instruction_long = True;
} else if(mnemonic <= MNEMONIC_BRBC) {
if(!get_bitnum(pi, operand1, &i))
return(False);
opcode = i;
if(!get_expr(pi, operand2, &i))
return(False);
i -= pi->cseg_addr + 1;
if((i < -64) || (i > 63))
print_msg(pi, MSGTYPE_ERROR, "Branch out of range (-64 <= k <= 63)");
opcode |= (i & 0x7f) << 3;
} else if(mnemonic <= MNEMONIC_MUL) {
i = get_register(pi, operand1);
opcode = i << 4;
i = get_register(pi, operand2);
opcode |= ((i & 0x10) << 5) | (i & 0x0f);
} else if(mnemonic <= MNEMONIC_MOVW) {
i = get_register(pi, operand1);
if((i % 2) == 1)
print_msg(pi, MSGTYPE_ERROR, "%s must use a even numbered register for Rd", instruction_list[mnemonic].mnemonic);
opcode = (i / 2) << 4;
i = get_register(pi, operand2);
if((i % 2) == 1)
print_msg(pi, MSGTYPE_ERROR, "%s must use a even numbered register for Rr", instruction_list[mnemonic].mnemonic);
opcode |= i / 2;
} else if(mnemonic <= MNEMONIC_MULS) {
i = get_register(pi, operand1);
if(i < 16)
print_msg(pi, MSGTYPE_ERROR, "%s can only use a high register (r16 - r31)", instruction_list[mnemonic].mnemonic);
opcode = (i & 0x0f) << 4;
i = get_register(pi, operand2);
if(i < 16)
print_msg(pi, MSGTYPE_ERROR, "%s can only use a high register (r16 - r31)", instruction_list[mnemonic].mnemonic);
opcode |= (i & 0x0f);
} else if(mnemonic <= MNEMONIC_FMULSU) {
i = get_register(pi, operand1);
if((i < 16) || (i >= 24))
print_msg(pi, MSGTYPE_ERROR, "%s can only use registers (r16 - r23)", instruction_list[mnemonic].mnemonic);
opcode = (i & 0x07) << 4;
i = get_register(pi, operand2);
if((i < 16) || (i >= 24))
print_msg(pi, MSGTYPE_ERROR, "%s can only use registers (r16 - r23)", instruction_list[mnemonic].mnemonic);
opcode |= (i & 0x07);
} else if(mnemonic <= MNEMONIC_SBIW) {
i = get_register(pi, operand1);
if(!((i == 24) || (i == 26) || (i == 28) || (i == 30)))
print_msg(pi, MSGTYPE_ERROR, "%s can only use registers R24, R26, R28 or R30", instruction_list[mnemonic].mnemonic);
opcode = ((i - 24) / 2) << 4;
if(!get_expr(pi, operand2, &i))
return(False);
if((i < 0) || (i > 63))
print_msg(pi, MSGTYPE_ERROR, "Constant out of range (0 <= k <= 63)");
opcode |= ((i & 0x30) << 2) | (i & 0x0f);
} else if(mnemonic <= MNEMONIC_CBR) {
i = get_register(pi, operand1);
if(i < 16)
print_msg(pi, MSGTYPE_ERROR, "%s can only use a high register (r16 - r31)", instruction_list[mnemonic].mnemonic);
opcode = (i & 0x0f) << 4;
if(!get_expr(pi, operand2, &i))
return(False);
if((i < -128) || (i > 255))
print_msg(pi, MSGTYPE_WARNING, "Constant out of range (-128 <= k <= 255). Will be masked");
if(mnemonic == MNEMONIC_CBR)
i = ~i;
opcode |= ((i & 0xf0) << 4) | (i & 0x0f);
} else if(mnemonic <= MNEMONIC_BLD) {
i = get_register(pi, operand1);
opcode = i << 4;
if(!get_bitnum(pi, operand2, &i))
return(False);
opcode |= i;
} else if(mnemonic == MNEMONIC_IN) {
i = get_register(pi, operand1);
opcode = i << 4;
if(!get_expr(pi, operand2, &i))
return(False);
if((i < 0) || (i > 63))
print_msg(pi, MSGTYPE_ERROR, "I/O out of range (0 <= P <= 63)");
opcode |= ((i & 0x30) << 5) | (i & 0x0f);
} else if(mnemonic == MNEMONIC_OUT) {
if(!get_expr(pi, operand1, &i))
return(False);
if((i < 0) || (i > 63))
print_msg(pi, MSGTYPE_ERROR, "I/O out of range (0 <= P <= 63)");
opcode = ((i & 0x30) << 5) | (i & 0x0f);
i = get_register(pi, operand2);
opcode |= i << 4;
} else if(mnemonic <= MNEMONIC_CBI) {
if(!get_expr(pi, operand1, &i))
return(False);
if((i < 0) || (i > 31))
print_msg(pi, MSGTYPE_ERROR, "I/O out of range (0 <= P <= 31)");
opcode = i << 3;
if(!get_bitnum(pi, operand2, &i))
return(False);
opcode |= i;
} else if(mnemonic == MNEMONIC_LDS) {
i = get_register(pi, operand1);
opcode = i << 4;
if(!get_expr(pi, operand2, &i))
return(False);
if((i < 0) || (i > 65535))
print_msg(pi, MSGTYPE_ERROR, "SRAM out of range (0 <= k <= 65535)");
opcode2 = i;
instruction_long = True;
} else if(mnemonic == MNEMONIC_STS) {
if(!get_expr(pi, operand1, &i))
return(False);
if((i < 0) || (i > 65535))
print_msg(pi, MSGTYPE_ERROR, "SRAM out of range (0 <= k <= 65535)");
opcode2 = i;
i = get_register(pi, operand2);
opcode = i << 4;
instruction_long = True;
} else if(mnemonic == MNEMONIC_LD) {
i = get_register(pi, operand1);
opcode = i << 4;
mnemonic = MNEMONIC_LD_X + get_indirect(pi, operand2);
} else if(mnemonic == MNEMONIC_ST) {
mnemonic = MNEMONIC_ST_X + get_indirect(pi, operand1);
i = get_register(pi, operand2);
opcode = i << 4;
} else if(mnemonic == MNEMONIC_LDD) {
i = get_register(pi, operand1);
opcode = i << 4;
if(tolower(operand2[0]) == 'z')
mnemonic = MNEMONIC_LDD_Z;
else if(tolower(operand2[0]) == 'y')
mnemonic = MNEMONIC_LDD_Y;
else
print_msg(pi, MSGTYPE_ERROR, "Garbage in second operand (%s)", operand2);
i = 1;
while((operand2[i] != '\0') && (operand2[i] != '+')) i++;
if(operand2[i] == '\0') {
print_msg(pi, MSGTYPE_ERROR, "Garbage in second operand (%s)", operand2);
return(False);
}
if(!get_expr(pi, &operand2[i + 1], &i))
return(False);
if((i < 0) || (i > 63))
print_msg(pi, MSGTYPE_ERROR, "Displacement out of range (0 <= q <= 63)");
opcode |= ((i & 0x20) << 8) | ((i & 0x18) << 7) | (i & 0x07);
} else if(mnemonic == MNEMONIC_STD) {
if(tolower(operand1[0]) == 'z')
mnemonic = MNEMONIC_STD_Z;
else if(tolower(operand1[0]) == 'y')
mnemonic = MNEMONIC_STD_Y;
else
print_msg(pi, MSGTYPE_ERROR, "Garbage in first operand (%s)", operand1);
i = 1;
while((operand1[i] != '\0') && (operand1[i] != '+')) i++;
if(operand1[i] == '\0') {
print_msg(pi, MSGTYPE_ERROR, "Garbage in first operand (%s)", operand1);
return(False);
}
if(!get_expr(pi, &operand1[i + 1], &i))
return(False);
if((i < 0) || (i > 63))
print_msg(pi, MSGTYPE_ERROR, "Displacement out of range (0 <= q <= 63)");
opcode = ((i & 0x20) << 8) | ((i & 0x18) << 7) | (i & 0x07);
i = get_register(pi, operand2);
opcode |= i << 4;
} else
print_msg(pi, MSGTYPE_ERROR, "Shit! Missing opcode check [%d]...", mnemonic);
}
if (pi->device->flag & instruction_list[mnemonic].flag) {
strncpy(temp, instruction_list[mnemonic].mnemonic, MAX_MNEMONIC_LEN);
print_msg(pi, MSGTYPE_ERROR, "%s instruction is not supported on %s",
my_strupr(temp), pi->device->name);
}
opcode |= instruction_list[mnemonic].opcode;
if(pi->list_on && pi->list_line) {
if(instruction_long)
fprintf(pi->list_file, "C:%06x %04x %04x %s\n", pi->cseg_addr, opcode, opcode2, pi->list_line);
else
fprintf(pi->list_file, "C:%06x %04x %s\n", pi->cseg_addr, opcode, pi->list_line);
pi->list_line = NULL;
}
if(pi->hfi) {
write_prog_word(pi, pi->cseg_addr, opcode);
if(instruction_long)
write_prog_word(pi, pi->cseg_addr + 1, opcode2);
}
if(instruction_long)
pi->cseg_addr += 2;
else
pi->cseg_addr++;
} else { // Pass 1
if((mnemonic == MNEMONIC_JMP) || (mnemonic == MNEMONIC_CALL)
|| (mnemonic == MNEMONIC_LDS) || (mnemonic == MNEMONIC_STS)) {
pi->cseg_addr += 2;
pi->cseg_count += 2;
} else {
pi->cseg_addr++;
pi->cseg_count++;
}
}
return(True);
}
int get_mnemonic_type(char *mnemonic)
{
int i;
for(i = 0; i < MNEMONIC_COUNT; i++) {
if(!strcmp(mnemonic, instruction_list[i].mnemonic)) {
return(i);
}
}
return(-1);
}
int get_register(struct prog_info *pi, char *data)
{
char *second_reg;
int reg = 0;
struct def *def;
// Check for any occurence of r1:r0 pairs, and if so skip to second register
second_reg = strchr(data, ':');
if(second_reg != NULL)
data = second_reg + 1;
for(def = pi->first_def; def; def = def->next)
if(!nocase_strcmp(def->name, data))
{
reg = def->reg;
return(reg);
}
if((tolower(data[0]) == 'r') && isdigit(data[1])) {
reg = atoi(&data[1]);
if(reg > 31)
print_msg(pi, MSGTYPE_ERROR, "R%d is not a valid register", reg);
}
else
print_msg(pi, MSGTYPE_ERROR, "No register associated with %s", data);
return(reg);
}
int get_bitnum(struct prog_info *pi, char *data, int *ret)
{
if(!get_expr(pi, data, ret))
return(False);
if((*ret < 0) || (*ret > 7)) {
print_msg(pi, MSGTYPE_ERROR, "Operand out of range (0 <= s <= 7)");
return(False);
}
return(True);
}
int get_indirect(struct prog_info *pi, char *operand)
{
int i = 1;
switch(tolower(operand[0])) {
case '-':
while(IS_HOR_SPACE(operand[i])) i++;
if(operand[i + 1] != '\0')
print_msg(pi, MSGTYPE_ERROR, "Garbage in operand (%s)", operand);
switch(tolower(operand[i])) {
case 'x':
if (pi->device->flag & DF_NO_XREG)
print_msg(pi, MSGTYPE_ERROR, "X register is not supported on %s", pi->device->name);
return(2);
case 'y':
if (pi->device->flag & DF_NO_YREG)
print_msg(pi, MSGTYPE_ERROR, "Y register is not supported on %s", pi->device->name);
return(5);
case 'z':
return(8);
default:
print_msg(pi, MSGTYPE_ERROR, "Garbage in operand (%s)", operand);
return(0);
}
case 'x':
if (pi->device->flag & DF_NO_XREG)
print_msg(pi, MSGTYPE_ERROR, "X register is not supported on %s", pi->device->name);
while(IS_HOR_SPACE(operand[i])) i++;
if(operand[i] == '+') {
if(operand[i + 1] != '\0')
print_msg(pi, MSGTYPE_ERROR, "Garbage in operand (%s)", operand);
return(1);
}
else if(operand[i] == '\0')
return(0);
else
print_msg(pi, MSGTYPE_ERROR, "Garbage after operand (%s)", operand);
return(0);
case 'y':
if (pi->device->flag & DF_NO_YREG)
print_msg(pi, MSGTYPE_ERROR, "Y register is not supported on %s", pi->device->name);
while(IS_HOR_SPACE(operand[i])) i++;
if(operand[i] == '+') {
if(operand[i + 1] != '\0')
print_msg(pi, MSGTYPE_ERROR, "Garbage in operand (%s)", operand);
return(4);
}
else if(operand[i] == '\0')
return(3);
else
print_msg(pi, MSGTYPE_ERROR, "Garbage after operand (%s)", operand);
return(0);
case 'z':
while(IS_HOR_SPACE(operand[i])) i++;
if(operand[i] == '+') {
if(operand[i + 1] != '\0')
print_msg(pi, MSGTYPE_ERROR, "Garbage in operand (%s)", operand);
return(7);
}
else if(operand[i] == '\0')
return(6);
else
print_msg(pi, MSGTYPE_ERROR, "Garbage after operand (%s)", operand);
return(0);
default:
print_msg(pi, MSGTYPE_ERROR, "Garbage in operand (%s)", operand);
}
return(0);
}
/* Return 1 if instruction name is supported by the current device,
0 if unsupported, -1 if it is invalid */
int is_supported(struct prog_info *pi, char *name) {
char temp[MAX_MNEMONIC_LEN+1];
int mnemonic;
strncpy(temp,name,MAX_MNEMONIC_LEN);
mnemonic = get_mnemonic_type(my_strlwr(temp));
if (mnemonic == -1) return -1;
if (pi->device->flag & instruction_list[mnemonic].flag) return 0;
return 1;
}
int count_supported_instructions(int flags)
{
int i = 0, count = 0;
while(i < MNEMONIC_END) {
if((i < MNEMONIC_LD) || (i > MNEMONIC_COUNT))
if(!(flags & instruction_list[i].flag))
count++;
i++;
}
return(count);
}
/* end of mnemonic.c */