OpenCores
URL https://opencores.org/ocsvn/raptor64/raptor64/trunk

Subversion Repositories raptor64

[/] [raptor64/] [trunk/] [software/] [c64/] [source/] [CodeGenerator.c] - Rev 51

Compare with Previous | Blame | View Log

#include        <stdio.h>
#include        "c.h"
#include        "expr.h"
#include "Statement.h"
#include        "gen.h"
#include        "cglbdec.h"
 
/*
 *	68000 C compiler
 *
 *	Copyright 1984, 1985, 1986 Matthew Brandt.
 *  all commercial rights reserved.
 *
 *	This compiler is intended as an instructive tool for personal use. Any
 *	use for profit without the written consent of the author is prohibited.
 *
 *	This compiler may be distributed freely for non-commercial use as long
 *	as this notice stays intact. Please forward any enhancements or questions
 *	to:
 *
 *		Matthew Brandt
 *		Box 920337
 *		Norcross, Ga 30092
 */
 
/*
 *      this module contains all of the code generation routines
 *      for evaluating expressions and conditions.
 */
 
/*******************************************************
	Modified to support Raptor64 'C64' language
	by Robert Finch
	robfinch@opencores.org
*******************************************************/
 
AMODE *GenerateExpression();            /* forward ParseSpecifieraration */
 
extern int throwlab;
/*
 *      construct a reference node for an internal label number.
 */
AMODE *make_label(__int64 lab)
{
	struct enode    *lnode;
    struct amode    *ap;
    lnode = xalloc(sizeof(struct enode));
    lnode->nodetype = en_labcon;
    lnode->i = lab;
    ap = xalloc(sizeof(struct amode));
    ap->mode = am_direct;
    ap->offset = lnode;
    return ap;
}
 
AMODE *make_string(char *s)
{
	ENODE *lnode;
    AMODE *ap;
 
    lnode = xalloc(sizeof(struct enode));
    lnode->nodetype = en_nacon;
    lnode->sp = s;
    ap = allocAmode();
    ap->mode = am_direct;
    ap->offset = lnode;
    return ap;
}
 
/*
 *      make a node to reference an immediate value i.
 */
AMODE *make_immed(__int64 i)
{
	AMODE *ap;
    ENODE *ep;
    ep = xalloc(sizeof(struct enode));
    ep->nodetype = en_icon;
    ep->i = i;
    ap = allocAmode();
    ap->mode = am_immed;
    ap->offset = ep;
    return ap;
}
 
AMODE *make_indirect(int i)
{
	AMODE *ap;
    ENODE *ep;
    ep = xalloc(sizeof(struct enode));
    ep->nodetype = en_uw_ref;
    ep->i = 0;
    ap = allocAmode();
	ap->mode = am_ind;
	ap->preg = i;
    ap->offset = ep;
    return ap;
}
 
AMODE *make_indexed(__int64 o, int i)
{
	AMODE *ap;
    ENODE *ep;
    ep = xalloc(sizeof(struct enode));
    ep->nodetype = en_icon;
    ep->i = o;
    ap = allocAmode();
	ap->mode = am_indx;
	ap->preg = i;
    ap->offset = ep;
    return ap;
}
 
/*
 *      make a direct reference to a node.
 */
AMODE *make_offset(ENODE *node)
{
	AMODE *ap;
    ap = allocAmode();
    ap->mode = am_direct;
    ap->offset = node;
    return ap;
}
 
/*
 *      MakeLegalAmode will coerce the addressing mode in ap1 into a
 *      mode that is satisfactory for the flag word.
 */
void MakeLegalAmode(AMODE *ap,int flags, int size)
{
	AMODE *ap2;
	__int64 i;
 
	if (ap==NULL) return;
    if( ((flags & F_VOL) == 0) || ap->tempflag )
    {
        switch( ap->mode ) {
            case am_immed:
					i = ((ENODE *)(ap->offset))->i;
					if (flags & F_IMMED18) {
						if (i < 0x1ffff && i > -0x1ffff)
							return;
					}
                    else if( flags & F_IMMED )
                        return;         /* mode ok */
                    break;
            case am_reg:
                    if( flags & F_REG )
                        return;
                    break;
            case am_ind:
			case am_indx:
            case am_indx2: 
			case am_direct:
			case am_indx3:
                    if( flags & F_MEM )
                        return;
                    break;
            }
        }
 
        if( flags & F_REG )
        {
            ReleaseTempRegister(ap);      /* maybe we can use it... */
            ap2 = GetTempRegister();      /* AllocateRegisterVars to dreg */
			if (ap->mode == am_ind || ap->mode==am_indx) {
				switch(size) {
				case 1:	GenerateDiadic(op_lb,0,ap2,ap); break;
				case 2:	GenerateDiadic(op_lc,0,ap2,ap); break;
				case 4:	GenerateDiadic(op_lh,0,ap2,ap); break;
				case 8:	GenerateDiadic(op_lw,0,ap2,ap); break;
				}
			}
			else if (ap->mode==am_immed)
				GenerateTriadic(op_ori,0,ap2,makereg(0),ap);
			else {
				if (ap->mode==am_reg)
					GenerateTriadic(op_or,0,ap2,ap,makereg(0));
				else {
					switch(size) {
					case 1:	GenerateDiadic(op_lb,0,ap2,ap); break;
					case 2:	GenerateDiadic(op_lc,0,ap2,ap); break;
					case 4:	GenerateDiadic(op_lh,0,ap2,ap); break;
					case 8:	GenerateDiadic(op_lw,0,ap2,ap); break;
					}
				}
			}
            ap->mode = am_reg;
            ap->preg = ap2->preg;
            ap->deep = ap2->deep;
            ap->tempflag = 1;
            return;
        }
        if( size == 1 )
		{
			ReleaseTempRegister(ap);
			ap2 = GetTempRegister();
			GenerateTriadic(op_or,0,ap2,ap,makereg(0));
			GenerateTriadic(op_sext8,0,ap2,ap2,NULL);
			ap->mode = ap2->mode;
			ap->preg = ap2->preg;
			ap->deep = ap2->deep;
			size = 2;
        }
        ap2 = GetTempRegister();
		switch(ap->mode) {
		case am_ind:
		case am_indx:
			switch(size) {
			case 1:	GenerateDiadic(op_lb,0,ap2,ap); break;
			case 2:	GenerateDiadic(op_lc,0,ap2,ap); break;
			case 4:	GenerateDiadic(op_lh,0,ap2,ap); break;
			case 8:	GenerateDiadic(op_lw,0,ap2,ap); break;
			}
			break;
		case am_immed:
			GenerateTriadic(op_ori,0,ap2,makereg(0),ap);
		case am_reg:
			GenerateTriadic(op_or,0,ap2,ap,makereg(0));
		default:
			switch(size) {
			case 1:	GenerateDiadic(op_lb,0,ap2,ap); break;
			case 2:	GenerateDiadic(op_lc,0,ap2,ap); break;
			case 4:	GenerateDiadic(op_lh,0,ap2,ap); break;
			case 8:	GenerateDiadic(op_lw,0,ap2,ap); break;
			}
		}
    ap->mode = am_reg;
    ap->preg = ap2->preg;
    ap->deep = ap2->deep;
    ap->tempflag = 1;
}
 
/*
 *      if isize is not equal to osize then the operand ap will be
 *      loaded into a register (if not already) and if osize is
 *      greater than isize it will be extended to match.
 */
void GenerateSignExtend(AMODE *ap, int isize, int osize, int flags)
{    
	struct amode *ap2;
 
	if( isize == osize )
        return;
    if(ap->mode != am_reg)
        MakeLegalAmode(ap,flags & F_REG,isize);
    switch( isize )
    {
    case 1:	GenerateDiadic(op_sext8,0,ap,ap); break;
    case 2:	GenerateDiadic(op_sext16,0,ap,ap); break;
    case 4:	GenerateDiadic(op_sext32,0,ap,ap); break;
    }
}
 
/*
 *      return true if the node passed can be generated as a short
 *      offset.
 */
int isshort(ENODE *node)
{
	return node->nodetype == en_icon &&
        (node->i >= -32768 && node->i <= 32767);
}
 
/*
 *      return true if the node passed can be evaluated as a byte
 *      offset.
 */
int isbyte(ENODE *node)
{
	return node->nodetype == en_icon &&
       (-128 <= node->i && node->i <= 127);
}
 
int ischar(ENODE *node)
{
	return node->nodetype == en_icon &&
        (node->i >= -32768 && node->i <= 32767);
}
 
/*
 *      generate code to evaluate an index node (^+) and return
 *      the addressing mode of the result. This routine takes no
 *      flags since it always returns either am_ind or am_indx.
 */
AMODE *GenerateIndex(ENODE *node)
{       
	AMODE *ap1, *ap2, *ap3;
 
    if( (node->p[0]->nodetype == en_tempref || node->p[0]->nodetype==en_regvar) && (node->p[1]->nodetype == en_tempref || node->p[1]->nodetype==en_regvar))
    {       /* both nodes are registers */
        ap1 = GenerateExpression(node->p[0],F_REG,8);
        ap2 = GenerateExpression(node->p[1],F_REG,8);
        ap1->mode = am_indx2;
        ap1->sreg = ap2->preg;
		ap1->offset = makeinode(en_icon,0);
		ap1->scale = node->scale;
        return ap1;
    }
    ap1 = GenerateExpression(node->p[0],F_REG | F_IMMED,8);
    if( ap1->mode == am_immed )
    {
		ap2 = GenerateExpression(node->p[1],F_REG,8);
		ap2->mode = am_indx;
		ap2->offset = ap1->offset;
		ReleaseTempRegister(ap1);
		return ap2;
    }
    ap2 = GenerateExpression(node->p[1],F_ALL,8);   /* get right op */
    if( ap2->mode == am_immed && ap1->mode == am_reg ) /* make am_indx */
    {
        ap2->mode = am_indx;
		ReleaseTempRegister(ap2);
        ap2->preg = ap1->preg;
        ap2->deep = ap1->deep;
        return ap2;
    }
	// ap1->mode must be F_REG
	MakeLegalAmode(ap2,F_REG,8);
//	ap3 = GetTempRegister();
//	GenerateTriadic(op_addu,0,ap3,ap1,ap2);             /* add left to address reg */
    ap1->mode = am_indx2;            /* make indirect */
	ap1->sreg = ap2->preg;
	ap1->offset = makeinode(en_icon,0);
	ap1->scale = node->scale;
//  ReleaseTempRegister(ap2);                    /* release any temps in ap2 */
//	ReleaseTempRegister(ap1);
    return ap1;                     /* return indirect */
}
 
long GetReferenceSize(ENODE *node)
{
    switch( node->nodetype )        /* get load size */
    {
    case en_b_ref:
    case en_ub_ref:
    case en_bfieldref:
    case en_ubfieldref:
            return 1;
	case en_c_ref:
	case en_uc_ref:
	case en_cfieldref:
	case en_ucfieldref:
			return 2;
	case en_h_ref:
	case en_uh_ref:
	case en_hfieldref:
	case en_uhfieldref:
			return 4;
    case en_w_ref:
	case en_uw_ref:
    case en_wfieldref:
	case en_uwfieldref:
	case en_tempref:
	case en_regvar:
            return 8;
    }
	return 8;
}
 
/*
 *      return the addressing mode of a dereferenced node.
 */
AMODE *GenerateDereference(ENODE *node,int flags,int size)
{    
	struct amode    *ap1;
    int             siz1;
 
	siz1 = GetReferenceSize(node);
    if( node->p[0]->nodetype == en_add )
    {
        ap1 = GenerateIndex(node->p[0]);
        GenerateSignExtend(ap1,siz1,size,flags);
        MakeLegalAmode(ap1,flags,size);
        return ap1;
    }
    else if( node->p[0]->nodetype == en_autocon )
    {
        ap1 = xalloc(sizeof(struct amode));
        ap1->mode = am_indx;
        ap1->preg = 27;
        ap1->offset = makeinode(en_icon,node->p[0]->i);
        GenerateSignExtend(ap1,siz1,size,flags);
        MakeLegalAmode(ap1,flags,size);
        return ap1;
    }
    ap1 = GenerateExpression(node->p[0],F_REG | F_IMMED,4); /* generate address */
    if( ap1->mode == am_reg )
    {
        ap1->mode = am_ind;
        GenerateSignExtend(ap1,siz1,size,flags);
        MakeLegalAmode(ap1,flags,size);
        return ap1;
    }
    ap1->mode = am_direct;
    GenerateSignExtend(ap1,siz1,size,flags);
    MakeLegalAmode(ap1,flags,size);
    return ap1;
}
 
void SignExtendBitfield(ENODE *node, struct amode *ap3, __int64 mask)
{
	struct amode *ap2;
	__int64 umask;
 
	umask = 0x8000000000000000L | ~(mask >> 1);
	ap2 = GetTempRegister();
	GenerateTriadic(op_ori,0,ap2,makereg(0),make_immed(umask));
	GenerateTriadic(op_add,0,ap3,ap3,ap2);
	GenerateTriadic(op_xor,0,ap3,ap3,ap2);
	ReleaseTempRegister(ap2);
}
 
AMODE *GenerateBitfieldDereference(ENODE *node, int flags, int size)
{
    AMODE *ap, *ap1,*ap2,*ap3;
    long            mask,umask;
    int             width = node->bit_width + 1;
	int isSigned;
 
	isSigned = node->nodetype==en_wfieldref || node->nodetype==en_hfieldref || node->nodetype==en_cfieldref || node->nodetype==en_bfieldref;
	mask = 0;
	while (--width)	mask = mask + mask + 1;
    ap = GenerateDereference(node, flags, node->esize);
    MakeLegalAmode(ap, flags, node->esize);
	ap3 = GetTempRegister();
	GenerateTriadic(op_or,0,ap3,ap,makereg(0));
	ReleaseTempRegister(ap);
    if (node->bit_offset > 0) {
		GenerateDiadic(op_shru, 0, ap3, make_immed((__int64) node->bit_offset));
		GenerateDiadic(op_and, 0, ap3, make_immed(mask));
		//MakeLegalAmode(ap, flags, node->esize);
		if (isSigned)
			SignExtendBitfield(node, ap3, mask);
    }
	else {
		GenerateTriadic(op_and, 0, ap3, ap3, make_immed(mask));
		if (isSigned)
			SignExtendBitfield(node, ap3, mask);
	}
    //mask = 0;
    //while (--width)	mask = mask + mask + 1;
//    GenerateDiadic(op_and, (int) node->esize, make_immed(mask), ap);
	MakeLegalAmode(ap3, flags, node->esize);
    return ap3;
}
 
/*
 *      generate code to evaluate a unary minus or complement.
 */
AMODE *GenerateUnary(ENODE *node,int flags, int size, int op)
{
	AMODE *ap,*ap1;
    ap = GenerateExpression(node->p[0],F_REG,size);
	ap1 = GetTempRegister();
    GenerateDiadic(op,0,ap1,ap);
    ReleaseTempRegister(ap);
    MakeLegalAmode(ap1,flags,size);
    return ap1;
}
 
AMODE *GenerateBinary(ENODE *node,int flags, int size, int op)
{
	AMODE *ap1, *ap2, *ap3;
	int op2;
    ap1 = GenerateExpression(node->p[0],F_REG,size);
    ap2 = GenerateExpression(node->p[1],F_REG|F_IMMED,size);
	ap3 = GetTempRegister();
	GenerateTriadic(op,0,ap3,ap1,ap2);
    ReleaseTempRegister(ap1);
    ReleaseTempRegister(ap2);
    MakeLegalAmode(ap3,flags,size);
    return ap3;
}
 
/*
 *      generate code to evaluate a mod operator or a divide
 *      operator.
 */
AMODE *GenerateModDiv(ENODE *node,int flags,int size, int op)
{
	AMODE *ap1, *ap2, *ap3;
 
    if( node->p[0]->nodetype == en_icon )
         swap_nodes(node);
    ap1 = GenerateExpression(node->p[0],F_REG,8);
    ap2 = GenerateExpression(node->p[1],F_REG | F_IMMED,8);
	ap3 = GetTempRegister();
	GenerateTriadic(op,0,ap3,ap1,ap2);
//    GenerateDiadic(op_ext,0,ap3,0);
    MakeLegalAmode(ap3,flags,4);
    ReleaseTempRegister(ap1);
    ReleaseTempRegister(ap2);
    return ap3;
}
 
/*
 *      exchange the two operands in a node.
 */
void swap_nodes(ENODE *node)
{
	ENODE *temp;
    temp = node->p[0];
    node->p[0] = node->p[1];
    node->p[1] = temp;
}
 
