/*
 * C compiler
 * ==========
 *
 * Copyright 1989, 1990, 1991 Christoph van Wuellen.
 * Credits to Matthew Brandt.
 * All commercial rights reserved.
 *
 * This compiler may be redistributed as long there is no
 * commercial interest. The compiler must not be redistributed
 * without its full sources. This notice must stay intact.
 *
 * History:
 *
 * 1989   starting an 68000 C compiler, starting with material
 *        originally by M. Brandt
 * 1990   68000 C compiler further bug fixes
 *        started i386 port (December)
 * 1991   i386 port finished (January)
 *        further corrections in the front end and in the 68000
 *        code generator.
 *        The next port will be a SPARC port
 *
 * 1995   Ivo Oesch, Started to build a codegenerator for the 
 *        signalprocessor TMS320C30 (December)
 */

#include "config.h"

#define MAX_WIDTH       60

#ifdef TMS320C30
#define TARGET_ROSSIN
#ifdef TARGET_ROSSIN

#include "chdr.h"
#include "expr.h"
#include "cglbdec.h"
#include "proto.h"
#include "genc30.h"
#include "outproto.h"
#include "version.h"
#include <time.h>

#ifdef MULTIPLE_ASSEMBLERS
#define PRIVATE static
#undef  put_code
#undef  put_label
#undef  put_byte
#undef  put_char
#undef  put_word
#undef  put_long
#undef  put_pointer
#undef  put_short
#undef  put_storage
#undef  put_literals
#undef  put_reference
#undef  put_align
#undef  put_cseg
#undef  put_dseg
#undef  put_float
#undef  put_double
#undef  put_longdouble
#else
#define PRIVATE
#endif /* MULTIPLE_ASSEMBLERS */

enum e_gt {
    bytegen, wordgen, longgen, floatgen, nogen
};
enum e_sg {
    noseg, codeseg, dataseg, bssseg, romseg
};

#if defined __STDC__ || defined __cplusplus
#define P_(s) s
#else
#define P_(s) ()
#endif

static void nl                  P_((void));
static void putop               P_((OPCODE));
static void putconst            P_((const EXPR *));
static void putamode            P_((ADDRESS *));
static void putreg              P_((REG));
static void put_header          P_((enum e_gt, SIZE));
static void seg                 P_((enum e_sg, char *, SIZE));

PRIVATE void put_align          P_((SIZE));
PRIVATE void put_long           P_((long));
PRIVATE void put_cseg           P_((SIZE));
PRIVATE void put_dseg           P_((SIZE));
PRIVATE void put_kseg           P_((SIZE));
PRIVATE void put_label          P_((LABEL));
PRIVATE void put_reference	P_((SYM *));
PRIVATE void put_byte           P_((int));
PRIVATE void put_char           P_((int));

#undef P_

/* variable initialization */

static enum e_gt gentype = nogen;
static enum e_sg curseg = noseg;
static int       outcol = 0;
static SIZE      align_type;
static char     *prefix = "L";
static char     *comment = "*";

