Archelon Ischyros Archelon Inc.

Programming tools for your new processor

Texas Instruments TMS320C30/TMS320C40

Example Machine Description File

This Machine Definition File (MDF) implements an optimizing assembler for the TMS320C30 or TMS320C40 target machine. The main optimizing function of the assembler is to try to move instructions forward into empty branch delay slots, wherever possible. The compactor uses the MDF to translate assembly language instructions for a TMS320C30 or TMS320C40 processor into an alternate form which is subsequently processed by the assembler into relocatable object files which can be linked to form a program which can be loaded into the processor's memory. The assembler is controlled by a DEF file which is optionally produced by the compactor after it has read the MDF.

Each time you run the compactor, it reads in an MDF before starting to process the code which you are giving it. Similarly, the assembler always reads in a DEF file before processing its input file.

The MDF contains:

The file content shown below contains macros which must be expanded (using the widely available m4 macro preprocessor) to generate an MDF for either the TMS320C30 or the TMS320C40 processor family.

For more information about the MDF, see the Technical Overview.

You can reach us by email at info@archelon.com.


Back to Archelon's Home Page.



/* @(#)		c3x.ms		1.19		01/10/15		12:46:35		@(#)
 * 
 * c3x.ms - MDF source for C3X and C4X
 *
 * Copyright (c) 1996-1998, 2001 Archelon Inc. All Rights Reserved.
 */