/*
 *      generate code to evaluate a multiply node. both operands
 *      are treated as words and the result is long and is always
 *      in a register so that the 68000 mul instruction can be used.
 */
AMODE *GenerateMultiply(ENODE *node, int flags, int size, int op)
{       
	AMODE *ap1, *ap2, *ap3;
    if( node->p[0]->nodetype == en_icon )
        swap_nodes(node);
    ap1 = GenerateExpression(node->p[0],F_REG,8);
    ap2 = GenerateExpression(node->p[1],F_REG | F_IMMED,8);
ap3 = GetTempRegister();
	if (ap2->mode == am_immed) {
		if (op==op_mulu)
			GenerateTriadic(op_mului,0,ap3,ap1,ap2);
		else
			GenerateTriadic(op_mulsi,0,ap3,ap1,ap2);
	}
	else
		GenerateTriadic(op,0,ap3,ap1,ap2);
    ReleaseTempRegister(ap1);
    ReleaseTempRegister(ap2);
    MakeLegalAmode(ap3,flags,8);
    return ap3;
}
 
/*
 *      generate code to evaluate a condition operator node (?:)
 */
AMODE *gen_hook(ENODE *node,int flags, int size)
{
	AMODE *ap1, *ap2;
    int false_label, end_label;
 
    false_label = nextlabel++;
    end_label = nextlabel++;
    flags = (flags & F_REG) | F_VOL;
    GenerateFalseJump(node->p[0],false_label);
    node = node->p[1];
    ap1 = GenerateExpression(node->p[0],flags,size);
    ReleaseTempRegister(ap1);
    GenerateDiadic(op_bra,0,make_label(end_label),0);
    GenerateLabel(false_label);
    ap2 = GenerateExpression(node->p[1],flags,size);
    if( !equal_address(ap1,ap2) )
    {
        ReleaseTempRegister(ap2);
//        GetTempRegister();
		GenerateTriadic(op_or,0,ap1,makereg(0),ap2);
    }
    GenerateLabel(end_label);
    return ap1;
}
 
AMODE *GenerateAssignAdd(ENODE *node,int flags, int size, int op)
{
	AMODE *ap1, *ap2, *ap3;
    int             ssize, mask0, mask1;
    ssize = GetNaturalSize(node->p[0]);
    if( ssize > size )
            size = ssize;
    ap1 = GenerateExpression(node->p[0],F_ALL,ssize);
    ap2 = GenerateExpression(node->p[1],F_REG | F_IMMED,size);
	if (ap2->mode ==am_immed)
		switch(op) {
		case op_addu:	op = op_addui; break;
		case op_add:	op = op_addui; break;
		case op_subu:	op = op_subui; break;
		case op_sub:	op = op_subui; break;
		}
	if (ap1->mode==am_reg) {
	    GenerateTriadic(op,0,ap1,ap1,ap2);
	}
	else {
		ap3 = GetTempRegister();
		switch(ssize) {
		case 1:	GenerateDiadic(op_lb,0,ap3,ap1); break;
		case 2:	GenerateDiadic(op_lc,0,ap3,ap1); break;
		case 4:	GenerateDiadic(op_lh,0,ap3,ap1); break;
		case 8:	GenerateDiadic(op_lw,0,ap3,ap1); break;
		}
		GenerateTriadic(op,0,ap3,ap3,ap2);
		switch(ssize) {
		case 1:	GenerateDiadic(op_sb,0,ap3,ap1); break;
		case 2:	GenerateDiadic(op_sc,0,ap3,ap1); break;
		case 4:	GenerateDiadic(op_sh,0,ap3,ap1); break;
		case 8:	GenerateDiadic(op_sw,0,ap3,ap1); break;
		}
		ReleaseTempRegister(ap3);
	}
    ReleaseTempRegister(ap2);
    GenerateSignExtend(ap1,ssize,size,flags);
    MakeLegalAmode(ap1,flags,size);
    return ap1;
}
 
AMODE *GenerateAssignLogic(ENODE *node,int flags, int size, int op)
{
	AMODE *ap1, *ap2, *ap3;
    int             ssize, mask0, mask1;
    ssize = GetNaturalSize(node->p[0]);
    if( ssize > size )
            size = ssize;
    ap1 = GenerateExpression(node->p[0],F_ALL,ssize);
    ap2 = GenerateExpression(node->p[1],F_REG | F_IMMED,size);
	if (ap2->mode==am_immed)
		switch(op) {
		case op_and:	op = op_andi; break;
		case op_or:		op = op_ori; break;
		case op_xor:	op = op_xori; break;
		}
	if (ap1->mode==am_reg) {
	    GenerateTriadic(op,0,ap1,ap1,ap2);
	}
	else {
		ap3 = GetTempRegister();
		switch(ssize) {
		case 1:	GenerateDiadic(op_lb,0,ap3,ap1); break;
		case 2:	GenerateDiadic(op_lc,0,ap3,ap1); break;
		case 4:	GenerateDiadic(op_lh,0,ap3,ap1); break;
		case 8:	GenerateDiadic(op_lw,0,ap3,ap1); break;
		}
		GenerateTriadic(op,0,ap3,ap3,ap2);
		switch(ssize) {
		case 1:	GenerateDiadic(op_sb,0,ap3,ap1); break;
		case 2:	GenerateDiadic(op_sc,0,ap3,ap1); break;
		case 4:	GenerateDiadic(op_sh,0,ap3,ap1); break;
		case 8:	GenerateDiadic(op_sw,0,ap3,ap1); break;
		}
		ReleaseTempRegister(ap3);
	}
    ReleaseTempRegister(ap2);
    GenerateSignExtend(ap1,ssize,size,flags);
    MakeLegalAmode(ap1,flags,size);
    return ap1;
}
 
/*
 *      generate a *= node.
 */
AMODE *GenerateAssignMultiply(ENODE *node,int flags, int size, int op)
{
	AMODE *ap1, *ap2, *ap3;
    int             ssize, mask0, mask1;
    ssize = GetNaturalSize(node->p[0]);
    if( ssize > size )
            size = ssize;
    ap1 = GenerateExpression(node->p[0],F_ALL,ssize);
    ap2 = GenerateExpression(node->p[1],F_REG | F_IMMED,size);
	if (ap2->mode==am_immed)
		switch(op) {
		case op_mulu:	op = op_mului; break;
		case op_muls:	op = op_mulsi; break;
		}
	if (ap1->mode==am_reg) {
	    GenerateTriadic(op,0,ap1,ap1,ap2);
	}
	else {
		ap3 = GetTempRegister();
		switch(ssize) {
		case 1:	GenerateDiadic(op_lb,0,ap3,ap1); break;
		case 2:	GenerateDiadic(op_lc,0,ap3,ap1); break;
		case 4:	GenerateDiadic(op_lh,0,ap3,ap1); break;
		case 8:	GenerateDiadic(op_lw,0,ap3,ap1); break;
		}
		GenerateTriadic(op,0,ap3,ap3,ap2);
		switch(ssize) {
		case 1:	GenerateDiadic(op_sb,0,ap3,ap1); break;
		case 2:	GenerateDiadic(op_sc,0,ap3,ap1); break;
		case 4:	GenerateDiadic(op_sh,0,ap3,ap1); break;
		case 8:	GenerateDiadic(op_sw,0,ap3,ap1); break;
		}
		ReleaseTempRegister(ap3);
	}
    ReleaseTempRegister(ap2);
    GenerateSignExtend(ap1,ssize,size,flags);
    MakeLegalAmode(ap1,flags,size);
    return ap1;
}
 
/*
 *      generate /= and %= nodes.
 */
AMODE *gen_asmodiv(ENODE *node,int flags,int size,int op)
{
	AMODE *ap1, *ap2, *ap3;
    int             siz1;
 
    siz1 = GetNaturalSize(node->p[0]);
    ap1 = GetTempRegister();
    ap2 = GenerateExpression(node->p[0],F_ALL & ~F_IMMED,siz1);
	if (ap2->mode==am_reg && ap2->preg != ap1->preg)
		GenerateTriadic(op_or,0,ap1,ap2,makereg(0));
	else {
		switch(siz1) {
		case 1:	GenerateDiadic(op_lb,0,ap1,ap2); break;
		case 2:	GenerateDiadic(op_lc,0,ap1,ap2); break;
		case 4:	GenerateDiadic(op_lh,0,ap1,ap2); break;
		case 8:	GenerateDiadic(op_lw,0,ap1,ap2); break;
		}
	}
    GenerateSignExtend(ap1,siz1,8,flags);
    ap3 = GenerateExpression(node->p[1],F_REG,2);
    GenerateTriadic(op,0,ap1,ap1,ap3);
    ReleaseTempRegister(ap3);
    //GenerateDiadic(op_ext,0,ap1,0);
	if (ap2->mode==am_reg)
		GenerateTriadic(op_or,0,ap2,ap1,makereg(0));
	else
		switch(siz1) {
			case 1:	GenerateDiadic(op_sb,0,ap1,ap2); break;
			case 2:	GenerateDiadic(op_sc,0,ap1,ap2); break;
			case 4:	GenerateDiadic(op_sh,0,ap1,ap2); break;
			case 8:	GenerateDiadic(op_sw,0,ap1,ap2); break;
		}
    ReleaseTempRegister(ap2);
    MakeLegalAmode(ap1,flags,size);
    return ap1;
}
 
/*
 *      generate code for an assignment node. if the size of the
 *      assignment destination is larger than the size passed then
 *      everything below this node will be evaluated with the
 *      assignment size.
 */