static char *opl[] = {
         "absf",        /* op_absf */
         "absi",        /* op_absi */
         "addc",        /* op_addc */
         "addf",        /* op_addf */
         "addi",        /* op_addi */
         "and",         /* op_and */
         "andn",        /* op_andn */
         "ash",         /* op_ash */
         "cmpf",        /* op_cmpf */
         "cmpi",        /* op_cmpi */
         "fix",         /* op_fix */
         "float",       /* op_float */
         "idle",        /* op_idle */
         "lde",         /* op_lde */
         "ldf",         /* op_ldf */
         "ldfi",        /* op_ldfi */
         "ldi",         /* op_ldi */
         "ldii",        /* op_ldii */
         "ldm",         /* op_ldm */
         "lsh",         /* op_lsh */
         "mpyf",        /* op_mpyf */
         "mpyi",        /* op_mpyi */
         "negb",        /* op_negb */
         "negf",        /* op_negf */
         "negi",        /* op_negi */
         "nop",         /* op_nop */
         "norm",        /* op_norm  */
         "not",         /* op_not */
         "pop",         /* op_pop */
         "popf",        /* op_popf */
         "push",        /* op_push */
         "pushf",       /* op_pushf */
         "or",          /* op_or */
         "rnd",         /* op_rnd */
         "rol",         /* op_rol */
         "rolc",        /* op_rolc */
         "ror",         /* op_ror */
         "rorc",        /* op_rorc */
         "rpts",        /* op_rpts */
         "stf",         /* op_stf */
         "stfi",        /* op_stfi */
         "sti",         /* op_sti */
         "stii",        /* op_stii */
         "sigi",        /* op_sigi */
         "subb",        /* op_subb */
         "subc",        /* op_subc */
         "subf",        /* op_subf */
         "subi",        /* op_subi */
         "subrb",       /* op_subrb */
         "subrf",       /* op_subrf */
         "subri",       /* op_subri */
         "tstb",        /* op_tstb  */
         "xor",         /* op_xor   */
         "iack",        /* op_iack  */
         "addc3",       /* op_addc3 */
         "addf3",       /* op_addf3 */
         "addi3",       /* op_addi3 */
         "and3",        /* op_and3  */
         "andn3",       /* op_andn3 */
         "ash3",        /* op_ash3  */
         "cmpf3",       /* op_cmpf3 */
         "cmpf3",       /* op_cmpf3 */
         "lsh3",        /* op_lsh3  */
         "mpyf3",       /* op_mpyf3 */
         "mpyi3",       /* op_mpyi3 */
         "or3",         /* op_or3   */
         "subb3",       /* op_subb3 */
         "subf3",       /* op_subf3 */
         "subi3",       /* op_subi3 */
         "tstb3",       /* op_tstb3 */
         "xor3",        /* op_xor3  */
         "ldfu",        /* op_ldfu  */
         "ldflo",       /* op_ldflo */ 
         "ldfls",       /* op_ldfls */
         "ldfhi",       /* op_ldfhi */
         "ldfhs",       /* op_ldfhs */
         "ldfeq",       /* op_ldfeq */
         "ldfne",       /* op_ldfne */
         "ldflt",       /* op_ldflt */
         "ldfle",       /* op_ldfle */
         "ldfgt",       /* op_ldfgt */
         "ldfge",       /* op_ldfge */
         "ldfz",        /* op_ldfz  */
         "ldfnz",       /* op_ldfnz */
         "ldfp",        /* op_ldfp  */
         "ldfn",        /* op_ldfn  */
         "ldfnn",       /* op_ldfnn */
         "ldiu",        /* op_ldiu  */
         "ldilo",       /* op_ldilo */
         "ldils",       /* op_ldils */
         "ldihi",       /* op_ldihi */
         "ldihs",       /* op_ldihs */
         "ldieq",       /* op_ldieq */
         "ldine",       /* op_ldine */
         "ldilt",       /* op_ldilt */
         "ldile",       /* op_ldile */
         "ldigt",       /* op_ldigt */
         "ldige",       /* op_ldige */
         "ldiz",        /* op_ldiz  */
         "ldinz",       /* op_ldinz */
         "ldip",        /* op_ldip  */
         "ldin",        /* op_ldin  */
         "ldinn",       /* op_ldinn */
         "br",          /* op_br    */
         "brd",         /* op_brd   */
         "call",        /* op_call  */
         "rptb",        /* op_rptb  */
         "swi",         /* op_swi   */
         "bu",          /* op_bu    */
         "blo",         /* op_blo   */
         "bls",         /* op_bls   */
         "bhi",         /* op_bhi   */
         "bhs",         /* op_bhs   */
         "beq",         /* op_beq   */
         "bne",         /* op_bne   */
         "blt",         /* op_blt   */
         "ble",         /* op_ble   */
         "bgt",         /* op_bgt   */
         "bge",         /* op_bge   */
         "bz",          /* op_bz    */
         "bnz",         /* op_bnz   */
         "bp",          /* op_bp    */
         "bn",          /* op_bn    */
         "bnn",         /* op_bnn   */
         "bud",         /* op_bud   */
         "blod",        /* op_blod  */
         "blsd",        /* op_blsd  */
         "bhid",        /* op_bhid  */
         "bhsd",        /* op_bhsd  */
         "beqd",        /* op_beqd  */
         "bned",        /* op_bned  */
         "bltd",        /* op_bltd  */
         "bled",        /* op_bled  */
         "bgtd",        /* op_bgtd  */
         "bged",        /* op_bged  */
         "bzd",         /* op_bzd   */
         "bnzd",        /* op_bnzd  */
         "bpd",         /* op_bpd   */
         "bnd",         /* op_bnd   */
         "bnnd",        /* op_bnnd  */
         "dbu",         /* op_dbu   */
         "dblo",        /* op_dblo  */
         "dbls",        /* op_dbls  */
         "dbhi",        /* op_dbhi  */
         "dbhs",        /* op_dbhs  */
         "dbeq",        /* op_dbeq  */
         "dbne",        /* op_dbne  */
         "dblt",        /* op_dblt  */
         "dble",        /* op_dble  */
         "dbgt",        /* op_dbgt  */
         "dbge",        /* op_dbge  */
         "dbz",         /* op_dbz   */
         "dbnz",        /* op_dbnz  */
         "dbp",         /* op_dbp   */
         "dbn",         /* op_dbn   */
         "dbnn",        /* op_dbnn  */
         "dbud",        /* op_dbud  */
         "dblod",       /* op_dblod */
         "dblsd",       /* op_dblsd */
         "dbhid",       /* op_dbhid */
         "dbhsd",       /* op_dbhsd */
         "dbeqd",       /* op_dbeqd */
         "dbned",       /* op_dbned */
         "dbltd",       /* op_dbltd */
         "dbled",       /* op_dbled */
         "dbgtd",       /* op_dbgtd */
         "dbged",       /* op_dbged */
         "dbzd",        /* op_dbzd  */
         "dbnzd",       /* op_dbnzd */
         "dbpd",        /* op_dbpd  */
         "dbnd",        /* op_dbnd  */
         "dbnnd",       /* op_dbnnd */
         "callu",       /* op_callu    */
         "calllo",      /* op_calllo   */
         "callls",      /* op_callls   */
         "callhi",      /* op_callhi   */
         "callhs",      /* op_callhs   */
         "calleq",      /* op_calleq   */
         "callne",      /* op_callne   */
         "calllt",      /* op_calllt   */
         "callle",      /* op_callle   */
         "callgt",      /* op_callgt   */
         "callge",      /* op_callge   */
         "callz",       /* op_callz    */
         "callnz",      /* op_callnz   */
         "callp",       /* op_callp    */
         "calln",       /* op_calln    */
         "callnn",      /* op_callnn   */
         "trapu",       /* op_trapu    */
         "traplo",      /* op_traplo   */
         "trapls",      /* op_trapls   */
         "traphi",      /* op_traphi   */
         "traphs",      /* op_traphs   */
         "trapeq",      /* op_trapeq   */
         "trapne",      /* op_trapne   */
         "traplt",      /* op_traplt   */
         "traple",      /* op_traple   */
         "trapgt",      /* op_trapgt   */
         "trapge",      /* op_trapge   */
         "trapz",       /* op_trapz    */
         "trapnz",      /* op_trapnz   */
         "trapp",       /* op_trapp    */
         "trapn",       /* op_trapn    */
         "trapnn",      /* op_trapnn   */
         "retiu",       /* op_retiu    */
         "retilo",      /* op_retilo   */
         "retils",      /* op_retils   */
         "retihi",      /* op_retihi   */
         "retihs",      /* op_retihs   */
         "retieq",      /* op_retieq   */
         "retine",      /* op_retine   */
         "retilt",      /* op_retilt   */
         "retile",      /* op_retile   */
         "retigt",      /* op_retigt   */
         "retige",      /* op_retige   */
         "retiz",       /* op_retiz    */
         "retinz",      /* op_retinz   */
         "retip",       /* op_retip    */
         "retin",       /* op_retin    */
         "retinn",      /* op_retinn   */
         "retsu",       /* op_retsu    */
         "retslo",      /* op_retslo   */
         "retsls",      /* op_retsls   */
         "retshi",      /* op_retshi   */
         "retshs",      /* op_retshs   */
         "retseq",      /* op_retseq   */
         "retsne",      /* op_retsne   */
         "retslt",      /* op_retslt   */
         "retsle",      /* op_retsle   */
         "retsgt",      /* op_retsgt   */
         "retsge",      /* op_retsge   */
         "retsz",       /* op_retsz    */
         "retsnz",      /* op_retsnz   */
         "retsp",       /* op_retsp    */
         "retsn",       /* op_retsn    */
         "retsnn",      /* op_retsnn   */
         "mpyf3_addf3", /* op_mpyf3_addf3 */
         "mpyf3_subf3", /* op_mpyf3_subf3 */
         "mpyi3_addi3", /* op_mpyi3_addi3 */
         "mpyi3_subi3", /* op_mpyi3_subi3 */
         "stf_stf",     /* op_stf_stf */
         "sti_sti",     /* op_sti_sti */
         "ldf_ldf",     /* op_ldf_ldf */
         "ldi_ldi",     /* op_ldi_ldi */
         "absf_stf",    /* op_absf_stf */
         "absi_sti",    /* op_absi_sti */
         "addf3_stf",   /* op_addf3_stf */
         "addi3_sti",   /* op_addi3_sti */
         "and3_sti",    /* op_and3_sti */
         "ash3_sti",    /* op_ash3_sti */
         "fix_sti",     /* op_fix_sti */
         "float_stf",   /* op_float_stf */
         "ldf_stf",     /* op_ldf_stf */
         "ldi_sti",     /* op_ldi_sti */
         "lsh3_sti",    /* op_lsh3_sti */
         "mpyf3_stf",   /* op_mpyf3_stf */
         "mpyi3_sti",   /* op_mpyi3_sti */
         "negf_stf",    /* op_negf_stf */
         "negi_sti",    /* op_negi_sti */
         "not_sti",     /* op_not_sti */
         "or3_sti",     /* op_or3_sti */
         "subf3_stf",   /* op_subf3_stf */
         "subi3_sti",   /* op_subi3_sti */
         "xor3_sti",    /* op_xor3_sti */
         
         "divs",        /* op_divs (pseudo) */
         "divu",        /* op_divu (pseudo) */

#ifdef ASM
         "",            /* op_asm */
#endif /* ASM */
         "*.line",      /* op_line */
         0              /* op_label*/
};

