Ejemplo n.º 1
0
STATIC void id32Block( obj_rec *objr, OBJ_WFILE *out, int_16 *delta,
                       uint_16 first_block_offset ) {
    /*
        Since LIDATAs are different under PharLap and MicroSoft 386 formats,
        we have to do some magic.
    */
    uint_16 rpt_count;
    uint_16 blk_count;
    uint_8  data_count;
    uint_8  *ptr;

    rpt_count = ObjGet16( objr );
    ObjWrite32( out, rpt_count );
    *delta += 2;    /* ok, everything from here on will be at +2 offset */
    LifixAdd( &lifList, ObjRTell( objr ) - first_block_offset, *delta );
    blk_count = ObjGet16( objr );
    ObjWrite16( out, blk_count );
    if( blk_count == 0 ) {
        data_count = ObjGet8( objr );
        ObjWrite8( out, data_count );
        ptr = ObjGet( objr, data_count );
        ObjWrite( out, ptr, data_count );
    } else {
        for( ; blk_count != 0; --blk_count ) {
            id32Block( objr, out, delta, first_block_offset );
        }
    }
}
Ejemplo n.º 2
0
STATIC int writeLedata( obj_rec *objr, pobj_state *state ) {

    OBJ_WFILE   *out;
    uint_16     save;
    uint_8      *ptr;
    uint_16     len;
    int         is32;

    /**/myassert( objr != NULL );
    /**/myassert( objr->command == CMD_LEDATA );
    /**/myassert( state != NULL );
    /**/myassert( state->pass == POBJ_WRITE_PASS );
#if ( _WOMP_OPT & _WOMP_WATFOR ) == 0
    LifixDestroy( &lifList );
    LifixInit( &lifList );
#endif
    out = state->file_out;
    is32 = objr->is_32 || objr->is_phar;
    ObjWBegRec( out, is32 ? CMD_LEDA32 : CMD_LEDATA );
    ObjWriteIndex( out, objr->d.ledata.idx );
    if( is32 ) {
        ObjWrite32( out, objr->d.ledata.offset );
    } else {
        ObjWrite16( out, (uint_16)objr->d.ledata.offset );
    }
    save = ObjRTell( objr );
    len = ObjRemain( objr );
    ptr = ObjGet( objr, len );
    /**/myassert( len <= 1024 );
    ObjWrite( out, ptr, len );
    ObjWEndRec( out );
    ObjRSeek( objr, save );
    return( 0 );
}
Ejemplo n.º 3
0
STATIC int writeFixup( obj_rec *objr, pobj_state *state ) {

    OBJ_WFILE   *out;
    int         is32;
    fixup       *walk;
    uint_8      buf[ FIX_GEN_MAX ];
    uint_16     len;
    uint_16     len_written;
    uint_8      cmd1;
    uint_8      cmd2;

    /**/myassert( objr != NULL );
    /**/myassert( objr->command == CMD_FIXUP );
    /**/myassert( state != NULL );
    /**/myassert( state->pass == POBJ_WRITE_PASS );
    walk = objr->d.fixup.fixup;
    if( walk == NULL ) {
        /* huh? this shouldn't really happen... */
        return( 0 );
    }
    out = state->file_out;
    is32 = objr->is_32 || objr->is_phar;
    cmd1 = is32 ? CMD_FIXU32 : CMD_FIXUP;
    cmd2 = is32 ? FIX_GEN_MS386 : FIX_GEN_INTEL;
    /* we don't want to write FIXUP records that are too large, so we limit
       our records to approximately 1024 bytes */
    do {
        len_written = 0;
        ObjWBegRec( out, cmd1 );
        while( walk != NULL && len_written < 1024 - FIX_GEN_MAX ) {
            walk->loc_offset += LifixDelta( &lifList, (uint_16)walk->loc_offset );
#if _WOMP_OPT & _WOMP_WOMP
            if( Can2MsOS2Flat() &&
                    ( walk->loc_method == FIX_OFFSET386
                      || walk->loc_method == FIX_POINTER386 ) ) {
                /* zap FIXUPs for OS/2 2.0 linker 21-mar-91 AFS */
                switch( walk->lr.frame ) {
                case FRAME_SEG:
                case FRAME_GRP:
                case FRAME_TARG:
                    walk->lr.frame = FRAME_GRP;
                    walk->lr.frame_datum = ObjFLATIndex;
                    break;
                }
            }
#endif
            len = FixGenFix( walk, buf, cmd2 );
            ObjWrite( out, buf, len );
            walk = walk->next;
            len_written += len;
        }
        ObjWEndRec( out );
    } while( walk != NULL );
    return( 0 );
}
Ejemplo n.º 4
0
STATIC int writeComdat( obj_rec *objr, pobj_state *state ) {

    OBJ_WFILE   *out;
    uint_8      *ptr;
    uint_16     len;
    uint_16     save;
    int         is32;

    /**/myassert( objr != NULL );
    /**/myassert( objr->command == CMD_COMDAT );
    /**/myassert( state != NULL );
    /**/myassert( state->pass == POBJ_WRITE_PASS );
    save = ObjRTell( objr );
    is32 = objr->is_32 || objr->is_phar;
    if( is32 ) {
        objr->command |= 1;
    }
    out = state->file_out;
    ObjWBegRec( out, objr->command );
    ObjWrite8( out, objr->d.comdat.flags );
    ObjWrite8( out, objr->d.comdat.attributes );
    ObjWrite8( out, objr->d.comdat.align );
    if( is32 ) {
        ObjWrite32( out, objr->d.comdat.offset );
    } else {
        ObjWrite16( out, (uint_16)objr->d.comdat.offset );
    }
    ObjWriteIndex( out, objr->d.comdat.type_idx );
    if( ( objr->d.comdat.attributes & COMDAT_ALLOC_MASK ) == COMDAT_EXPLICIT ) {
        writeBase( objr, out );
    }
    ObjWriteIndex( out, objr->d.comdat.public_name_idx );
    if( ( objr->d.comdat.flags & COMDAT_ITERATED ) == 0 || objr->is_phar == 0 ) {
        /* record is already in ms omf format */
        len = ObjRemain( objr );
        ptr = ObjGet( objr, len );
        /**/    myassert( len <= 1024 );
        ObjWrite( out, ptr, len );
    } else {
        int_16 delta;
        uint_16 first_block_offset;

        delta = 0;  /* id32Block needs to play with this */
        first_block_offset = ObjRTell( objr );
        while( !ObjEOR( objr ) ) {
            id32Block( objr, out, &delta, first_block_offset );
        }
    }
    ObjWEndRec( out );
    ObjRSeek( objr, save );
    return( 0 );
}
Ejemplo n.º 5
0
STATIC int writeLidata( obj_rec *objr, pobj_state *state ) {

    OBJ_WFILE   *out;
    uint_16     save;
    uint_8      *ptr;
    uint_16     len;
    int         is32;

    /**/myassert( objr != NULL );
    /**/myassert( objr->command == CMD_LIDATA );
    /**/myassert( state != NULL );
    /**/myassert( state->pass == POBJ_WRITE_PASS );
    LifixDestroy( &lifList );
    LifixInit( &lifList );
    out = state->file_out;
    save = ObjRTell( objr );
    is32 = objr->is_32 || objr->is_phar;
    ObjWBegRec( out, is32 ? CMD_LIDA32 : CMD_LIDATA );
    ObjWriteIndex( out, objr->d.lidata.idx );
    if( is32 ) {
        ObjWrite32( out, objr->d.lidata.offset );
    } else {
        ObjWrite16( out, (uint_16)objr->d.lidata.offset );
    }
    if( objr->is_phar == 0 ) {
        /* ok, already in our format */
        len = ObjRemain( objr );
        ptr = ObjGet( objr, len );
        ObjWrite( out, ptr, len );
    } else {
        int_16 delta;
        uint_16 first_block_offset;

        delta = 0;  /* id32Block needs to play with this */
        first_block_offset = ObjRTell( objr );
        while( !ObjEOR( objr ) ) {
            id32Block( objr, out, &delta, first_block_offset );
        }
    }
    ObjWEndRec( out );
    ObjRSeek( objr, save );
    return( 0 );
}
Ejemplo n.º 6
0
STATIC int writePubdef( obj_rec *objr, pobj_state *state ) {

    int         is32;
    OBJ_WFILE   *out;
    const char  *name;
    size_t       name_len;
    pubdef_data *pubdata;
    pubdef_data *pubstop;

    /**/myassert( objr != NULL );
    /**/myassert( objr->command == CMD_PUBDEF || objr->command == CMD_STATIC_PUBDEF );
    /**/myassert( state != NULL );
    /**/myassert( state->pass == POBJ_WRITE_PASS );
    is32 = objr->is_32 || objr->is_phar;
    if( is32 ) {
        objr->command |= 1;
    }
    out = state->file_out;
    ObjWBegRec( out, objr->command );
    writeBase( objr, out );
    pubdata = objr->d.pubdef.pubs;
    if( pubdata != NULL ) {
        pubstop = pubdata + objr->d.pubdef.num_pubs;
        while( pubdata < pubstop ) {
            name = NameGet( pubdata->name );
            name_len = strlen( name );
            if( name_len > 255 )
                name_len = 255;
            ObjWrite8( out, (uint_8)name_len );
            ObjWrite( out, (uint_8 *)name, (uint_16)name_len );
            if( is32 ) {
                ObjWrite32( out, pubdata->offset );
            } else {
                ObjWrite16( out, (uint_16)pubdata->offset );
            }
            ObjWriteIndex( out, pubdata->type.idx );
            ++pubdata;
        }
    }
    ObjWEndRec( out );
    return( 0 );
}
Ejemplo n.º 7
0
STATIC int writeComent( obj_rec *objr, pobj_state *state ) {

    uint_8  *ptr;
    uint_16 len;
    uint_16 save;
    OBJ_WFILE *out;

    /**/myassert( objr != NULL );
    /**/myassert( objr->data != NULL );
    /**/myassert( state != NULL );
    /**/myassert( state->pass == POBJ_WRITE_PASS );
    out = state->file_out;
    ObjWBegRec( out, CMD_COMENT );
    ObjWrite8( out, objr->d.coment.attr );
    ObjWrite8( out, objr->d.coment.class );
    save = ObjRTell( objr );
    len = ObjRemain( objr );
    ptr = ObjGet( objr, len );
    ObjWrite( out, ptr, len );
    ObjRSeek( objr, save );
    ObjWEndRec( out );
    return( 0 );
}
Ejemplo n.º 8
0
void Pass2(Instruction *instr, int pc)
{
	Expression	*expr = instr->optexpr;
	int		opcode = instr->opcode;
	int		result = 0;

	if (instr->combine == 0) {
		/* no post processesing required */
		/* pass opcode straight to the object formatter */
		WriteCodeWord(opcode);
		return;
	}

	switch (instr->combine) {

	/* diadic combine commands					*/
	/* All these commands will only use combine, NOT combine2	*/

	/* Register addressing doesn't need to be checked		*/
	case COM_DIA_REG:
		/* do nothing */
		break;

	/* Check signed immediate <= 16 bits and insert int bits 0-15	*/
	case COM_DIA_IMM:
		result = Eval(expr, pc);
		if (!fits_in_16_bits(result)) {
			char Err[80];

			sprintf(Err, "signed immediate value (%d) will not fit in 16 bits", result);
			Error(Err);
		}
		opcode |= result & 0xffff;
		break;

	/* Check UNsigned immediate <= 16 bits and insert int bits 0-15	*/
	case COM_DIA_IMM_UNSIGNED:
		result = Eval(expr, pc);
		if (!fits_in_16_bits_unsigned(result)) {
			char Err[80];

			sprintf(Err, "unsigned immediate value (%#x) will not fit in 16 bits", result);
			Error(Err);
		}
		opcode |= result;
		break;

	/* Shift immediate >> 16 and insert int bits 0-15		*/
	case COM_DIA_IMM_LDP:
		opcode |= (Eval(expr, pc) >> 16) & 0xffff;
		break;

	/* Check unsigned disp <= 8 bits and insert into bits 0-7	*/
	case COM_DIA_IND:
		result = Eval(expr, pc);
		if (!fits_in_8_bits_unsigned(result)) {
			char Err[80];

			sprintf(Err, "unsigned indirect displacement (%d) is too large to be held in 8 bits", result);
			Error(Err);
		}

		opcode |= result;
		break;

	/* Check direct unsigned offset <= 16 bits and insert into bits 0-15 */
	case COM_DIA_DIR:
		result = Eval(expr, pc);
		if (!fits_in_16_bits_unsigned(result)) {
			char Err[80];

			sprintf(Err, "unsigned direct offset of (%d) cannot be held in 16 bits", result);
			Error(Err);
		}
		opcode |= result;
		break;

	/* Check signed immediate is <= 5 bits and insert into bits 16-20 */
	case COM_STIK_IMM:
		result = Eval(expr, pc);
		if (!fits_in_5_bits(result)) {
			char Err[80];

			sprintf(Err, "STIK signed immediate value (%d) cannot be held in 5 bits", result);
			Error(Err);
		}
		opcode |= (result & B_11111) << 16;
		break;


	/* triadic combine commands					*/
	/* Notes arg position by: _A1 = bits 0-7, _A2 = bits 8-15	*/

	/* Triadic type 1 indirect addressing, args 1 and 2		*/
	/* If instr->optexpr is NULL then there is no need to check the	*/
	/* displacement as it will be an index reg.			*/
	/* Check displacement is only 1 or 0.				*/
	/* If displacement is 0, then convert mod to 0b11000:		*/
	/*	(*+ARn(0) -> *ARn)					*/

	case COM_TRI_IND1_A1:		/* mod = bits 3-7 */
		if (expr != NULL) {
			if((result = Eval(expr, pc)) > 1 || result < 0)
				Error("indirect displacement value should only be 1 or 0");

			if (result == 0)
				/* convert to a *ARn type indirection preserving ARn */
				opcode = (opcode & ~B_11111000) | B_11000000;
		}
		break;

	case COM_TRI_IND1_A2:		/* mod = bits 11-15 */
		if (expr != NULL) {
			if((result = Eval(expr, pc)) > 1 || result < 0)
				Error("indirect displacement value should only be 1 or 0");

			if (result == 0)
				/* convert to a *ARn type indirection preserving ARn */
				opcode = (opcode & ~(B_11111000 << 8)) | (B_11000000 << 8);
		}
		break;

	/* Triadic type 2 indirect addressing, args 1 and 2		*/
	/* Check unsigned displacement is <= 5 bits and insert disp. 	*/
	/* into bits 11-15 or 3-7					*/

	case COM_TRI_IND2_A1:		/* bits 3-7 */
		if (expr != NULL) {
			result = Eval(expr, pc);
			if (!fits_in_5_bits_unsigned(result)) {
				char Err[80];

				sprintf(Err, "indirect displacement value (%d) cannot be held in 5 bits", result);
				Error(Err);
			}

#if 0	/* @@@ opt syntax #4 - would also have to convert T field */
			if (result == 0) {
				/* convert to a type 1, *ARn type indirection */
				/* preserving ARn - opt syntax #4 */
				opcode = ((opcode & ~TRI_TYPE_2) & ~B_11111000) | B_11000000;
			}
			else
#endif
				/* insert 5bit displacement into mod field */
				opcode = (opcode & ~B_11111000) | (result << 3);
		}
		else
			FatalNullExpr();
		break;
	
	case COM_TRI_IND2_A2:		/* bits 11-15 */
		if (expr != NULL) {
			result = Eval(expr, pc);
			if (!fits_in_5_bits_unsigned(result)) {
				char Err[80];

				sprintf(Err, "unsigned indirect displacement value (%d) cannot be held in 5 bits", result);
				Error(Err);
			}

#if 0	/* @@@ opt syntax #4 - would also have to convert T field */
			if (result == 0) {
				/* convert to a type 1, *ARn type indirection */
				/* preserving ARn - opt syntax #4 */
				opcode = ((opcode & ~TRI_TYPE_2) & ~(B_11111000 << 8)) | (B_11000000 << 8);
			}
			else
#endif
				opcode = (opcode & ~(B_11111000 << 8)) | (result << 11);
		}
		else
			FatalNullExpr();
		break;
	
	/* Triadic type 2 immediate addressing, arg 1 only		*/
	/* Check immediate <= eight bits and insert into bits 0-7 of	*/
	/* instruction.							*/

	case COM_TRI_IMM_A1:
		if (expr != NULL) {
			result = Eval(expr, pc);
			if (!fits_in_8_bits(result)) {
				char Err[80];

				sprintf(Err, "signed immediate value (%d) cannot be held in 8 bits", result);
				Error(Err);
			}
			opcode |= (result & 0xff);
		}
		break;

	case COM_TRI_IMM_A1_UNSIGNED:
		if (expr != NULL) {
			result = Eval(expr, pc);
			if (!fits_in_8_bits_unsigned(result)) {
				char Err[80];

				sprintf(Err, "unsigned immediate value (%d) cannot be held in 8 bits", result);
				Error(Err);
			}
			opcode |= result;
		}
		break;
	
	/* parallel store combine commands				*/
	/* Check displacement is only 1 or 0, If displacement is 0,	*/
	/* then convert mod to 0b11000 (*+ARn(0) -> *ARn)		*/

	case COM_PST_IND_S1:	/* 1st src operand: mod = bits 3-7	*/
		if (expr != NULL) {
			if((result = Eval(expr, pc)) > 1 || result < 0)
				Error("indirect displacement value should only be 1 or 0");

			if (result == 0)
				/* convert to a *ARn type indirection preserving ARn */
				opcode = (opcode & ~B_11111000) | B_11000000;
		}
		break;

	case COM_PST_IND_D2:	/* Store dest operand: mod = bits 11-15	*/
		if (expr != NULL) {
			if((result = Eval(expr, pc)) > 1 || result < 0)
				Error("indirect displacement value should only be 1 or 0");

			if (result == 0)
				/* convert to a *ARn type indirection preserving ARn */
				opcode = (opcode & ~(B_11111000 << 8)) | (B_11000000 << 8);
		}
		break;

	/* parallel multiply add/sub combine commands			*/
	/* Check displacement is only 1 or 0, If displacement is 0, 	*/
	/* then convert mod to 0b11000 (*+ARn(0) -> *ARn)		*/

	case COM_PMPY_IND1:	/* mod bits 11-15 */
		if (expr != NULL) {
			if((result = Eval(expr, pc)) > 1 || result < 0)
				Error("indirect displacement value should only be 1 or 0");

			if (result == 0)
				/* convert to a *ARn type indirection preserving ARn */
				opcode = (opcode & ~(B_11111000 << 8)) | (B_11000000 << 8);
		}
		break;

	case COM_PMPY_IND2:	/* mod bits 3-7 */
		if (expr != NULL) {
			if((result = Eval(expr, pc)) > 1 || result < 0)
				Error("indirect displacement value should only be 1 or 0");

			if (result == 0)
				/* convert to a *ARn type indirection preserving ARn */
				opcode = (opcode & ~B_11111000) | B_11000000;
		}
		break;


	/* branch combine commands					*/

	/* If operation is a delayed branch then subtract 3 from the	*/
	/* offset before inserting it into the instruction, otherwise	*/
	/* subtract 1. These combine commands will only ever occur in	*/
	/* the first ->combine						*/

	/* Check PC relative offset <= 16 bits and insert into 		*/
	/* bits 0-15. Used in conditional branch instructions.		*/
	/* Bit 21 specifies if it is a delayed branch.			*/

	case COM_CBR_PCREL:	/* default for pcrel mode */
		/* pipeline adjustment for normal or delayed branch */
		if ( opcode & (1 << 21))
			result = -3;
		else
			result = -1;

		if (expr->what == E_Str) { /* possible imported label ? */
			Symbol *s = FindSymb(expr->type.name);

			if (s != NULL && s->what == HT_IMPORT) {
				/* output instruction with codestub patch */

				FlushCodeBuffer();

				/* assume word sized instruction */
				GHOFEncode(GHOF_WORD);

				/* output the machine specific patch */
				GHOFEncode(PATCH_C40MASK16ADD);

				/* output the assembled instruction as the */
				/* patches data */
				opcode |= result & 0xffff;
				GHOFEncode(opcode);

				/* For the C40 we have to shift the labelref */
				/* value to a word pointer */
				GHOFEncode(PATCH_SHIFT);
				GHOFEncode(-2);

				/* Other machines may use labelrefs if they */
				/* have not implemented linker codestubs */
				GHOFEncode(GHOF_CODESTUB);
				ObjWrite(s->name, strlen(s->name)+1);

				return;
			}
		}

		result += Eval(expr, pc);

		if (!fits_in_16_bits(result)) {
			char Err[80];

			sprintf(Err,"pc relative offset (%#x) is larger than can be held in 16 bits", result);
			Error(Err);
		}

		opcode |= result & 0xffff;
		break;

	/* Check PC relative offset < 24 bits and insert into bits 0-23 */
	/* Used in UNconditional branch instructions and RPTB(D) */
	/* Bit 24 specifies if it is a delayed branch */
	case COM_BR_PCREL:
		if ( opcode & (1 << 24))
			result = -3;
		else
			result = -1;

		if (expr->what == E_Str) { /* possible imported label ? */
		/* pipeline adjustment for normal or delayed branch */
			Symbol *s = FindSymb(expr->type.name);

			if (s != NULL && s->what == HT_IMPORT) {
				/* output instruction with codestub patch */

				FlushCodeBuffer();

				/* assume word sized instruction */
				GHOFEncode(GHOF_WORD);

				/* output the machine specific patch */
				GHOFEncode(PATCH_C40MASK24ADD);

				/* output the assembled instruction as the */
				/* patches data */
				opcode |= result & 0xffffff;
				GHOFEncode(opcode);

				/* For the C40 we have to shift the labelref */
				/* value to a word pointer */
				GHOFEncode(PATCH_SHIFT);
				GHOFEncode(-2);

				/* Other machines may use labelrefs if they */
				/* have not implemented linker codestubs */
				GHOFEncode(GHOF_CODESTUB);
				ObjWrite(s->name, strlen(s->name)+1);

				return;
			}
		}

		result += Eval(expr, pc);

		if (!fits_in_24_bits(result)) {
			char Err[80];

			sprintf(Err, "pc relative offset (%#x) is larger than can be held in 24 bits", result);
			Error(Err);
		}

		opcode |= result & 0x00ffffff;
		break;

	/* Check immediate value is <= 9 bits and insert into bits 0-8 */
	case COM_TRAP:
		if ((result = Eval(expr, pc)) & ~(B_111111111))
			Error("cannot have a trap vector higher than 511");

		opcode |= result;
		break;

	default:
		{
			char Err[80];

			sprintf(Err, "Unknown combine 1 command (%d) in second pass", \
				instr->combine);
			Fatal(Err);
			break;
		}
	}


	if (instr->combine2 == 0) {
		/* no second operand to post process */
		/* pass opcode on to the object formatter */
		WriteCodeWord(opcode);
		return;
	}

	/* now check for combine commands on a second operand */
	expr = instr->optexpr2;

	switch (instr->combine2) {

	/* triadic combine commands					*/
	/* Notes arg position by: _A1 = bits 0-7, _A2 = bits 8-15	*/

	/* Triadic type 1 indirect addressing, args 1 and 2		*/
	/* Check displacement is only 1 or 0.				*/
	/* If displacement is 0, then convert mod to 0b11000:		*/
	/*	(*+ARn(0) -> *ARn)					*/

	case COM_TRI_IND1_A1:		/* mod = bits 3-7 */
		if (expr != NULL) {
			if((result = Eval(expr, pc)) > 1 || result < 0)
				Error("indirect displacement value should only be 1 or 0");

			if (result == 0)
				/* convert to a *ARn type indirection preserving ARn */
				opcode = (opcode & ~B_11111000) | B_11000000;
		}
		break;

	case COM_TRI_IND1_A2:		/* mod = bits 11-15 */
		if (expr != NULL) {
			if ((result = Eval(expr, pc)) > 1 || result < 0)
				Error("indirect displacement value should only be 1 or 0");

			if (result == 0)
				/* convert to a *ARn type indirection preserving ARn */
				opcode = (opcode & ~(B_11111000 << 8)) | (B_11000000 << 8);
		}
		break;

	/* Triadic type 2 indirect addressing, args 1 and 2		*/
	/* Check displacement is <= 5 bits and insert disp. into	*/
	/* bits 11-15 or 3-7						*/

	case COM_TRI_IND2_A1:		/* bits 3-7 */
		if (expr != NULL) {
			result = Eval(expr, pc);
			if (!fits_in_5_bits_unsigned(result)) {
				char Err[80];

				sprintf(Err, "indirect displacement value (%d) cannot be held in 5 bits", result);
				Error(Err);
			}

#if 0	/* would also have to convert T field */
			if (result == 0) {
				/* convert to a type 1, *ARn type indirection */
				/* preserving ARn - opt syntax #4 */
				opcode = ((opcode & ~TRI_TYPE_2) & ~B_11111000) | B_11000000;
			}
			else
#endif
				opcode = (opcode & ~B_11111000) | (result << 3);
		}
		else
			FatalNullExpr();
		break;

	case COM_TRI_IND2_A2:		/* bits 11-15 */
		if (expr != NULL) {
			result = Eval(expr, pc);
			if (!fits_in_5_bits_unsigned(result)) {
				char Err[80];

				sprintf(Err, "indirect displacement value (%d) will not fit into 5 bits", result);
				Error(Err);
			}

#if 0	/* would also have to convert T field */
			if (result == 0) {
				/* convert to a type 1, *ARn type indirection */
				/* preserving ARn - opt syntax #4 */
				opcode = ((opcode & ~TRI_TYPE_2) & ~(B_11111000 << 8)) | (B_11000000 << 8);
			}
			else
#endif
				opcode = (opcode & ~(B_11111000 << 8)) | (result << 11);
		}
		else
			FatalNullExpr();
		break;


	/* parallel store combine commands				*/
	/* Check displacement is only 1 or 0, If displacement is 0,	*/
	/* then convert mod to 0b11000 (*+ARn(0) -> *ARn)		*/

	case COM_PST_IND_S1:	/* 1st src operand: mod = bits 3-7	*/
		if (expr != NULL) {
			if((result = Eval(expr, pc)) > 1 || result < 0)
				Error("indirect displacement value should only be 1 or 0");

			if (result == 0)
				/* convert to a *ARn type indirection preserving ARn */
				opcode = (opcode & ~B_11111000) | B_11000000;
		}
		break;

	case COM_PST_IND_D2:	/* Store dest operand: mod = bits 11-15	*/
		if (expr != NULL) {
			if((result = Eval(expr, pc)) > 1 || result < 0)
				Error("indirect displacement value should only be 1 or 0");

			if (result == 0)
				/* convert to a *ARn type indirection preserving ARn */
				opcode = (opcode & ~(B_11111000 << 8)) | (B_11000000 << 8);
		}
		break;

	/* parallel multiply add/sub combine commands			*/
	/* Check displacement is only 1 or 0, If displacement is 0, 	*/
	/* then convert mod to 0b11000 (*+ARn(0) -> *ARn)		*/

	case COM_PMPY_IND1:	/* mod bits 11-15 */
		if (expr != NULL) {
			if((result = Eval(expr, pc)) > 1 || result < 0)
				Error("indirect displacement value should only be 1 or 0");

			if (result == 0)
				/* convert to a *ARn type indirection preserving ARn */
				opcode = (opcode & ~B_11111000) | B_11000000;
		}
		break;

	case COM_PMPY_IND2:	/* mod bits 3-7 */
		if (expr != NULL) {
			if((result = Eval(expr, pc)) > 1 || result < 0)
				Error("indirect displacement value should only be 1 or 0");

			if (result == 0)
				/* convert to a *ARn type indirection preserving ARn */
				opcode = (opcode & ~(B_11111000 << 8)) | (B_11000000 << 8);
		}
		break;

	/* Following two commands should only get into second combine */
	/* if used with a STIK instruction */
	/* Check unsigned disp <= 8 bits and insert into bits 0-7	*/
	case COM_DIA_IND:
		result = Eval(expr, pc);
		if (!fits_in_8_bits_unsigned(result)) {
			char Err[80];

			sprintf(Err, "indirect displacement of (%d) will not fit into 8 bits", result);
			Error(Err);
		}

		opcode |= result;
		break;


	/* Check direct unsigned offset <= 16 bits and insert into bits 0-15 */
	case COM_DIA_DIR:
		result = Eval(expr, pc);
		if (!fits_in_16_bits_unsigned(result)) {
			char Err[128];
			sprintf(Err, "direct offset of (%d) cannot be held in 16 bits", result);
			Error(Err);
		}
		opcode |= result;
		break;

	default:
		{
			char Err[80];

			sprintf(Err, "Unknown combine 2 command (%d) in second pass", \
				instr->combine2);
			Fatal(Err);
			break;
		}
	}

	/* pass opcode on to the object formatter */
	WriteCodeWord(opcode);
}