AMODE *GenerateAssign(ENODE *node, int flags, int size)
{       struct amode    *ap1, *ap2 ,*ap3;
        int             ssize;
		ENODE *ep;
    if (node->p[0]->nodetype == en_uwfieldref ||
		node->p[0]->nodetype == en_wfieldref ||
		node->p[0]->nodetype == en_uhfieldref ||
		node->p[0]->nodetype == en_hfieldref ||
		node->p[0]->nodetype == en_ucfieldref ||
		node->p[0]->nodetype == en_cfieldref ||
		node->p[0]->nodetype == en_ubfieldref ||
		node->p[0]->nodetype == en_bfieldref) {
		long            mask;
		int             i;
		/*
		* Field assignment
		*/
		/* get the value */
		ap1 = GenerateExpression(node->p[1], F_REG | F_VOL,8);
		i = node->p[0]->bit_width;
		for (mask = 0; i--; mask = mask + mask + 1);
		GenerateDiadic(op_and, 0, make_immed(mask), ap1);
		mask <<= node->p[0]->bit_offset;
		if (!(flags & F_NOVALUE)) {
			/*
			* result value needed
			*/
			ap3 = GetTempRegister();
			GenerateTriadic(op_or, 0, ap3, ap1, makereg(0));
		} else
	    ap3 = ap1;
		if (node->p[0]->bit_offset > 0) {
			if (node->p[0]->bit_offset < 9) {
				GenerateTriadic(op_shl, 0, ap3,ap3,make_immed((long) node->p[0]->bit_offset));
			}
			else {
				ap2 = GetTempRegister();
				GenerateTriadic(op_ori, 0, ap2,makereg(0),make_immed((long) node->p[0]->bit_offset));
				GenerateTriadic(op_shl, 0, ap3, ap3, ap2);
				ReleaseTempRegister(ap2);
			}
		}
		ep = makenode(en_w_ref, node->p[0]->p[0], NULL);
		ap2 = GenerateExpression(ep, F_MEM,8);
		//ap2 = GenerateExpression(node->v.p[0],F_ALL,4);
		GenerateTriadic(op_andi, 0, ap2,ap2,make_immed(~mask));
		GenerateTriadic(op_or, 0, ap2, ap2, ap3);
		ReleaseTempRegister(ap2);
		if (!(flags & F_NOVALUE)) {
			ReleaseTempRegister(ap3);
		}
		MakeLegalAmode(ap1, flags, size);
		return ap1;
    }
 
	ssize = GetReferenceSize(node->p[0]);
	if( ssize > size )
			size = ssize;
	ap2 = GenerateExpression(node->p[1],F_REG,size);
	ap1 = GenerateExpression(node->p[0],F_ALL,ssize);
	if (ap1->mode == am_reg) {
		GenerateDiadic(op_mov,0,ap1,ap2);
	}
	else {
		switch(size) {
		case 1:	GenerateDiadic(op_sb,0,ap2,ap1); break;
		case 2:	GenerateDiadic(op_sc,0,ap2,ap1); break;
		case 4: GenerateDiadic(op_sh,0,ap2,ap1); break;
		case 8:	GenerateDiadic(op_sw,0,ap2,ap1); break;
		}
	}
	ReleaseTempRegister(ap1);
	return ap2;
}
 
/*
 *      generate an auto increment or decrement node. op should be
 *      either op_add (for increment) or op_sub (for decrement).
 */
AMODE *GenerateAutoIncrement(ENODE *node,int flags,int size,int op)
{
	AMODE *ap1, *ap2;
    int siz1;
 
    siz1 = GetNaturalSize(node->p[0]);
    if( flags & F_NOVALUE )         /* dont need result */
            {
            ap1 = GenerateExpression(node->p[0],F_ALL,siz1);
			switch(op) {
			case op_addu:	op = op_addui; break;
			case op_add:	op = op_addui; break;
			case op_subu:	op = op_subui; break;
			case op_sub:	op = op_subui; break;
			}
			if (ap1->mode != am_reg) {
				ap2 = GetTempRegister();
				switch(size) {
				case 1:	GenerateTriadic(op_lb,0,ap2,ap1,NULL); break;
				case 2:	GenerateTriadic(op_lc,0,ap2,ap1,NULL); break;
				case 4:	GenerateTriadic(op_lh,0,ap2,ap1,NULL); break;
				case 8:	GenerateTriadic(op_lw,0,ap2,ap1,NULL); break;
				}
	            GenerateTriadic(op,0,ap2,ap2,make_immed(node->i));
				switch(size) {
				case 1:	GenerateTriadic(op_sb,0,ap2,ap1,NULL); break;
				case 2:	GenerateTriadic(op_sc,0,ap2,ap1,NULL); break;
				case 4:	GenerateTriadic(op_sh,0,ap2,ap1,NULL); break;
				case 8:	GenerateTriadic(op_sw,0,ap2,ap1,NULL); break;
				}
				ReleaseTempRegister(ap2);
			}
			else
				GenerateTriadic(op,0,ap1,ap1,make_immed(node->i));
            ReleaseTempRegister(ap1);
            return ap1;
            }
    ap2 = GenerateExpression(node->p[0],F_ALL,siz1);
	if (ap2->mode == am_reg) {
	    GenerateTriadic(op,0,ap2,ap2,make_immed(node->i));
		return ap2;
	}
	else {
	    ap1 = GetTempRegister();
		switch(siz1) {
		case 1:	GenerateDiadic(op_lb,0,ap1,ap2); break;
		case 2:	GenerateDiadic(op_lc,0,ap1,ap2); break;
		case 4:	GenerateDiadic(op_lh,0,ap1,ap2); break;
		case 8:	GenerateDiadic(op_lw,0,ap1,ap2); break;
		}
		switch(op) {
		case op_addu:	op = op_addui; break;
		case op_add:	op = op_addui; break;
		case op_subu:	op = op_subui; break;
		case op_sub:	op = op_subui; break;
		}
		GenerateTriadic(op,0,ap1,ap1,make_immed(node->i));
		switch(siz1) {
		case 1:	GenerateDiadic(op_sb,0,ap1,ap2); break;
		case 2:	GenerateDiadic(op_sc,0,ap1,ap2); break;
		case 4:	GenerateDiadic(op_sh,0,ap1,ap2); break;
		case 8:	GenerateDiadic(op_sw,0,ap1,ap2); break;
		}
	}
    ReleaseTempRegister(ap2);
    GenerateSignExtend(ap1,siz1,size,flags);
    return ap1;
}
 
/*
 *      general expression evaluation. returns the addressing mode
 *      of the result.
 */
AMODE *GenerateExpression(ENODE *node, int flags, int size)
{   
	AMODE *ap1, *ap2;
    int lab0, lab1;
    int natsize;
 
    if( node == NULL )
    {
        printf("DIAG - null node in GenerateExpression.\n");
        return NULL;
    }
    switch( node->nodetype )
            {
            case en_icon:
            case en_labcon:
            case en_nacon:
                    ap1 = allocAmode();
                    ap1->mode = am_immed;
                    ap1->offset = node;
                    MakeLegalAmode(ap1,flags,size);
                    return ap1;
            case en_autocon:
                    ap1 = GetTempRegister();
                    ap2 = allocAmode();
                    ap2->mode = am_indx;
                    ap2->preg = 27;          /* frame pointer */
                    ap2->offset = node;     /* use as constant node */
                    GenerateDiadic(op_lea,0,ap1,ap2);
                    MakeLegalAmode(ap1,flags,size);
                    return ap1;             /* return reg */
            case en_b_ref:
			case en_c_ref:
			case en_h_ref:
            case en_ub_ref:
			case en_uc_ref:
			case en_uh_ref:
            case en_w_ref:
			case en_uw_ref:
                    return GenerateDereference(node,flags,size);
			case en_uwfieldref:
			case en_wfieldref:
			case en_bfieldref:
			case en_ubfieldref:
			case en_cfieldref:
			case en_ucfieldref:
			case en_hfieldref:
			case en_uhfieldref:
					return GenerateBitfieldDereference(node,flags,size);
			case en_regvar:
            case en_tempref:
                    ap1 = xalloc(sizeof(struct amode));
                    ap1->mode = am_reg;
                    ap1->preg = node->i;
                    ap1->tempflag = 0;      /* not a temporary */
                    MakeLegalAmode(ap1,flags,size);
                    return ap1;
            case en_uminus: return GenerateUnary(node,flags,size,op_neg);
            case en_compl:  return GenerateUnary(node,flags,size,op_not);
            case en_add:    return GenerateBinary(node,flags,size,op_add);
            case en_sub:    return GenerateBinary(node,flags,size,op_sub);
            case en_and:    return GenerateBinary(node,flags,size,op_and);
            case en_or:     return GenerateBinary(node,flags,size,op_or);
			case en_xor:	return GenerateBinary(node,flags,size,op_xor);
            case en_mul:    return GenerateMultiply(node,flags,size,op_muls);
            case en_mulu:   return GenerateMultiply(node,flags,size,op_mulu);
            case en_div:    return GenerateModDiv(node,flags,size,op_divs);
            case en_udiv:   return GenerateModDiv(node,flags,size,op_divu);
            case en_mod:    return GenerateModDiv(node,flags,size,op_mod);
            case en_umod:   return GenerateModDiv(node,flags,size,op_modu);
            case en_shl:    return GenerateShift(node,flags,size,op_shl);
            case en_shr:	return GenerateShift(node,flags,size,op_shr);
            case en_shru:   return GenerateShift(node,flags,size,op_shru);
            case en_asadd:  return GenerateAssignAdd(node,flags,size,op_add);
            case en_assub:  return GenerateAssignAdd(node,flags,size,op_sub);
            case en_asand:  return GenerateAssignLogic(node,flags,size,op_and);
            case en_asor:   return GenerateAssignLogic(node,flags,size,op_or);
			case en_asxor:  return GenerateAssignLogic(node,flags,size,op_xor);
            case en_aslsh:
                    return GenerateAssignShift(node,flags,size,op_shl);
            case en_asrsh:
                    return GenerateAssignShift(node,flags,size,op_shr);
            case en_asmul: return GenerateAssignMultiply(node,flags,size,op_muls);
            case en_asmulu: return GenerateAssignMultiply(node,flags,size,op_mulu);
            case en_asdiv:
                    return gen_asmodiv(node,flags,size,op_divs);
            case en_asmod:
                    return gen_asmodiv(node,flags,size,op_muls);
            case en_assign:
                    return GenerateAssign(node,flags,size);
            case en_ainc:
                    return GenerateAutoIncrement(node,flags,size,op_add);
            case en_adec:
                    return GenerateAutoIncrement(node,flags,size,op_sub);
            case en_land:   case en_lor:
            case en_eq:     case en_ne:
            case en_lt:     case en_le:
            case en_gt:     case en_ge:
            case en_ult:    case en_ule:
            case en_ugt:    case en_uge:
            case en_not:
                    lab0 = nextlabel++;
                    lab1 = nextlabel++;
                    GenerateFalseJump(node,lab0);
                    ap1 = GetTempRegister();
                    GenerateTriadic(op_ori,0,ap1,makereg(0),make_immed(1));
                    GenerateTriadic(op_bra,0,make_label(lab1),NULL,NULL);
                    GenerateLabel(lab0);
                    GenerateTriadic(op_ori,0,ap1,makereg(0),make_immed(0));
                    GenerateLabel(lab1);
                    return ap1;
            case en_cond:
                    return gen_hook(node,flags,size);
            case en_void:
                    natsize = GetNaturalSize(node->p[0]);
                    ReleaseTempRegister(GenerateExpression(node->p[0],F_ALL | F_NOVALUE,natsize));
                    return GenerateExpression(node->p[1],flags,size);
            case en_fcall:
                    return GenerateFunctionCall(node,flags);
            default:
                    printf("DIAG - uncoded node in GenerateExpression.\n");
                    return 0;
            }
}
 
/*
 *      return the natural evaluation size of a node.
 */