static OPCODE ParallelOp [][2] =
{
         {op_mpyf3, op_addf3}, /* op_mpyf3_addf3 */
         {op_mpyf3, op_subf3}, /* op_mpyf3_subf3 */
         {op_mpyi3, op_addi3}, /* op_mpyi3_addi3 */
         {op_mpyi3, op_subi3}, /* op_mpyi3_subi3 */
         {op_stf,   op_stf},   /* op_stf_stf     */
         {op_sti,   op_sti},   /* op_sti_sti     */
         {op_ldf,   op_ldf},   /* op_ldf_ldf   */
         {op_ldi,   op_ldi},   /* op_ldi_ldi   */
         {op_absf,  op_stf},   /* op_absf_stf  */
         {op_absi,  op_sti},   /* op_absi_sti  */
         {op_addf3, op_stf},   /* op_addf3_stf */
         {op_addi3, op_sti},   /* op_addi3_sti */
         {op_and3,  op_sti},   /* op_and3_sti  */
         {op_ash3,  op_sti},   /* op_ash3_sti  */
         {op_fix,   op_sti},   /* op_fix_sti   */
         {op_float, op_stf},   /* op_float_stf */
         {op_ldf,   op_stf},   /* op_ldf_stf   */
         {op_ldi,   op_sti},   /* op_ldi_sti   */
         {op_lsh3,  op_sti},   /* op_lsh3_sti  */
         {op_mpyf3, op_stf},   /* op_mpyf3_stf */
         {op_mpyi3, op_sti},   /* op_mpyi3_sti */
         {op_negf,  op_stf},   /* op_negf_stf  */
         {op_negi,  op_sti},   /* op_negi_sti  */
         {op_not,   op_sti},   /* op_not_sti   */
         {op_or3,   op_sti},   /* op_or3_sti   */
         {op_subf3, op_stf},   /* op_subf3_stf */
         {op_subi3, op_sti},   /* op_subi3_sti */
         {op_xor3,  op_sti},   /* op_xor3_sti  */
};

static void
putop P1(OPCODE, op)
{
    if (op >= OP_MIN && op <= OP_MAX && opl[op] != (char *)0) {
        oprintf ("\t%s",opl[op]);
    } else {
        FATAL((__FILE__,"putop","illegal opcode %d",op));
    }
}

/*
 * put a constant to the output file.
 */
static void
putconst P1(const EXPR *, ep)
{

    switch (ep->nodetype) {
      case en_autocon:
      case en_icon:
        oprintf("%ld", ep->v.i);
        break;
      case en_fcon:
        if (is_short_float(ep->v.f)) {   
            oprintf("%f", (double)ep->v.f);
        } else {
            FATAL((__FILE__,"putconst","illegal constant node (float) %d",ep->nodetype));
        }                         
        break;
      case en_labcon:
        oprintf("%s%u", prefix, (unsigned)ep->v.l);
        break;
      case en_nacon:
        oprintf("%s",outlate(ep->v.str));
        break;
      case en_add:
        if (  (ep->v.p[0]->nodetype == en_icon)
            ||(ep->v.p[0]->nodetype == en_autocon)){
            /* avoid a number on first position (ROSSIN_AS30 2.4 hates that) */
            putconst(ep->v.p[1]);
            oprintf("+");
            putconst(ep->v.p[0]);
        } else {
            putconst(ep->v.p[0]);
            oprintf("+");
            putconst(ep->v.p[1]);
        }
        break;
      case en_sub:
        putconst(ep->v.p[0]);
        oprintf("-");
        putconst(ep->v.p[1]);
        break;
      case en_uminus:
        oprintf("-");
        /*FALLTHRU*/
      case en_cast:
        putconst(ep->v.p[0]);
        break;
      case en_str:
        oprintf("%s",ep->v.str);
        break;
      default:
        FATAL((__FILE__,"putconst","illegal constant node %d",ep->nodetype));
        break;
    }
}

