📄 asm.c
字号:
/*
* File: asm.c
* Purpose: Assembly routines for ColdFire Debuggers
*
* Notes:
*
*/
#include "src/include/dbug.h"
#include "src/uif/sym.h"
#include "src/cpu/coldfire/ea.h"
/********************************************************************/
#define MAX_OPERAND 30
/* Globals */
int8 size = 0; /* written by check_size_and_label(), used by afun's */
int8 word_sel =0; /* written by getwordselect(), used by afun's */
uint8 error; /* global error flag */
uint8 reg_error; /* global error flag set in get_XXXX_register() */
uint8 ext_word_flag; /* used in handle_ext_words(), set if ext_word exists */
uint8 ext_long_flag; /* used in handle_ext_words(), set if ext_long exists */
uint8 opword2_flag; /* used in handle_ext_words(), set if opword2 exists */
uint32 addr_mode; /* written by get_ea(), used by afun26 (MOVE) */
uint16 opword2; /* written by various afun's, used in handle_ext_words()*/
uint16 ext_word; /* written in get_ea() and afun's, used by " */
uint32 ext_long; /* " */
int success; /* global error flag set by get_value() */
char user_input[UIF_MAX_LINE]; /* raw user input, unparsed */
char *instruct[UIF_MAX_ARGS]; /* parsed inputs */
ADDRESS asm_pc; /* address where opcode is written */
static const char ERR_ADDR_REG[] = "Not a valid address register: %s\n";
static const char ERR_DATA_REG[] = "Not a valid data register: %s\n";
static const char ERR_REG[] = "Not a valid register: %s\n";
static const char ERR_OPER[]= "Not a valid operand: %s\n";
static const char data_register[8][3] = {"D0","D1","D2","D3","D4","D5","D6","D7"};
static const char addr_register[8][3] = {"A0","A1","A2","A3","A4","A5","A6","A7"};
/****************************************************************/
static void
get_word_select(int operand)
{
int i,j;
j=operand;
for (i=2; (instruct[j][i] != ':') && (instruct[j][i] != '.') && (instruct[j][i] != '\0') ; i++)
{}
if (instruct[j][i] == '\0') /* No word select found !*/
{
word_sel = 0; /* default to "lower word" (L) */
}
else if((instruct[j][i] == '.') || (instruct[j][i] == ':'))
{
switch (instruct[j][i+1])
{
case 'l':
case 'L':
word_sel=0;
break;
case 'u':
case 'U':
word_sel=1;
break;
default:
error = TRUE;
printf("Not a valid attribute %s\n",instruct[j]);
break;
}
instruct[j][i] = '\0';
}
else
{
word_sel = -1; /* error */
}
}
/****************************************************************/
static int
get_data_register (char *reg)
{
int Dn, i;
Dn = 8; /* return value of 8 is error */
for (i=0; i<8; i++)
{
if (strncasecmp(reg,data_register[i],2) == 0)
{
Dn = i;
reg_error = FALSE;
break;
}
}
if (Dn == 8)
reg_error = TRUE;
return Dn;
}
/****************************************************************/
static int
get_addr_register (char *reg)
{
int An, i;
An = 8; /* return value of 8 is error */
for (i=0; i<8; i++)
{
if (strncasecmp(reg,addr_register[i],2) == 0)
{
An = i;
reg_error = FALSE;
break;
}
}
/* A7 is SP */
if (strncasecmp(reg,"sp",2) == 0)
{
An = 7;
reg_error = FALSE;
}
if (An == 8)
reg_error = TRUE;
return An;
}
/****************************************************************/
static void
check_base (char *data, int *temp_base)
{
if (data[0] == '0' && (data[1] == 'x' || data[1] == 'X'))
*temp_base = 16;
else if (data[0] == '$')
*temp_base = 16;
else if (data[0] == '%')
*temp_base = 2;
else if (data[0] == '@')
*temp_base = 8;
else
*temp_base = 10;
}
/****************************************************************/
static void
write_data(int size, int data)
{
switch (size)
{
case SIZE_16:
*((uint16 *) asm_pc) = (uint16)data;
asm_pc += 2;
break;
case SIZE_32:
*((uint32 *) asm_pc) = (uint32)data;
asm_pc += 4;
break;
}
}
/****************************************************************/
static void
handle_ext_words(void)
{
if (opword2_flag)
write_data (16,opword2);
/* Extend uint16 operand to uint32 opcode */
if (ext_word_flag && ext_long_flag)
{
ext_long = (uint32)ext_word;
write_data (32,ext_long);
}
else if (ext_word_flag)
write_data (16,ext_word);
else if (ext_long_flag)
write_data (32,ext_long);
}
/****************************************************************/
static uint32
get_imm_data (char *data_str,uint32 mask)
{
int temp_base, offset;
uint32 imm_data;
if (data_str[0] != '#')
{
error = TRUE;
printf("Not valid immediate data: %s\n", data_str);
printf("It might help if you use '#'.\n");
return 0;
}
check_base(&data_str[1],&temp_base);
/* adjust string so call to stroul in get_value() doesn't
* choke on special base indication characters
*/
if (data_str[1] == '$' || data_str[1] == '%' || data_str[1] == '@')
offset = 2;
else
offset = 1;
imm_data = get_value(&data_str[offset],&success,temp_base);
if (success == 0)
{
error = TRUE;
printf(INVALUE,&data_str[1]);
return 0;
}
else if (imm_data & mask)
{
error = TRUE;
printf("Not valid immediate data: %s\n",&data_str[1]);
printf("Value is larger than specified.\n");
return 0;
}
else
return imm_data;
}
/****************************************************************/
static int
size_is_long(void)
{
switch (size)
{
case 0:
case 1:
printf("Invalid size: .L only\n");
return 0;
case 2:
case -1:
return 1;
}
return 0;
}
/****************************************************************/
static int
is_DRD (int* reg, int* mod, char* raw)
{
if ((*reg = get_data_register(raw)) != 8)
{ /* Dn */
*mod = 0x0;
addr_mode = DRD;
return 1;
}
return 0;
}
static int
is_ARD (int* reg, int* mod, char* raw)
{
if ((*reg = get_addr_register(raw)) != 8)
{ /* An */
*mod = 0x1;
addr_mode = ARD;
return 1;
}
return 0;
}
static int
is_ARI (int* reg, int* mod, char* raw)
{
if (raw[0] == '(' && raw[3] == ')' && raw[4] == '\0')
{
if ((*reg = get_addr_register(&raw[1])) != 8)
{
*mod = 0x2;
addr_mode = ARI;
return 1;
}
}
return 0;
}
static int
is_ARIPR (int* reg, int* mod, char* raw)
{
if (raw[0] == '-' && raw[1] == '(' && raw[4] == ')' && raw[5] == '\0')
{
if ((*reg = get_addr_register(&raw[2])) != 8)
{
*mod = 0x4;
addr_mode = ARIPR;
return 1;
}
}
return 0;
}
static int
is_ARIPO (int* reg, int* mod, char* raw)
{
if (raw[0] == '(' && raw[3] == ')' && raw[4] == '+' && raw[5] == '\0')
{
if ((*reg = get_addr_register(&raw[1])) != 8)
{
*mod = 0x3;
addr_mode = ARIPO;
return 1;
}
}
return 0;
}
static int
is_IM (int* reg, int* mod, char* raw)
{
int32 temp;
if (raw[0] == '#')
{
*reg = 0x4;
*mod = 0x7;
addr_mode = IM;
temp = (uint32)get_imm_data(raw,0x0); /* FIX !!! usage of temp */
if (!error || symtab_convert_string(raw,(ADDRESS *)&temp))
{
if (temp & 0xFFFF0000)
{
ext_long = temp;
ext_long_flag = 1;
}
else
{
ext_word = (uint16)temp;
ext_word_flag = 1;
}
return 1;
}
}
return 0;
}
static int
is_AS_AL (int* reg, int* mod, char* raw)
{ /* (xxx).W or (xxx).L */
int i, force = 0, parens = 0;
uint32 temp;
char *tstr[1], copy[MAX_OPERAND];
strcpy(copy,raw);
tstr[0] = ©[0];
if (copy[0] == '(')
{
parens++;
tstr[0] = ©[1];
}
for (i=0; (tstr[0][i] != '.' && tstr[0][i] != '\0'); i++) {}
if (tstr[0][i] == '.')
{
tstr[0][i] = '\0';
switch (tstr[0][i+1])
{
case 'w':
case 'W':
break;
case 'l':
case 'L':
force = 1;
break;
default:
return 0;
}
if (tstr[0][i+2] == ')')
parens--;
}
for (i=1; (copy[i] != '\0' && copy[i] != ')'); i++) {}
if (copy[i] == ')')
{
parens--;
copy[i] = '\0';
}
if (parens)
return 0;
if (((tstr[0][0] == '0' && (tstr[0][1] == 'x' || tstr[0][1] == 'X'))
|| tstr[0][0] == '$') || (symtab_convert_string(raw,(ADDRESS *)&temp)))
{
*mod = 0x7;
temp = get_value(tstr[0],&success,16);
if (success && ((temp & 0xffff0000) || force))
{ /* Absolute Long */
*reg = 0x1;
addr_mode = AL;
ext_long = temp;
ext_long_flag = 1;
return 1;
}
else if (success)
{ /* Absolute Short */
*reg = 0x0;
addr_mode = AS;
ext_word = (uint16)temp;
ext_word_flag = 1;
return 1;
}
else
return 0;
}
return 0;
}
static int
is_ARID_PCID (int* reg, int* mod, char **strg)
{
int temp_base, go_ahead = 0;
int32 temp;
if (strg[0][0] != '\0' && strg[1][0] != '\0' && strg[2][0] == '\0')
{
if ((*reg = get_addr_register(strg[1])) != 8)
{
go_ahead = 1;
addr_mode = ARID;
*mod = 0x5;
}
else if (strncasecmp(strg[1],"pc",2) == 0)
{
go_ahead = 1;
addr_mode = PCID;
*mod = 0x7;
*reg = 0x2;
}
if (go_ahead)
{
check_base(strg[0],&temp_base);
temp = get_value(strg[0],&success,temp_base);
/* 16-bit */
if (success && temp >= -32768 && temp <= 32767)
{
ext_word_flag = 1;
ext_word = (uint16)temp;
return 1;
}
}
}
return 0;
}
static int
is_ARII8_PCII8 (int* reg, int* reg2, int* mod, char **strg)
{
int temp_base, go_ahead = 0;
int32 temp;
if (strg[0][0] != '\0' && strg[1][0] != '\0' && strg[2][0] != '\0')
{
if ((*reg = get_addr_register(strg[1])) != 8)
{
go_ahead = 1;
addr_mode = ARII8;
*mod = 0x6;
}
else if (strncasecmp(strg[1],"pc",2) == 0)
{
go_ahead = 1;
addr_mode = PCII8;
*mod = 0x7;
*reg = 0x3;
}
if (go_ahead)
{
check_base(strg[0],&temp_base);
temp = get_value(strg[0],&success,temp_base);
/* 8-bit */
if (success && temp >= -128 && temp <= 127)
{
ext_word_flag = 1;
ext_word = (uint16)(temp & 0x00FF);
if ((*reg2 = get_data_register(strg[2])) != 8)
temp = 0x0; /* write Data bit */
else if ((*reg2 = get_addr_register(strg[2])) != 8)
temp = 0x8000; /* write Addr bit */
else
{
error = TRUE;
return 0;
}
ext_word = (uint16)(ext_word | temp | (*reg2 << 12) | 0x800);
strg[2] = &strg[2][2];
if (strg[2][0] == '.')
{
switch (strg[2][1])
{
case 'L':
case 'l':
/* wrote .L above with XXX | 0x800; */
break;
default:
error = TRUE;
return 0;
}
strg[2] = &strg[2][2];
}
if (strg[2][0] == '*')
{
switch (strg[2][1])
{
case '1':
break;
case '2':
ext_word = ext_word | 0x200;
break;
case '4':
ext_word = ext_word | 0x400;
break;
case '8':
ext_word = ext_word | 0x600;
break;
default:
error = TRUE;
return 0;
}
strg[2] = &strg[2][2];
}
if (strg[2][0] != '\0')
{
error = TRUE;
return 0;
}
return 1;
}
}
}
return 0;
}
/****************************************************************/
static int
parse_operand (char *temp[], char *raw)
{
int i, j, parens;
i = j = parens = 0;
temp[0] = raw;
temp[1] = temp [2] = '\0';
if (raw[0] == '(')
{
temp[0] = &raw[1];
parens++;
i++;
}
while (raw[i] != '\0')
{
if (raw[i] == '(' || raw[i] == ',' || raw[i] == ')')
{
j++;
if (raw[i] == '(')
parens++;
if (raw[i] == ')')
parens--;
raw[i] = '\0';
temp[j] = &raw[i+1];
}
i++;
}
if (parens != 0)
return 0;
else
return 1;
}
/****************************************************************/
static uint16
get_ea (char *operand, int ea_mask, int force_long)
{
uint16 ea;
int reg, reg2, mode;
char *tstr[3], raw[MAX_OPERAND];
strcpy(raw,operand);
if (is_DRD(®, &mode, raw))
{}
else if (is_ARD(®, &mode, raw))
{}
else if (is_ARI(®, &mode, raw))
{}
else if (is_ARIPO(®, &mode, raw))
{}
else if (is_ARIPR(®, &mode, raw))
{}
else if (is_IM(®, &mode, raw))
{
if (force_long && ext_word_flag)
{
ext_long_flag = 1;
ext_long = (uint32) ext_word;
ext_word_flag = 0;
}
}
else if (is_AS_AL(®, &mode, raw))
{}
else /* Must seperate the operand */
{
if (parse_operand(tstr, raw))
{
if (is_ARID_PCID(®, &mode, tstr))
{}
else if (is_ARII8_PCII8(®, ®2, &mode, tstr))
{}
else
{
printf("Invalid operand: %s\n",operand);
error = TRUE;
return 0;
}
}
else
{
printf("Syntax Error: %s\n",operand);
error = TRUE;
return 0;
}
}
if (!(addr_mode & ea_mask))
{
error = TRUE;
printf("Invalid addressing mode for '%s' instruction\n",instruct[0]);
return 0;
}
ea = (uint16)((mode << 3) | reg);
return ea;
}
/****************************************************************/
void
afun1 (int ea_mask, uint16 opword) /* funcs already have access to instruct[] */
{
(void) ea_mask;
/* This function is used for all instructions
* whose opcode is written entirely in the isa table
* RTS, NOP, HALT, PULSE, RTE
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -