Source Code of Assembler in c


#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <a.out.h>

#include <assy.h>
#include <io.h>
#include <assembler.h>
#include <formats.h>
#include <symtable.h>  /* for insert_relocation() prototype */
#include <expr.h>
#include <shortcut_alloc.h>

#ifdef USE_DMALLOC
#include <dmalloc.h>
#endif

void write_instn(int *instn);
int real_asm_nop(void);
int asm_set_numeric(struct asm_stmnt *stmnt);
int asm_set_symbolic(struct asm_stmnt *stmnt);

extern struct mnm *sethi_dummy;
extern struct mnm *or_dummy;
extern struct mnm *sub_dummy;
extern struct mnm *jmpl_dummy;
extern struct mnm *st_dummy;

extern struct mnm *stdf_dummy;
extern struct mnm *stdfq_dummy;
extern struct mnm *stfsr_dummy;
extern struct mnm *stf_dummy;
extern struct mnm *stc_dummy;
extern struct mnm *stdc_dummy;
extern struct mnm *stcsr_dummy;

extern struct mnm *lddf_dummy;
extern struct mnm *lddfq_dummy;
extern struct mnm *ldfsr_dummy;
extern struct mnm *ldf_dummy;
extern struct mnm *ldc_dummy;
extern struct mnm *lddc_dummy;
extern struct mnm *ldcsr_dummy;
extern struct mnm *rdy_dummy;
extern struct mnm *rdpsr_dummy;
extern struct mnm *rdwim_dummy;
extern struct mnm *rdtbr_dummy;
extern struct mnm *wry_dummy;
extern struct mnm *wrpsr_dummy;
extern struct mnm *wrwim_dummy;
extern struct mnm *wrtbr_dummy;

struct register_rep reg_g0_dummy = { REGULAR, 0 };
struct register_rep reg_o7_dummy = { REGULAR, 15 };
struct register_rep reg_i7_dummy = { REGULAR, 31 };

extern struct mem_stack register_alloc;
extern struct mem_stack int_alloc;

extern int text_size;
#define CURRADDR ((TEXT_SEG==current_segment)?outs_offset[TEXT_SEG]:text_size+outs_offset[DATA_SEG])

/* catchall - output to notify that some mnemonic or synthic instruction isn't
 * implemented yet
 */
int
unimplemented_mnm(struct asm_stmnt  *stmnt)
{
            assert(NULL != stmnt);

            input_problem("unimplemented mnemonic \"%s\"\n",
                        stmnt->mnemonic->op_mnm);

            return real_asm_nop();
}

/* asm_rd() exists because of the "suggested assembly language syntax".
 * RDY, RDASR, RDPSR, RDWIM, RDTBR all have different op3 fields,
 * but have the same mnemonic, "rd".  That means setting op3 based on
 * the single operand register name.
 */
int
asm_rd(struct asm_stmnt  *stmnt)
{
            assert(NULL != stmnt);

            ASM_ALLOC(stmnt->rs2, register_alloc, struct register_rep);
            stmnt->rs2->type = REGULAR;
            stmnt->rs2->regno = 0;

            /* switch on the type of "special" register 1st address */
            switch (stmnt->rs1->type)
            {
            case Y:   stmnt->mnemonic = rdy_dummy;   stmnt->rs1->regno = 0; break;
            case ASR: stmnt->mnemonic = rdy_dummy;                          break;
            case PSR: stmnt->mnemonic = rdpsr_dummy; stmnt->rs1->regno = 0; break;
            case WIM: stmnt->mnemonic = rdwim_dummy; stmnt->rs1->regno = 0; break;
            case TBR: stmnt->mnemonic = rdtbr_dummy; stmnt->rs1->regno = 0; break;
            default:
                        input_problem("Extremely goofy rd instruction\n");
                        return real_asm_nop();
                        break;
            }

            return asm_format3(stmnt);
}

int
asm_wr(struct asm_stmnt  *stmnt)
{
            assert(NULL != stmnt);

            if (!stmnt->immediate && !stmnt->rs2)
            {
                        ASM_ALLOC(stmnt->rs2, register_alloc, struct register_rep);
                        stmnt->rs2->type = REGULAR;
                        stmnt->rs2->regno = 0;
            }

            if (stmnt->rd->type != ASR)
                        stmnt->rd->regno = 0;

            switch (stmnt->rd->type)
            {
            case Y:   stmnt->mnemonic = wry_dummy;    break;
            case ASR: stmnt->mnemonic = wry_dummy;    break;
            case PSR: stmnt->mnemonic = wrpsr_dummy;  break;
            case WIM: stmnt->mnemonic = wrwim_dummy;  break;
            case TBR: stmnt->mnemonic = wrtbr_dummy;  break;
            default:
                        input_problem("Extremely goofy wr instruction\n");
                        return real_asm_nop();
                        break;
            }

            return asm_format3(stmnt);
}

int
asm_format1(struct asm_stmnt *stmnt)
{
            struct format1 instn;

            assert(NULL != stmnt);

            /* how do I tell? */
            if (NULL != stmnt->rs1 || NULL != stmnt->rs2)
            {
                        /* table A-1, SPARC v8 synthetic instructions: call _address_
                         * where _address_ has a register named in it.  Assembles as
                         * jmpl address, %o7 */

                        stmnt->mnemonic = jmpl_dummy;
                        if (!stmnt->rd)
                                    ASM_ALLOC(stmnt->rd, register_alloc, struct register_rep);
                        stmnt->rd->regno = 15;

                        return asm_load(stmnt);
            }

            instn.op = stmnt->mnemonic->op;

            if (stmnt->symbol)
            {
                        if (IS_SYMBOL_TYPE(stmnt->symbol, CURR_SEG_TYPE))
                        {
                                    /* PC-relative, no need to have a relocation record since
                                     * the call destination is in this segment */

                                    if (stmnt->immediate)
                                                instn.disp30 = ((*stmnt->immediate - CURRADDR) >> 2);
                                    else if (stmnt->symbol)
                                                instn.disp30 = (stmnt->symbol->n_value - CURRADDR) >> 2;
                                    else
                                                instn.disp30 = (0 - CURRADDR) >> 2;

                                    if (stmnt->reloc)
                                    {
                                                free(stmnt->reloc);
                                                stmnt->reloc = NULL;
                                    }
                        } else {
                                    if (stmnt->reloc)
                                    {
                                                stmnt->reloc->r_type = RELOC_WDISP30;
                                                stmnt->reloc->r_addend = 0 - CURROFFSET;
                                                insert_relocation(__FILE__, __LINE__, stmnt->reloc, stmnt->symbol);
                                    }

                                    instn.disp30 = (stmnt->symbol->n_value) >> 2;
                        }
            } else {
                        instn.disp30 = ((*stmnt->immediate - CURRADDR) >> 2);
            }

            write_instn((int *)&instn);

            return 1;
}

/* branches are also format 2 instructions, but there's enough weirdness
 * to them that you can't use a generic "assemble format 2" routine on
 * them.  One of the weird things is the use of the "rd" field as yet
 * another part of the opcode, the "cond".
 */
int
asm_branch(struct asm_stmnt *stmnt)
{
            struct format2 instn;

            assert(NULL != stmnt);

            instn.op = stmnt->mnemonic->op;

            /* here's where op3 field of struct mnm is used as cond field,
             * and that's why asm_branch() is not the same as asm_format2() */
            instn.rd = stmnt->mnemonic->op3;
            if (stmnt->mnemonic->anul_bit)
                        instn.rd |= 0x10;  /* set anul bit on instn.rd field */
            instn.op2 = stmnt->mnemonic->op2;

            if (stmnt->symbol)
            {
                        if (IS_SYMBOL_TYPE(stmnt->symbol, CURR_SEG_TYPE))
                        {
                                    instn.imm22 = (*stmnt->immediate + stmnt->reloc->r_addend - CURRADDR) >> 2;
                                    free(stmnt->reloc);
                        } else {
                                    if (stmnt->reloc)
                                    {
                                                if (RELOC_UNUSED3 == stmnt->reloc->r_type)
                                                            stmnt->reloc->r_type = RELOC_WDISP22;
                                                stmnt->reloc->r_addend = 0 - CURROFFSET;
                                                insert_relocation(__FILE__, __LINE__, stmnt->reloc, stmnt->symbol);
                                    }

                                    /* this is kind of bogus, since it will be overwritten during
                                     * relocation, but it makes output exactly like GAS output. */
                                    instn.imm22 = ((stmnt->symbol->n_value - CURRADDR)/4 & 0x3FFFFF);
                        }

            } else {

                        if (!strcmp(stmnt->mnemonic->op_mnm, "unimp"))
                                    if (stmnt->immediate)
                                                instn.imm22 = *stmnt->immediate;
                                    else
                                                instn.imm22 = 0;
                        else {
                                    /* this appears to be a violation of the "suggested assembly
                                     * language syntax" in that a branch mnemonic is only supposed
                                     * to have a label not a constant address - but GAS accepts it. */
                                    instn.imm22 = (*stmnt->immediate - CURROFFSET) >> 2;
                        }
            }

            write_instn((int *)&instn);

            return 1;
}

int
asm_format3(struct asm_stmnt *stmnt)
{
            struct format3a instn3a;
            struct format3b instn3b;
            int *x, flag = 0;

            assert(NULL != stmnt);

            if (!strcmp("restore", stmnt->mnemonic->op_mnm) ||
                        !strcmp("save", stmnt->mnemonic->op_mnm))
            {
                        if (NULL == stmnt->rs1 && NULL == stmnt->rs1 &&  NULL == stmnt->rd)
                        {
                                    /* this is a cheat */
                                    memset((void *)&instn3a, 0, sizeof(instn3a));
                                    instn3a.op = stmnt->mnemonic->op;
                                    instn3a.op3 = stmnt->mnemonic->op3;

                                    write_instn((int *)&instn3a);

                                    return 1;
                        }
            }

            instn3a.op  = instn3b.op  = stmnt->mnemonic->op;
            instn3a.op3 = instn3b.op3 = stmnt->mnemonic->op3;
            instn3a.rd  = instn3b.rd  = stmnt->rd->regno;
            if (stmnt->rs1)
                        instn3a.rs1 = instn3b.rs1 = stmnt->rs1->regno;
            else
                        instn3a.rs1 = instn3b.rs1 = 0;  /* implied %g0 */

            if (stmnt->rs2)       flag |= 4;
            if (stmnt->symbol)    flag |= 2;
            if (stmnt->immediate) flag |= 1;

            switch (flag)
            {
            case 5:  /* icky special case: op imm,r1,rd - lcc does this. */
            case 7:  /* icky special case: op sym,r1,rd */
                        instn3b.rs1 = stmnt->rs2->regno;
                        /* FALL THROUGH */

            case 1: case 2: case 3:  /* r1,imm,rd or r1,sym,rd */
                        instn3b.i = 1;

                        if (-1 != stmnt->asi)
                                    input_problem("%s instruction, ASI of %d can't be here.\n",
                                                stmnt->mnemonic->op_mnm,
                                                stmnt->asi);

                        if (stmnt->reloc)
                        {
                                    if (RELOC_UNUSED3 == stmnt->reloc->r_type)
                                                stmnt->reloc->r_type = RELOC_13;
                                    insert_relocation(__FILE__, __LINE__, stmnt->reloc, stmnt->symbol);
                                    instn3b.simm13 = 0;  /* taken care of in relocation */
                        } else if (stmnt->immediate)
                                    instn3b.simm13 = *stmnt->immediate;
                        else
                                    instn3b.simm13 = 0;

                        x = (int *)&instn3b; break;

            case 4:                  /* r1,r2,rd  */
                        instn3a.i = 0;

                        instn3a.rs2 = stmnt->rs2->regno;

                        /* ASI instructions only non-immediate forms */
                        if (-1 != stmnt->asi)
                                    instn3a.asi = stmnt->asi;
                        else
                                    instn3a.asi = 0;

                        x = (int *)&instn3a;
                        break;

            default:
                        internal_problem(__FILE__, __LINE__, "%s: Incredibly horrible error\n", stmnt->mnemonic->op_mnm);
                        return real_asm_nop();
                        break;
            }

            write_instn(x);

            return 1;
}

/* asm_format3c() - assembly of floating point opcodes.
 * fp ops are again a bit unusual: the ASI field is used as another
 * partial opcode.  */
int
asm_format3c(struct asm_stmnt *stmnt)
{
            if (!stmnt->rs2)
            {         
                        if (0xff == stmnt->mnemonic->op2)
                        {
                                    /* mnemonic freg_rs2,freg_rd */
                                    stmnt->rs2 = stmnt->rs1;
                                    stmnt->rs1 = NULL;
                        } else {
                                    /* mnemonic freg_rs1,freg_rs2 */
                                    stmnt->rs2 = stmnt->rd;
                                    ASM_ALLOC(stmnt->rd, register_alloc, struct register_rep);
                                    stmnt->rd->type  = REGULAR;
                                    stmnt->rd->regno = 0;
                        }
            }

            stmnt->asi = stmnt->mnemonic->opf;

            return asm_format3(stmnt);
}

/* trap instructions use a weird form of format 3a and 3b:
 * the rd field of formats 3a and 3b is 5 bits, 4 of which
 * are used to indicate the trap "cond".  asm_trap() covers
 * up the use of rd field by filling in a "phony" asm_address
 * with a register number that is actually the "cond" field.
 * In turn, the "cond" field is taken from the op2 field of the
 * struct mnm, which represents the opcode mnemonic.
 */

int
asm_trap(struct asm_stmnt *stmnt)
{
            assert(NULL != stmnt);
            ASM_ALLOC(stmnt->rd, register_alloc, struct register_rep);
            stmnt->rd->regno = (stmnt->mnemonic->op2 & 0xf);
            return asm_load(stmnt);
}

/*
 * asm_ret() and asm_retl() handle some synthetic instructions
 * that map directly into jmpl variants.
 */

int
asm_ret_retl(struct asm_stmnt *stmnt, int regno)
{
            assert(NULL != stmnt);

            stmnt->mnemonic = jmpl_dummy;
            ASM_ALLOC(stmnt->rs1, register_alloc, struct register_rep);
            ASM_ALLOC(stmnt->rd,  register_alloc, struct register_rep);

            stmnt->rs1->type  = REGULAR;
            stmnt->rs1->regno = regno;
            stmnt->rs2 = NULL;
            stmnt->rd->type   = REGULAR;
            stmnt->rd->regno  = 0;

            if (!stmnt->immediate)
                        ASM_ALLOC(stmnt->immediate, int_alloc, int);
            *stmnt->immediate = 8;

            stmnt->reloc = NULL;
            stmnt->symbol = NULL;
            stmnt->asi = -1;

            return asm_load(stmnt);
}

int
asm_ret(struct asm_stmnt *stmnt)
{
            return asm_ret_retl(stmnt, 31);
}

int
asm_retl(struct asm_stmnt *stmnt)
{
            return asm_ret_retl(stmnt, 15);
}

int
asm_jmp(struct asm_stmnt *stmnt)
{
            assert(NULL != stmnt);

            ASM_ALLOC(stmnt->rd, register_alloc, struct register_rep);
            stmnt->rd->type = REGULAR;
            stmnt->rd->regno = 0;

            if (!stmnt->immediate && !stmnt->symbol && !stmnt->rs2)
            {
                        ASM_ALLOC(stmnt->rs2, register_alloc, struct register_rep);
                        stmnt->rs2->type = REGULAR;
                        stmnt->rs2->regno = 0;
            }

            return asm_load(stmnt);
}

/* cmp rs1,reg_or_imm -> subcc rs1,reg_or_imm,%g0 */
int
asm_cmp(struct asm_stmnt *stmnt)
{
            assert(NULL != stmnt);

            stmnt->rs2 = stmnt->rd;

            ASM_ALLOC(stmnt->rd, register_alloc, struct register_rep);
            stmnt->rd->type  = REGULAR;
            stmnt->rd->regno = 0;

            return asm_format3(stmnt);
}

/* not rs1,rd  ->  xnor rs1,%g0,rd
 * not rd      ->  xnor  rd,%g0,rd
 */
int
asm_not(struct asm_stmnt *stmnt)
{
            assert(NULL != stmnt);

            ASM_ALLOC(stmnt->rs2, register_alloc, struct register_rep);
            stmnt->rs2->type  = REGULAR;
            stmnt->rs2->regno = 0;

            /* how to distinguish 'not rs1,rd', from 'not rd'? */
            if (!stmnt->rd)
            {
                        ASM_ALLOC(stmnt->rd, register_alloc, struct register_rep);
                        stmnt->rd->type  = stmnt->rs1->type;
                        stmnt->rd->regno = stmnt->rs1->regno;
            }

            return asm_format3(stmnt);
}

/* bset|bclr|btog reg-or-imm,rd -> opcode rd,reg-or-imm,rd */
int
asm_synth(struct asm_stmnt *stmnt)
{
            assert(NULL != stmnt);

            stmnt->rs2 = stmnt->rs1;
           
            ASM_ALLOC(stmnt->rs1, register_alloc, struct register_rep);
            stmnt->rs1->type  = stmnt->rd->type;
            stmnt->rs1->regno = stmnt->rd->regno;

            return asm_format3(stmnt);
}

/* inc, dec, inccc, deccc synthetics
 * opcode rd -> opcode rd,1,rd
 * opcode const13,rd -> opcode rd,const13,rd
 */
int
asm_inc_dec(struct asm_stmnt *stmnt)
{
            struct register_rep *r;

            ASM_ALLOC(r, register_alloc, struct register_rep);
            if (stmnt->rs1)
            {
                        /* op rd */
                        r->type = stmnt->rs1->type;
                        r->regno = stmnt->rs1->regno;
                        stmnt->rd = r;
                        ASM_ALLOC(stmnt->immediate, int_alloc, int);
                        *stmnt->immediate = 1;
            } else {
                        /* op const13, rd */
                        r->type = stmnt->rd->type;
                        r->regno = stmnt->rd->regno;
                        stmnt->rs1 = r;
            }

            return asm_format3(stmnt);
}

/* neg rs2,rd  ->  sub %g0,rs2,rd ! stmnt->rs1 has rs2 in it.
 * neg rd      ->  sub %g0,rd, rd ! stmnt->rs1 has rd in it.
 */
int
asm_neg(struct asm_stmnt *stmnt)
{
            assert(NULL != stmnt);

            if (stmnt->rd)
            {
                        /* it's a 'neg rs2, rd' */
                        stmnt->rs2 = stmnt->rs1;
            } else {
                        /* it's a 'neg rd' */
                        stmnt->rd = stmnt->rs1;
                        ASM_ALLOC(stmnt->rs2, register_alloc, struct register_rep);
                        stmnt->rs2->type = stmnt->rd->type;
                        stmnt->rs2->regno = stmnt->rd->regno;
            }

            ASM_ALLOC(stmnt->rs1, register_alloc, struct register_rep);
            stmnt->rs1->type = REGULAR;
            stmnt->rs1->regno = 0;

            return asm_format3(stmnt);
}

/* btst reg_or_imm,rs1  ->  andcc rs1,reg_or_imm,%g0
 *
 * Gnu Assembler apparently doesn't re-arrange the operands _if_
 * they are both registers.
 */
int
asm_btst(struct asm_stmnt *stmnt)
{
            if (!stmnt->rs1)
            {
                        stmnt->rs2 = stmnt->rs1;
                        stmnt->rs1 = stmnt->rd;
            } else {
                        /* Gnu 'as' does it this way */
                        stmnt->rs2 = stmnt->rd;
            }

            ASM_ALLOC(stmnt->rd, register_alloc, struct register_rep);
            stmnt->rd->type = REGULAR;
            stmnt->rd->regno = 0;

            return asm_format3(stmnt);
}

int
asm_tst(struct asm_stmnt *stmnt)
{
            ASM_ALLOC(stmnt->rs2, register_alloc, struct register_rep);
            ASM_ALLOC(stmnt->rd, register_alloc, struct register_rep);
            stmnt->rs2->regno = stmnt->rd->regno = 0;
            stmnt->rs2->type = stmnt->rd->type = REGULAR;
            return asm_format3(stmnt);
}

int
asm_mov(struct asm_stmnt *stmnt)
{
            assert(NULL != stmnt);

            if (stmnt->rs1 && REGULAR != stmnt->rs1->type)
                        return asm_rd(stmnt);

            if (stmnt->rd && REGULAR != stmnt->rd->type)
                        return asm_wr(stmnt);

            stmnt->mnemonic = or_dummy;
            ASM_ALLOC(stmnt->rs2, register_alloc, struct register_rep);
            if (stmnt->rs1)
            {
                        stmnt->rs2->regno = stmnt->rs1->regno;
                        stmnt->rs2->type  = stmnt->rs1->type;

                        stmnt->rs1->regno = REGULAR;
                        stmnt->rs1->type  = 0;
            } else {
                        stmnt->rs1 = stmnt->rs2;
                        stmnt->rs1->type  = REGULAR;
                        stmnt->rs1->regno = 0;
                        stmnt->rs2 = NULL;
            }

            return asm_format3(stmnt);
}


/* assemble a "set" synthetic instruction mnemonic into a sethi
 * instruction and an or instruction as per Table A-1 of
 * SPARC v8 architecture manual */

int
asm_set(struct asm_stmnt *stmnt)
{
            int r = 0;

            assert(NULL != stmnt);

            if ((stmnt->symbol && N_ABS == (stmnt->symbol->n_type&N_TYPE)) || NULL == stmnt->symbol )
                        r = asm_set_numeric(stmnt);
            else if (NULL != stmnt->symbol)
                        r = asm_set_symbolic(stmnt);
            else
                        internal_problem(__FILE__, __LINE__, "goofy set synthetic ");

            return r;
}

/* set LXX23,%i0 or something */
int
asm_set_symbolic(struct asm_stmnt *stmnt)
{
            unsigned int orig_imm;
            struct relocation_info *r;

            /* the %hi() part */
            stmnt->mnemonic = sethi_dummy;

            /* asm_sethi() doesn't set relocation type to RELOC_HI22 without %hi */
            if (stmnt->immediate)
            {
                        orig_imm = *stmnt->immediate;
                        *stmnt->immediate >>= 10;
            }

            if (stmnt->reloc)
                        stmnt->reloc->r_type = RELOC_HI22;

            asm_sethi(stmnt);

            /* the %lo() part - stmnt looks like:
             * set identifier NULL register_rd
             * assemble  "or rd,%lo(identifier),rd" */

            stmnt->mnemonic = or_dummy;

            if (stmnt->immediate)
                        *stmnt->immediate = (orig_imm & 0x3ff);

            ASM_ALLOC(stmnt->rs1, register_alloc, struct register_rep);
            stmnt->rs1->regno = stmnt->rd->regno;  /* r[1] and r[rd] the same */

            if (stmnt->reloc)
            {          /* have to put together a new struct relocation_info for
                         * the 2nd instruction of this pair */

                        r = stmnt->reloc;

                        STRUCT_ALLOC(stmnt->reloc, struct relocation_info);

                        *stmnt->reloc = *r;
                        stmnt->reloc->r_address = CURROFFSET;
                        stmnt->reloc->r_type    = RELOC_LO10;
            }

            return asm_format3(stmnt);
}

int
asm_set_numeric(struct asm_stmnt *stmnt)
{
            if (-4096 <= *stmnt->immediate && 4095 >= *stmnt->immediate)
            {
                        /* or %g0, value, %rd */

                        stmnt->mnemonic = or_dummy;

                        assert(NULL == stmnt->rs2);
                        stmnt->rs1 = &reg_g0_dummy;

                        asm_format3(stmnt);

                        stmnt->rs1 = NULL;

            } else {

                        int constant = *stmnt->immediate;

                        stmnt->mnemonic = sethi_dummy;
                        *stmnt->immediate = *stmnt->immediate >> 10;
                        asm_sethi(stmnt);

                        if (constant & 0x3ff)
                        {
                                    /* assemble the low 10 bit part */
                                    stmnt->mnemonic = or_dummy;

                                    /* asm_format3 trims to low 13 bits - need low 10 bits */
                                    *stmnt->immediate = (constant & 0x3ff);

                                    stmnt->rs1 = stmnt->rd;

                                    asm_format3(stmnt);

                                    stmnt->rs1 = NULL;
                        }
            }

            return 1;
}