/*
 * put a constant to the output file.
 */
static void
putconstneg P1(EXPR *, ep)
{

    switch (ep->nodetype) {
      case en_autocon:
      case en_icon:
        oprintf("%ld", -ep->v.i);
        break;
      case en_fcon:
        if (is_short_float(ep->v.f)) {   
            oprintf("$%f", -(double)ep->v.f);
        } else {
            FATAL((__FILE__,"putconstneg","illegal constant node (float) %d",ep->nodetype));
        }                         
        break;
      case en_labcon:
        oprintf("-%s%u", prefix, (unsigned)ep->v.l);
        break;
      case en_nacon:
        oprintf("-%s",outlate(ep->v.str));
        break;
      case en_add:
        putconstneg(ep->v.p[0]);
        oprintf("-");
        putconst(ep->v.p[1]);
        break;
      case en_sub:
        putconst(ep->v.p[1]);
        oprintf("-");
        putconst(ep->v.p[0]);
        break;
      case en_uminus:
        /*oprintf("+");*/
        /*FALLTHRU*/
      case en_cast:
        putconst(ep->v.p[0]);
        break;
      default:
        FATAL((__FILE__,"putconstneg","illegal constant node %d",ep->nodetype));
        break;
    }
}

/*
 * put a constant to the output file.
 */