ifdef( `CPU', `', `define( `CPU', `C3X' )' )
ifelse( CPU, `C3X', `define( `REGS', `28' )', `define( `REGS', `32' )' )

.wordsize 32;

.ignore_token_case; 	/* instructions are not case sensitive */
undefine(`substr')		/* turn off substr built in in m4 */
.noop "no_op";

.reverse;	/* provide better compaction for machines with branch delay slots*/
/* consumable resources */
.resource JUMP;
.resource REGISTER[ REGS ];
.resource CC;
.resource MEMORY;
.resource DP;
ifelse( CPU, `C3X', `', `.resource IVTP; .resource TVTP;')

/*
 * tokens
 */

/* token definations with token classes */
ifelse( CPU, `C3X', `', `
/* additional opcode token for c4x */
.token TOK_LB0 "lb0" TC_DOUBLE TC_II;
.token TOK_LB1 "lb1" TC_DOUBLE TC_II;
.token TOK_LB2 "lb2" TC_DOUBLE TC_II;
.token TOK_LB3 "lb3" TC_DOUBLE TC_II;
.token TOK_LBU0 "lbu0" TC_DOUBLE TC_II;
.token TOK_LBU1 "lbu1" TC_DOUBLE TC_II;
.token TOK_LBU2 "lbu2" TC_DOUBLE TC_II;
.token TOK_LBU3 "lbu3" TC_DOUBLE TC_II;
.token TOK_LDA "lda" TC_DOUBLE TC_II;
.token TOK_LDEP "ldep" TC_DOUBLE TC_II;
.token TOK_LDHI "ldhi" TC_DOUBLE TC_II;
.token TOK_LDPE "ldpe" TC_DOUBLE TC_II;
.token TOK_LDPK "ldpk" TC_SGL TC_II;
.token TOK_LH0 "lh0" TC_DOUBLE TC_II;
.token TOK_LH1 "lh1" TC_DOUBLE TC_II;
.token TOK_LHU0 "lhu0" TC_DOUBLE TC_II;
.token TOK_LHU1 "lhu1" TC_DOUBLE TC_II;
.token TOK_LWL0 "lwl0" TC_DOUBLE TC_II;
.token TOK_LWL1 "lwl1" TC_DOUBLE TC_II;
.token TOK_LWL2 "lwl2" TC_DOUBLE TC_II;
.token TOK_LWL3 "lwl3" TC_DOUBLE TC_II;
.token TOK_LWR3 "lwr3" TC_DOUBLE TC_II;
.token TOK_LWR2 "lwr2" TC_DOUBLE TC_II;
.token TOK_LWR1 "lwr1" TC_DOUBLE TC_II;
.token TOK_LWR0 "lwr0" TC_DOUBLE TC_II;
.token TOK_STIK "stik" TC_DOUBLE TC_II;
.token TOK_FRIEEE "frieee" TC_DOUBLE TC_FF;
.token TOK_MB0 "mb0" TC_DOUBLE TC_II;
.token TOK_MB1 "mb1" TC_DOUBLE TC_II;
.token TOK_MB2 "mb2" TC_DOUBLE TC_II;
.token TOK_MB3 "mb3" TC_DOUBLE TC_II;
.token TOK_MH0 "mh0" TC_DOUBLE TC_II;
.token TOK_MH1 "mh1" TC_DOUBLE TC_II;
.token TOK_MPYSHI "mpyshi" TC_DOUBLE TC_II;
.token TOK_MPYUHI "mpyuhi" TC_DOUBLE TC_II;
.token TOK_RCPF "rcpf" TC_DOUBLE TC_FF;
.token TOK_RSQRF "rsqrf" TC_DOUBLE TC_FF;
.token TOK_TOIEEE "toieee" TC_DOUBLE TC_FF;
.token TOK_MPYSHI3 "mpyshi3" TC_TRIPPLE TC_II;
.token TOK_MPYUHI3 "mpyuhi3" TC_TRIPPLE TC_FFF;
.token TOK_BUAF "buaf" TC_OPC_BRPC TC_CC_U TC_SGL;
.token TOK_BLOAF "bloaf" TC_OPC_BRPC TC_CC_LO TC_SGL;
.token TOK_BLSAF "blsaf" TC_OPC_BRPC TC_CC_LS TC_SGL;
.token TOK_BHIAF "bhiaf" TC_OPC_BRPC TC_CC_HI TC_SGL;
.token TOK_BHSAF "bhsaf" TC_OPC_BRPC TC_CC_HS TC_SGL;
.token TOK_BEQAF "beqaf" TC_OPC_BRPC TC_CC_EQ TC_SGL;
.token TOK_BNEAF "bneaf" TC_OPC_BRPC TC_CC_NE TC_SGL;
.token TOK_BLTAF "bltaf" TC_OPC_BRPC TC_CC_LT TC_SGL;
.token TOK_BLEAF "bleaf" TC_OPC_BRPC TC_CC_LE TC_SGL;
.token TOK_BGTAF "bgtaf" TC_OPC_BRPC TC_CC_GT TC_SGL;
.token TOK_BGEAF "bgeaf" TC_OPC_BRPC TC_CC_GE TC_SGL;
.token TOK_BNVAF "bnvaf" TC_OPC_BRPC TC_CC_NV TC_SGL;
.token TOK_BVAF "bvaf" TC_OPC_BRPC TC_CC_V TC_SGL;
.token TOK_BNUFAF "bnufaf" TC_OPC_BRPC TC_CC_NUF TC_SGL;
.token TOK_BUFAF "bufaf" TC_OPC_BRPC TC_CC_UF TC_SGL;
.token TOK_BNLVAF "bnlvaf" TC_OPC_BRPC TC_CC_NLV TC_SGL;
.token TOK_BLVAF "blvaf" TC_OPC_BRPC TC_CC_LV TC_SGL;
.token TOK_BLUFAF "blufaf" TC_OPC_BRPC TC_CC_LUF TC_SGL;
.token TOK_BZUFAF "bzufaf" TC_OPC_BRPC TC_CC_ZUF TC_SGL;

.token TOK_BUAT "buat" TC_OPC_BRPC TC_CC_U TC_SGL;
.token TOK_BLOAT "bloat" TC_OPC_BRPC TC_CC_LO TC_SGL;
.token TOK_BLSAT "blsat" TC_OPC_BRPC TC_CC_LS TC_SGL;
.token TOK_BHIAT "bhiat" TC_OPC_BRPC TC_CC_HI TC_SGL;
.token TOK_BHSAT "bhsat" TC_OPC_BRPC TC_CC_HS TC_SGL;
.token TOK_BEQAT "beqat" TC_OPC_BRPC TC_CC_EQ TC_SGL;
.token TOK_BNEAT "bneat" TC_OPC_BRPC TC_CC_NE TC_SGL;
.token TOK_BLTAT "bltat" TC_OPC_BRPC TC_CC_LT TC_SGL;
.token TOK_BLEAT "bleat" TC_OPC_BRPC TC_CC_LE TC_SGL;
.token TOK_BGTAT "bgtat" TC_OPC_BRPC TC_CC_GT TC_SGL;
.token TOK_BGEAT "bgeat" TC_OPC_BRPC TC_CC_GE TC_SGL;
.token TOK_BNVAT "bnvat" TC_OPC_BRPC TC_CC_NV TC_SGL;
.token TOK_BVAT "bvat" TC_OPC_BRPC TC_CC_V TC_SGL;
.token TOK_BNUFAT "bnufat" TC_OPC_BRPC TC_CC_NUF TC_SGL;
.token TOK_BUFAT "bufat" TC_OPC_BRPC TC_CC_UF TC_SGL;
.token TOK_BNLVAT "bnlvat" TC_OPC_BRPC TC_CC_NLV TC_SGL;
.token TOK_BLVAT "blvat" TC_OPC_BRPC TC_CC_LV TC_SGL;
.token TOK_BLUFAT "blufat" TC_OPC_BRPC TC_CC_LUF TC_SGL;
.token TOK_BZUFAT "bzufat" TC_OPC_BRPC TC_CC_ZUF TC_SGL;')

ifelse( CPU, `C3X', `', `

.token TOK_LAJ "laj" TC_OPC_BRPC TC_SGL;
.token TOK_LAJU "laju" TC_OPC_BRPC TC_CC_U TC_SGL;
.token TOK_LAJLO "lajlo" TC_OPC_BRPC TC_CC_LO TC_SGL;
.token TOK_LAJLS "lajls" TC_OPC_BRPC TC_CC_LS TC_SGL;
.token TOK_LAJHI "lajhi" TC_OPC_BRPC TC_CC_HI TC_SGL;
.token TOK_LAJHS "lajhs" TC_OPC_BRPC TC_CC_HS TC_SGL;
.token TOK_LAJEQ "lajeq" TC_OPC_BRPC TC_CC_EQ TC_SGL;
.token TOK_LAJNE "lajne" TC_OPC_BRPC TC_CC_NE TC_SGL;
.token TOK_LAJLT "lajlt" TC_OPC_BRPC TC_CC_LT TC_SGL;
.token TOK_LAJLE "lajle" TC_OPC_BRPC TC_CC_LE TC_SGL;
.token TOK_LAJGT "lajgt" TC_OPC_BRPC TC_CC_GT TC_SGL;
.token TOK_LAJGE "lajge" TC_OPC_BRPC TC_CC_GE TC_SGL;
.token TOK_LAJNV "lajnv" TC_OPC_BRPC TC_CC_NV TC_SGL;
.token TOK_LAJV "lajv" TC_OPC_BRPC TC_CC_V TC_SGL;
.token TOK_LAJNUF "lajnuf" TC_OPC_BRPC TC_CC_NUF TC_SGL;
.token TOK_LAJUF "lajuf" TC_OPC_BRPC TC_CC_UF TC_SGL;
.token TOK_LAJNLV "lajnlv" TC_OPC_BRPC TC_CC_NLV TC_SGL;
.token TOK_LAJLV "lajlv" TC_OPC_BRPC TC_CC_LV TC_SGL;
.token TOK_LAJLUF "lajluf" TC_OPC_BRPC TC_CC_LUF TC_SGL;
.token TOK_LAJZUF "lajzuf" TC_OPC_BRPC TC_CC_ZUF TC_SGL;

.token TOK_LATU "latu" TC_OPC_RTPC TC_CC_U TC_SGL;
.token TOK_LATLO "latlo" TC_OPC_RTPC TC_CC_LO TC_SGL;
.token TOK_LATLS "latls" TC_OPC_RTPC TC_CC_LS TC_SGL;
.token TOK_LATHI "lathi" TC_OPC_RTPC TC_CC_HI TC_SGL;
.token TOK_LATHS "laths" TC_OPC_RTPC TC_CC_HS TC_SGL;
.token TOK_LATEQ "lateq" TC_OPC_RTPC TC_CC_EQ TC_SGL;
.token TOK_LATNE "latne" TC_OPC_RTPC TC_CC_NE TC_SGL;
.token TOK_LATLT "latlt" TC_OPC_RTPC TC_CC_LT TC_SGL;
.token TOK_LATLE "latle" TC_OPC_RTPC TC_CC_LE TC_SGL;
.token TOK_LATGT "latgt" TC_OPC_RTPC TC_CC_GT TC_SGL;
.token TOK_LATGE "latge" TC_OPC_RTPC TC_CC_GE TC_SGL;
.token TOK_LATNV "latnv" TC_OPC_RTPC TC_CC_NV TC_SGL;
.token TOK_LATV "latv" TC_OPC_RTPC TC_CC_V TC_SGL;
.token TOK_LATNUF "latnuf" TC_OPC_RTPC TC_CC_NUF TC_SGL;
.token TOK_LATUF "latuf" TC_OPC_RTPC TC_CC_UF TC_SGL;
.token TOK_LATNLV "latnlv" TC_OPC_RTPC TC_CC_NLV TC_SGL;
.token TOK_LATLV "latlv" TC_OPC_RTPC TC_CC_LV TC_SGL;
.token TOK_LATLUF "latluf" TC_OPC_RTPC TC_CC_LUF TC_SGL;
.token TOK_LATZUF "latzuf" TC_OPC_RTPC TC_CC_ZUF TC_SGL;

.token TOK_RETIUD "retiud" TC_OPC_RTPC TC_CC_U TC_NONE;
.token TOK_RETILOD "retilod" TC_OPC_RTPC TC_CC_LO TC_NONE;
.token TOK_RETILSD "retilsd" TC_OPC_RTPC TC_CC_LS TC_NONE;
.token TOK_RETIHID "retihid" TC_OPC_RTPC TC_CC_HI TC_NONE;
.token TOK_RETIHSD "retihsd" TC_OPC_RTPC TC_CC_HS TC_NONE;
.token TOK_RETIEQD "retieqd" TC_OPC_RTPC TC_CC_EQ TC_NONE;
.token TOK_RETINED "retined" TC_OPC_RTPC TC_CC_NE TC_NONE;
.token TOK_RETILTD "retiltd" TC_OPC_RTPC TC_CC_LT TC_NONE;
.token TOK_RETILED "retiled" TC_OPC_RTPC TC_CC_LE TC_NONE;
.token TOK_RETIGTD "retigtd" TC_OPC_RTPC TC_CC_GT TC_NONE;
.token TOK_RETIGED "retiged" TC_OPC_RTPC TC_CC_GE TC_NONE;
.token TOK_RETINVD "retinvd" TC_OPC_RTPC TC_CC_NV TC_NONE;
.token TOK_RETIVD "retivd" TC_OPC_RTPC TC_CC_V TC_NONE;
.token TOK_RETINUFD "retinufd" TC_OPC_RTPC TC_CC_NUF TC_NONE;
.token TOK_RETIUFD "retiufd" TC_OPC_RTPC TC_CC_UF TC_NONE;
.token TOK_RETINLVD "retinlvd" TC_OPC_RTPC TC_CC_NLV TC_NONE;
.token TOK_RETILVD "retilvd" TC_OPC_RTPC TC_CC_LV TC_NONE;
.token TOK_RETILUFD "retilufd" TC_OPC_RTPC TC_CC_LUF TC_NONE;
.token TOK_RETIZUFD "retizufd" TC_OPC_RTPC TC_CC_ZUF TC_NONE;

.token TOK_RPTBD "rptbd" TC_SGL TC_II;
/* these two used only in ldep and ldpe instructions for C4X */
.token TOK_IVTP "ivtp";
.token TOK_TVTP "tvtp";
')

/* load-store token classes */
.token TOK_LDE "lde"  TC_DOUBLE TC_FF ;
.token TOK_LDF "ldf"  TC_DOUBLE TC_FF ;
.token TOK_LDI "ldi"  TC_DOUBLE TC_II ;
.token TOK_LDM "ldm"  TC_DOUBLE TC_FF ;
.token TOK_LDP "ldp"  TC_SGL;
.token TOK_POP "pop"  TC_SGL TC_II ;
.token TOK_POPF "popf"  TC_SGL TC_FF ;
.token TOK_PUSH "push"  TC_SGL TC_II ;
.token TOK_PUSHF "pushf"  TC_SGL TC_FF ;
.token TOK_STF "stf"  TC_DOUBLE TC_FF ;
.token TOK_STI "sti"  TC_DOUBLE TC_II ;
.token TOK_LDIU "ldiu"  TC_II TC_DOUBLE ;
.token TOK_LDILO "ldilo"  TC_II TC_DOUBLE ;
.token TOK_LDILS "ldils"  TC_II TC_DOUBLE ;
.token TOK_LDIHI "ldihi"  TC_II TC_DOUBLE ;
.token TOK_LDIHS "ldihs"  TC_II TC_DOUBLE ;
.token TOK_LDIEQ "ldieq"  TC_II TC_DOUBLE ;
.token TOK_LDINE "ldine"  TC_II TC_DOUBLE ;
.token TOK_LDILT "ldilt"  TC_II TC_DOUBLE ;
.token TOK_LDILE "ldile"  TC_II TC_DOUBLE ;
.token TOK_LDIGT "ldigt"  TC_II TC_DOUBLE ;
.token TOK_LDIGE "ldige"  TC_II TC_DOUBLE ;
.token TOK_LDINV "ldinv"  TC_II TC_DOUBLE ;
.token TOK_LDIV "ldiv"  TC_II TC_DOUBLE ;
.token TOK_LDINUF "ldinuf"  TC_II TC_DOUBLE ;
.token TOK_LDIUF "ldiuf"  TC_II TC_DOUBLE ;
.token TOK_LDINLV "ldinlv"  TC_II TC_DOUBLE ;
.token TOK_LDILV "ldilv"  TC_II TC_DOUBLE ;
.token TOK_LDINLUF "ldinluf"  TC_II TC_DOUBLE ;
.token TOK_LDILUF "ldiluf"  TC_II TC_DOUBLE ;
.token TOK_LDIZUF "ldizuf"  TC_II TC_DOUBLE ;

.token TOK_LDFU "ldfu"  TC_FF TC_DOUBLE ;
.token TOK_LDFLO "ldflo"  TC_FF TC_DOUBLE ;
.token TOK_LDFLS "ldfls"  TC_FF TC_DOUBLE ;
.token TOK_LDFHI "ldfhi"  TC_FF TC_DOUBLE ;
.token TOK_LDFHS "ldfhs"  TC_FF TC_DOUBLE ;
.token TOK_LDFEQ "ldfeq"  TC_FF TC_DOUBLE ;
.token TOK_LDFNE "ldfne"  TC_FF TC_DOUBLE ;
.token TOK_LDFLT "ldflt"  TC_FF TC_DOUBLE ;
.token TOK_LDFLE "ldfle"  TC_FF TC_DOUBLE ;
.token TOK_LDFGT "ldfgt"  TC_FF TC_DOUBLE ;
.token TOK_LDFGE "ldfge"  TC_FF TC_DOUBLE ;
.token TOK_LDFNV "ldfnv"  TC_FF TC_DOUBLE ;
.token TOK_LDFV "ldfv"  TC_FF TC_DOUBLE ;
.token TOK_LDFNUF "ldfnuf"  TC_FF TC_DOUBLE ;
.token TOK_LDFUF "ldfuf"  TC_FF TC_DOUBLE ;
.token TOK_LDFNLV "ldfnlv"  TC_FF TC_DOUBLE ;
.token TOK_LDFLV "ldflv"  TC_FF TC_DOUBLE ;
.token TOK_LDFNLUF "ldfnluf"  TC_FF TC_DOUBLE ;
.token TOK_LDFLUF "ldfluf"  TC_FF TC_DOUBLE ;
.token TOK_LDFZUF "ldfzuf"  TC_FF TC_DOUBLE ;

/* two-operand operations */
.token TOK_ABSF "absf" TC_DOUBLE TC_FF ;
.token TOK_ABSI "absi" TC_DOUBLE TC_II ;
.token TOK_ADDC "addc" TC_DOUBLE TC_II  ;
.token TOK_ADDF "addf" TC_DOUBLE TC_FF  ;
.token TOK_ADDI "addi" TC_DOUBLE TC_II  ;
.token TOK_AND "and" TC_DOUBLE TC_II  ;
.token TOK_ANDN "andn" TC_DOUBLE TC_II  ;
.token TOK_ASH "ash" TC_DOUBLE TC_II  ;
.token TOK_CMPF "cmpf" TC_DOUBLE TC_FF  ;
.token TOK_CMPI "cmpi" TC_DOUBLE TC_II  ;
.token TOK_FIX "fix" TC_DOUBLE;
.token TOK_FLOAT "float" TC_DOUBLE;
.token TOK_LSH "lsh" TC_DOUBLE TC_II  ;
.token TOK_MPYF "mpyf" TC_DOUBLE TC_FF  ;
.token TOK_MPYI "mpyi" TC_DOUBLE TC_II  ;
.token TOK_NEGB "negb" TC_DOUBLE TC_II ;
.token TOK_NEGF "negf" TC_DOUBLE TC_FF ;
.token TOK_NEGI "negi" TC_DOUBLE TC_II ;
.token TOK_NORM "norm" TC_DOUBLE TC_FF ;
.token TOK_NOT "not" TC_DOUBLE TC_II ;
.token TOK_OR "or" TC_DOUBLE TC_II  ;
.token TOK_RND "rnd" TC_DOUBLE TC_FF ;
.token TOK_ROL "rol" TC_SGL TC_II ;
.token TOK_ROLC "rolc" TC_SGL TC_II ;
.token TOK_ROR "ror" TC_SGL TC_II ;
.token TOK_RORC "rorc" TC_SGL TC_II ;
.token TOK_SUBB "subb" TC_DOUBLE TC_II  ;
.token TOK_SUBC "subc" TC_DOUBLE TC_II ;
.token TOK_SUBF "subf" TC_DOUBLE TC_FF ;
.token TOK_SUBI "subi" TC_DOUBLE TC_II ;
.token TOK_SUBRB "subrb" TC_DOUBLE TC_II ;
.token TOK_SUBRF "subrf" TC_DOUBLE TC_FF ;
.token TOK_SUBRI "subri" TC_DOUBLE TC_II ;
.token TOK_TSTB "tstb" TC_DOUBLE TC_II  ;
.token TOK_XOR "xor" TC_DOUBLE TC_II  ;

/* three-operand opcodes */
.token TOK_ADDC3 "addc3" TC_TRIPPLE TC_II ;
.token TOK_ADDF3 "addf3" TC_TRIPPLE TC_FFF ;
.token TOK_ADDI3 "addi3" TC_TRIPPLE TC_II ;
.token TOK_AND3 "and3" TC_TRIPPLE TC_II ;
.token TOK_ANDN3 "andn3" TC_TRIPPLE TC_II ;
.token TOK_ASH3 "ash3" TC_TRIPPLE TC_II ;
.token TOK_CMPF3 "cmpf3" TC_TRIPPLE TC_FFF ;
.token TOK_CMPI3 "cmpi3" TC_TRIPPLE TC_II ;
.token TOK_LSH3 "lsh3" TC_TRIPPLE TC_II ;
.token TOK_MPYF3 "mpyf3" TC_TRIPPLE TC_FFF ;
.token TOK_MPYI3 "mpyi3" TC_TRIPPLE TC_II ;
.token TOK_OR3 "or3" TC_TRIPPLE TC_II ;
.token TOK_SUBB3 "subb3" TC_TRIPPLE TC_II ;
.token TOK_SUBF3 "subf3" TC_TRIPPLE TC_FFF ;
.token TOK_SUBI3 "subi3" TC_TRIPPLE TC_II ;
.token TOK_TSTB3 "tstb3" TC_TRIPPLE TC_II ;
.token TOK_XOR3 "xor3" TC_TRIPPLE TC_II ;

/* program control opcodes */
.token TOK_BU "bu" TC_OPC_BRPC TC_CC_U  TC_SGL ;
.token TOK_BLO "blo" TC_OPC_BRPC TC_CC_LO  TC_SGL ;
.token TOK_BPC "bls" TC_OPC_BRPC TC_CC_LS  TC_SGL ;
.token TOK_BHI "bhi" TC_OPC_BRPC TC_CC_HI  TC_SGL ;
.token TOK_BHS "bhs" TC_OPC_BRPC TC_CC_HS  TC_SGL ;
.token TOK_BEQ "beq" TC_OPC_BRPC TC_CC_EQ  TC_SGL ;
.token TOK_BNE "bne" TC_OPC_BRPC TC_CC_NE  TC_SGL ;
.token TOK_BLT "blt" TC_OPC_BRPC TC_CC_LT  TC_SGL ;
.token TOK_BLE "ble" TC_OPC_BRPC TC_CC_LE  TC_SGL ;
.token TOK_BGT "bgt" TC_OPC_BRPC TC_CC_GT  TC_SGL ;
.token TOK_BGE "bge" TC_OPC_BRPC TC_CC_GE  TC_SGL ;
.token TOK_BNV "bnv" TC_OPC_BRPC TC_CC_NV  TC_SGL ;
.token TOK_BV "bv" TC_OPC_BRPC TC_CC_V  TC_SGL ;
.token TOK_BNUF "bnuf" TC_OPC_BRPC TC_CC_NUF  TC_SGL ;
.token TOK_BUF "buf" TC_OPC_BRPC TC_CC_UF  TC_SGL ;
.token TOK_BNLV "bnlv" TC_OPC_BRPC TC_CC_NLV  TC_SGL ;
.token TOK_BLV "blv" TC_OPC_BRPC TC_CC_LV  TC_SGL ;
.token TOK_BNLUF "bnluf" TC_OPC_BRPC TC_CC_NLUF  TC_SGL ;
.token TOK_BLUF "bluf" TC_OPC_BRPC TC_CC_LUF  TC_SGL ;
.token TOK_BZUF "bzuf" TC_OPC_BRPC TC_CC_ZUF  TC_SGL ;

.token TOK_BUD "bud" TC_OPC_BRPC TC_CC_U  TC_SGL ;
.token TOK_BLOD "blod" TC_OPC_BRPC TC_CC_LO  TC_SGL ;
.token TOK_BPCD "blsd" TC_OPC_BRPC TC_CC_LS  TC_SGL ;
.token TOK_BHID "bhid" TC_OPC_BRPC TC_CC_HI  TC_SGL ;
.token TOK_BHSD "bhsd" TC_OPC_BRPC TC_CC_HS  TC_SGL ;
.token TOK_BEQD "beqd" TC_OPC_BRPC TC_CC_EQ  TC_SGL ;
.token TOK_BNED "bned" TC_OPC_BRPC TC_CC_NE  TC_SGL ;
.token TOK_BLTD "bltd" TC_OPC_BRPC TC_CC_LT  TC_SGL ;
.token TOK_BLED "bled" TC_OPC_BRPC TC_CC_LE  TC_SGL ;
.token TOK_BGTD "bgtd" TC_OPC_BRPC TC_CC_GT  TC_SGL ;
.token TOK_BGED "bged" TC_OPC_BRPC TC_CC_GE  TC_SGL ;
.token TOK_BNVD "bnvd" TC_OPC_BRPC TC_CC_NV  TC_SGL ;
.token TOK_BVD "bvd" TC_OPC_BRPC TC_CC_V  TC_SGL ;
.token TOK_BNUFD "bnufd" TC_OPC_BRPC TC_CC_NUF  TC_SGL ;
.token TOK_BUFD "bufd" TC_OPC_BRPC TC_CC_UF  TC_SGL ;
.token TOK_BNLVD "bnlvd" TC_OPC_BRPC TC_CC_NLV  TC_SGL ;
.token TOK_BLVD "blvd" TC_OPC_BRPC TC_CC_LV  TC_SGL ;
.token TOK_BNLUFD "bnlufd" TC_OPC_BRPC TC_CC_NLUF  TC_SGL ;
.token TOK_BLUFD "blufd" TC_OPC_BRPC TC_CC_LUF  TC_SGL ;
.token TOK_BZUFD "bzufd" TC_OPC_BRPC TC_CC_ZUF  TC_SGL ;

.token TOK_CALLU "callu" TC_OPC_BRPC TC_CC_U  TC_SGL ;
.token TOK_CALLLO "calllo" TC_OPC_BRPC TC_CC_LO  TC_SGL ;
.token TOK_CALLPC "callls" TC_OPC_BRPC TC_CC_LS  TC_SGL ;
.token TOK_CALLHI "callhi" TC_OPC_BRPC TC_CC_HI  TC_SGL ;
.token TOK_CALLHS "callhs" TC_OPC_BRPC TC_CC_HS  TC_SGL ;
.token TOK_CALLEQ "calleq" TC_OPC_BRPC TC_CC_EQ  TC_SGL ;
.token TOK_CALLNE "callne" TC_OPC_BRPC TC_CC_NE  TC_SGL ;
.token TOK_CALLLT "calllt" TC_OPC_BRPC TC_CC_LT  TC_SGL ;
.token TOK_CALLLE "callle" TC_OPC_BRPC TC_CC_LE  TC_SGL ;
.token TOK_CALLGT "callgt" TC_OPC_BRPC TC_CC_GT  TC_SGL ;
.token TOK_CALLGE "callge" TC_OPC_BRPC TC_CC_GE  TC_SGL ;
.token TOK_CALLNV "callnv" TC_OPC_BRPC TC_CC_NV  TC_SGL ;
.token TOK_CALLV "callv" TC_OPC_BRPC TC_CC_V  TC_SGL ;
.token TOK_CALLNUF "callnuf" TC_OPC_BRPC TC_CC_NUF  TC_SGL ;
.token TOK_CALLUF "calluf" TC_OPC_BRPC TC_CC_UF  TC_SGL ;
.token TOK_CALLNLV "callnlv" TC_OPC_BRPC TC_CC_NLV  TC_SGL ;
.token TOK_CALLLV "calllv" TC_OPC_BRPC TC_CC_LV  TC_SGL ;
.token TOK_CALLNLUF "callnluf" TC_OPC_BRPC TC_CC_NLUF  TC_SGL ;
.token TOK_CALLLUF "callluf" TC_OPC_BRPC TC_CC_LUF  TC_SGL ;
.token TOK_CALLZUF "callzuf" TC_OPC_BRPC TC_CC_ZUF  TC_SGL ;

.token TOK_DBU "dbu" TC_OPC_BRPC TC_CC_U  TC_DOUBLE ;
.token TOK_DBLO "dblo" TC_OPC_BRPC TC_CC_LO  TC_DOUBLE ;
.token TOK_DBPC "dbls" TC_OPC_BRPC TC_CC_LS  TC_DOUBLE ;
.token TOK_DBHI "dbhi" TC_OPC_BRPC TC_CC_HI  TC_DOUBLE ;
.token TOK_DBHS "dbhs" TC_OPC_BRPC TC_CC_HS  TC_DOUBLE ;
.token TOK_DBEQ "dbeq" TC_OPC_BRPC TC_CC_EQ  TC_DOUBLE ;
.token TOK_DBNE "dbne" TC_OPC_BRPC TC_CC_NE  TC_DOUBLE ;
.token TOK_DBLT "dblt" TC_OPC_BRPC TC_CC_LT  TC_DOUBLE ;
.token TOK_DBLE "dble" TC_OPC_BRPC TC_CC_LE  TC_DOUBLE ;
.token TOK_DBGT "dbgt" TC_OPC_BRPC TC_CC_GT  TC_DOUBLE ;
.token TOK_DBGE "dbge" TC_OPC_BRPC TC_CC_GE  TC_DOUBLE ;
.token TOK_DBNV "dbnv" TC_OPC_BRPC TC_CC_NV  TC_DOUBLE ;
.token TOK_DBV "dbv" TC_OPC_BRPC TC_CC_V  TC_DOUBLE ;
.token TOK_DBNUF "dbnuf" TC_OPC_BRPC TC_CC_NUF  TC_DOUBLE ;
.token TOK_DBUF "dbuf" TC_OPC_BRPC TC_CC_UF  TC_DOUBLE ;
.token TOK_DBNLV "dbnlv" TC_OPC_BRPC TC_CC_NLV  TC_DOUBLE ;
.token TOK_DBLV "dblv" TC_OPC_BRPC TC_CC_LV  TC_DOUBLE ;
.token TOK_DBNLUF "dbnluf" TC_OPC_BRPC TC_CC_NLUF  TC_DOUBLE ;
.token TOK_DBLUF "dbluf" TC_OPC_BRPC TC_CC_LUF  TC_DOUBLE ;
.token TOK_DBZUF "dbzuf" TC_OPC_BRPC TC_CC_ZUF  TC_DOUBLE ;

.token TOK_DBUD "dbud" TC_OPC_BRPC TC_CC_U  TC_DOUBLE ;
.token TOK_DBLOD "dblod" TC_OPC_BRPC TC_CC_LO  TC_DOUBLE ;
.token TOK_DBPCD "dblsd" TC_OPC_BRPC TC_CC_LS  TC_DOUBLE ;
.token TOK_DBHID "dbhid" TC_OPC_BRPC TC_CC_HI  TC_DOUBLE ;
.token TOK_DBHSD "dbhsd" TC_OPC_BRPC TC_CC_HS  TC_DOUBLE ;
.token TOK_DBEQD "dbeqd" TC_OPC_BRPC TC_CC_EQ  TC_DOUBLE ;
.token TOK_DBNED "dbned" TC_OPC_BRPC TC_CC_NE  TC_DOUBLE ;
.token TOK_DBLTD "dbltd" TC_OPC_BRPC TC_CC_LT  TC_DOUBLE ;
.token TOK_DBLED "dbled" TC_OPC_BRPC TC_CC_LE  TC_DOUBLE ;
.token TOK_DBGTD "dbgtd" TC_OPC_BRPC TC_CC_GT  TC_DOUBLE ;
.token TOK_DBGED "dbged" TC_OPC_BRPC TC_CC_GE  TC_DOUBLE ;
.token TOK_DBNVD "dbnvd" TC_OPC_BRPC TC_CC_NV  TC_DOUBLE ;
.token TOK_DBVD "dbvd" TC_OPC_BRPC TC_CC_V  TC_DOUBLE ;
.token TOK_DBNUFD "dbnufd" TC_OPC_BRPC TC_CC_NUF  TC_DOUBLE ;
.token TOK_DBUFD "dbufd" TC_OPC_BRPC TC_CC_UF  TC_DOUBLE ;
.token TOK_DBNLVD "dbnlvd" TC_OPC_BRPC TC_CC_NLV  TC_DOUBLE ;
.token TOK_DBLVD "dblvd" TC_OPC_BRPC TC_CC_LV  TC_DOUBLE ;
.token TOK_DBNLUFD "dbnlufd" TC_OPC_BRPC TC_CC_NLUF  TC_DOUBLE ;
.token TOK_DBLUFD "dblufd" TC_OPC_BRPC TC_CC_LUF  TC_DOUBLE ;
.token TOK_DBZUFD "dbzufd" TC_OPC_BRPC TC_CC_ZUF  TC_DOUBLE ;
  
.token TOK_RETIU "retiu" TC_OPC_RTPC TC_CC_U  TC_NONE ;
.token TOK_RETILO "retilo" TC_OPC_RTPC TC_CC_LO  TC_NONE ;
.token TOK_RETIPC "retils" TC_OPC_RTPC TC_CC_LS  TC_NONE ;
.token TOK_RETIHI "retihi" TC_OPC_RTPC TC_CC_HI  TC_NONE ;
.token TOK_RETIHS "retihs" TC_OPC_RTPC TC_CC_HS  TC_NONE ;
.token TOK_RETIEQ "retieq" TC_OPC_RTPC TC_CC_EQ  TC_NONE ;
.token TOK_RETINE "retine" TC_OPC_RTPC TC_CC_NE  TC_NONE ;
.token TOK_RETILT "retilt" TC_OPC_RTPC TC_CC_LT  TC_NONE ;
.token TOK_RETILE "retile" TC_OPC_RTPC TC_CC_LE  TC_NONE ;
.token TOK_RETIGT "retigt" TC_OPC_RTPC TC_CC_GT  TC_NONE ;
.token TOK_RETIGE "retige" TC_OPC_RTPC TC_CC_GE  TC_NONE ;
.token TOK_RETINV "retinv" TC_OPC_RTPC TC_CC_NV  TC_NONE ;
.token TOK_RETIV "retiv" TC_OPC_RTPC TC_CC_V  TC_NONE ;
.token TOK_RETINUF "retinuf" TC_OPC_RTPC TC_CC_NUF  TC_NONE ;
.token TOK_RETIUF "retiuf" TC_OPC_RTPC TC_CC_UF  TC_NONE ;
.token TOK_RETINLV "retinlv" TC_OPC_RTPC TC_CC_NLV  TC_NONE ;
.token TOK_RETILV "retilv" TC_OPC_RTPC TC_CC_LV  TC_NONE ;
.token TOK_RETINLUF "retinluf" TC_OPC_RTPC TC_CC_NLUF  TC_NONE ;
.token TOK_RETILUF "retiluf" TC_OPC_RTPC TC_CC_LUF  TC_NONE ;
.token TOK_RETIZUF "retizuf" TC_OPC_RTPC TC_CC_ZUF  TC_NONE ;

.token TOK_RETSU "retsu" TC_OPC_RTPC TC_CC_U  TC_NONE ;
.token TOK_RETSLO "retslo" TC_OPC_RTPC TC_CC_LO  TC_NONE ;
.token TOK_RETSPC "retsls" TC_OPC_RTPC TC_CC_LS  TC_NONE ;
.token TOK_RETSHI "retshi" TC_OPC_RTPC TC_CC_HI  TC_NONE ;
.token TOK_RETSHS "retshs" TC_OPC_RTPC TC_CC_HS  TC_NONE ;
.token TOK_RETSEQ "retseq" TC_OPC_RTPC TC_CC_EQ  TC_NONE ;
.token TOK_RETSNE "retsne" TC_OPC_RTPC TC_CC_NE  TC_NONE ;
.token TOK_RETSLT "retslt" TC_OPC_RTPC TC_CC_LT  TC_NONE ;
.token TOK_RETSLE "retsle" TC_OPC_RTPC TC_CC_LE  TC_NONE ;
.token TOK_RETSGT "retsgt" TC_OPC_RTPC TC_CC_GT  TC_NONE ;
.token TOK_RETSGE "retsge" TC_OPC_RTPC TC_CC_GE  TC_NONE ;
.token TOK_RETSNV "retsnv" TC_OPC_RTPC TC_CC_NV  TC_NONE ;
.token TOK_RETSV "retsv" TC_OPC_RTPC TC_CC_V  TC_NONE ;
.token TOK_RETSNUF "retsnuf" TC_OPC_RTPC TC_CC_NUF  TC_NONE ;
.token TOK_RETSUF "retsuf" TC_OPC_RTPC TC_CC_UF  TC_NONE ;
.token TOK_RETSNLV "retsnlv" TC_OPC_RTPC TC_CC_NLV  TC_NONE ;
.token TOK_RETSLV "retslv" TC_OPC_RTPC TC_CC_LV  TC_NONE ;
.token TOK_RETSNLUF "retsnluf" TC_OPC_RTPC TC_CC_NLUF  TC_NONE ;
.token TOK_RETSLUF "retsluf" TC_OPC_RTPC TC_CC_LUF  TC_NONE ;
.token TOK_RETSZUF "retszuf" TC_OPC_RTPC TC_CC_ZUF  TC_NONE ;

.token TOK_TRAPU "trapu" TC_OPC_RTPC TC_CC_U  TC_SGL ;
.token TOK_TRAPLO "traplo" TC_OPC_RTPC TC_CC_LO  TC_SGL ;
.token TOK_TRAPPC "trapls" TC_OPC_RTPC TC_CC_LS  TC_SGL ;
.token TOK_TRAPHI "traphi" TC_OPC_RTPC TC_CC_HI  TC_SGL ;
.token TOK_TRAPHS "traphs" TC_OPC_RTPC TC_CC_HS  TC_SGL ;
.token TOK_TRAPEQ "trapeq" TC_OPC_RTPC TC_CC_EQ  TC_SGL ;
.token TOK_TRAPNE "trapne" TC_OPC_RTPC TC_CC_NE  TC_SGL ;
.token TOK_TRAPLT "traplt" TC_OPC_RTPC TC_CC_LT  TC_SGL ;
.token TOK_TRAPLE "traple" TC_OPC_RTPC TC_CC_LE  TC_SGL ;
.token TOK_TRAPGT "trapgt" TC_OPC_RTPC TC_CC_GT  TC_SGL ;
.token TOK_TRAPGE "trapge" TC_OPC_RTPC TC_CC_GE  TC_SGL ;
.token TOK_TRAPNV "trapnv" TC_OPC_RTPC TC_CC_NV  TC_SGL ;
.token TOK_TRAPV "trapv" TC_OPC_RTPC TC_CC_V  TC_SGL ;
.token TOK_TRAPNUF "trapnuf" TC_OPC_RTPC TC_CC_NUF  TC_SGL ;
.token TOK_TRAPUF "trapuf" TC_OPC_RTPC TC_CC_UF  TC_SGL ;
.token TOK_TRAPNLV "trapnlv" TC_OPC_RTPC TC_CC_NLV  TC_SGL ;
.token TOK_TRAPLV "traplv" TC_OPC_RTPC TC_CC_LV  TC_SGL ;
.token TOK_TRAPNLUF "trapnluf" TC_OPC_RTPC TC_CC_NLUF  TC_SGL ;
.token TOK_TRAPLUF "trapluf" TC_OPC_RTPC TC_CC_LUF  TC_SGL ;
.token TOK_TRAPZUF "trapzuf" TC_OPC_RTPC TC_CC_ZUF  TC_SGL ;

.token TOK_BR "br" TC_SGL ;
.token TOK_BRD "brd" TC_SGL ;
.token TOK_CALL "call" TC_SGL ;
.token TOK_IACK "iack" TC_SGL TC_II;
.token TOK_IDLE "idle" TC_NONE ;
.token TOK_NOP "nop"   TC_NONE TC_SGL TC_II;
.token TOK_RPTB "rptb" TC_SGL TC_II;
.token TOK_RPTS "rpts" TC_SGL TC_II;
.token TOK_SWI "swi"   TC_NONE ;

/* interlocked opcodes */
.token TOK_LDFI "ldfi"  TC_FF TC_DOUBLE ;
.token TOK_LDII "ldii"  TC_II TC_DOUBLE ;
.token TOK_STFI "stfi"  TC_FF TC_DOUBLE ;
.token TOK_STII "stii"  TC_II TC_DOUBLE ;
.token TOK_SIGI "sigi"  ifelse( CPU, `C3X', `TC_NONE', `TC_DOUBLE TC_II') ;

/* delimenators and expression tokens */
.token TOK_DVB "||";
.token TOK_COMMA ",";
.token TOK_TILDE   "~";
.token TOK_MINUS   "-";
.token TOK_MMINUS  "--";
.token TOK_PPLUS   "++";
.token TOK_PLUS    "+";
.token TOK_LOG_NOT "!";
.token TOK_MULT    "*";
.token TOK_DIV     "/";
.token TOK_REM     "%";
.token TOK_ANDEXPR "&";
.token TOK_OREXPR  "|";
.token TOK_XOREXPR "^";
.token TOK_SHL     "<<";
.token TOK_SHR     ">>";
.token TOK_LPAREN  "(";
.token TOK_RPAREN  ")";
.token TOK_ATP 	   "@";

/* registers */
.token TOK_R0 "r0" TC_EXT_REG TC_REG;
.token TOK_R1 "r1"  TC_EXT_REG TC_REG;
.token TOK_R2 "r2"  TC_EXT_REG TC_REG;
.token TOK_R3 "r3"  TC_EXT_REG TC_REG;
.token TOK_R4 "r4"  TC_EXT_REG TC_REG;
.token TOK_R5 "r5"  TC_EXT_REG TC_REG;
.token TOK_R6 "r6"  TC_EXT_REG TC_REG;
.token TOK_R7 "r7"  TC_EXT_REG TC_REG;

ifelse( CPU, `C3X', 
`/* c3x supports alternate register syntax */
.token TOK_R8 "r8"  TC_REG;
.token TOK_R9 "r9"  TC_REG;
.token TOK_R10 "r10"  TC_REG;
.token TOK_R11 "r11"  TC_REG;
.token TOK_R12 "r12"  TC_REG;
.token TOK_R13 "r13"  TC_REG;
.token TOK_R14 "r14"  TC_REG;
.token TOK_R15 "r15"  TC_REG;
.token TOK_R16 "r16" TC_REG;
.token TOK_R17 "r17" TC_REG;
.token TOK_R18 "r18" TC_REG;
.token TOK_R19 "r19" TC_REG;
.token TOK_R20 "r20" TC_REG;
.token TOK_R21 "r21" TC_REG;
.token TOK_R22 "r22" TC_REG;
.token TOK_R23 "r23" TC_REG;
.token TOK_R24 "r24" TC_REG;
.token TOK_R25 "r25" TC_REG;
.token TOK_R26 "r26" TC_REG;
.token TOK_R27 "r27" TC_REG;
', `/* c4x has more extended precision registers */
.token TOK_R8 "r8" TC_EXT_REG TC_REG;
.token TOK_R9 "r9" TC_EXT_REG TC_REG;
.token TOK_R10 "r10" TC_EXT_REG TC_REG;
.token TOK_R11 "r11" TC_EXT_REG TC_REG;
')
.token TOK_AR0 "ar0"  TC_REG;
.token TOK_AR1 "ar1"  TC_REG;
.token TOK_AR2 "ar2"  TC_REG;
.token TOK_AR3 "ar3"  TC_REG;
.token TOK_AR4 "ar4"  TC_REG;
.token TOK_AR5 "ar5"  TC_REG;
.token TOK_AR6 "ar6"  TC_REG;
.token TOK_AR7 "ar7"  TC_REG;

.token TOK_DP "dp" TC_REG;
.token TOK_IR0 "ir0" TC_REG;
.token TOK_IR1 "ir1" TC_REG;
.token TOK_BK "bk" TC_REG;
.token TOK_SP "sp" TC_REG;

.token TOK_ST "st" TC_REG;
.token TOK_IE "ie" TC_REG;
.token TOK_IF "if" TC_REG;
.token TOK_IOF "iof" TC_REG;

.token TOK_RS "rs" TC_REG;
.token TOK_RE "re" TC_REG;
.token TOK_RC "rc" TC_REG;
.token TOK_B "b";		/* for bit reversed indirect addressing mode */

/* 
 * field definitions
 */

.field
DISP [.unsigned 8] {
	.constant;
}
.location DISP 0;

.field
WORD [16] {
	.constant;
}
.location WORD 0;

.field
WORD32 [32] {
	.constant;
}
.location WORD32 0;

.field
ADDR [24] {
	.constant;
}
.location ADDR 0;

.field
ZREG [5] {
	.mnemonics {
		r0			= 0;
		r1			= 1;
		r2			= 2;
		r3			= 3;
		r4			= 4;
		r5			= 5;
		r6			= 6;
		r7			= 7;

ifelse( CPU, `C3X', `', `
		r8			= 28;
		r9			= 29;
		r10			= 30;
		r11			= 31;
' )

		ar0			= 8;
		ar1			= 9;
		ar2			= 10;
		ar3			= 11;
		ar4			= 12;
		ar5			= 13;
		ar6			= 14;
		ar7			= 15;

		dp			= 16;
		ir0			= 17;
		ir1			= 18;
		bk			= 19;
		sp			= 20;

		st			= 21;
		ie			= 22;
		if			= 23;
		iof			= 24;

		rs			= 25;
		re			= 26;
		rc			= 27;
	}
}
.location ZREG 0;

/* src general addressing mode */
.field
MODE [2] {
	.mnemonics {
		reg			= 0;
		dir			= 1;
		ind			= 2;
		imm			= 3;

		reg_reg		= 0;
		ind_reg		= 1;
		reg_ind		= 2;
		ind_ind		= 3;
	}
}
.location MODE 21;

.field
DST [5] {
	.same_as ZREG;
}
.location DST 16;

.field
SRC [5] {
	.same_as ZREG;
}
.location SRC 0;

.field
SRC1 [5] {
	.same_as ZREG;
}
.location SRC1 8;

.field
SRC2 [5] {
	.same_as ZREG;
}
.location SRC2 0;

.field
ZMODN [5] {
	.mnemonics {
		disp_offset_add			= 000;
		disp_offset_sub			= 001;
		disp_pre_add			= 002;
		disp_pre_sub			= 003;
		disp_post_add			= 004;
		disp_post_sub			= 005;
		disp_circular_add		= 006;
		disp_circular_sub		= 007;

		ir0_offset_add			= 010;
		ir0_offset_sub			= 011;
		ir0_pre_add				= 012;
		ir0_pre_sub				= 013;
		ir0_post_add			= 014;
		ir0_post_sub			= 015;
		ir0_circular_add		= 016;
		ir0_circular_sub		= 017;

		ir1_offset_add			= 020;
		ir1_offset_sub			= 021;
		ir1_pre_add				= 022;
		ir1_pre_sub				= 023;
		ir1_post_add			= 024;
		ir1_post_sub			= 025;
		ir1_circular_add		= 026;
		ir1_circular_sub		= 027;

		special_offset_zero		= 030;
		special_bit_reverse		= 031;
	}
}
.location ZMODN 0;

.field
MODN1 [5] {
	.same_as ZMODN;
}
.location MODN1 11;

.field
MODN2 [5] {
	.same_as ZMODN;
}
.location MODN2 3;

.field
AR1 [3] {
	.constant;
}
.location AR1 8;

.field
AR2 [3] {
	.constant;
}
.location AR2 0;

.field
ARN [3] {
	.constant;
}
.location ARN 22;

.field
ZCOND [5] {
	.mnemonics {
		u			= 0;
		lo			= 1;
		ls			= 2;
		hi			= 3;
		hs			= 4;
		eq			= 5;
		ne			= 6;
		lt			= 7;
		le			= 8;
		gt			= 9;
		ge			= 10;

		nv			= 12;
		v			= 13;
		nuf			= 14;
		uf			= 15;
		nlv			= 16;
		lv			= 17;
		nluf		= 18;
		luf			= 19;
		zuf			= 20;
	}
}
.location ZCOND 0;

.field
COND [5] {
	.same_as ZCOND;
}
.location COND 16;

.field
B [1] {
	.constant;
}
.location B 25;

.field
BRANCH [6, 1] {
	.mnemonics {
		bra_cond		= 032, 0;
		bra_cond_delay	= 032, 1;
		db_cond			= 033, 0;
		db_cond_delay	= 033, 1;
		call_cond		= 034, 0;
ifelse( CPU, `C3X', `', `
		laj_cond		= 034, 1;
		bra_af			= 032, 1;
		bra_at			= 032, 1;')
	}
}
.location BRANCH 26, 21;

.field
OPCODE0 [9, 23] {
	.mnemonics {
		idle			= 0014, 0;
		sigi			= 0054, 0;
		swi				= 0314, 0;
		no_op			= 0031, 0;
	}
}
.location OPCODE0 23, 0;

.field
OPCODE21 [11] {
	.mnemonics {
		pop				= 0x071;
		popf			= 0x075;
		push			= 0x079;
		pushf			= 0x07d;
ifelse( CPU, `C3X', `', `
		ldpk			= 0x0fb;
		lat				= 0x3a4;
		reti_cond_delay = 0x3c1;')
		reti			= 0x3c0;
		rets			= 0x3c4;
		trap			= 0x3a0;
	}
}
.location OPCODE21 21;

.field
OPCODE24 [8] {
	.mnemonics {
		bra				= 0x60;
		bra_delay		= 0x61;
		call			= 0x62;
		rptb			= 0x64;
ifelse( CPU, `C3X', `', `
		rptbd_i			= 0x65;
		laj				= 0x63;')
	}
}
.location OPCODE24 24;

.field
GENERAL [9] {
	.mnemonics {
		absf			= 0000;
		absi			= 0001;
		addc			= 0002;
		addc3			= 0100;
		addf			= 0003;
		addf3			= 0101;
		addi			= 0004;
		addi3			= 0102;
		and				= 0005;
		and3			= 0103;
		andn			= 0006;
		andn3			= 0104;
		ash				= 0007;
		ash3			= 0105;
		cmpf			= 0010;
		cmpf3			= 0106;
		cmpi			= 0011;
		cmpi3			= 0107;
		fix				= 0012;
		float			= 0013;
		iack			= 0066;
		lde				= 0015;
		ldf				= 0016;

		ldfu			= 0200;
		ldflo			= 0201;
		ldfls			= 0202;
		ldfhi			= 0203;
		ldfhs			= 0204;
		ldfeq			= 0205;
		ldfne			= 0206;
		ldflt			= 0207;
		ldfle			= 0210;
		ldfgt			= 0211;
		ldfge			= 0212;

		ldfnv			= 0214;
		ldfv			= 0215;
		ldfnuf			= 0216;
		ldfuf			= 0217;
		ldfnlv			= 0220;
		ldflv			= 0221;
		ldfnluf			= 0222;
		ldfluf			= 0223;
		ldfzuf			= 0224;

		ldfi			= 0017;
		ldi				= 0020;
		
ifelse( CPU, `C3X', `', `
		ldhi			= 0077;
		rptbd_r			= 0363;
		stik 			= 0052;
		toieee			= 0067;
		frieee			= 0070;
		rcpf 			= 0072;
		rsqrf			= 0071;
		lb0			= 0540;
		lb1 			= 0541;
		lb2 			= 0542;
		lb3 			= 0543;
		lbu0			= 0544;
		lbu1			= 0545;
		lbu2			= 0546;
		lbu3			= 0547;
		lh0				= 0564;
		lh1				= 0565;
		lhu0			= 0566;
		lhu1			= 0567;
		lwl0			= 0550;
		lwl1			= 0551;
		lwl2			= 0552;
		lwl3			= 0553;
		lwr0			= 0554;
		lwr1			= 0555;
		lwr2			= 0556;
		lwr3			= 0557;
		mb0				= 0560;
		mb1				= 0561;
		mb2				= 0562;
		mb3				= 0563;
		mh0				= 0570;
		mh1				= 0571;
		lda				= 0075;
		mpyshi3			= 0121;
		mypuhi3			= 0122;
' )

		ldiu			= 0240;
		ldilo			= 0241;
		ldils			= 0242;
		ldihi			= 0243;
		ldihs			= 0244;
		ldieq			= 0245;
		ldine			= 0246;
		ldilt			= 0247;
		ldile			= 0250;
		ldigt			= 0251;
		ldige			= 0252;

		ldinv			= 0254;
		ldiv			= 0255;
		ldinuf			= 0256;
		ldiuf			= 0257;
		ldinlv			= 0260;
		ldilv			= 0261;
		ldinluf			= 0262;
		ldiluf			= 0263;
		ldizuf			= 0264;

		ldii			= 0021;
		ldm				= 0022;
		ldp				= 0020;
		lsh				= 0023;
		lsh3			= 0110;
		mpyf			= 0024;
		mpyf3			= 0111;
		mpyi			= 0025;
		mpyi3			= 0112;
		negb			= 0026;
		negf			= 0027;
		negi			= 0030;
		nop				= 0031;
		norm			= 0032;
		not				= 0033;
		or				= 0040;
		or3				= 0113;
		rnd				= 0042;
		rol				= 0043;
		rolc			= 0044;
		ror				= 0045;
		rorc			= 0046;
		rpts			= 0047;
		stf				= 0050;
		stfi			= 0051;
		sti				= 0052;
		stii			= 0053;
		subb			= 0055;
		subb3			= 0114;
		subc			= 0056;
		subf			= 0057;
		subf3			= 0115;
		subi			= 0060;
		subi3			= 0116;
		subrb			= 0061;
		subrf			= 0062;
		subri			= 0063;
		tstb			= 0064;
		tstb3			= 0117;
		xor				= 0065;
		xor3			= 0120;
	}
}
.location GENERAL 23;

/* Globals */
.numvar error_detected = 0;
/* first source operand */
.strvar disp = 0;		/* displacement used in indirect addressing mode */
.strvar mode = "";		/* source addressing mode, ind, imm, dir, reg */
.strvar mode_ind = "";	/* Indirect addressing modes */
/* second source operand */
.strvar disp1 = 0;
.strvar mode1 = "";
.strvar mode_ind1 = "";

/* 
 * utility functions
 */

/* utility function parsing an expected token */
.func
expect( tok )
{
	.numvar token;
	token = .get_tok();
	.if( token != tok ) {
		.error( "expected '", .tok_name(tok), "', got '", .tok_val(), "'");
		.unget_tok();
		error_detected = 1;
	}
}

/* utility function expected an aux. reg. */
.func
expect_aux()
{
	.numvar tok;
	tok = .get_tok();
	.if( 
ifelse( CPU, `C3X', `tok != TOK_R8 && tok != TOK_R9 && tok != TOK_R10 &&
	tok != TOK_R11 && tok != TOK_R12 && tok != TOK_R13 && tok != TOK_R14 &&
	tok != TOK_R15 &&', `' )
	tok != TOK_AR0 && tok != TOK_AR1 && tok != TOK_AR2 && tok != TOK_AR3 &&
	tok != TOK_AR4 && tok != TOK_AR5 && tok != TOK_AR6 && tok != TOK_AR7 ) {
		.error("expected auxiliary register, got '", .tok_val(), "'");
		.unget_tok();
		error_detected = 1;
		.done;
	}
	.else 
		.done ifelse( CPU, `C3X', `trans_reg(tok)', `.tok_val()');
}

ifelse( CPU, `C3X', `', `
/* utility function expecting a expansion register */
.func
expect_expreg()
{
	.numvar tok;
	tok = .get_tok();
	.if( tok != TOK_IVTP && tok != TOK_TVTP ) {
		.error("expected IVTP or TVTP\n");
		.unget_tok();
		error_detected = 1;
		.done;
	}
	.else
		.done .tok_val();
}

/* return 1 if the string represents a extended precision register */
.func
is_ext_reg(s)
{
	.if( s !: "r0" && s !: "r1" && s !: "r2" && s !: "r2" && s !: "r3" &&
		s !: "r4" && s !: "r5" && s !: "r6" && s !: "r7" && s !: "r8" && 
		s !: "r9" && s !: "r10" && s !: "r11" )
		.done 0;
	.else
		.done 1;
}')

/* return condition code, input is opcode token */
.func
get_cond( tok )
{
	.if( .tok_class( tok ) & TC_CC_U )
		.done u;
	.elif( .tok_class( tok ) & TC_CC_LO )
		.done lo;
	.elif( .tok_class( tok ) & TC_CC_LS )
		.done ls;
	.elif( .tok_class( tok ) & TC_CC_HI )
		.done hi;
	.elif( .tok_class( tok ) & TC_CC_HS )
		.done hs;
	.elif( .tok_class( tok ) & TC_CC_EQ )
		.done eq;
	.elif( .tok_class( tok ) & TC_CC_NE )
		.done ne;
	.elif( .tok_class( tok ) & TC_CC_LT )
		.done lt;
	.elif( .tok_class( tok ) & TC_CC_LE )
		.done le;
	.elif( .tok_class( tok ) & TC_CC_GT )
		.done gt;
	.elif( .tok_class( tok ) & TC_CC_GE )
		.done ge;
	.elif( .tok_class( tok ) & TC_CC_NV )
		.done nv;
	.elif( .tok_class( tok ) & TC_CC_V )
		.done v;
	.elif( .tok_class( tok ) & TC_CC_NUF )
		.done nuf;
	.elif( .tok_class( tok ) & TC_CC_UF )
		.done uf;
	.elif( .tok_class( tok ) & TC_CC_NLV )
		.done nlv;
	.elif( .tok_class( tok ) & TC_CC_LV )
		.done lv;
	.elif( .tok_class( tok ) & TC_CC_NLUF )
		.done nluf;
	.elif( .tok_class( tok ) & TC_CC_LUF )
		.done luf;
	.elif( .tok_class( tok ) & TC_CC_ZUF )
		.done zuf;
}

/* check if the register is extended precision register for float operations */
.func
chk_reg(tok, src, f) {
	.if( src && (f&1) && !(.tok_class(tok) & TC_EXT_REG) )
		.error( "Invalid floating point source register.\n");
	.elif( !src && (f&2) && !(.tok_class(tok) & TC_EXT_REG) )
		.error("Invalid floating point destination register.\n");
}

/* check and store type of addressing modes */
.func
get_modn(state, state1, ch) {
	.strvar modn1, modn2, modn3;
	.select( state ) {
	.case 0:
	.case 2:
	.case 4:
		modn3 = "_add";
		.break;
	.case 1:
	.case 3:
	.case 5:
		modn3 = "_sub";
		.break;
	}
	.select( state1 ) {
	.case 0:
	.case 1:
	.case 2:
		.select( state ) {
		.case 0: 
		.case 1:
			modn2 = "_post";
			.break;
		.case 2:
		.case 3:
			modn2 = "_offset";
			.break;
		.case 4:
		.case 5:
			modn2 = "_pre";
			.break;
		}
		.select( state1 ) {
		.case 0:
			modn1 = "disp";
			.break;
		.case 1:
			modn1 = "ir0";
			.break;
		.case 2:
			modn1 = "ir1";
			.break;
		}
		.break;
	.case 3:
	.case 4:
	.case 5:
		modn2 = "_circular";
		.select( state1 ) {
		.case 3:
			modn1 = "disp";
			.break;
		.case 4:
			modn1 = "ir0";
			.break;
		.case 5:
			modn1 = "ir1";
			.break;
		}
		.break;
	}

	.if( ch == 1 )
		mode_ind = .concat( modn1, .concat( modn2, modn3 ) );
	.else
		mode_ind1 = .concat( modn1, .concat( modn2, modn3 ) );
}

/* identify "ar" and return the index of ar register */
.func
get_ar(ea) {
	.numvar finish;

	finish = .search(ea, "ar"); 
	.if (finish < 0)
		.done 0;

	.done .substr(ea, finish, finish);
}

/* check the expression of ar and read coresponding resources */
.func
chk_ar(ea) {
	.strvar r;

	r = get_ar(ea);
	.if ( ( r >= 0 ) && ( r <= 7 ) ) 
		.reads REGISTER[ r + 8 ];
	.else 
		.error( "indirect not through an address register: ", ea );
}

/* writes to different resources according to opcode and dest. operand */
.func
write_res(code, d) {
	.select(code) {
	.case "stf": .case "stfi": .case "sti": .case "stii":
		.writes MEMORY; .break;
	.case "nop": .case "iack": 
		.break;
	.default:
		.writes REGISTER[ .value( d ) ];
		.break;
	}
	.writes CC;
	.if( code :: "rpts" )
		.reads JUMP;
}

/* return pattern field of conditional branch operation */
/* return values: bra_cond; bra_cond_delay; db_cond; db_cond_delay */
.func
get_br(code) {
	.if( .search(code, "^b") > 0 && .search(code, "d$") < 0 )
		.done bra_cond;
	.elif( .search(code, "^b") > 0 && .search(code, "d$") > 0 ) 
		.done bra_cond_delay;
	.elif( .search(code, "^db") > 1 && .search(code, "d$") < 0 )
		.done db_cond;
	.elif( .search(code, "^db") > 1 && .search(code, "d$") > 0 )
		.done db_cond_delay;
ifelse( CPU, `C3X', `', `
	.elif( .search(code, "^b") > 0 && .search(code, "af$") > 0 )
		.done bra_af;
	.elif( .search(code, "^b") > 0 && .search(code, "at$") > 0 )
		.done bra_at;
	.elif( .search(code, "^laj") > 2 )
		.done laj_cond;')
	.else
		.done call_cond;
}

/* return pattern field of conditional return, trap operations */
.func
get_rt(code) {
	.if( .search(code, "^reti") > 3 && .search(code, "d$") < 0 )
		.done reti;
	.elif( .search(code, "^rets") > 3 )
		.done rets;
ifelse( CPU, `C3X', `', `
	.elif( .search(code, "^lat") > 2 )
		.done lat;
	.elif( .search(code, "^reti") > 3 && .search(code, "d$") > 0 )
		.done reti_cond_delay;')
	.else
		.done trap;
}

 
 * main internal parsing function 
 */

.intern
user_parsing() 
{
	.strvar s, d, g, s1, code, addr, cond, ar;
	.numvar f, optok, nxt_tok;

	/* get the opcode token */
	optok = .get_tok();
	code = .tok_val();

	/* determine the float compatible variable f for src and dst,
	 * f = 0 : both integer; f = 1 : src float, dest. int.; 
	 * f = 2 : src int., dest. float; f = 3 : both float. 
	 * f = 7 : src1, src2, dest all float; f = -1 : other. */
	.if( .tok_class( optok ) & TC_II ) 
		f = 0;
	.elif( optok == TOK_FIX )
		f = 1;
	.elif( optok == TOK_FLOAT )
		f = 2;
	.elif( .tok_class( optok ) & TC_FF )
		f = 3;
	.elif( .tok_class( optok ) & TC_FFF )
		f = 7;
	.else 
		f = -1;

	/* parse instrunction with opcode and no operands */
	.if( .tok_class( optok ) & TC_NONE ) {
		/* nop opcode may or may not have a source operand */
		.if( optok == TOK_NOP ) {
			nxt_tok = .get_tok();
			.if( nxt_tok == TOK_EOL ) {
				.unget_tok();
				opcode0( code );
			}
			.else {
				.unget_tok();
				s = scan_src_operand(f);
				general( nop, s, 0, f );
			}
		}
		/* conditional return instructions */
		.elif( .tok_class( optok ) & TC_OPC_RTPC ) {
			code = get_rt( code );
			cond = get_cond( optok );
			ret_trap( code, cond, 0 );
		}
		.else
			opcode0( code );
	}

	/* parse instructions with single operand */
	.elif( .tok_class( optok ) & TC_SGL ) {
		/* ldp instruction can have 1 or 2 operands */ 
		.if( optok == TOK_LDP ) {
			s = scan_src_operand(f);
			nxt_tok = .get_tok();
			.if( nxt_tok != TOK_COMMA ) {
				.unget_tok();
				do_ldp(s);
			}
			.else {
				expect(TOK_DP);
				do_ldp(s);
			}
		}
ifelse( CPU, `C3X', `', `
		.elif( optok == TOK_LDPK ) {
			s = parse_expr();
			.if( .numeric(s) && (s < 0 || s > 65535) ) {
				.error("Expected unsigned 16-bit immediate\n");
				error_detected = 1;
				s = 0;
			}
			emit_ldpk(s);
		}
		.elif( optok == TOK_RPTBD ) {
			nxt_tok = .get_tok();
			.if( .tok_class(nxt_tok) & TC_REG ) 
				emit_rptbd_reg(.tok_val());
			.else {
				.unget_tok();
				s = parse_expr();
				.if( .numeric(s) && (s<-8388608 || s>8388607) ) {
					.error("Expected signed 24-bit immediate\n");
					error_detected = 1;
					s = 0;
				}
				code = rptbd_i;
				jump(code, s);
			}
		}')
		/* stack operations go here */
		.elif( optok == TOK_POP || optok == TOK_POPF || optok == TOK_PUSH ||
			optok == TOK_PUSHF ) {
			nxt_tok = .get_tok();
			.if( (f != 0) && !(.tok_class(nxt_tok) & TC_EXT_REG ) ) {
				.error("Expect src r0..7, got '", .tok_val(), "'");
				.unget_tok();
				error_detected = 1;
			}
			.elif( (f == 0) && !(.tok_class(nxt_tok) & TC_REG ) ) {
				.error("Expect src r0..27, got '", .tok_val(), "'");
				.unget_tok();
				error_detected = 1;
			}
			.elif( .tok_class(nxt_tok) & TC_REG ) {
				s = ifelse( CPU, `C3X', `trans_reg(nxt_tok)', `.tok_val()');
				do_stack(code, s);
			}
			.else {
				.error("Expected src to be registers, got '", .tok_val(), "'");
				.unget_tok();
				error_detected = 1;
			}
		}
		/* instructions with opcode rol, rolc, ror, rorc go here */
		.elif( optok == TOK_ROL || optok == TOK_ROLC || optok == TOK_ROR ||
			optok == TOK_RORC ) {
			d = scan_dst_operand(f);
			.if( optok == TOK_ROL || optok == TOK_ROLC )
				s = 0;
			.else
				s = -1;
			mode = "imm";
			general( code, s, d, f );
		}
		/* unconditional branch instructions */
		.elif( optok == TOK_BR || optok == TOK_BRD || optok == TOK_CALL 
		ifelse( CPU, `C3X', `', ` || optok == TOK_LAJ ') ) {
			nxt_tok = .get_tok();
			.if( nxt_tok == TOK_ATP ) 
			  addr = parse_expr();
			.else {
				.unget_tok();
				addr = parse_expr();
			}
			.if( optok == TOK_BR )
				code = bra;
			.elif( optok == TOK_BRD )
				code = bra_delay;
ifelse(CPU, `C3X', `', `
			.elif( optok == TOK_LAJ )
				code = laj;')
			.else
				code = call;
			do_jump( code, addr );
		}
		/* special program control instructions: iack, rptb, rpts */
		.elif( optok == TOK_RPTS || optok == TOK_RPTB || optok == TOK_IACK ) {
			s = scan_src_operand(f);
			.if( optok == TOK_RPTS ) {
				d = rc;
				general(code, s, d, f);
			}
			.elif( optok == TOK_RPTB ) {
				jump( code, s );
			}
			.else {
				d = 0;
				general(code, s, d, f);
			}
		}
		/* conditional branch instruction */
		.elif( .tok_class( optok ) & TC_OPC_BRPC ) {
			code = get_br( code );		/* return pattern of cond. branch */
			cond = get_cond( optok );  	/* get condition code */
ifelse( CPU, `C3X', `
			ar = 0;', `
			.if( code :: "bra_af" )
				ar = ar2;
			.elif( code :: "bra_at" )
				ar = ar1;
			.else
				ar = 0;')
			d = parse_branch_dst();
			do_branch( code, cond, ar, d );
		}
		/* conditional return, trap instructions */
		.elif( .tok_class( optok ) & TC_OPC_RTPC ) {
			d = parse_expr();
			.if( .numeric(d) && 
				( d < 0 || d > ifelse( CPU, `C3X', `31', `511' ) ) ) {
				error_detected = 1;
				d = 0;
				.error( "trap vector out of range." );
			}
			code = get_rt( code );
			cond = get_cond( optok );
			ret_trap( code, cond, d );
		}
		.else {
			error_detected = 1;
			.error( "This should never happen.\n");
			.unget_tok();
		}
	}

	/* parse instructions with double operand */
	.elif( .tok_class( optok ) & TC_DOUBLE ) {
		.if( .tok_class( optok ) & TC_OPC_BRPC ) {
			s = expect_aux();
			expect(TOK_COMMA);
			d = parse_branch_dst();
			code = get_br( code );
			cond = get_cond( optok );
			do_branch( code, cond, s, d );
		}
		.elif( optok == TOK_STI || optok == TOK_STII || 
			optok == TOK_STF || optok == TOK_STFI ) {
			s = scan_dst_operand(f);
			expect(TOK_COMMA);
			d = scan_src_operand(f);
			general(code, d, s, f);
		}
ifelse( CPU, `C3X', `', `
		.elif( optok == TOK_LDEP || optok == TOK_LDPE ) {
			.if( optok == TOK_LDEP ) {
				s = expect_expreg();
				expect(TOK_COMMA);
				d = scan_dst_operand(f);
				emit_exp(code, s, d);
			}
			.else {
				s = scan_src_operand(f);
				expect(TOK_COMMA);
				d = expect_expreg();
				emit_exp(code, s, d);
			}
		}
		.elif( optok == TOK_STIK || optok == TOK_LDHI ) {
			s = parse_expr();
			.if( optok == TOK_STIK && .numeric(s) && (s<-16 || s>15) ) {
				.error("Expected 5-bit signed integer.\n");
				error_detected = 1;
				s = 0;
			}
			.elif( optok == TOK_LDHI && .numeric(s) && (s<0 || s>65535)) {
				.error("Expected 16-bit unsigned integer.\n");
				error_detected = 1;
				s = 0;
			}
			expect(TOK_COMMA);
			mode = imm;
			d = scan_dst_operand(f);
			general(code, s, d, f);
		}')
		.else {
			s = scan_src_operand(f);
			expect(TOK_COMMA);
			d = scan_dst_operand(f);
			general(code, s, d, f);
		}
	}

	/* instructions with tripple operands */
	.elif( .tok_class( optok ) & TC_TRIPPLE ) {
		s = scan_src1_operand(f);
		expect(TOK_COMMA);		/* consume the "," */
		s1 = scan_src_operand(f);
		/* instructions with 2 operands but specified in 3-operand format */
		.if( optok == TOK_CMPF3 || optok == TOK_CMPI3 || optok == TOK_TSTB3 )
			d = 0;
		.else {
			expect(TOK_COMMA);		/* consume the "," */
			d = scan_dst_operand(f);
		}
		three( code, s1, s, d);
	}

	.else {
		.unget_tok();
		error_detected = 1;
		.error( "Invalid opcode: `", code, "'" );
	}

	/* reset global variables */
	disp = 0;
	disp1 = 0;
	mode = "";
	mode1 = "";
	mode_ind = "";
	mode_ind1 = "";
	nxt_tok = .get_tok();
	.if( nxt_tok != TOK_EOL && error_detected == 0 ) {
		.error("Extra character, '", .tok_val(), "'");
		.unget_tok();
	}
}

ifelse( CPU, `C3X', `
/* transfer alternate form of reg. to the primary form */
/* only c3x support the alternate register syntax */
.func
trans_reg(tok) {
	.strvar orig;
	orig = .tok_val();
	.if( tok == TOK_R8 ) 
		.done ar0;
	.elif( tok == TOK_R9 )
		.done ar1;
	.elif( tok == TOK_R10 )
		.done ar2;
	.elif( tok == TOK_R11 )
		.done ar3;
	.elif( tok == TOK_R12 )
		.done ar4;
	.elif( tok == TOK_R13 )
		.done ar5;
	.elif( tok == TOK_R14 )
		.done ar6;
	.elif( tok == TOK_R15 )
		.done ar7;
	.elif( tok == TOK_R16 )
		.done dp;
	.elif( tok == TOK_R17 )
		.done ir0;
	.elif( tok == TOK_R18 )
		.done ir1;
	.elif( tok == TOK_R19 )
		.done bk;
	.elif( tok == TOK_R20 )
		.done sp;
	.elif( tok == TOK_R21 )
		.done st;
	.elif( tok == TOK_R22 )
		.done ie;
	.elif( tok == TOK_R23 )
		.done if;
	.elif( tok == TOK_R24 )
		.done iof;
	.elif( tok == TOK_R25 )
		.done rs;
	.elif( tok == TOK_R26 )
		.done re;
	.elif( tok == TOK_R27 )
		.done rc;
	/* the rest of registers don't need transfer */
	.else 
		.done orig;
}
, `')

/* parse branch destination */
.func
parse_branch_dst()
{
	.numvar tok;
	.strvar val;
	tok = .get_tok();
	.if( tok == TOK_ATP ) {
		val = parse_expr();
		mode = "dir";
		.done val;
	}
	.elif( .tok_class( tok ) & TC_REG ) {
		mode = "reg";
		.done ifelse( CPU, `C3X', `trans_reg(tok)', `.tok_val()');
	}
	.else {
		.unget_tok();
		val = parse_expr();
		mode = "imm";
		.done val;
	}
}

/* scan source operands with indirect addressing modes */
.func
scan_mod_ind(ch) {

  /* state: ar++, 0; ar--, 1; +ar, 2; -ar, 3; ++ar, 4; --ar, 5; */
  /* state1: disp, 0; ir0, 1; ir1, 2; disp%, 3; ir0%, 4; ir1%, 5; */
  /* the 2 variables are used to determine addressing mode after parsing */
  .numvar tok, state, state1;
  .strvar val;

  /* first stage of parsing */
  tok = .get_tok();

  .if( 
ifelse( CPU, `C3X', `tok == TOK_R8 || tok == TOK_R9 || tok == TOK_R10 ||
	tok == TOK_R11 || tok == TOK_R12 || tok == TOK_R13 || tok == TOK_R14 ||
	tok == TOK_R15 ||', `' )
	tok == TOK_AR0 || tok == TOK_AR1 || tok == TOK_AR2 || tok == TOK_AR3 ||
	tok == TOK_AR4 || tok == TOK_AR5 || tok == TOK_AR6 || tok == TOK_AR7 ) {
	val = ifelse( CPU, `C3X', `trans_reg(tok)', `.tok_val()');
	tok = .get_tok();
	.if( tok == TOK_PPLUS ) 
		state = 0;
	.elif( tok == TOK_MMINUS ) 
		state = 1;
	.else {
		.unget_tok();
		state = -1;
		.if( ch == 1 )
			mode_ind = "special_offset_zero";
		.else
			mode_ind1 = "special_offset_zero";
		.done val;
	}
  }
  .elif( tok == TOK_PLUS || tok == TOK_MINUS || tok == TOK_PPLUS || 
			tok == TOK_MMINUS ) {
	val = expect_aux();
	.if( tok == TOK_PLUS )
		state = 2;
	.elif( tok == TOK_MINUS )
		state = 3;
	.elif( tok == TOK_PPLUS )
		state = 4;
	.else
		state = 5;
  }
  .else {
	.unget_tok();
	error_detected = 1;
	.error("Syntax error with indirect addressing mode.\n");
	.done;
  }
  /* second stage of parsing */
  tok = .get_tok();
  /* (disp) or (ir0) or (ir1) ? */
  .if( tok == TOK_LPAREN ) {
	tok = .get_tok();
	.if( 
ifelse( CPU, `C3X', `tok == TOK_R17 ||', `' ) tok == TOK_IR0 ) 
		state1 = 1;
	.elif( 
ifelse( CPU, `C3X', `tok == TOK_R18 ||', `' ) tok == TOK_IR1 )
		state1 = 2;
	.else {
		.unget_tok();
		.if( ch == 1 )
			disp = parse_expr();
		.else
			disp1 = parse_expr();
		state1 = 0;
	}
	expect(TOK_RPAREN);
	tok = .get_tok();
	/* circular ? */
	.if( tok == TOK_REM ) {
		.if( state == 0 || state == 1 ) {
			.if( state1 == 1 )
				state1 = 4;
			.elif( state1 == 2 )
				state1 = 5;
			.else
				state1 = 3;
		}
		.else {
			.unget_tok();
			error_detected = 1;
			.error("Circular addressing not allowed.\n");
			.done;
		}
	}
	/* bit-reversed ? */
	.elif( tok == TOK_B && state1 == 1 && state == 0 ) {
		.if( ch == 1 )
			mode_ind = "special_bit_reverse";
		.else
			mode_ind1 = "special_bit_reverse";
		.done val;
	}
	.else 
		.unget_tok();
	get_modn(state, state1, ch);
	.done val;
  }
  .else {
	.unget_tok();
	.if( ch == 1 )
		mode_ind = "special_offset_zero";
	.else
		mode_ind1 = "special_offset_zero";
	.done val;
  }
}


/* scan operand, set source addressing mode, set displacement and indirect 
   addressing type if necessary, return register name if reg. mode, return 
   value of expression if imm. mode, return ar register if ind. mode, return
   address if dir. mode. */
.func
scan_opnd(ch, f) {
	.numvar tok, tok1, tok2;
	.strvar val, val1, val2;

	tok = .get_tok();
	val = .tok_val();
	/* first source operand */
	.if( ch == 1 ) {
		.if( tok == TOK_ATP ) {
			val = parse_expr();
			mode = "dir";
		}
		.elif( tok == TOK_MULT ) {
			mode = "ind";
			val = scan_mod_ind(ch);
		}
		.elif( .tok_class(tok) & TC_REG ) {
			mode = "reg";
			chk_reg(tok, 1, f);
			val = ifelse( CPU, `C3X', `trans_reg(tok)', `val');
		}
		.else {
			.unget_tok();
			mode = "imm";
			.if( (f&1) ) 
				val = .get_delim_tok( ",;\n" );
			.else
				val = parse_expr();
		}
		.done val;
	}
	/* second source operand */
	.if( ch == 2 ) {
		.if( tok == TOK_ATP ) {
			val = parse_expr();
			mode1 = "dir";
		}
		.elif( tok == TOK_MULT ) {
			mode1 = "ind";
			val = scan_mod_ind(ch);
		}
		.elif( .tok_class(tok) & TC_REG ) {
			mode1 = "reg";
			chk_reg(tok, 1, f);
			val = ifelse( CPU, `C3X', `trans_reg(tok)', `val');
		}
		.else {
			.unget_tok();
			mode1 = "imm";
			.if( (f&1) )
				val = .get_delim_tok( ",;\n" );
			.else
				val = parse_expr();
		}
		.done val;
	}
	/* destination operand */
	.else {
		.if( !(.tok_class(tok) & TC_REG) ) {
			.error("Expected registers r[0-27], got `", .tok_val(), "'");
			.unget_tok();
			error_detected = 1;
			.done;
		}
		.else {
			chk_reg(tok, 0, f);
			.done ifelse( CPU, `C3X', `trans_reg(tok)', `val');
		}
	}
}

/* parse first source operand */
.func
scan_src_operand(f) {

  .done scan_opnd(1, f);
}

/* parse second source operand */
.func
scan_src1_operand(f) {
	.done scan_opnd(2, f);
}

/* parse destination operand */
.func
scan_dst_operand(f) {
	.done scan_opnd(0, f);
}

/* 2-operand instructions syntax check */
.func
general(code, s, d, f) {
	.select (code) {
	.case iack:
	.case ldfi:
	.case ldii:
	.case stf:
	.case sti:
		.select (mode) {
		.case "reg":
		.case "imm":
			.error("Invalid destination operand: ", s);
			error_detected = 1;
			.done;
		}
		.break;
ifelse( CPU, `C3X', `', `
	.case toieee:
	.case frieee:
	.case rcpf:
	.case rsqrf:
		.select (mode) {
		.case "imm":
			.error("Source mode immediate not allowed.\n");
			error_detected = 1;
			.done;
		.case "reg":
			.if( !is_ext_reg(s) || !is_ext_reg(d) ) {
				error_detected = 1;
				.error("Expected extended precision registers.\n");   
				.done;
			}
		}
		.break;
	.case lb0: .case lb1: .case lb2: .case lb3:
	.case lbu0: .case lbu1: .case lbu2: .case lbu3:
	.case lh0: .case lh1: .case lhu0: .case lhu1: 
	.case lwl0: .case lwl1: .case lwl2: .case lwl3: 
	.case lwr0: .case lwr1: .case lwr2: .case lwr3: 
	.case mb0: .case mb1: .case mb2: .case mb3: .case mh0: .case mh1:
		.select(mode) {
		.case "imm":
			.error("Source mode immediate not allowed.\n");
			error_detected = 1;
			.done;
		}
		.break;')
	.case nop:
		.select (mode) {
		.case dir:
		.case imm:
			.error("Invalid operand: ", s);
			.done;
		}
		.break;
	}

	.select (mode) {
	/* source is a register */
	.case reg:
		general_reg(code, d, s);
		.reads REGISTER[ .value(s) ];
		write_res(code, d);
		.break;
	/* source is indirect */
	.case ind:
		general_ind(code, d, s);
		chk_ar(s);
		write_res(code, d);
		.break;
	.default:
		.if ( mode :: "dir" ) {
			do_ldp(s);
		}
		general_g(code, mode, d, s, f);
		.if( mode :: "reg" )
			.reads REGISTER[ .value(s) ];
		.writes REGISTER[ .value(d) ];
		.writes CC;
		.if( code :: "rpts" )
			.reads JUMP;
	}
}

/* parse branch instructions */
.func
do_branch(code, cond, ar, dst) {
	.bundle {
		.if (.numeric(dst) && mode :: "imm" ) {
			branch_disp(code, cond, ar, dst);
		} .elif (mode :: "reg") {
			branch_ind(code, cond, ar, dst);
		} .else {
			/* Distance between label and program counter.
			 *
			 * The displacement is relative the start of the
			 * branch instruction plus one.
			 */
ifelse( CPU, `C3X', `
			branch_disp( 
				code, cond, ar, .concat("(", .concat(dst, " - . - 1)")) );', `
			.if( code !: "laj_cond" && code !: "bra_af" && code !: "bra_at" )
				branch_disp(
				code, cond, ar, .concat("(", .concat(dst, " - . - 1)"))
			);
			.else 
				branch_disp(
				code, cond, ar, .concat("(", .concat(dst, " - . - 3)"))
			);')
		}
		.select (code) {
ifelse( CPU, `C3X', `', `
		.case laj_cond:
			.writes REGISTER[11];
			.break;')
		.case bra_cond_delay:
		.case db_cond_delay:
			delay();
			delay();
			delay();
		}
	}
	.reads JUMP;
	.reads CC;
	.writes RES_BRANCH;
}

/* emit jump instructions with necessary delay slots */
.func
do_jump(code, addr) {
	.bundle {
		jump(code, addr);

		.if (code :: "bra_delay") {
			delay();
			delay();
			delay();
		}
	}
}

/* check syntax of stack instructions and write related resources */
.func 
do_stack(code, d) {

	stack(code, d);
	.select( code ) {
	.case pop:
	.case popf:
		.writes REGISTER[ .value( d ) ];
	}
}

/* parse load data pointer instruction */
.func
do_ldp(s) {

	.select (mode) {
	.case dir:
	.case imm:
		emit_ldp(s);
		.break;
	.default:
		.error("Invalid source operand: ", s);
	}
}

/* parse 3-operands instructions */
.func
three(code, s1, s2, d) {

	.if( mode :: "imm" || mode :: "dir" || mode1 :: "imm" || mode1 :: "dir" ){
		error_detected = 1;
		.error("Invalid combination of source operands: ", s1, ",", s2);
	}
	.elif( mode :: "reg" && mode1 :: "reg" ) {
		three_reg_reg(code, d, s1, s2);
		.reads REGISTER[ .value( s1 ) ];
		.reads REGISTER[ .value( s2 ) ];
	}
	.elif( mode :: "reg" && mode1 :: "ind" ) {
		three_reg_ind(code, d, s1, s2);
		chk_ar(s2);
		.reads REGISTER[ .value( s1 ) ];
	}
	.elif( mode :: "ind" && mode1 :: "reg" ) {
		three_ind_reg(code, d, s1, s2);
		chk_ar(s1);
		.reads REGISTER[ .value( s2 ) ];
	}
	.else {
		three_ind_ind(code, d, s1, s2);
		chk_ar(s1);
		chk_ar(s2);
	}
	.if( code !: "cmpf3" && code !: "cmpi3" && code !: "tstb3" )
		.writes REGISTER[ .value( d ) ];
	.writes CC;
}

/* 
 * MOPs
 */

/* emit instructions where dest. and src. are both register based */
.mop
general_reg(code, d, s) {
	.expansion GENERAL, MODE, DST, SRC;

	GENERAL = code;
	MODE = reg;
	DST = d;
	SRC = s;
}

/* emit instrutions with indirect addressing mode */
.mop
general_ind(code, d, s) {
	.expansion GENERAL, MODE, DST, MODN1, "AR1#", AR1, 
		"DISP# .bits(0, 7,", DISP, ")";

	GENERAL = code;
	MODE = ind;
	DST = d;
	MODN1 = mode_ind;
	AR1 = get_ar(s);
	DISP = disp;
}

/* emit instructions with other addressing modes(imm, dir) */
.mop
general_g(code, g, d, s, f) {
	.expansion GENERAL, MODE, DST, "WORD# .bits(0, 15,", WORD, ")";

	GENERAL = code;
	MODE = g;
	DST = d;
	.if( (f&1) && .valid_float(s) )
		.c3x_fp_short(s, WORD);
	.else
		WORD = s;
}

ifelse( CPU, `C3X', `', `
/* emit instructions with opcode ldep and ldpe */
.mop
emit_exp(code, s, d)
{
	.expansion GENERAL, DST, SRC;
	.if( code :: "ldep" ) {
		DST = d;
		SRC = 0;
		.if( s :: "ivtp" )
			.reads IVTP;
		.else
			.reads TVTP;
	}
	.else {
		SRC = s;
		DST = 0;
		.if( s :: "ivtp" )
			.writes IVTP;
		.else
			.writes TVTP;
	}
	GENERAL = code;
}

/* emit ldpk instructions */
.mop
emit_ldpk(s)
{
	.expansion OPCODE21, DST, "WORD# .bits(0, 15,", WORD, ")";
	OPCODE21 = ldpk;
	DST = dp;
	WORD = s;
	.writes DP;
}

/* emit rptbd instructions */
.mop
emit_rptbd_reg(s)
{
	.expansion GENERAL, SRC;
	GENERAL = rptbd_r;
	SRC = s;
}')


/* emit instructions with direct addressing modes */
.mop
emit_ldp(s) {
	.expansion GENERAL, MODE, DST, "WORD# .bits(16, 31,", WORD, ")";

	GENERAL = ldi;
	MODE = imm;
	DST = dp;
	WORD = s;
	.writes DP;
}

/* emit 3-operand instructions where both src1 and src2 are register based */
.mop
three_reg_reg(code, d, s1, s2) {
	.expansion GENERAL, MODE, DST, SRC1, SRC2;

	GENERAL = code;
	MODE = reg_reg;
	DST = d;
	SRC1 = s1;
	SRC2 = s2;
}

/* emit 3-operand instructions where src1 is register based, src2 is indirect*/
.mop
three_reg_ind(code, d, s1, s2) {
	.expansion GENERAL, MODE, DST, SRC1, MODN2, "AR2#", AR2;

	GENERAL = code;
	MODE = reg_ind;
	DST = d;
	SRC1 = s1;
	MODN2 = mode_ind1;
	AR2 = get_ar(s2);
}

/* emit 3-operand instructions, src1 is indirect, src2 is register based */
.mop
three_ind_reg(code, d, s1, s2) {
	.expansion GENERAL, MODE, DST, MODN1, "AR1#", AR1, SRC2;

	GENERAL = code;
	MODE = ind_reg;
	DST = d;
	MODN1 = mode_ind;
	AR1 = get_ar(s1);
	SRC2 = s2;

}

/* emit 3-operand instructions, both src1 and src2 are indirect */
.mop
three_ind_ind(code, d, s1, s2) {
	.expansion GENERAL, MODE, DST, MODN1, "AR1#", AR1, MODN2, "AR2#", AR2;

	GENERAL = code;
	MODE = ind_ind;
	DST = d;
	MODN1 = mode_ind;  
	AR1 = get_ar(s1);
	MODN2 = mode_ind1;
	AR2 = get_ar(s2);
}

/* emit instructions with no operands */
.mop
opcode0(code) {
	.expansion OPCODE0;

	OPCODE0 = code;
	.if (code :: "idle")
		.reads JUMP;
}

/* emit instructions with indirect addressing mode */
.mop
branch_ind(code, cond, ar, dst) {
	.expansion BRANCH, "B#", B, "ARN#", ARN, COND, SRC;

	BRANCH = code;
	B = 0;
	ARN = get_ar(ar);
		
	COND = cond;
	SRC = dst;
}

/* emit instructions with displacement indirect addressing mode */
.mop
branch_disp(code, cond, ar, dst) {
	.expansion BRANCH, "B#", B, "ARN#", ARN, COND, 
		"WORD# .bits(0, 15,", WORD, ")";

	BRANCH = code;
	B = 1;
	ARN = get_ar(ar);
	COND = cond;
	WORD = dst;
}

/* emit return, trap instructions */
.mop
ret_trap(code, cond, vector) {
	.expansion OPCODE21, COND, "WORD#", WORD;

	OPCODE21 = code;
	COND = cond;
	/* c3x allows 20 traps; c4x allows 256 traps. 
	 * A return instruction allows has vector 0.
	 */
	WORD = vector;
	.if( code :: "lat" )
		.writes REGISTER[ 11 ];
	.reads JUMP;
}

/* emit a delay slot */
.mop
delay() {
	.req_delay;
	.writes JUMP;
}

/* emit jump instructions */
.mop
jump(code, addr) {
	.expansion OPCODE24, "ADDR# .bits(0, 23,", ADDR, ")";

	OPCODE24 = code;
ifelse( CPU, `C3X', 
	`ADDR  = addr;', `
	.if ( code :: "brd" || code :: "rptbd_i" || code :: "laj" ) {
		ADDR = .concat( addr, " - . - 3 " );
	}
	.else {
		ADDR = .concat( addr, " - . - 1 " );
	}
' )
	.if( code :: "laj" )
		.writes REGISTER[11];
	.reads JUMP;
}

/* emit stack manipulation operations */
.mop
stack(code, d) {
	.expansion OPCODE21, DST, "WORD#", WORD;
	OPCODE21 = code;
	DST = d;
	WORD = 0;
}

.vop
def_float( s )
{
	emit_float_word( s );
}

/* emit a floating point number */
.mop
emit_float_word( string )
{
	.expansion ".data ", WORD32;
	.c3x_fp_single( string, WORD32 );
}


/*
 *   C O N S T A N T   E X P R E S S I O N   E V A L U A T O R
 */
/*
 * val_stk is a stack of expression values.
 * this is necessary, because local variables are allocated as statics,
 * but we want to be able to call the expression parsing functions
 * recursively. 
 *
 * The code supports binary &, |, ^, <<, >, /, %, *, +, and -,
 * unary -, ~, +, !, ++, -- and expressions in parentheses.
 *
 * if the stack overflows,
 * mcpack will generate a subscript error message.
 *
 * All operations are 32 bit signed.
 */
.strvar val_stk[128];
.numvar stk_index = 0;

.func
primary_expr()
{
	.numvar nxt_tok;
	.strvar value;

	stk_index = stk_index + 1;
	nxt_tok = .get_tok();
	.if( nxt_tok == TOK_LPAREN ){
		value = parse_expr();
		.if( (nxt_tok = .get_tok()) != TOK_RPAREN ){
			.error("Expected ``)'', got ``", .tok_val(), "''" );
			error_detected = 1;
		}
		.if( !.numeric( value ) ){
			value = .concat( "(", 
				.concat( value, ")" )
			);
		}
	} .elif( nxt_tok == TOK_NUMBER
	|| nxt_tok == TOK_NAME ){
		value = .tok_val();
	} .else {
		.if( error_detected == 0 )
			.if( nxt_tok == TOK_EOL ){
				.error(
					"Expected label or constant, found ``''"
				);
			} .else {
				.error(
					"Expected label or constant, found ``", .tok_val(), "''"
				);
			}
		error_detected = 1;
		value = 0;
		.unget_tok();
	}
	stk_index = stk_index - 1;
	.done value;
}

.func
unary_expr()
{
	.numvar nxt_tok;
	.strvar value;

	nxt_tok = .get_tok();
	.if( nxt_tok == TOK_MINUS ){
		value = unary_expr();
		.if( .numeric( value ) )
			.done - value;
		.done .concat( "-", value );
	}
	.if( nxt_tok == TOK_TILDE ){
		value = unary_expr();
		.if( .numeric( value ) )
			.done ~ value;
		.done .concat( "~", value );
	}
	.if( nxt_tok == TOK_LOG_NOT ){
		value = unary_expr();
		.if( .numeric( value ) )
			.done ! value;
		.done .concat( "!", value );
	}
	.if( nxt_tok == TOK_PPLUS ) {
		value = unary_expr();
		.done .concat( "++", value );
	}
	.if( nxt_tok == TOK_MMINUS ) {
		value = unary_expr();
		.done .concat( "--", value );
	}
	.if( nxt_tok == TOK_PLUS ){
		.done unary_expr();
	}
	.unget_tok();
	.done primary_expr();
}

.func
mul_expr()
{
	.numvar nxt_tok;
	.strvar value;

	stk_index = stk_index + 1;
	val_stk[stk_index] = unary_expr();
	.for(;;){
		.if( (nxt_tok = .get_tok()) == TOK_MULT ){
			value = unary_expr();
			.if( .numeric(value) && .numeric( val_stk[stk_index] ) ){
				val_stk[stk_index] = val_stk[stk_index] * value;
			} .else {
				val_stk[stk_index] = .concat( val_stk[stk_index],
					.concat( "*",  value ) 
				);
			}
		}
		.elif( nxt_tok == TOK_DIV ){
			value = unary_expr();
			.if( .numeric(value) && .numeric( val_stk[stk_index] ) ){
				val_stk[stk_index] = val_stk[stk_index] / value;
			} .else {
				val_stk[stk_index] = .concat( val_stk[stk_index],
					.concat( "/",  value ) 
				);
			}
		}
		.elif( nxt_tok == TOK_REM ){
			value = unary_expr();
			.if( .numeric(value) && .numeric( val_stk[stk_index] ) ){
				val_stk[stk_index] = val_stk[stk_index] % value;
			} .else {
				val_stk[stk_index] = .concat( val_stk[stk_index],
					.concat( "%",  value ) 
				);
			}
		}
		.else {
			.unget_tok();
			.break;
		}
	}
	stk_index = stk_index - 1;
	.done val_stk[stk_index + 1];
}

.func
add_expr()
{
	.numvar nxt_tok;
	.strvar value;

	stk_index = stk_index + 1;
	val_stk[stk_index] = mul_expr();
	.for(;;){
		.if( (nxt_tok = .get_tok()) == TOK_PLUS ){
			value = mul_expr();
			.if( .numeric(value) && .numeric( val_stk[stk_index] ) ){
				val_stk[stk_index] = val_stk[stk_index] + value;
			} .else {
				val_stk[stk_index] = .concat( val_stk[stk_index],
					.concat( "+",  value ) 
				);
			}
		}
		.elif( nxt_tok == TOK_MINUS ){
			value = mul_expr();
			.if( .numeric(value) && .numeric( val_stk[stk_index] ) ){
				val_stk[stk_index] = val_stk[stk_index] - value;
			} .else {
				val_stk[stk_index] = .concat( val_stk[stk_index],
					.concat( "-",  value ) 
				);
			}
		}
		.else {
			.unget_tok();
			.break;
		}
	}
	stk_index = stk_index - 1;
	.done val_stk[stk_index + 1];
}

.func
shift_expr()
{
	.numvar nxt_tok;
	.strvar value;

	stk_index = stk_index + 1;
	val_stk[stk_index] = add_expr();
	.for(;;){
		.if( (nxt_tok = .get_tok()) == TOK_SHL ){
			value = add_expr();
			.if( .numeric(value) && .numeric( val_stk[stk_index] ) ){
				val_stk[stk_index] = val_stk[stk_index] << value;
			} .else {
				val_stk[stk_index] = .concat( val_stk[stk_index],
					.concat( "<<",  value ) 
				);
			}
		}
		.elif( nxt_tok == TOK_SHR ){
			value = add_expr();
			.if( .numeric(value) && .numeric( val_stk[stk_index] ) ){
				val_stk[stk_index] = val_stk[stk_index] >> value;
			} .else {
				val_stk[stk_index] = .concat( val_stk[stk_index],
					.concat( ">>",  value ) 
				);
			}
		}
		.else {
			.unget_tok();
			.break;
		}
	}
	stk_index = stk_index - 1;
	.done val_stk[stk_index + 1];
}

.func
xor_expr()
{
	.strvar value;

	stk_index = stk_index + 1;
	val_stk[stk_index] = shift_expr();
	.for(;;){
		.if( .get_tok() == TOK_XOREXPR ){
			value = shift_expr();
			.if( .numeric(value) && .numeric( val_stk[stk_index] ) ){
				val_stk[stk_index] = val_stk[stk_index] ^ value;
			} .else {
				val_stk[stk_index] = .concat( val_stk[stk_index],
					.concat( "^",  value ) 
				);
			}
		}
		.else {
			.unget_tok();
			.break;
		}
	}
	stk_index = stk_index - 1;
	.done val_stk[stk_index + 1];
}

.func
and_expr()
{
	.strvar value;

	stk_index = stk_index + 1;
	val_stk[stk_index] = xor_expr();
	.for(;;){
		.if( .get_tok() == TOK_ANDEXPR ){
			value = xor_expr();
			.if( .numeric(value) && .numeric( val_stk[stk_index] ) ){
				val_stk[stk_index] = val_stk[stk_index] & value;
			} .else {
				val_stk[stk_index] = .concat( val_stk[stk_index],
					.concat( "&",  value ) 
				);
			}
		}
		.else  {
			.unget_tok();
			.break;
		}
	}
	stk_index = stk_index - 1;
	.done val_stk[stk_index + 1];
}

.func
parse_expr()
{
	/*
	 * evaluate a c_style expression
	 * using recursive descent
	 * folding constants when possible
	 */
	.strvar value;

	stk_index = stk_index + 1;
	val_stk[stk_index] = and_expr();
	.for(;;){
		.if( .get_tok() == TOK_OREXPR ){
			value = and_expr();
			.if( .numeric(value) && .numeric( val_stk[stk_index] ) ){
				val_stk[stk_index] = val_stk[stk_index] | value;
			} .else {
				val_stk[stk_index] = .concat( val_stk[stk_index],
					.concat( "|",  value ) 
				);
			}
		} .else {
			.unget_tok();
			.break;
		}
	}
	stk_index = stk_index - 1;
	.done val_stk[stk_index + 1];
}


Back to Archelon's Home Page