int
asm_load(struct asm_stmnt *stmnt)
{
            int r;
            unsigned int old_op3;
           
            assert(NULL != stmnt);

            if (!stmnt->rs1)
            {
                        /* implied %g0 */
                        ASM_ALLOC(stmnt->rs1, register_alloc, struct register_rep);
                        stmnt->rs1->type = REGULAR;
                        stmnt->rs1->regno = 0;
            }

            if (!stmnt->rs2 && !stmnt->symbol && !stmnt->immediate)
            {
                        /* implied %g0 */
                        ASM_ALLOC(stmnt->rs2, register_alloc, struct register_rep);
                        stmnt->rs2->type = REGULAR;
                        stmnt->rs2->regno = 0;
            }

            old_op3 = stmnt->mnemonic->op3;

            if (stmnt->rd && REGULAR != stmnt->rd->type)
                        switch (stmnt->rd->type)
                        {
                        case FP:
                                    /* should check for lddf, stdf: is the %frd dest fp reg evenly-numbered? */
                                    stmnt->mnemonic->op3 |= 0x20;
                                    break;
                        case FSR:
                                    if ('l' == *stmnt->mnemonic->op_mnm)
                                                stmnt->mnemonic->op3 = ldfsr_dummy->op3;
                                    else
                                                stmnt->mnemonic->op3 = stfsr_dummy->op3;
                                    break;
                        case COPROC:
                                    stmnt->mnemonic->op3 |= 0x30;
                                    break;
                        case CSR:
                                    if ('l' == *stmnt->mnemonic->op_mnm)
                                                stmnt->mnemonic->op3 = ldcsr_dummy->op3;
                                    else
                                                stmnt->mnemonic->op3 = stcsr_dummy->op3;
                                    break;
                        case FQ:
                                    stmnt->mnemonic = stdfq_dummy;
                                    break;
                        case Y: case ASR: case PSR: case WIM: case TBR:
                                    break;
                        case REGULAR:
                                    /* nothing */
                                    break;
                        }

            r = asm_format3(stmnt);

            stmnt->mnemonic->op3 = old_op3;

            return r;
}

/* clr %rd -> or %g0,%g0,%rd */
int
asm_clr(struct asm_stmnt *stmnt)
{
            return asm_format3(stmnt);
}

/* clr|clrh|clrb [address]  => st %g0,[address]
 *
 * This has ugly special purpose code in it because there's no way to tell
 * a 'clr %r15' from a 'clr [%r15]' with my current grammar.  This is the only
 * instruction that has this problem, so I chose to hack around it rather than
 * fix the statement rep struct for the other 200+ opcodes
 */
int
asm_clr_mem(struct asm_stmnt *stmnt)
{
            int r;
            struct mnm *old_mnemonic;

            old_mnemonic = stmnt->mnemonic;

            if (!strcmp(stmnt->mnemonic->op_mnm, "clr"))
            {
                        if (!stmnt->asi)
                        {
                                    stmnt->rd = stmnt->rs1;
                                    ASM_ALLOC(stmnt->rs1, register_alloc, struct register_rep);
                                    ASM_ALLOC(stmnt->rs2, register_alloc, struct register_rep);

                                    stmnt->rs1->type = stmnt->rs2->type = REGULAR;
                                    stmnt->rs1->regno = stmnt->rs2->regno = 0;

                                    stmnt->asi = -1;  /* clr synthetic _can't_ have an ASI */

                                    r = asm_format3(stmnt);

                                    return r;

                        } else
                                    stmnt->mnemonic = st_dummy;
            }

            ASM_ALLOC(stmnt->rd, register_alloc, struct register_rep);
            stmnt->rd->type = REGULAR;
            stmnt->rd->regno = 0;

            r = asm_load(stmnt);

            stmnt->mnemonic = old_mnemonic;

            return r;
}

/*  this is so I can use it as a place-holder */
int
real_asm_nop(void)
{
            struct format2 instn;

            instn.op = 0x0;
            instn.rd = 0x0;
            instn.op2 = 0x4;
            instn.imm22 = 0;

            write_instn((void *)&instn);

            return 1;
}