static int
testconst P1(EXPR *, ep)
{

    switch (ep->nodetype) {
      case en_autocon:
      case en_icon:
        return (ep->v.i>= 0?1:-1);
      case en_fcon:
        return (ep->v.f>= 0.0?2:-2);
      case en_labcon:
        return 3;
      case en_nacon:
        return 3;
      case en_add:
        return 4;       
      case en_sub:
        return 5;       
      case en_cast:
        return testconst(ep->v.p[0]);
      case en_uminus:
        return -testconst(ep->v.p[0]);
      default:
        return 99;      
    }
}


/*
 * output a general addressing mode.
 */
static void
putamode P1(ADDRESS *, ap)
{
    switch (ap->mode) {
      case am_direct:
        oprintf("@");
        /*FALLTHRU*/
      case am_immed:
        putconst(ap->u.offset);
        break;
      case am_areg:
      case am_dreg:
      case am_ireg:
      case am_sreg:
      case am_freg:
        putreg(ap->preg);
        break;
      case am_ind:
        oprintf("*ar%d", ap->preg-REG_AR0);
        break;
      case am_ainc:
        oprintf("*ar%d++(", ap->preg-REG_AR0);
        putconst(ap->u.offset);
        oprintf(")");
        break;
      case am_adec:
        oprintf("*ar%d--(", ap->preg-REG_AR0);
        putconst(ap->u.offset);
        oprintf(")");
        break;
      case am_indx:
        if (testconst(ap->u.offset) >= 0) {         
            oprintf("*+ar%d(", ap->preg-REG_AR0);
            putconst(ap->u.offset);
        } else {         
            oprintf("*-ar%d(", ap->preg-REG_AR0);
            putconstneg(ap->u.offset);
        }
        oprintf(")");
        break;
      case am_indx2:
        oprintf("*+ar%d(ir%d)", ap->preg-REG_AR0, ap->sreg-REG_IR0);
        break;
      case am_line:
      case am_str:
        putconst(ap->u.offset);
        break;
      default:
        FATAL((__FILE__,"putamode","illegal address mode %d",ap->mode));
        break;
    }
}

/*
 * output a generic instruction.
 */
PRIVATE void
put_code P1(const CODE *, ip)
{   
    if (ip->opcode < op_mpyf3_addf3) {    
        putop(ip->opcode);
        if (ip->oper1 != 0) {
            oprintf("\t");
            putamode(ip->oper1);
            if (ip->oper2 != 0) {
                oprintf(",");
                putamode(ip->oper2);
                if (ip->oper3 != 0) {
                    oprintf(",");
                    putamode(ip->oper3);
                }
            }
        }
        oprintf("%s", newline);
    } else if (ip->opcode <= op_xor3_sti) {
        putop(ParallelOp[ip->opcode-op_mpyf3_addf3][0]);
        if (ip->oper1 != 0) {
            oprintf("\t");
            putamode(ip->oper1);
            if (ip->oper2 != 0) {
                oprintf(",");
                putamode(ip->oper2);
                if (ip->oper3 != 0) {
                    oprintf(",");
                    putamode(ip->oper3);
                }
            }
        }
        oprintf("%s|| ", newline);
        putop(ParallelOp[ip->opcode-op_mpyf3_addf3][1]);
        if (ip->oper21 != 0) {
            oprintf("\t");
            putamode(ip->oper21);
            if (ip->oper22 != 0) {
                oprintf(",");
                putamode(ip->oper22);
                if (ip->oper23 != 0) {
                    oprintf(",");
                    putamode(ip->oper23);
                }
            }
        }
        oprintf("%s", newline);
    } else if (ip->opcode == op_asm) {
        oprintf("\t");
        putamode(ip->oper1);           
        oprintf("\n");
    } else if (ip->opcode == op_line) {
        oprintf("\n*>>>> line ");
        putamode(ip->oper1);           
        oprintf(": ");
        putamode(ip->oper2);           
        oprintf("%s%s", newline, newline);
    } else {
        FATAL((__FILE__,"put_code","illegal op %d", ip->opcode));
    }                                                                    
}