int GetNaturalSize(ENODE *node)
{ 
	int     siz0, siz1;
    if( node == NULL )
            return 0;
    switch( node->nodetype )
        {
		case en_uwfieldref:
		case en_wfieldref:
			return 8;
		case en_bfieldref:
		case en_ubfieldref:
			return 1;
		case en_cfieldref:
		case en_ucfieldref:
			return 2;
		case en_hfieldref:
		case en_uhfieldref:
			return 4;
        case en_icon:
                if( -128 <= node->i && node->i <= 127 )
                        return 1;
                if( -32768 <= node->i && node->i <= 32767 )
                        return 2;
				if (-2147483648L <= node->i && node->i <= 2147483647L)
					return 4;
				return 8;
        case en_fcall:  case en_labcon:
        case en_nacon:  case en_autocon:
		case en_tempref:
		case en_regvar:
        case en_cbw:
		case en_ccw:
		case en_chw:
                return 8;
		case en_b_ref:
		case en_ub_ref:
                return 1;
        case en_cbc:
		case en_c_ref:	return 2;
		case en_uc_ref:	return 2;
		case en_cbh:	return 4;
		case en_cch:	return 4;
		case en_h_ref:	return 4;
		case en_uh_ref:	return 4;
		case en_w_ref:  case en_uw_ref:
                return 8;
        case en_not:    case en_compl:
        case en_uminus: case en_assign:
        case en_ainc:   case en_adec:
                return GetNaturalSize(node->p[0]);
        case en_add:    case en_sub:
        case en_mul:    case en_div:
        case en_mod:    case en_and:
        case en_or:     case en_xor:
        case en_shl:    case en_shr:	case en_shru:
        case en_eq:     case en_ne:
        case en_lt:     case en_le:
        case en_gt:     case en_ge:
		case en_ult:	case en_ule:
		case en_ugt:	case en_uge:
        case en_land:   case en_lor:
        case en_asadd:  case en_assub:
        case en_asmul:  case en_asdiv:
        case en_asmod:  case en_asand:
		case en_asor:   case en_asxor:	case en_aslsh:
        case en_asrsh:
                siz0 = GetNaturalSize(node->p[0]);
                siz1 = GetNaturalSize(node->p[1]);
                if( siz1 > siz0 )
                    return siz1;
                else
                    return siz0;
        case en_void:   case en_cond:
                return GetNaturalSize(node->p[1]);
        default:
                printf("DIAG - natural size error %d.\n", node->nodetype);
                break;
        }
    return 0;
}
 
 
void gen_b(ENODE *node, int op, int label)
{
	int size;
	struct amode *ap1, *ap2;
 
	size = GetNaturalSize(node);
	ap1 = GenerateExpression(node->p[0],F_REG, size);
	ap2 = GenerateExpression(node->p[1],F_REG|F_IMMED18,size);
    GenerateTriadic(op,0,ap1,ap2,make_label(label));
	ReleaseTempRegister(ap2);
	ReleaseTempRegister(ap1);
}
/*
 *      generate a jump to label if the node passed evaluates to
 *      a true condition.
 */
void GenerateTrueJump(ENODE *node, int label)
{       AMODE  *ap1,*ap2;
        int             siz1;
        int             lab0;
		int size;
        if( node == 0 )
                return;
        switch( node->nodetype )
                {
                case en_eq:	gen_b(node, op_beq, label); break;
                case en_ne: gen_b(node, op_bne, label); break;
                case en_lt: gen_b(node, op_blt, label); break;
                case en_le:	gen_b(node, op_ble, label); break;
                case en_gt: gen_b(node, op_bgt, label); break;
                case en_ge: gen_b(node, op_bge, label); break;
                case en_ult: gen_b(node, op_bltu, label); break;
                case en_ule: gen_b(node, op_bleu, label); break;
                case en_ugt: gen_b(node, op_bgtu, label); break;
                case en_uge: gen_b(node, op_bgeu, label); break;
                case en_land:
                        lab0 = nextlabel++;
                        GenerateFalseJump(node->p[0],lab0);
                        GenerateTrueJump(node->p[1],label);
                        GenerateLabel(lab0);
                        break;
                case en_lor:
                        GenerateTrueJump(node->p[0],label);
                        GenerateTrueJump(node->p[1],label);
                        break;
                case en_not:
                        GenerateFalseJump(node->p[0],label);
                        break;
                default:
                        siz1 = GetNaturalSize(node);
                        ap1 = GenerateExpression(node,F_REG,siz1);
//                        GenerateDiadic(op_tst,siz1,ap1,0);
                        ReleaseTempRegister(ap1);
                        GenerateTriadic(op_bne,0,ap1,makereg(0),make_label(label));
                        break;
                }
}
 
/*
 *      generate code to execute a jump to label if the expression
 *      passed is false.
 */
void GenerateFalseJump(ENODE *node,int label)
{
	AMODE *ap,*ap1,*ap2;
		int size;
        int             siz1;
        int             lab0;
        if( node == NULL )
                return;
        switch( node->nodetype )
                {
                case en_eq:	gen_b(node, op_bne, label); break;
                case en_ne: gen_b(node, op_beq, label); break;
                case en_lt: gen_b(node, op_bge, label); break;
                case en_le: gen_b(node, op_bgt, label); break;
                case en_gt: gen_b(node, op_ble, label); break;
                case en_ge: gen_b(node, op_blt, label); break;
                case en_ult: gen_b(node, op_bgeu, label); break;
                case en_ule: gen_b(node, op_bgtu, label); break;
                case en_ugt: gen_b(node, op_bleu, label); break;
                case en_uge: gen_b(node, op_bltu, label); break;
                case en_land:
                        GenerateFalseJump(node->p[0],label);
                        GenerateFalseJump(node->p[1],label);
                        break;
                case en_lor:
                        lab0 = nextlabel++;
                        GenerateTrueJump(node->p[0],lab0);
                        GenerateFalseJump(node->p[1],label);
                        GenerateLabel(lab0);
                        break;
                case en_not:
                        GenerateTrueJump(node->p[0],label);
                        break;
                default:
                        siz1 = GetNaturalSize(node);
                        ap = GenerateExpression(node,F_REG,siz1);
//                        GenerateDiadic(op_tst,siz1,ap,0);
                        ReleaseTempRegister(ap);
                        GenerateTriadic(op_beq,0,ap,makereg(0),make_label(label));
                        break;
                }
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.