ack/mach/m68020/ce/as.c

353 lines
6.8 KiB
C
Raw Normal View History

1988-08-18 14:33:57 +00:00
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "as.h"
#include "arg_type.h"
process_label() {}
process_mnemonic( m)
char *m;
{
for ( ; *m != '\0'; m++)
if ( *m == '.')
*m = '_';
}
process_operand( str, op)
char *str;
struct t_operand *op;
{
char *glob_lbl();
op->type = 0;
switch ( *str) {
case '#' : op->type = IS_IMMEDIATE;
op->expr = str+1;
if ( *(op->expr) != '$') { /* #1 */
op->val = atoi( str+1);
if ( 1 <= op->val && op->val <= 8 ) {
op->type = IS_QUICK;
op->lbl = NULL;
}
}
else
if ( arg_type( str+1) == STRING) { /* #$1+$2 */
op->lbl = op->expr;
*(op->lbl+2) = '\0';
op->expr = op->lbl+3;
}
else /* #$1 */
op->lbl = NULL;
break;
case '(' : if ( index( str+1, ',') == NULL)
if ( is_reg( str+1)) {
op->reg = reg_val( str+1);
if ( *(str+4) == '+') /* (sp)+ */
op->type = IS_INCR;
else /* (a0) */
op->type = IS_IND_REG;
}
else {
op->type = IS_IND_MEM;
op->expr = str+1;
for ( str++; *++str != ')';)
;
*str = '\0';
if ( *(op->expr) == '$')
if ( arg_type( op->expr) == STRING) {
/* ($1+$2) */
op->lbl = op->expr;
if ( strlen( op->lbl) == 2)
op->expr = "0";
else {
*(op->lbl+2) = '\0';
op->expr = op->lbl+3;
}
}
else /* ($1) */
op->lbl = NULL;
else if ( isdigit( *(op->expr))) /* (1) */
op->lbl = NULL;
else { /* (.trppc) */
op->lbl = glob_lbl( op->expr);
op->expr = "0";
}
}
else
if ( *(str+1) == '[') {
op->type = IS_IND_IND;
op->expr = str+2;
for ( str += 2; *++str != ',';)
;
*str++ = '\0';
for ( ; *str == ' '; str++)
;
op->reg = reg_val( str);
for ( ; *str++ != ']';)
;
if ( *str == ')') /* ([$1, a6]) */
op->expr2 = 0;
else { /* ([8,a6],8) */
for ( ; *str++ != ',';)
;
for ( ; *str == ' '; str++)
;
op->expr2 = atoi( str);
}
}
else {
op->expr = str+1;
for ( str++; *++str != ',';)
;
*str++ = '\0';
for ( ; *str == ' '; str++)
;
op->reg = reg_val( str);
if ( *(str+2) == ')') /* (4, a0) */
op->type = IS_IND_REG_DISPL;
else { /* (0, sp, d0.l*1) */
op->type = IS_3_OPS;
for ( str++; *++str != ',';)
;
for ( ; *str == ' '; str++)
;
op->reg2 = reg_val( str);
for ( ; *str++ != '*';)
;
op->scale = atoi( str);
}
}
break;
case '-' : op->type = IS_DECR; /* -(sp) */
op->reg = reg_val( str+2);
break;
case '$' : op->type = IS_GLOB_LBL; /* $1 */
op->lbl = str;
op->expr ="0";
break;
default : if ( is_reg( str)) {
op->reg = reg_val( str);
if ( *(str+2) == ':') { /* d2:d1 */
op->type = IS_REG_PAIR;
op->reg2 = reg_val( str+3);
}
else /* a6 */
op->type = ( *str == 'd' ? IS_D_REG : IS_A_REG);
}
else if ( isdigit( *str)) { /* 1f */
op->type = IS_LOC_LBL;
op->lbl = str;
op->expr = "0";
*(str+1) ='\0';
}
else { /* .strhp */
op->type = IS_GLOB_LBL;
op->lbl = glob_lbl( str);
*(str+1) ='\0';
op->expr = "0";
}
}
}
int reg_val( reg)
char *reg;
{
return( *reg == 's' ? 7 : atoi( reg+1));
}
int is_reg( str)
char *str;
{
switch ( *str) {
case 'a' :
case 'd' : return( isdigit( *(str+1)));
case 's' : return( *(str+1) == 'p');
default : return( 0);
}
}
char *glob_lbl( lbl)
char *lbl;
{
char *gl, *malloc();
gl = malloc( strlen( lbl) + 3);
sprintf( gl, "\"%s\"", lbl);
return( gl);
}
/******************************************************************************/
int mode_reg( eaddr)
struct t_operand *eaddr;
{
switch ( eaddr->type) {
case IS_A_REG : return( 0x08 | eaddr->reg);
case IS_D_REG : return( 0x00 | eaddr->reg);
case IS_IND_REG : return( 0x10 | eaddr->reg);
case IS_INCR : return( 0x18 | eaddr->reg);
case IS_DECR : return( 0x20 | eaddr->reg);
case IS_IND_MEM : return( 0x39);
case IS_IND_IND : return( 0x30 | eaddr->reg);
case IS_IND_REG_DISPL : return( 0x28 | eaddr->reg);
case IS_GLOB_LBL : return( 0x39);
case IS_3_OPS : if ( isdigit( *(eaddr->expr)) &&
atoi( eaddr->expr) < 128)
return( 0x30 | eaddr->reg);
else
fprintf( stderr, "FOUT in IS_3_OPS\n");
break;
case IS_QUICK :
case IS_IMMEDIATE : return( 0x3c);
default : fprintf( stderr,
"mode_reg(), verkeerde operand %d\n",
eaddr->type);
abort();
break;
}
}
code_extension( eaddr)
struct t_operand *eaddr;
{
switch ( eaddr->type) {
case IS_IND_MEM : if ( eaddr->lbl == NULL)
@text4( %$( eaddr->expr));
else
@reloc4( %$( eaddr->lbl),
%$( eaddr->expr),
ABSOLUTE);
break;
case IS_IND_IND : if ( eaddr->expr2 == 0) {
@text2( 0x161);
@text2( %$(eaddr->expr));
}
else {
@text2( 0x162);
@text2( %$(eaddr->expr));
@text2( %d(eaddr->expr2));
}
break;
case IS_IND_REG_DISPL : @text2( %$( eaddr->expr));
break;
case IS_GLOB_LBL : @reloc4( %$(eaddr->lbl),
%$(eaddr->expr),
ABSOLUTE);
break;
case IS_3_OPS : if ( isdigit( *(eaddr->expr)) &&
atoi( eaddr->expr) < 128) {
@text2( %d( 0x0800 |
( eaddr->reg2 << 12) |
( two_log( eaddr->scale)<<9) |
atoi( eaddr->expr)));
}
else
fprintf( stderr, "FOUT in IS_3_OPS\n");
break;
case IS_QUICK :
case IS_IMMEDIATE : if ( eaddr->lbl != NULL)
@reloc4( %$(eaddr->lbl),
%$(eaddr->expr),
ABSOLUTE);
else
@text4( %$(eaddr->expr));
}
}
int reg_mode( eaddr)
struct t_operand *eaddr;
{
int mr;
mr = mode_reg( eaddr);
return( ((mr & 0x7) << 3) | ((mr & 0x38) >> 3));
}
code_opcode( opcode, field1, field2, eaddr)
int opcode, field1, field2;
struct t_operand *eaddr;
{
@text2( %d(((opcode & 0xf) << 12) | ((field1 & 0x7) << 9) |
((field2 & 0x7) << 6) | (mode_reg(eaddr) & 0x3f)));
}
code_instr( opcode, field1, field2, eaddr)
int opcode, field1, field2;
struct t_operand *eaddr;
{
code_opcode( opcode, field1, field2, eaddr);
code_extension( eaddr);
}
code_move( size, src, dst)
int size;
struct t_operand *src, *dst;
{
@text2( %d( ((size & 0x3) << 12) | ((reg_mode( dst) & 0x3f) << 6) |
(mode_reg( src) & 0x3f)));
code_extension( src);
code_extension( dst);
}
code_dist4( dst)
struct t_operand *dst;
{
@reloc4( %$(dst->lbl), %$(dst->expr) + 4, PC_REL);
}
int two_log( nr)
int nr;
{
int log;
for ( log = 0; nr >= 2; nr >>= 1)
log++;
return( log);
}