/*
 * generate a register name
 */
static void
putreg P1(REG, r)
{
    static char *regname[] = {
        "r0",   /* REG_R0 */
        "r1",   /* REG_R1 */
        "r2",   /* REG_R2 */
        "r3",   /* REG_R3 */
        "r4",   /* REG_R4 */
        "r5",   /* REG_R5 */
        "r6",   /* REG_R6 */
        "r7",   /* REG_R7 */
        "ar0",  /* REG_AR0 */
        "ar1",  /* REG_AR1 */
        "ar2",  /* REG_AR2 */
        "ar3",  /* REG_AR3 */
        "ar4",  /* REG_AR4 */
        "ar5",  /* REG_AR5 */
        "ar6",  /* REG_AR6 */
        "ar7",  /* REG_AR7 */
        "dp",   /* REG_DP */
        "ir0",  /* REG_IR0 */
        "ir1",  /* REG_IR1 */
        "bk",   /* REG_BK */
        "sp",   /* REG_SP */
        "st",   /* REG_ST */
        "ie",   /* REG_IE */
        "if",   /* REG_IF */
        "iof",  /* REG_IOF */
        "rs",   /* REG_RS */
        "re",   /* REG_RE */
        "rc"    /* REG_RC */
    };

    if (r >= REG_R0 && r <= REG_RC) {
        oprintf("%s", regname[r]);
    } else {
        oprintf("R%d??",r);
    }
}

/*
 * generate a named label.
 */
PRIVATE void
put_name P1(SYM*, sp)
{
    put_reference(sp);
    oprintf("%s:%s",outlate(sp->name), newline);
}

/*
 * output a compiler generated label.
 */
PRIVATE void
put_label P1(LABEL, lab)
{
    oprintf("%s%u:%s", prefix, (unsigned int)lab, newline);
}

static void
put_header P2(enum e_gt, gtype, SIZE, al)
{
    static char *directive[] = {
        ".word \t",       /* bytegen */
        ".word \t",       /* wordgen */
        ".word \t",       /* longgen */
        ".float\t",      /* floatgen */
        };

    if (gentype != gtype || outcol >= MAX_WIDTH) {
        put_align(al);
        gentype = gtype;
        outcol = 15;
        oprintf("\t%s", directive[gtype]);
    } else
        oprintf(",");
}

PRIVATE void
put_byte P1(int, val)
{
    put_header(bytegen, alignment(tp_char));
    oprintf("%d", val & 0x00ff);
    outcol += 4;
}

PRIVATE void
put_char P1(int, val)
{
    put_byte(val);
}

PRIVATE void
put_word P1(int, val)
{
    put_header(wordgen, alignment(tp_short));
    oprintf(",%d", val & 0xffff);
    outcol += 6;
}

PRIVATE void
put_float P1(RVAL *, vp)
{
    put_header (floatgen, alignment(tp_float));
    oprintf("%f", *vp);
    outcol += 80;
}

PRIVATE void
put_double P1(RVAL *, vp)
{
    put_header (floatgen, alignment(tp_double));
    oprintf("%f", *vp);
    outcol += 80;
}

PRIVATE void
put_longdouble P1(RVAL *, vp)
{
    put_header (floatgen, alignment(tp_longdouble));
    oprintf("%f", *vp);
    outcol += 80;
}

PRIVATE void
put_long P1(IVAL, val)
{
    put_header (longgen, alignment(tp_long));
    oprintf("%lxh", val);
    outcol += 10;
}

#ifndef RELOC_BUG
PRIVATE void
put_short P1(const EXPR *, ep)
{
    put_header (wordgen, alignment(tp_short));
    putconst(ep);
    outcol += 10;
}
#endif /* RELOC_BUG */

PRIVATE void
put_pointer P1(const EXPR *, ep)
{
    put_header (longgen, alignment(tp_pointer));
    putconst(ep);
    outcol += 10;
}