int
asm_nop(struct asm_stmnt *stmnt)
{
            return real_asm_nop();
}


int
asm_sethi(struct asm_stmnt *stmnt)
{
            struct format2 instn;

            assert(NULL != stmnt);

            instn.op  = stmnt->mnemonic->op;
            instn.op2 = stmnt->mnemonic->op2;
            instn.rd  = stmnt->rd->regno;

            if (NULL == stmnt->symbol && NULL == stmnt->immediate)
            {
                        input_problem("something wrong, constant part NULL\n");
            } else {

                        if (stmnt->reloc)
                        {
                                    /* this is a little tricky: whoever calls this routine needs
                                     * to set the relocation to RELOC_HI22 or RELOC_LO10.
                                     * Otherwise, some assembly programmer may be counting on
                                     * RELOC_22 rather than RELOC_HI22. */

                                    if (RELOC_UNUSED3 == stmnt->reloc->r_type)
                                                stmnt->reloc->r_type = RELOC_22;
                                    insert_relocation(__FILE__, __LINE__, stmnt->reloc, stmnt->symbol);

                                    instn.imm22 = 0;
                        } else if (stmnt->immediate)
                                    instn.imm22 = *stmnt->immediate;
            }

            write_instn((int *)&instn);

            return 1;
}

int
asm_set_size(struct asm_stmnt *stmnt)
{
            int r = 4;

            if (!stmnt->symbol)
            {
                        if (!stmnt->immediate)
                                    input_problem("set without symbol or immediate\n");
                        else {
                                    if (-4096 <= *stmnt->immediate && 4095 >= *stmnt->immediate)
                                                r = 4;                            /* or %g0,value,%rd */
                                    else if (0 == (*stmnt->immediate & 0x3ff))
                                                r = 4;                            /* sethi value, %rd (no %hi)*/
                                    else
                                                r = 8;                            /* sethi; or; */
                        }
            } else {
                        if (N_ABS == (stmnt->symbol->n_type & N_TYPE))
                                    r = 4;
                        else
                                    r = 8;    /* always a 'sethi' and an 'or' */
            }

            return r;
}

int
asm_ld2(struct asm_stmnt *stmnt)
{
            int r;
            int imm = 4, used_imm = 0;

            r = asm_load(stmnt);

            /* bump up the FP register by one */
            ++stmnt->rd->regno;

            /* add a 4-byte immediate */
            if (stmnt->immediate)
                        *stmnt->immediate += 4;
            else {
                        stmnt->immediate = &imm;
                        used_imm = 1;
            }

            if (stmnt->rs2)
            {
                        ASM_DEALLOC(stmnt->rs2, register_alloc);
                        stmnt->rs2 = NULL;
            }

            r += asm_load(stmnt);

            if (used_imm)
                        stmnt->immediate = NULL;

            return r;
}

void
symbol_equals_expr(struct expr_node *sym, struct expr_node *expr)
{
            struct nlist *ntmp, *nsym;
            struct relocation_info *rtmp;
            int *val;
            struct register_address reg;

            assert(NULL != sym);
            assert(NULL != expr);

            if (ExprSym != sym->kind)
            {
                        input_problem("symbol = expression, but symbol hasn't got a string name\n");
                        return;
            }

if (NULL == (nsym = symbol_named(sym->u.id)))
                        nsym = add_symbol_named(sym->u.id);

            nsym->n_type = N_ABS;

            expr_to_imm(expr, &ntmp, &rtmp, &val, &reg);

            if (val)
            {
                        nsym->n_value = *val;
                        ASM_DEALLOC(val, int_alloc);
            } else
                        internal_problem(__FILE__, __LINE__, "no value?\n");

            if (rtmp)
            {
                        if (RELOC_UNUSED3 == rtmp->r_type)
                                    rtmp->r_type = RELOC_32;

                        insert_relocation(__FILE__, __LINE__, rtmp, ntmp);
            }
}

posted under |

0 comments:

Post a Comment

Newer Post Home

About

Cool na? :) Now Learn How to create one by Clicking here


Followers

About This Blog