PRIVATE void
put_storage P1(SYM *, sp)
{
    nl();
    oprintf("\t.bss   ");
    /*bseg();*/
    
    if (sp->storage_class == sc_static) {
        put_label (sp->value.l);
    } else {
#if 0
        put_name (sp);
#else
	oprintf("%s",outlate(sp->name));
#endif
    }
    oprintf(", %ld%s", sp->tp->size, newline);
}


/*
 * dump the string literal pool.
 * if we are producing single copies of strings (which should therefore
 * be read only we put them in the text segement - else in the data segment.
 */
PRIVATE void
put_literals P0(void)
{
    const CHAR *cp;
    size_t      len;
    if (trad_option) {
        put_dseg(alignment(tp_char));
    } else {
        put_kseg(alignment(tp_char));
    }
    for ( ; strtab != 0; strtab = strtab->next) {
        nl();
        put_label(strtab->label);
        cp = strtab->str;
        for (len = strtab->len; len--; )
            put_char(*cp++);
        put_byte(0);
        nl();     
    }
    nl();
}

/* put the definition of an external name in the ouput file */
PRIVATE void
put_reference P1(SYM *, sp)
{
    if (!is_symbol_output(sp)) {
	switch (sp->storage_class) {
	  case sc_global:
	    nl();
	    oprintf("\t.global %s%s", outlate(sp->name), newline);
	    break;
	  case sc_external:
	    nl();
	    oprintf("\t.global %s%s", outlate(sp->name), newline);
	    break;
	  default:
	    break;
	}
    }
}

/* align the following data */
PRIVATE void
put_align P1(SIZE, al)
{
    nl();
    if (al > align_type) {
        switch (al) {
          case 1:
            break;
          case 2:
          case 4:
            oprintf("\t.even%s", newline);
            break;
        }
    }
    align_type = al;
}

PRIVATE void
nl P0(void)
{
    if (outcol > 0) {
        oprintf("%s", newline);
        gentype = nogen;
        outcol = 0;
    }
}

static void
seg P3(enum e_sg, segtype, char *, segname, SIZE, al)
{
    nl();
    if (curseg != segtype) {
        oprintf("\t%s%s", segname, newline);
        curseg = segtype;
        align_type = 0;
    }
    put_align(al);
}

PRIVATE void
put_cseg P1(SIZE, al)
{
    seg(codeseg,".text", al);
}

PRIVATE void
put_dseg P1(SIZE, al)
{
    seg(dataseg,".data", al);
}

PRIVATE void
put_kseg P1(SIZE, al)
{
    seg(romseg,".sect \".rom\"", al);
}


PRIVATE void
put_finish P0(void)
{
}

PRIVATE void
put_start P0(void)
{
    oprintf("%s Generated by %s %s %s (%s) from \"%s\"%s",
        comment, PROGNAME, VERSION, LAST_CHANGE_DATE, __DATE__, act_file,
        newline);
#ifdef VERBOSE
    {
        time_t time_of_day;
        VOIDCAST time (&time_of_day);
        oprintf("%s Compilation date/time: %s%s",
            comment, ctime(&time_of_day), newline);
    }
#endif /* VERBOSE */
    /* introduce the sections */
    seg(codeseg, ".text", 0L);
    seg(romseg, ".sect \".rom\"", 0L);
    seg(dataseg, ".data", 0L);
    /*seg(bssseg, ".bss", 0L);*/
}
#ifdef MULTIPLE_ASSEMBLERS
struct funcs rosc30_funcs = {
        put_code,
        put_name,
        put_label,
        put_byte,
        put_char,
        put_word,
        put_long,
        put_pointer,
#ifndef RELOC_BUG
        put_short,
#endif /* RELOC_BUG */
        put_storage,
        put_literals,
        put_finish,
        put_start,
        put_reference,
        put_cseg,
        put_dseg,
        put_kseg,
#ifdef FLOAT_SUPPORT
        put_float,
        put_double,
        put_longdouble
#endif /* FLOAT_SUPPORT */
        };
#endif /* MULTIPLE_ASSEMBLERS */
#endif /* TARGET_ROSSIN */
#endif /* TMS320C30 */
