############################
#
# PA-RISC 1.1 Instructions
#
############################

with : phase=1 {

############################
# Load and Store and Address Generation Instructions
############################
:LDW OFF_BASE_14,R1dst		is opfam=0x12 & OFF_BASE_14 & R1dst {
	addr:$(ADDRSIZE) = OFF_BASE_14;
    R1dst =  zext(*[ram]:4 addr) ;
 } 

:LDH OFF_BASE_14,R1dst		is opfam=0x11 & OFF_BASE_14 & R1dst { 
	addr:$(ADDRSIZE) = OFF_BASE_14;
    R1dst = zext(*[ram]:2 addr) ;
}

:LDB OFF_BASE_14,R1dst		is opfam=0x10 & OFF_BASE_14 & R1dst {
	addr:$(ADDRSIZE) = OFF_BASE_14;
    R1dst = zext(*[ram]:1 addr) ;
} 

:STW R1,OFF_BASE_14		is opfam=0x1A & OFF_BASE_14 & R1 {
	addr:$(ADDRSIZE) = OFF_BASE_14;
	*[ram]:4 addr = R1:4; 
 } 

:STH R1,OFF_BASE_14 		is opfam=0x19 & R1 & OFF_BASE_14 { 
	addr:$(ADDRSIZE) = OFF_BASE_14;
	*[ram]:2 addr = R1:2; 
}
:STB R1,OFF_BASE_14		is opfam=0x18 & OFF_BASE_14 & R1 {
	addr:$(ADDRSIZE) = OFF_BASE_14;
	*[ram]:1 addr = R1:1; 
} 

:LDW^",M" OFF_BASE_14,R1dst		is opfam=0x13 & OFF_BASE_14 & R1dst & RB & SPCBASE & lse14 {
	off:$(ADDRSIZE) = 0;
	if (lse14 s>=  0x0) goto <IGNOREIMM>;
	off = sext(lse14);
	<IGNOREIMM> 
	addr:$(ADDRSIZE) = SPCBASE + off;
	RB = RB + lse14;
    R1dst = zext( *[ram]:4 addr );
} 

:STW^",M" R1,OFF_BASE_14		is opfam=0x1B & OFF_BASE_14 & R1 & RB & SPCBASE & lse14 {
	addr:$(ADDRSIZE) = SPCBASE;
    local imm = sext(lse14);
	if (imm s>=  0x0) goto <IGNOREIMM>;
	addr = addr + imm;
	<IGNOREIMM> 
	*[ram]:4 addr = R1; 
	RB = RB + imm;
} 

# LDWX
:LDW^indexedWordAccessCmplt^loadCC RX^SRRB,RT is opfam=0x03 & subop=2 & zero=0 & indexedWordAccessCmplt & loadCC & RX & RT & SRRB {
	address:$(ADDRSIZE) = indexedWordAccessCmplt;  
    RT =  zext(*[ram]:4 address) ;
 }
 
 #LDHX
:LDH^indexedHalfwordAccessCmplt^loadCC RX^SRRB,RT is opfam=0x03 & subop=1 & zero=0 & indexedHalfwordAccessCmplt & loadCC & RX & SRRB & RT {
	address:$(ADDRSIZE) = indexedHalfwordAccessCmplt;  
    RT =  zext(*[ram]:2 address) ;
}

#LDBX
:LDB^indexedByteAccessCmplt^loadCC RX^SRRB,RT is opfam=0x03 & subop=0 & zero=0 & indexedByteAccessCmplt & loadCC & RX & SRRB & RT {
	address:$(ADDRSIZE) = indexedByteAccessCmplt;  
    RT =  zext(*[ram]:1 address) ;
}

# same as LDWX, except that it checks privilege levels
:LDWAX^indexedWordAccessCmplt^loadCC RX(RB),RT 				is opfam=0x03 & subop=6 & zero=0 & s=0 & indexedWordAccessCmplt & loadCC & RX & SRRB & RB & RT {
	address:$(ADDRSIZE) = indexedWordAccessCmplt;  
    RT =  zext(*[ram]:4 address) ;
}

:LDCWX^indexedDoublewordAccessCmplt^loadClearCC RX^SRRB,RT 		is opfam=0x03 & subop=7 & zero=0 & indexedDoublewordAccessCmplt & loadClearCC & RX & SRRB & RT {
	address:$(ADDRSIZE) = indexedDoublewordAccessCmplt;  
    RT =  zext(*[ram]:4 address);
    *[ram]:4 address = 0:4; 
 }

# LDWS
:LDW^shortDispCmplt^loadCC highlse5^SRRB,RT			is opfam=0x03 & subop=2 & one=1 & shortDispCmplt & loadCC & highlse5 & SRRB & RT {
	addr:$(ADDRSIZE) = shortDispCmplt;
    RT =  zext(*[ram]:4 addr) ;
}

# LDHS
:LDH^shortDispCmplt^loadCC highlse5^SRRB,RT			is opfam=0x03 & subop=1 & one=1 & shortDispCmplt & loadCC & highlse5 & SRRB & RT {
	addr:$(ADDRSIZE) = shortDispCmplt;
    RT =  zext(*[ram]:2 addr) ;
}

# LDBS
:LDB^shortDispCmplt^loadCC highlse5^SRRB,RT			is opfam=0x03 & subop=0 & one=1 & shortDispCmplt & loadCC & highlse5 & SRRB & RT {
	addr:$(ADDRSIZE) = shortDispCmplt;
    RT =  zext(*[ram]:1 addr) ;
}

#STWS
:STW^storeShortDispCmplt^storeCC RR,lse5^SRRB				is opfam=0x03 & subop=0xA & one=1 & storeShortDispCmplt & storeCC & lse5 & SRRB & RR {
	addr:$(ADDRSIZE) = storeShortDispCmplt;
	*[ram]:4 addr = RR:4; 
}

#STHS
:STH^storeShortDispCmplt^storeCC RR,lse5^SRRB				is opfam=0x03 & subop=0x9 & one=1 & storeShortDispCmplt & storeCC & lse5 & SRRB & RR {
	addr:$(ADDRSIZE) = storeShortDispCmplt;
	*[ram]:2 addr = RR:2; 
}

#STBS
:STB^storeShortDispCmplt^storeCC RR,lse5^SRRB				is opfam=0x03 & subop=0x8 & one=1 & storeShortDispCmplt & storeCC & lse5 & SRRB & RR {
	addr:$(ADDRSIZE) = storeShortDispCmplt;
	*[ram]:1 addr = RR:1; 
}

:LDWAS^shortDispCmplt^loadCC highlse5(RB),RT			is opfam=0x03 & subop=6 & one=1 & shortDispCmplt & loadCC & highlse5 & RB & RT {
	addr:$(ADDRSIZE) = shortDispCmplt;
    RT =  zext(*[ram]:4 addr) ;
}

:LDCWS^shortDispCmplt^loadClearCC highlse5^SRRB,RT		is opfam=0x03 & subop=7 & one=1 & shortDispCmplt & loadClearCC & highlse5 & SRRB & RT {
	address:$(ADDRSIZE) = shortDispCmplt;  
    RT =  zext(*:4 address);
    *[ram]:4 address = 0:4; 
}

:STWAS^shortDispCmplt^storeCC RR,lse5(RB)				is opfam=0x03 & subop=0xE & one=1 & shortDispCmplt & storeCC & lse5 & RB & RR {
	addr:$(ADDRSIZE) = shortDispCmplt;
	*[ram] :4 addr = RR:4; 
}

# This is the "begin" version for big endian. I am not doing the little endian version.
:STBYS^storeBytesShortCmplt^storeCC RR,lse5^SRRB 		is opfam=0x03 & subop=0xC & one=1 & storeBytesShortCmplt & storeCC & lse5 & SRRB & RR & u=0 {
	# get the address, which is most likely not word aligned
	addr:$(ADDRSIZE) = storeBytesShortCmplt;
	# figure out how many bytes need to be written
	local numBytes = 4 - (addr & 0x3);
	# this is the address where we stop (one byte past the last address to which we write)
	local finalAddr = addr + numBytes;
	# copy the contents of RR
	data:$(REGSIZE) = RR >> ((4 - numBytes) * 8);
	# use a for loop to write out the 1,2,3, or 4 bytes
	<LOOP>
	if (addr == finalAddr) goto <DONE>;
	*[ram]:1 addr = data:1;
	data = data >> 8;
	addr = addr + 1;
	goto <LOOP>;
	<DONE>
}

# This is the "end" version for big endian. I am not doing the little endian version.
:STBYS^storeBytesShortCmplt^storeCC RR,lse5^SRRB 		is opfam=0x03 & subop=0xC & one=1 & storeBytesShortCmplt & storeCC & lse5 & SRRB & RR & u=1 {
	# get the address, which is most likely not word aligned
	addr:$(ADDRSIZE) = storeBytesShortCmplt;
	# figure out how many bytes need to be written
	local numBytes = (addr & 0x3);
	# now make a word aligned address
	addr = addr & 0x3;
	# this is the address where we stop (one byte past the last address to which we write)
	local finalAddr = addr + numBytes;
	# copy the contents of RR
	data:$(REGSIZE) = RR >> ((4 - numBytes) * 8);

	# use a for loop to write out the 1,2,3, or 4 bytes
	<LOOP>
	if (addr == finalAddr) goto <DONE>;
	*[ram]:1 addr = data:1;
	data = data >> 8;
	addr = addr + 1;
	goto <LOOP>;
	<DONE>
}

# Note: LDO and LDIL do not access memory, they just load an address into a register
# LDI is a pseudo-op that is commonly used to load immediate values into registers. The values may or may not be addresses.
:LDO lse14(RB),R1dst										is opfam=0x0D & lse14 & RB & R1dst {
	R1dst = RB + lse14;
 }

# LDO is often used as a copy operator, so when the offset is zero, we display it as a copy
:COPY RB,R1dst										is opfam=0x0D & im14=0 & RB & R1dst {
	R1dst = RB;
 }
 
:LDI lse14,R1dst									is opfam=0x0D & b=0 & lse14 & R1dst {
	R1dst = lse14;
}

:LDIL lse21,R2									is opfam=0x08 & R2 & lse21 {
	R2 = lse21;
}

# this instruction adds lse21 + R2 and puts the result into the hard coded r1 register
# (not the register specified by bitfield reg1, the actual register r1)
:ADDIL lse21, R2, r1							is opfam=0x0A & R2 & lse21 & r1 {
	r1 = R2 + lse21;
}

################################################################################
# Branch Instructions
################################################################################

################################################################################
# unconditional immediate calls
################################################################################
# non-nullifying unconditional immediate call
:B^",L"^nullifyForBranch branchTarget3W,R2dst						is opfam=0x3A & c=0x0 & R2dst & nullifyForBranch & n=0 & branchTarget3W & $(COMMON) 
	[
	  branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 1; # unconditional imm call
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	R2dst = inst_start+8;
	branchExecuted = 1;
}

# nullifying unconditional immediate call
# special case that doesn't need the deferral mechanism 
:B^",L"^nullifySymForBranch branchTarget3W,R2dst						is opfam=0x3A & c=0x0 & R2dst & nullifySymForBranch & n=1 & branchTarget3W & $(COMMON) 
{
	R2dst = inst_start+8;
	call branchTarget3W;
}

################################################################################
# unconditional immediate branches
# since PA-RISC doesn't have a straight branch without link, it uses branch and link into the R0 register.
# By having a second op for it, we can use a goto and prevent analysis tools from thinking this is a legitimate subroutine call
################################################################################
# non-nullifying unconditional immediate branch (no link)
:B^nullifyForBranch branchTarget3W							is opfam=0x3A & c=0x0 & reg2=0 & nullifyForBranch & n=0 & branchTarget3W & $(COMMON) 
	[
	  branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 0; # unconditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	  
	]
{
	branchExecuted = 1;
}

# nullifying unconditional immediate branch (no link)
# This is a special case, as we just do the branch and don't use
# our defered branching mechanism
:B^nullifySymForBranch branchTarget3W							is opfam=0x3A & c=0x0 & reg2=0 & nullifySymForBranch & n=1 & branchTarget3W & $(COMMON) 
{
	goto branchTarget3W;
}

################################################################################
# conditional immediate branches - comparison with registers
################################################################################
:CMPBT^RegCSCondSym^nullifyForBranch R1,R2,branchTarget2W		is opfam=0x20 & R1 & R2 & nullifyForBranch & n=0 & branchTarget2W & RegCSCondSym & RegCSCond & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	branchCond = RegCSCond;
	branchExecuted = 1;
}

 :CMPBT^RegCSCondSym^nullifyForBranch R1,R2,branchTarget2W		is opfam=0x20 & R1 & R2 & nullifyForBranch & n=1 & branchTarget2W & displacement2W & RegCSCondSym & RegCSCond & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	branchCond = RegCSCond;
	branchExecuted = 1;
	nullifyNextCond = ( ! branchCond && (displacement2W s< 0)) || ( branchCond && (displacement2W s>= 0) );
}

:CMPBF^RegCSCondSym^nullifyForBranch R1,R2,branchTarget2W		is opfam=0x22 & R1 & R2 & nullifyForBranch & n=0 & branchTarget2W & RegCSCondSym & RegCSCond & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	branchCond = ! RegCSCond;
	branchExecuted = 1;
}

:CMPBF^RegCSCondSym^nullifyForBranch R1,R2,branchTarget2W		is opfam=0x22 & R1 & R2 & nullifyForBranch & n=1 & branchTarget2W & displacement2W & RegCSCondSym & RegCSCond & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	branchCond = ! RegCSCond;
	branchExecuted = 1;
	nullifyNextCond = ( ! branchCond && (displacement2W s< 0)) || ( branchCond && (displacement2W s>= 0) );
}

################################################################################
# conditional immediate branches -- comparison with immediates
################################################################################
:CMPIBT^RegCSCondSym^nullifyForBranch highlse5,R2,branchTarget2W	is opfam=0x21 & highlse5 & R2 & nullifyForBranch & branchTarget2W & RegCSCondSym & RegCSCondI & n=0 & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	branchCond = RegCSCondI;
	branchExecuted = 1;
}

:CMPIBT^RegCSCondSym^nullifyForBranch highlse5,R2,branchTarget2W	is opfam=0x21 & highlse5 & R2 & nullifyForBranch & branchTarget2W & displacement2W & RegCSCondSym & RegCSCondI & n=1 & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	branchCond = RegCSCondI;
	branchExecuted = 1;
	nullifyNextCond = ( ! branchCond && (displacement2W s< 0)) || ( branchCond && (displacement2W s>= 0) );
}

:CMPIBF^RegCSCondSym^nullifyForBranch highlse5,R2,branchTarget2W	is opfam=0x23 & highlse5 & R2 & nullifyForBranch & branchTarget2W & RegCSCondSym & RegCSCondI & n=0 & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	branchCond = !RegCSCondI;
	branchExecuted = 1;
}

:CMPIBF^RegCSCondSym^nullifyForBranch highlse5,R2,branchTarget2W	is opfam=0x23 & highlse5 & R2 & nullifyForBranch & branchTarget2W & displacement2W & RegCSCondSym & RegCSCondI & n=1 & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	branchCond = !RegCSCondI;
	branchExecuted = 1;
	nullifyNextCond = ( ! branchCond && (displacement2W s< 0)) || ( branchCond && (displacement2W s>= 0) );
}

################################################################################
# unconditional indirect calls & branches
################################################################################
# IP relative unconditional indirect call
:BLR^nullifyForBranch RR,R2dst									is opfam=0x3A & c=0x2 & R2dst & nullifyForBranch & RR & IPRelativeIndexedTarget & n=0 & $(COMMON)
	[
	  branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 5; # unconditional indirect call
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	R2dst = inst_start+8;
	branchExecuted = 1;
}

# IP relative unconditional indirect call
:BLR^nullifySymForBranch RR,R2dst									is opfam=0x3A & c=0x2 & R2dst & nullifySymForBranch & RR & IPRelativeIndexedTarget & n=1 & $(COMMON)
{
	R2dst = inst_start+8;
	call [branchIndDest];
}

# vectored (offset register plus index register) unconditional indirect branch
:BV^nullifyForBranch RX(RB)									is opfam=0x3A & c=0x6 & RB & nullifyForBranch & RX & IndexedTarget & bit0=0 & n=0 & $(COMMON)
	[
	  branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 4; # unconditional indirect branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	branchExecuted = 1;
}

# vectored (offset register plus index register) unconditional indirect branch
:BV^nullifySymForBranch RX(RB)								is opfam=0x3A & c=0x6 & RB & nullifySymForBranch & RX & IndexedTarget & bit0=0 & n=1 & $(COMMON)
{
	goto [branchIndDest];
}

# this is the idiom for return from subroutine
# currently we pull it out so we don't print out the R0, but we could modify this to do a return...
:BV^nullifyForBranch (RB)									is opfam=0x3A & c=0x6 & RB & nullifyForBranch & reg1=0 & ReturnTarget & bit0=0 & n=0 & $(COMMON)
	[
	  branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 4; # unconditional indirect branch
	  globalset(inst_next, branchType);
	  branchIsReturn=1;
	  globalset(inst_next, branchIsReturn);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	branchExecuted = 1;
}

# this is the idiom for return from subroutine
# currently we pull it out so we don't print out the R0, but we could modify this to do a return...
:BV^nullifyForBranch (RB)									is opfam=0x3A & c=0x6 & RB & nullifyForBranch & reg1=0 & ReturnTarget & bit0=0 & n=1 & $(COMMON)
{
	return [branchIndDest];
}

###########################

#### MOVB

:MOVB^SEDCondSym^nullifyForBranch R1,R2dst,branchTarget2W			is opfam=0x32 & R2dst & R1 & nullifyForBranch & branchTarget2W & DepCond & SEDCondSym & n=0 & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	R2dst = R1;
	nullifyCondResult = R1;
	build DepCond; # force the condition evaluation after the move
	branchCond = DepCond;
	branchExecuted = 1;
}

:MOVB^SEDCondSym^nullifyForBranch R1,R2dst,branchTarget2W			is opfam=0x32 & R2dst & R1 & nullifyForBranch & branchTarget2W & displacement2W & DepCond & SEDCondSym & n=1 & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	R2dst = R1;
	nullifyCondResult = R1;
	build DepCond; # force the condition evaluation after the move
	branchCond = DepCond;
	branchExecuted = 1;
	nullifyNextCond = ( ! branchCond && (displacement2W s< 0)) || ( branchCond && (displacement2W s>= 0) );
}

###########################

#### MOVIB

:MOVIB^SEDCondSym^nullifyForBranch im5,R2dst,branchTarget2W		is opfam=0x33 & R2dst & im5 & nullifyForBranch & branchTarget2W & DepCond & SEDCondSym & n=0 & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	R2dst = sext(im5:1);
	nullifyCondResult = sext(im5:1);
	build DepCond; # force the condition evaluation after the move
	branchExecuted = 1;
	branchCond = DepCond;
}

:MOVIB^SEDCondSym^nullifyForBranch im5,R2dst,branchTarget2W		is opfam=0x33 & R2dst & im5 & nullifyForBranch & branchTarget2W & displacement2W & DepCond & SEDCondSym & n=1 & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	R2dst = sext(im5:1);
	nullifyCondResult = sext(im5:1);
	build DepCond; # force the condition evaluation after the move
	branchCond = DepCond;
	branchExecuted = 1;
	nullifyNextCond = ( ! branchCond && (displacement2W s< 0)) || ( branchCond && (displacement2W s>= 0) );
}

###########################
:ADDBT^RegAddCondSym^nullifyForBranch R1,R2dst,branchTarget2W		is opfam=0x28 & R1 & R2dst & R2 & nullifyForBranch & branchTarget2W & RegAddCond & RegAddCondSym & n=0 & $(COMMON) 
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	build RegAddCond; # force the condition evaluation before the move
	branchCond = RegAddCond;
	branchExecuted = 1;
	R2dst = R1 + R2;
}

:ADDBT^RegAddCondSym^nullifyForBranch R1,R2dst,branchTarget2W		is opfam=0x28 & R1 & R2dst & R2 & nullifyForBranch & branchTarget2W & displacement2W & RegAddCond & RegAddCondSym & n=1 & $(COMMON) 
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	build RegAddCond; # force the condition evaluation before the move
	branchCond = RegAddCond;
	branchExecuted = 1;
	nullifyNextCond = ( ! branchCond && (displacement2W s< 0)) || ( branchCond && (displacement2W s>= 0) );

	R2dst = R1 + R2;
}

###########################
:ADDBF^RegAddCondSym^nullifyForBranch R1,R2dst,branchTarget2W		is opfam=0x2A & R1 & R2dst & R2 & nullifyForBranch & branchTarget2W & RegAddCond & RegAddCondSym & n=0 & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	build RegAddCond; # force the condition evaluation before the move
	branchCond = !RegAddCond;
	branchExecuted = 1;
	R2dst = R1 + R2;
}

:ADDBF^RegAddCondSym^nullifyForBranch R1,R2dst,branchTarget2W		is opfam=0x2A & R1 & R2 & R2dst & nullifyForBranch & branchTarget2W & displacement2W & RegAddCondSym & RegAddCond & n=1 & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	build RegAddCond; # force the condition evaluation before the move
	branchCond = !RegAddCond;
	branchExecuted = 1;
	nullifyNextCond = ( ! branchCond && (displacement2W s< 0)) || ( branchCond && (displacement2W s>= 0) );
	R2dst = R1 + R2;
}

###########################
:ADDIBT^RegAddCondSym^nullifyForBranch highlse5,R2dst,branchTarget2W	is opfam=0x29 & highlse5 & R2 & R2dst & nullifyForBranch & branchTarget2W & RegAddCondI & RegAddCondSym & n=0 & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	build RegAddCondI; # force the condition evaluation before the move
	branchCond = RegAddCondI;
	branchExecuted = 1;
	R2dst = R2 + sext(highlse5);
}

:ADDIBT^RegAddCondSym^nullifyForBranch highlse5,R2dst,branchTarget2W	is opfam=0x29 & highlse5 & R2 & R2dst & nullifyForBranch & branchTarget2W & displacement2W & RegAddCondI & RegAddCondSym & n=1 & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	build RegAddCondI; # force the condition evaluation before the move
	branchCond = RegAddCondI;
	branchExecuted = 1;
	nullifyNextCond = ( ! branchCond && (displacement2W s< 0)) || ( branchCond && (displacement2W s>= 0) );
	R2dst = R2 + sext(highlse5);
}

:ADDIBF^RegAddCondSym^nullifyForBranch highlse5,R2dst,branchTarget2W	is opfam=0x2B & highlse5 & R2 & R2dst & nullifyForBranch & branchTarget2W & RegAddCondI & RegAddCondSym & n=0 & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	build RegAddCondI; # force the condition evaluation before the move
	branchCond = ! RegAddCondI;
	branchExecuted = 1;
	R2dst = R2 + sext(highlse5);
}

:ADDIBF^RegAddCondSym^nullifyForBranch highlse5,R2dst,branchTarget2W	is opfam=0x2B & highlse5 & R2 & R2dst & nullifyForBranch & branchTarget2W & displacement2W & RegAddCondI & RegAddCondSym & n=1 & $(COMMON)
 	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	build RegAddCondI; # force the condition evaluation before the move
	branchCond = ! RegAddCondI;
	branchExecuted = 1;
	nullifyNextCond = ( ! branchCond && (displacement2W s< 0)) || ( branchCond && (displacement2W s>= 0) );
	R2dst = R2 + sext(highlse5);
}
	
#######################################
:BB^SEDCondSym^nullifyForBranch R1,SAR,branchTarget2W				is opfam=0x30 & branchTarget2W & nullifyForBranch & R1 & BVBCond & SEDCondSym & SAR & n=0 & $(COMMON)
	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	branchCond = BVBCond;
	branchExecuted = 1;
}						

:BB^SEDCondSym^nullifyForBranch R1,SAR,branchTarget2W				is opfam=0x30 & branchTarget2W & nullifyForBranch & displacement2W & R1 & BVBCond & SEDCondSym & SAR & n=1 & $(COMMON) 
	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	branchCond = BVBCond;
	branchExecuted = 1;
	nullifyNextCond = ( ! branchCond && (displacement2W s< 0)) || ( branchCond && (displacement2W s>= 0) );
}

#######################################
:BB^SEDCondSym^nullifyForBranch R1,bboffset,branchTarget2W			is opfam=0x31 & branchTarget2W & nullifyForBranch & R1 & BBCond & SEDCondSym & n=0 & bboffset & $(COMMON)
	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	branchCond = BBCond;
	branchExecuted = 1;
}						

:BB^SEDCondSym^nullifyForBranch R1,bboffset,branchTarget2W			is opfam=0x31 & branchTarget2W & displacement2W & nullifyForBranch & R1 & BBCond & SEDCondSym & n=1 & bboffset & $(COMMON)
	[ branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 2; # conditional imm branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	branchCond = BBCond;
	branchExecuted = 1;
	nullifyNextCond = ( ! branchCond && (displacement2W s< 0)) || ( branchCond && (displacement2W s>= 0) );
}

#######################################
# These instructions change the privilege level or the space register
define pcodeop changePrivLevel;
define pcodeop changeSpace;
define pcodeop getCurrentSpace;

:BE^nullifyForBranch externalTarget		is opfam=0x38 & nullifyForBranch & externalTarget & SR3bit & n=0 & $(COMMON)
	[
	  branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 4; # unconditional indirect branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	iasq_front = SR3bit; # set the space ID to the new space ID
	# with the current deferral system, this will mean the sr is wrong during the delay slot
	branchExecuted = 1;
}

:BE^nullifyForBranch externalTarget		is opfam=0x38 & nullifyForBranch & externalTarget & SR3bit & n=1 & $(COMMON)
{
	iasq_front = SR3bit; # set the space ID to the new space ID
	goto [externalTarget];
}

:BE^",L"^nullifyForBranch externalTarget,SR0,R31	is opfam=0x39 & nullifyForBranch & SR0 & R31 & SR3bit & externalTarget & n=0 & $(COMMON)
	[
	  branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 5; # unconditional indirect call
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	r31 = inst_next+4;  # store the link/return address
	sr0 = iasq_front; # store the link/return space ID 
	iasq_front = SR3bit; # set the space ID to the new space ID
	# with the current deferral system, this will mean the sr is wrong during the delay slot
	branchExecuted = 1;
}

:BE^",L"^nullifyForBranch externalTarget,SR0,R31	is opfam=0x39 & nullifyForBranch & SR0 & R31 & SR3bit & externalTarget & n=1 & $(COMMON)
{
	r31 = inst_next+4; # store the link/return address
	sr0 = iasq_front; # store the link/return space ID 
	iasq_front = SR3bit; # set the space ID to the new space ID
	call [externalTarget];
}

:B^",GATE"^nullifyForBranch branchTarget3W,R2dst					is opfam=0x3A & c=0x1 & R2dst & nullifyForBranch & branchTarget3W & n=0 & $(COMMON) 
	[
	  branchEnable = 1;
	  globalset(inst_next, branchEnable);
	  branchType = 0; # unconditional immediate branch
	  globalset(inst_next, branchType);
	  branchCouldBeNullified = nullifyEnable;
	  globalset(inst_next, branchCouldBeNullified);
	]
{
	R2dst = changePrivLevel();
	branchExecuted = 1;
}

:B^",GATE"^nullifyForBranch branchTarget3W,R2dst					is opfam=0x3A & c=0x1 & R2dst & nullifyForBranch & branchTarget3W & n=1 & $(COMMON)
{
	R2dst = changePrivLevel();
	goto [branchTarget3W];
}


#######################################
#######################################
# General Arithmetic/Logic Instructions
#######################################
#######################################
define pcodeop trap;

:ADD^AddCondSym R1,R2,RT	is opfam=0x02 & op=0x18 & m=0 & R1 & R2 & RT & AddCondNullify & AddCondSym {
	pswCB = carry(R1,R2);
	RT = R1 + R2;
	build AddCondNullify;
}

# this version intentionally does not set the carry bits
:ADD^",L"^AddCondSym R1,R2,RT	is opfam=0x02 & op=0x28 & m=0 & R1 & R2 & RT & AddCondNullify & AddCondSym {
	RT = R1 + R2;
	build AddCondNullify;
}

:ADDO^AddCondSym R1,R2,RT	is opfam=0x02 & op=0x38 & m=0 & R1 & R2 & RT & AddCondSym & AddCondNullify {
	if (scarry(R1,R2)) goto <TRAP>;
	pswCB = carry(R1,R2);
	RT = R1 + R2;
	goto <DONE>;
	<TRAP>
	trap();
	<DONE>
	build AddCondNullify;
}

:ADD^",C"^AddCondSym R1,R2,RT	is opfam=0x02 & op=0x1C & m=0 & R1 & R2 & RT & AddCondSym & AddCondNullify {
	local partialSum = R2 + zext(pswCB);
	pswCB = carry(partialSum, R1);
	RT = partialSum + R1;
	build AddCondNullify;
}

# TODO This may need some work
:ADD^",CO"^AddCondSym R1,R2,RT	is opfam=0x02 & op=0x3C & m=0 & R1 & R2 & RT & AddCondSym & AddCondNullify {
	local partialSum = R2 + zext(pswCB);
	partialCarry:1 = carry(R2, zext(pswCB));
	partialOverflow:1 = scarry(R2, zext(pswCB));
	takeTrap:1 = partialOverflow == 0x1:1; 
	if (takeTrap) goto <TRAP>;
	RT = partialSum + R1;
	finalCarry:1 = carry(partialSum, R1);
	finalOverflow:1 = scarry(partialSum, R1);
	takeTrap = finalOverflow == 0x1:1;
	if (takeTrap) goto <TRAP>;
	goto <DONE>;
	<TRAP>
	trap();
	<DONE>
	pswCB = partialCarry ^ finalCarry;
	build AddCondNullify;
}

:SH1ADD^AddCondSym R1,R2,RT	is opfam=0x02 & op=0x19 & m=0 & R1 & R2 & RT & AddCond & AddCondSym & AddCondNullify {
	local shiftedR1 = R1 << 1;
	pswCB = carry(shiftedR1,R2);
	RT = shiftedR1 + R2;
	build AddCondNullify;
}

:SH1ADDL^AddCondSym R1,R2,RT	is opfam=0x02 & op=0x29 & m=0 & R1 & R2 & RT & AddCondNullify & AddCondSym {
	local shiftedR1 = R1 << 1;
	RT = shiftedR1 + R2;
	build AddCondNullify;
}

:SH1ADDO^SEDCondSym R1,R2,RT	is opfam=0x02 & op=0x39 & m=0 & R1 & R2 & RT & AddCondNullify & SEDCondSym {
	local shiftedR1 = R1 << 1;
	if (scarry(shiftedR1, R2)) goto <TRAP>;
	pswCB = carry(shiftedR1,R2);
	RT = shiftedR1 + R2;
	goto <DONE>;
	<TRAP>
	trap();
	<DONE>
	build AddCondNullify;
}

:SH2ADD^SEDCondSym R1,R2,RT	is opfam=0x02 & op=0x1A & m=0 & R1 & R2 & RT & AddCondNullify & SEDCondSym {
	local shiftedR1 = R1 << 2;
	pswCB = carry(shiftedR1,R2);
	RT = shiftedR1 + R2;
	build AddCondNullify;
}

:SH2ADDL^AddCondSym R1,R2,RT	is opfam=0x02 & op=0x2A & m=0 & R1 & R2 & RT & AddCondNullify & AddCondSym {
	local shiftedR1 = R1 << 2;
	RT = shiftedR1 + R2;
	build AddCondNullify;
}

:SH2ADDO^AddCondSym R1,R2,RT	is opfam=0x02 & op=0x3A & m=0 & R1 & R2 & RT & AddCondNullify & AddCondSym {
	local shiftedR1 = R1 << 2;
	if (scarry(shiftedR1, R2)) goto <TRAP>;
	pswCB = carry(shiftedR1,R2);
	RT = shiftedR1 + R2;
	goto <DONE>;
	<TRAP>
	trap();
	<DONE>
	build AddCondNullify;
}

:SH3ADD^AddCondSym R1,R2,RT	is opfam=0x02 & op=0x1B & m=0 & R1 & R2 & RT & AddCondNullify & AddCondSym {
	local shiftedR1 = R1 << 3;
	pswCB = carry(shiftedR1,R2);
	RT = shiftedR1 + R2;
	build AddCondNullify;
}

:SH3ADDL^AddCondSym R1,R2,RT	is opfam=0x02 & op=0x2B & m=0 & R1 & R2 & RT & AddCondNullify & AddCondSym {
	local shiftedR1 = R1 << 3;
	RT = shiftedR1 + R2;
	build AddCondNullify;
}

:SH3ADDO^AddCondSym R1,R2,RT	is opfam=0x02 & op=0x3B & m=0 & R1 & R2 & RT & AddCondNullify & AddCondSym {
	local shiftedR1 = R1 << 3;
	if (scarry(shiftedR1, R2)) goto <TRAP>;
	pswCB = carry(shiftedR1,R2);
	RT = shiftedR1 + R2;
	goto <DONE>;
	<TRAP>
	trap();
	<DONE>
	build AddCondNullify;
}

:SUB^CSCondSym R1,R2,RT	is opfam=0x02 & op=0x10 & m=0 & R1 & R2 & RT & CSCondSym & CSCondNullify {
	pswCB = ! (R1 < R2);
	RT = R1 - R2;
	build CSCondNullify;
}

:SUB",O"^CSCondSym R1,R2,RT	is opfam=0x02 & op=0x30 & m=0 & R1 & R2 & RT & CSCondSym & CSCondNullify {
	if (sborrow(R1,R2)) goto <TRAP>;
	pswCB = ! (R1 < R2);
	RT = R1 - R2;
	build CSCondNullify;
	goto <DONE>;
	<TRAP>
	trap();
	<DONE>
}

:SUB",B"^CSCondSym R1,R2,RT	is opfam=0x02 & op=0x14 & m=0 & R1 & R2 & RT & CSCondSym & CSCondNullify {
	right:$(REGSIZE) = ~R2 + zext(pswCB);
	pswCB =  ! (R1 < right); #! carry(R1, right);
	RT = R1 + right;
	build CSCondNullify;
}

:SUB",BO"^CSCondSym R1,R2,RT	is opfam=0x02 & op=0x34 & m=0 & R1 & R2 & RT & CSCondSym & CSCondNullify {
	right:$(REGSIZE) = ~R2 + zext(pswCB);
	if (sborrow(R1,right)) goto <TRAP>;
	pswCB =  ! (R1 < right);
	RT = R1 + right;
	build CSCondNullify;
	goto <DONE>;
	<TRAP>
	trap();
	<DONE>
}

# subtract and trap on condition
# this instruction does not have a nullify form
:SUB",T"^CSCondSym R1,R2,RT	is opfam=0x02 & op=0x13 & m=0 & R1 & R2 & RT & CSCondSym & CSCond {
	pswCB = ! (R1 < R2);
	RT = R1 - R2;
	build CSCond;
	if (CSCond) goto <TRAP>;
	goto <DONE>;
	<TRAP>
	trap();
	<DONE>
}

:SUB",TO"^CSCondSym R1,R2,RT	is opfam=0x02 & op=0x33 & m=0 & R1 & R2 & RT & CSCondSym & CSCond {
	if (sborrow(R1,R2)) goto <TRAP>;
	pswCB = ! (R1<R2);
	RT = R1 - R2;
	build CSCond;
	if (CSCond) goto <TRAP>;
	goto <DONE>;
	<TRAP>
	trap();
	<DONE>
}

# R1 is partial remainder, R2 is denominator, RT is updated partial remainder
:DS^CSCondSym R1,R2,RT	is opfam=0x02 & op=0x11 & m=0 & R1 & R2 & RT & CSCondSym & CSCondNullify {
	local origR2 = R2;
	left:$(REGSIZE) =  (R1 << 1) | zext(pswCB);
	if (pswV) goto <MINUS>;
		right:$(REGSIZE) = R2;
		goto <CONTINUE>;
	<MINUS>
		right = ~R2 + 1;
	<CONTINUE>	

	RT = left + right;

	pswCB = carry(left,right);

# handle pswV -- I'm using R2 here, the book says R2, but non-restoring algorithms usually use R1, so
# this could be the error.
	shiftBit:1 = ((origR2 >> 31) & 0x1) == 1;
	pswV = pswCB ^ shiftBit;
		
# handle nullification -- TODO This condition is special and the stock CSCondNullify won't work -- broken -- see page 5-103
	build CSCondNullify;
}

:CMPCLR^CSCondSym R1,R2,RT	is opfam=0x02 & op=0x22 & m=0 & R1 & R2 & RT & CSCondSym & CSCondNullify
{
	build CSCondNullify; # must do this before setting register
	RT = 0;
}

# COPY is a pseudo-op using OR to move values between registers
:COPY R1,RT				is opfam=0x02 & op=0x09 & m=0 & R1 & reg2=0 & RT & c=0 & fv=0 {
	RT = R1;
 }
 
# nop is a pseudo-op for OR R0,R0, which is one way to make a nop
:NOP					is opfam=0x02 & op=0x09 & m=0 & reg1=0 & reg2=0 & t=0 & c=0 & fv=0 { } # intentionally left blank

:OR^LogicCondSym R1,R2,RT	is opfam=0x02 & op=0x09 & m=0 & R1 & R2 & RT & LogicCondSym & LogicCondNullify {
	RT = R1 | R2;
	build LogicCondNullify;
}

:XOR^LogicCondSym R1,R2,RT	is opfam=0x02 & op=0x0A & m=0 & R1 & R2 & RT & LogicCondSym & LogicCondNullify {
	RT = R1 ^ R2;
	build LogicCondNullify;
}

:AND^LogicCondSym R1,R2,RT	is opfam=0x02 & op=0x08 & m=0 & R1 & R2 & RT & LogicCondSym & LogicCondNullify {
	RT = R1 & R2;
	build LogicCondNullify;
}

:ANDCM^LogicCondSym R1,R2,RT	is opfam=0x02 & op=0x00 & m=0 & R1 & R2 & RT & LogicCondSym & LogicCondNullify {
	RT = R1 & ~R2;
	build LogicCondNullify;
}

:UXOR^UnitCondSym R1,R2,RT		is opfam=0x02 & op=0x0E & m=0 & R1 & R2 & RT & UnitCondSym & UnitCondNullify {
	RT = R1 ^ R2;
	build UnitCondNullify;
}

:UADDCM^UnitCondSym R1,R2,RT	is opfam=0x02 & op=0x26 & m=0 & R1 & R2 & RT & UnitCondSym & UnitCondNullify {
	RT = R1 + ~R2;
	build UnitCondNullify;
	
}

:UADDCMT^UnitCondSym R1,R2,RT	is opfam=0x02 & op=0x27 & m=0 & R1 & R2 & RT & UnitCond & UnitCondSym {
	if (UnitCond) goto <TRAP>;
	RT = R1 + ~R2;
	goto <DONE>;
	<TRAP>
	trap();
	<DONE>
}

:ADDI^AddCondSym lse11,R2,R1dst	is opfam=0x2D & bit11=0 & lse11 & R2 & R1dst & AddCondSym & AddCondI11Nullify {
	tmp:$(REGSIZE) = R2; # Don't clobber the original value, when R1 is the same as R2
	R1dst = R2 + lse11;
	pswCB = carry(tmp,lse11);
	build AddCondI11Nullify;
}

# PA1.1 this is ADDIO, PA2.0 is ADDI,TSV (trap on signed overflow)
:ADDI^",TSV"^AddCondSym lse11,R2,R1dst	is opfam=0x2D & bit11=1 & lse11 & R2 & R1dst & AddCondSym & AddCondI11Nullify {
        tmp:$(REGSIZE) = R2; # Don't clobber the original value, when R1 is the same as R2
	if (scarry(R2, lse11) == 1:1) goto <TRAP>;
	R1dst = R2 + lse11;
	pswCB = carry(tmp,sext(lse11));
	goto <DONE>;
	<TRAP>
	trap();
	<DONE>
	build AddCondI11Nullify;
}

# PA11 this is ADDIT, PA2.0 this is ADDI,TC
:ADDI^",TC"^AddCondSym lse11,R2,R1dst	is opfam=0x2C & bit11=0 & lse11 & R2 & R1dst & AddCondSym & AddCondI11 {
        tmp:$(REGSIZE) = R2; # Don't clobber the original value, when R1 is the same as R2
	R1dst = R2 + lse11;
	build AddCondI11;
	if (AddCondI11) goto <TRAP>;
	pswCB = carry(tmp,lse11);
	goto <DONE>;
	<TRAP>
	trap();
	<DONE>
}

# PA11 this is ADDITO, PA2.0 this is ADDI,TC,TSV
:ADDI^",TC,TSV"^AddCondSym lse11,R2,R1dst	is opfam=0x2C & bit11=1 & lse11 & R2 & R1dst & AddCondSym & AddCondI11 {
        tmp:$(REGSIZE) = R2; # Don't clobber the original value, when R1 is the same as R2
	R1dst = R2 + lse11;
	build AddCondI11;
	if (AddCondI11) goto <TRAP>;
	if (scarry(tmp, lse11) == 1:1) goto <TRAP>;
	pswCB = carry(tmp,lse11);
	goto <DONE>;
	<TRAP>
	trap();
	<DONE>
}

:SUBI^CSCondSym lse11,R2,R1dst		is opfam=0x25 & bit11=0 & lse11 & R2 & R1dst & CSCondI11Nullify & CSCondSym {
        tmp:$(REGSIZE) = R2; # Don't clobber the original value, when R1 is the same as R2
	R1dst = lse11 - R2;
	pswCB = !(lse11 < tmp);
	build CSCondI11Nullify;
}

:SUBI^",TSV"^CSCondSym lse11,R2,R1dst	is opfam=0x25 & bit11=1 & lse11 & R2 & R1dst & CSCondI11 & CSCondSym & CSCondI11Nullify {
        tmp:$(REGSIZE) = R2; # Don't clobber the original value, when R1 is the same as R2
	if (sborrow(lse11, R2) == 1:1) goto <TRAP>;
	R1dst = lse11 - R2;
	pswCB = !(lse11 < tmp);
	goto <DONE>;
	<TRAP>
	trap();
	<DONE>
	build CSCondI11Nullify;
}

:CMPICLR^CSCondSym lse11,R2,R1dst	is opfam=0x24 & bit11=0 & lse11 & R2 & R1dst & CSCondI11Nullify & CSCondSym
{
	R1dst = 0;
}

:SHRPW^SEDCondSym R1,R2,SAR,RT		is opfam=0x34 & subop1012=0 & bits59=0 & R1 & R2 & RT & ShiftCondNullify & SEDCondSym & SAR {
	left:8 = zext( (R1 & 0x7FFFFFFF) ) << 32;
	concat:8 = left | zext(R2);
	concat = concat >> SAR;
	nullifyCondResult=concat:$(REGSIZE);
	RT = concat:4;
	
	build ShiftCondNullify; 
}

# previously this was shd, now is shrpw form 14
:SHRPW^SEDCondSym R1,R2,shiftC,RT	is opfam=0x34 & R2 & R1 & subop1012=2 & shiftC & RT & SEDCondSym & ShiftCondNullify  {
	left:8 = zext( (R1 & 0x7FFFFFFF) ) << 32;
	concat:8 = left | zext(R2);
	concat = concat >> shiftC;
	nullifyCondResult=concat:$(REGSIZE);
	RT = concat:4;
	
	build ShiftCondNullify; 
}

# extract unsigned using SAR
:EXTRW",U"^SEDCondSym R2,SAR,shiftCLen,R1dst	is opfam=0x34 & bits59=0 & subop1012=4 & R2 & shiftCLen & R1dst & SEDCondSym & ExtrCondNullify & SAR {
	local value = R2 >> (31-SAR);
	mask:4 = 0xffffffff >> (32 - shiftCLen);
	nullifyCondResult = value & mask;
	R1dst = nullifyCondResult;
	
	build ExtrCondNullify; 
}

# extract signed using SAR
:EXTRW",S"^SEDCondSym R2,SAR,shiftCLen,R1dst	is opfam=0x34 & bits59=0 & subop1012=5 & R2 & shiftCLen & R1dst & SEDCondSym & ExtrCondNullify & SAR {
	local value = R2 s>> (31-SAR);
	value = value << (32 - shiftCLen);
	value = value s>> (32 - shiftCLen);
	nullifyCondResult = value;
	R1dst = value;
	build ExtrCondNullify;
}

# extract unsigned using immediate
:EXTRW^",U"^SEDCondSym R2,cp,shiftCLen,R1dst	is opfam=0x34 & subop1012=6 & cp & R2 & shiftCLen & R1dst & SEDCondSym & ExtrCondNullify & shiftC {
	local value = R2 >> shiftC;
	mask:4 = 0xffffffff >> (32-shiftCLen);
	nullifyCondResult = value & mask;
	R1dst = nullifyCondResult;

	build ExtrCondNullify;
}

# extract signed using immediate
:EXTRW^",S"^SEDCondSym R2,cp,shiftCLen,R1dst	is opfam=0x34 & subop1012=7 & cp & R2 & shiftC & shiftCLen & R1dst & SEDCondSym & ExtrCondNullify {
	local value = R2 s>> shiftC;
	value = value << (32 - shiftCLen);
	value = value s>> (32 - shiftCLen);
	nullifyCondResult = value;
	R1dst = value;
	build ExtrCondNullify;
}

# non-zeroing SAR version (VDEP)
:DEPW^SEDCondSym R1,SAR,shiftCLen,R2dst       is opfam=0x35 & bits59=0 & subop1012=1 & R1 & R2 & R2dst & shiftCLen & DepCondNullify & SEDCondSym & SAR {
        mask:4 = 0xffffffff >> (32-shiftCLen);
        local value = R1 & mask;
        value = value << (31-SAR);
        mask = mask << (31-SAR);
        local result = R2 & ~mask;
        result = result | value; 
        R2dst = result;
        nullifyCondResult = result;
        
        build DepCondNullify;
}

# non-zeroing constant version (DEP)
:DEPW^SEDCondSym R1,shiftC,shiftCLen,R2dst is opfam=0x35 & subop1012=3 & shiftC & shiftCLen & R1 & R2 & R2dst & DepCondNullify & SEDCondSym & cp {
        mask:4 = 0xffffffff >> (32-shiftCLen);
        local value = R1 & mask;
        value = value << cp;
        mask = mask << cp;
        local result = R2 & ~mask;
        result = result | value;
        R2dst = result;
        nullifyCondResult = result;
        build DepCondNullify;
}

# non-zeroing immediate SAR version (VDEPI)
:DEPWI^SEDCondSym highlse5,SAR,shiftCLen,R2dst is opfam=0x35 & bits59=0 & subop1012=5 & shiftCLen & highlse5 & R2 & R2dst & DepCondNullify & SEDCondSym & SAR {
        mask:4 = 0xffffffff >> (32 - shiftCLen);
        depbits:4 = sext(highlse5);
        depbits = sext(depbits); 
        local value = depbits & mask;
        value = value << (31-SAR);
        mask = mask << (31-SAR);
        local result = R2 & ~mask;
        result = result | value;
        R2dst = result;
        nullifyCondResult = result;
        build DepCondNullify;
}

# non-zeroing immediate constant version (DEPI)
:DEPWI^SEDCondSym highlse5,shiftC,shiftCLen,R2dst  is opfam=0x35 & subop1012=7 & shiftC & highlse5 & R2 & R2dst & shiftCLen & DepCondNullify & SEDCondSym & cp {
        mask:4 = 0xffffffff >> (32-shiftCLen);
        depbits:4 = sext(highlse5);
        local value = depbits & mask;
        value = value << cp;
        mask = mask << cp;
        local result = R2 & ~mask;
        result = result | value;
        R2dst = result;
        nullifyCondResult = result;
        build DepCondNullify;
}

# DEPW,Z SAR version (ZVDEP)
:DEPW",Z"^SEDCondSym R1,SAR,shiftCLen,R2dst        is opfam=0x35 & bits59=0 & subop1012=0 & R1 & shiftCLen & R2 & R2dst & DepCondNullify & SEDCondSym & SAR {
        mask:4 = 0xffffffff >> (32-shiftCLen);
        local value = R1 & mask;
        value = value << (31-SAR);
        R2dst = value;
        nullifyCondResult = value;
        build DepCondNullify;
}

# DEPW,Z constant version (ZDEP)
:DEPW^",Z"^SEDCondSym R1,shiftC,shiftCLen,R2dst    is opfam=0x35 & subop1012=2 & shiftC & R2 & R2dst & shiftCLen & R1 & DepCondNullify & SEDCondSym & cp {
        mask:4 = 0xffffffff >> (32-shiftCLen);
        local value = R1 & mask;
        value = value << cp;
        R2dst = value;
        nullifyCondResult = value;
        build DepCondNullify;
}

# DEPWI,Z SAR version (ZVDEPI)
:DEPWI",Z"^SEDCondSym highlse5,SAR,shiftCLen,R2dst is opfam=0x35 & SAR & bits59=0 & subop1012=4 & shiftCLen & highlse5 & R2dst & DepCondNullify & SEDCondSym {
        mask:4 = 0xffffffff >> (32-shiftCLen);
        depbits:4 = sext(highlse5);
        local value = depbits & mask;
        value = value << (31-SAR);
        R2dst = value;
        nullifyCondResult = value;
        build DepCondNullify;
}

# DEPWI,Z constant version (ZDEPI)
:DEPWI",Z"^SEDCondSym highlse5,shiftC,shiftCLen,R2dst      is opfam=0x35 & subop1012=6 & shiftC & highlse5 & R2dst & shiftCLen & DepCondNullify & SEDCondSym & cp {
        mask:4 = 0xffffffff >> (32-shiftCLen);
        depbits:4 = sext(highlse5);
        local value = depbits & mask;
        value = value << cp;
        nullifyCondResult = value;
        R2dst = value;

        build DepCondNullify;
}


# BCD instructions
:DCOR^UnitCondSym R2,RT		is opfam=0x02 & op=0x2E & R2 & reg1=0x0 & RT & UnitCond & UnitCondSym { } # TODO
:IDCOR^UnitCondSym R2,RT		is opfam=0x02 & op=0x2F & R2 & reg1=0x0 & RT & UnitCond & UnitCondSym { } # TODO

#################################################
# System Instructions
#################################################
define pcodeop break;
:BREAK im5,im13							is opfam=0x0 & sysop=0x00 & im5 & im13 { break(); }

:RFI									is opfam=0x0 & sysop=0x60 & im5=0x0 {
	iaoq_back = cr18;
	iaoq_front = cr18;
	iasq_back = cr17;
	iasq_front = cr17; 
	upperBits:8 = zext(iasq_front);
	lowerBits:8 = zext(iaoq_front);
	local returnAddr = (upperBits << 32) | lowerBits;
	goto [returnAddr];
 }

:RFI^",R"									is opfam=0x0 & sysop=0x65 & im5=0x0 {
	r1 = shr0;
	r8 = shr1;
	r9 = shr2;
	r16 = shr3;
	r17 = shr4;
	r24 = shr5;
	r25 = shr6;
	# psw = ipsw;

	iaoq_back = cr18;
	iaoq_front = cr18;
	iasq_back = cr17;
	iasq_front = cr17;
	upperBits:8 = zext(iasq_front);
	lowerBits:8 = zext(iaoq_front); 
	returnAddr:8 = (upperBits << 32) | lowerBits;
	goto [returnAddr];
}

:SSM highIm10,RT							is opfam=0x0 & sysop=0x6B & c=0x0 & highIm10 & RT {
	widePswG:4 = zext(pswG);
	widePswF:4 = zext(pswG);
	widePswR:4 = zext(pswG);
	widePswP:4 = zext(pswG);
	widePswD:4 = zext(pswG);
	widePswI:4 = zext(pswG);
	RT = (widePswG << 31) | (widePswF << 30) | (widePswR << 29) | (widePswP << 27) | (widePswD << 26) | (widePswI << 25);
	pswG = pswG || (highIm10 & 0x40);
	pswF = pswF || (highIm10 & 0x20);
	pswR = pswR || (highIm10 & 0x10);
	pswP = pswP || (highIm10 & 0x4); 
	pswD = pswD || (highIm10 & 0x2); 
	pswI = pswI || (highIm10 & 0x1); 
}

:RSM highIm10,RT							is opfam=0x0 & sysop=0x73 & c=0x0 & highIm10 & RT {
	widePswG:4 = zext(pswG);
	widePswF:4 = zext(pswG);
	widePswR:4 = zext(pswG);
	widePswP:4 = zext(pswG);
	widePswD:4 = zext(pswG);
	widePswI:4 = zext(pswG);
	RT = (widePswG << 31) | (widePswF << 30) | (widePswR << 29) | (widePswP << 27) | (widePswD << 26) | (widePswI << 25);
	pswG = pswG && ((highIm10 & 0x40:1) == 0);
	pswF = pswF && ((highIm10 & 0x20:1) == 0);
	pswR = pswR && ((highIm10 & 0x10:1) == 0);
	pswP = pswP && ((highIm10 & 0x4:1) == 0); 
	pswD = pswD && ((highIm10 & 0x2:1) == 0); 
	pswI = pswI && ((highIm10 & 0x1:1) == 0); 
 }

:MTSM R1								is opfam=0x0 & sysop=0xC3 & c=0x0 & im5=0 & R1 {
	pswG = ((R1 & 0x00000040:4) != 0);
	pswF = (R1 & 0x00000020:4) != 0;
	pswR = (R1 & 0x00000010:4) != 0;
	pswQ = (R1 & 0x00000008:4) != 0;
	pswP = (R1 & 0x00000004:4) != 0;
	pswD = (R1 & 0x00000002:4) != 0;
	pswI = (R1 & 0x00000001:4) != 0;
}

:LDSID SRRB,RT						is opfam=0x0 & sysop=0x85 & u=0 & RT & SRRB & SR & SRVAL {
											RT = SRVAL;
}

:MTSP R1,SR3bit							is opfam=0x0 & sysop=0xC1 & im5=0 & R1 & SR3bit {
	SR3bit = R1;
 }

:MTCTL R1,crname2						is opfam=0x0 & sysop=0xC2 & im5=0 & R1 & crname2 & cr {
	cr = R1;
 }

:MTSAR R1								is opfam=0x0 & sysop=0xC2 & im5=0 & R1 & crname2 & cr=11 {
	sar = (R1 & 0x1F);
 }

:MFSP SR3bit,RT							is opfam=0x0 & sysop=0x25 & reg1=0x0 & RT & SR3bit {
	RT = SR3bit;
}

:MFCTL crname2,RT						is opfam=0x0 & sysop=0x45 & RT & crname2 & reg1=0  & cr {
	RT = cr;
}

# this instruction is PA-RISC 2.0 only, but here to avoid disassembler comparison issues
:MFIA RT								is opfam=0x0 & sysop=0xA5 & RT & reg1=0 {
	RT = iaoq_front;
}

define pcodeop sync;
:SYNC									is opfam=0x0 & sysop=0x20 & im5=0 & c=0 & bit20=0 { sync(); } # sync cache
:SYNCDMA								is opfam=0x0 & sysop=0x20 & im5=0 & c=0 & bit20=1 { sync(); } # sync DMA
define pcodeop probe;
:PROBER SRRB,R1,RT					is opfam=0x1 & sysopshifted=0x46 & m=0 & SRRB & R1 & RT & SPCBASE { RT = probe(R1, SPCBASE); } # probe read
:PROBERI SRRB,highIm5,RT				is opfam=0x1 & sysopshifted=0xC6 & m=0 & SRRB & highIm5 & RT & SPCBASE { RT = probe(highIm5:1, SPCBASE); } # probe read imm
:PROBEW SRRB,R1,RT					is opfam=0x1 & sysopshifted=0x47 & m=0 & SRRB & R1 & RT & SPCBASE { RT = probe(R1, SPCBASE); } # probe write
:PROBEWI SRRB,highIm5,RT				is opfam=0x1 & sysopshifted=0xC7 & m=0 & SRRB & highIm5 & RT & SPCBASE { RT = probe(highIm5:1, SPCBASE); } # probe write imm
define pcodeop physicalAddress;
:LPA^sysCmplt RX^SRRB,RT  				is opfam=0x1 & sysopshifted=0x4D & sysCmplt & RX & SRRB & RT & SPCBASE { RT = physicalAddress(SPCBASE); } # virt to phy addr translation
define pcodeop coherenceIndex;
:LCI RX^SRRB,RT						is opfam=0x1 & sysopshifted=0x4C & m=0 & RX & SRRB & RT & SPCBASE { RT = coherenceIndex(SPCBASE); } # load coherence index
define pcodeop purgeTLB;
:PDTLB^sysCmplt RX^SRRB3bit				is opfam=0x1 & sysopshifted=0x48 & RX & SRRB3bit & sysCmplt & m=0 & SPCBASE { purgeTLB(RX, SPCBASE); }
:PDTLB^sysCmplt RX^SRRB3bit				is opfam=0x1 & sysopshifted=0x48 & RX & SRRB3bit & sysCmplt & m=1 & SPCBASE & RB { RB = RB + RX; purgeTLB(RX, SPCBASE); }

:PITLB^sysCmplt RX^SRRB3bit				is opfam=0x1 & sysopshifted=0x8 & RX & SRRB3bit & sysCmplt & m=0 & SPCBASE { purgeTLB(RX, SPCBASE); }
:PITLB^sysCmplt RX^SRRB3bit				is opfam=0x1 & sysopshifted=0x8 & RX & SRRB3bit & sysCmplt & m=1 & SPCBASE & RB { RB = RB + RX; purgeTLB(RX, SPCBASE); }

:PDTLBE^sysCmplt RX^SRRB3bit			is opfam=0x1 & sysopshifted=0x49 & RX & SRRB3bit & sysCmplt & m=0 & SPCBASE { purgeTLB(RX, SPCBASE); }
:PDTLBE^sysCmplt RX^SRRB3bit			is opfam=0x1 & sysopshifted=0x49 & RX & SRRB3bit & sysCmplt & m=1 & SPCBASE & RB { RB = RB + RX; purgeTLB(RX, SPCBASE); }

:PITLBE^sysCmplt RX^SRRB3bit			is opfam=0x1 & sysopshifted=0x9 & RX & SRRB3bit & sysCmplt & m=0 & SPCBASE { purgeTLB(RX, SPCBASE); }
:PITLBE^sysCmplt RX^SRRB3bit			is opfam=0x1 & sysopshifted=0x9 & RX & SRRB3bit & sysCmplt & m=1 & SPCBASE & RB { RB = RB + RX; purgeTLB(RX, SPCBASE); }

define pcodeop insertTLBEntry;
:IDTLBA R1,SRRB							is opfam=0x1 & sysopshifted=0x41 & m=0 & SRRB & R1 & SPCBASE & im5=0 { insertTLBEntry(SPCBASE, R1); }
:IITLBA R1,(SR3bit,RB)					is opfam=0x1 & sysopshiftedshort=0x01 & m=0 & SR3bit & RB & R1 & im5=0 { insertTLBEntry(SR3bit, RB, R1); }
:IDTLBP R1,SRRB							is opfam=0x1 & sysopshifted=0x40 & m=0 & SRRB & R1 & SPCBASE & im5=0 { insertTLBEntry(SPCBASE, R1); }
:IITLBP R1,(SR3bit,RB)					is opfam=0x1 & sysopshiftedshort=0x00 & m=0 & im5=0 & SR3bit & RB & R1 { insertTLBEntry(SR3bit, RB, R1); }
:IITLBT R1, R2							is opfam=0x1 & sysopshiftedshort=0x20 & m=0 & im5=0 & fpsub=0 & R2 & R1 { insertTLBEntry(R1, R2); }

define pcodeop purgeCache;
:PDC^indexedWordAccessCmplt RX^SRRB			is opfam=0x1 & sysopshifted=0x4E & indexedWordAccessCmplt & RX & SRRB & SPCBASE & im5=0 & m=0 { purgeCache(SPCBASE, RX); }
:PDC^indexedWordAccessCmplt RX^SRRB			is opfam=0x1 & sysopshifted=0x4E & indexedWordAccessCmplt & RX & SRRB & SPCBASE & RB & im5=0 & m=1 { purgeCache(SPCBASE, RX); RB = RB + RX; }

:FDC^indexedWordAccessCmplt RX^SRRB			is opfam=0x1 & sysopshifted=0x4A & indexedWordAccessCmplt & RX & SRRB & SPCBASE & m=0 { purgeCache(SPCBASE, RX); }
:FDC^indexedWordAccessCmplt RX^SRRB			is opfam=0x1 & sysopshifted=0x4A & indexedWordAccessCmplt & RX & SRRB & SPCBASE & RB & m=1 { purgeCache(SPCBASE, RX); RB = RB + RX; }

:FIC^indexedWordAccessCmplt RX(SR3bit,RB)		is opfam=0x1 & sysopshiftedshort=0x0A & indexedWordAccessCmplt & RX & SR3bit & RB & m=0 { purgeCache(SR3bit, RB, RX); }
:FIC^indexedWordAccessCmplt RX(SR3bit,RB)		is opfam=0x1 & sysopshiftedshort=0x0A & indexedWordAccessCmplt & RX & SR3bit & RB & m=1 { purgeCache(SR3bit, RB, RX); RB = RB + RX;}

:FDCE^indexedWordAccessCmplt RX^SRRB			is opfam=0x1 & sysopshifted=0x4B & indexedWordAccessCmplt & RX & SRRB & SPCBASE & m=0 { purgeCache(SPCBASE, RX); }
:FDCE^indexedWordAccessCmplt RX^SRRB			is opfam=0x1 & sysopshifted=0x4B & indexedWordAccessCmplt & RX & SRRB & SPCBASE & RB & m=1 { purgeCache(SPCBASE, RX); RB = RB + RX; }

:FICE^indexedWordAccessCmplt RX(SR3bit,RB) 	is opfam=0x1 & sysopshiftedshort=0x0B & indexedWordAccessCmplt & RX & SR3bit & RB & m=0 { purgeCache(SR3bit, RB, RX); }
:FICE^indexedWordAccessCmplt RX(SR3bit,RB) 	is opfam=0x1 & sysopshiftedshort=0x0B & indexedWordAccessCmplt & RX & SR3bit & RB & m=1 { purgeCache(SR3bit, RB, RX); RB = RB + RX; }

define pcodeop diag;
:DIAG im26								is opfam=0x05 & im26 { diag(im26:4); }

#################################################
# Coprocessor and Special Function Instructions
#################################################
:SPOP0,SFU^nullifyForSpecial sop					is opfam=0x04 & specop=0 & SFU & nullifyForSpecial & im5 & im15 [ sop=(im15 << 5) | im5; ] unimpl
:SPOP1,SFU^nullifyForSpecial sop					is opfam=0x04 & specop=1 & SFU & nullifyForSpecial & im5 & sopim10 [ sop=(sopim10 << 5) | im5; ] unimpl
:SPOP2,SFU^nullifyForSpecial sop R2					is opfam=0x04 & specop=2 & SFU & nullifyForSpecial & R2 & im5 & sopim5 [ sop=(sopim5 << 5) | im5; ] unimpl
:SPOP3,SFU^nullifyForSpecial sop R1,R2				is opfam=0x04 & specop=3 & SFU & nullifyForSpecial & R1 & R2 & im5 & sopim5 [ sop=(sopim5 << 5) | im5; ] unimpl
:COPR,SFU,sop^nullifyForSpecial						is opfam=0x0C & SFU & nullifyForSpecial & im5 & sopim17 [ sop=(sopim17 << 5) | im5; ] unimpl

:CLDW,SFU^indexedWordAccessCmplt^loadCC RX^SRRB,RT		is opfam=0x09 & bit9=0 & zero=0 & RX & SRRB & RT & SFU & indexedWordAccessCmplt & loadCC unimpl 
:CLDD,SFU^indexedDoublewordAccessCmplt^loadCC RX^SRRB,RT		is opfam=0x0B & bit9=0 & zero=0 & RX & SRRB & RT & SFU & indexedDoublewordAccessCmplt & loadCC unimpl
:CSTW,SFU^indexedWordAccessCmplt^storeCC RT,RX^SRRB	is opfam=0x09 & bit9=1 & zero=0 & RX & SRRB & RT & SFU & indexedWordAccessCmplt & storeCC unimpl
:CSTD,SFU^indexedDoublewordAccessCmplt^storeCC RT,RX^SRRB	is opfam=0x0B & bit9=1 & zero=0 & RX & SRRB & RT & SFU & indexedDoublewordAccessCmplt & storeCC unimpl

:CLDW,SFU^shortDispCmplt^loadCC highlse5^SRRB,RT	is opfam=0x09 & bit9=0 & one=1 & SRRB & RT & SFU & highlse5 & shortDispCmplt & loadCC unimpl 
:CLDD,SFU^shortDispCmplt^loadCC highlse5^SRRB,RT	is opfam=0x0B & bit9=0 & one=1 & SRRB & RT & SFU & highlse5 & shortDispCmplt & loadCC unimpl 
:CSTW,SFU^shortDispCmplt^storeCC RT,highlse5^SRRB	is opfam=0x09 & bit9=1 & one=1 & SRRB & RT & SFU & highlse5 & shortDispCmplt & storeCC unimpl 
:CSTD,SFU^shortDispCmplt^storeCC RT,highlse5^SRRB	is opfam=0x0B & bit9=1 & one=1 & SRRB & RT & SFU & highlse5 & shortDispCmplt & storeCC unimpl
 
 
#################################################
# Floating Point Instructions
#################################################
# These ld/st instructions are the same as the coprocessor instructions, with an SFU of zero or one

# Floating Point Loads, 32 bit, indirect/indexed
:FLDW^indexedWordAccessCmplt^loadCC RX^SRRB,FPRT32		is opfam=0x09 & zero=0 & bit9=0 & bits78=0 & indexedWordAccessCmplt & loadCC & SRRB & RX & FPRT32 & SPCBASE & u=0 & m=0 {
	addr:$(ADDRSIZE) = SPCBASE + sext(RX);
    FPRT32 = zext(*:4 addr);
} 

:FLDW^indexedWordAccessCmplt^loadCC RX^SRRB,FPRT32		is opfam=0x09 & zero=0 & bit9=0 & bits78=0 & indexedWordAccessCmplt & loadCC & SRRB & RX & FPRT32 & SPCBASE & u=1 & m=0 {
	addr:$(ADDRSIZE) = SPCBASE + (sext(RX) << 2);
    FPRT32 = zext(*:4 addr);
} 

:FLDW^indexedWordAccessCmplt^loadCC RX^SRRB,FPRT32		is opfam=0x09 & zero=0 & bit9=0 & bits78=0 & indexedWordAccessCmplt & loadCC & SRRB & RX & RB & FPRT32 & SPCBASE & u=0 & m=1 {
	addr:$(ADDRSIZE) = SPCBASE + sext(RX);
    FPRT32 = zext(*:4 addr);
    RB = RB + RX;
} 

:FLDW^indexedWordAccessCmplt^loadCC RX^SRRB,FPRT32		is opfam=0x09 & zero=0 & bit9=0 & bits78=0 & indexedWordAccessCmplt & loadCC & SRRB & RB & RX & FPRT32 & SPCBASE & u=1 & m=1 {
	addr:$(ADDRSIZE) = SPCBASE + (sext(RX) << 2);
    FPRT32 = zext(*:4 addr);
    RB = RB + RX;
} 

# Floating Point Loads, 64 bit, indirect/indexed
:FLDD^indexedDoublewordAccessCmplt^loadCC RX^SRRB,FPRT64		is opfam=0x0B & zero=0 & bit9=0 & sfu=0 & indexedDoublewordAccessCmplt & loadCC & SRRB & RX & FPRT64 & SPCBASE & u=0 & m=0 {
	addr:$(ADDRSIZE) = SPCBASE + sext(RX);
    FPRT64 = zext(*:8 addr);
} 

:FLDD^indexedDoublewordAccessCmplt^loadCC RX^SRRB,FPRT64		is opfam=0x0B & zero=0 & bit9=0 & sfu=0 & indexedDoublewordAccessCmplt & loadCC & SRRB & RX & FPRT64 & SPCBASE & u=1 & m=0 {
	addr:$(ADDRSIZE) = SPCBASE + (sext(RX) << 2);
    FPRT64 = zext(*:8 addr);
} 

:FLDD^indexedDoublewordAccessCmplt^loadCC RX^SRRB,FPRT64		is opfam=0x0B & zero=0 & bit9=0 & sfu=0 & indexedDoublewordAccessCmplt & loadCC & SRRB & RX & RB & FPRT64 & SPCBASE & u=0 & m=1 {
	addr:$(ADDRSIZE) = SPCBASE + sext(RX);
    FPRT64 = zext(*:8 addr);
    RB = RB + RX;
} 

:FLDD^indexedDoublewordAccessCmplt^loadCC RX^SRRB,FPRT64		is opfam=0x0B & zero=0 & bit9=0 & sfu=0 & indexedDoublewordAccessCmplt & loadCC & SRRB & RB & RX & FPRT64 & SPCBASE & u=1 & m=1 {
	addr:$(ADDRSIZE) = SPCBASE + (sext(RX) << 3);
    FPRT64 = zext(*:8 addr);
    RB = RB + RX;
} 


# Floating Point Stores -- 32 and 64 bits
:FSTW^indexedWordAccessCmplt^storeCC FPRT32,RX^SRRB		is opfam=0x09 & zero=0 & bit9=1 & bits78=0 & indexedWordAccessCmplt & storeCC & SRRB & RX & FPRT32 & SPCBASE & u=0 & m=0 {
	addr:$(ADDRSIZE) = SPCBASE + sext(RX);
	*addr = FPRT32:4; 
}

:FSTW^indexedWordAccessCmplt^storeCC FPRT32,RX^SRRB		is opfam=0x09 & zero=0 & bit9=1 & bits78=0 & indexedWordAccessCmplt & storeCC & SRRB & RX & FPRT32 & SPCBASE & u=1 & m=0 {
	addr:$(ADDRSIZE) = SPCBASE + (sext(RX) << 2);
	*addr = FPRT32:4; 
}

:FSTW^indexedWordAccessCmplt^storeCC FPRT32,RX^SRRB		is opfam=0x09 & zero=0 & bit9=1 & bits78=0 & indexedWordAccessCmplt & storeCC & SRRB & RX & RB & FPRT32 & SPCBASE & u=0 & m=1 {
	addr:$(ADDRSIZE) = SPCBASE + sext(RX);
	*addr = FPRT32:4; 
    RB = RB + RX;
}

:FSTW^indexedWordAccessCmplt^storeCC FPRT32,RX^SRRB		is opfam=0x09 & zero=0 & bit9=1 & bits78=0 & indexedWordAccessCmplt & storeCC & SRRB & RX & RB & FPRT32 & SPCBASE & u=1 & m=1 {
	addr:$(ADDRSIZE) = SPCBASE + (sext(RX) << 2);
	*addr = FPRT32:4; 
    RB = RB + RX;
}

:FSTD^indexedDoublewordAccessCmplt^storeCC FPRT64,RX^SRRB		is opfam=0x0B & zero=0 & bit9=1 & bits78=0 & indexedDoublewordAccessCmplt & storeCC & SRRB & RX & FPRT64 & SPCBASE & u=0 & m=0 {
	addr:$(ADDRSIZE) = SPCBASE + sext(RX);
	*addr = FPRT64:8; 
}

:FSTD^indexedDoublewordAccessCmplt^storeCC FPRT64,RX^SRRB		is opfam=0x0B & zero=0 & bit9=1 & bits78=0 & indexedDoublewordAccessCmplt & storeCC & SRRB & RX & FPRT64 & SPCBASE & u=1 & m=0 {
	addr:$(ADDRSIZE) = SPCBASE + (sext(RX) << 3);
	*addr = FPRT64:8; 
}

:FSTD^indexedDoublewordAccessCmplt^storeCC FPRT64,RX^SRRB		is opfam=0x0B & zero=0 & bit9=1 & bits78=0 & indexedDoublewordAccessCmplt & storeCC & SRRB & RX & RB & FPRT64 & SPCBASE & u=0 & m=1 {
	addr:$(ADDRSIZE) = SPCBASE + sext(RX);
	*addr = FPRT64:8; 
    RB = RB + RX;
}

:FSTD^indexedDoublewordAccessCmplt^storeCC FPRT64,RX^SRRB		is opfam=0x0B & zero=0 & bit9=1 & bits78=0 & indexedDoublewordAccessCmplt & storeCC & SRRB & RX & RB & FPRT64 & SPCBASE & u=1 & m=1 {
	addr:$(ADDRSIZE) = SPCBASE + (sext(RX) << 2);
	*addr = FPRT64:8; 
    RB = RB + RX;
}


# Floating Point Load Word with Short Displacement, no modification to RB
:FLDW^shortDispCmplt^loadCC highlse5^SRRB,FPRT32	is opfam=0x09 & one=1 & bit9=0 & bits78=0 & shortDispCmplt & loadCC & SRRB & SPCBASE & FPRT32 & highlse5 & m=0 {
	addr:$(ADDRSIZE) = SPCBASE + sext(highlse5);
    FPRT32 = zext(*:4 addr);
}

# Floating Point Load Word with Short Displacement, post-modification to RB
:FLDW^shortDispCmplt^loadCC highlse5^SRRB,FPRT32	is opfam=0x09 & one=1 & bit9=0 & bits78=0 & shortDispCmplt & loadCC & SRRB & SPCBASE & FPRT32 & RB & highlse5 & m=1 & u=0 {
	addr:$(ADDRSIZE) = SPCBASE;
    FPRT32 = zext(*:4 addr);
    RB = RB + sext(highlse5);
}

# Floating Point Load Word with Short Displacement, pre-modification to RB
:FLDW^shortDispCmplt^loadCC highlse5^SRRB,FPRT32	is opfam=0x09 & one=1 & bit9=0 & bits78=0 & shortDispCmplt & loadCC & SRRB & RB & SPCBASE & FPRT32 & highlse5 & m=1 & u=1 {
	addr:$(ADDRSIZE) = SPCBASE + sext(highlse5);
    FPRT32 = zext(*:4 addr);
    RB = RB + sext(highlse5);
}

:FLDD^shortDispCmplt^loadCC highlse5^SRRB,FPRT64	is opfam=0x0B & one=1 & bit6=0 & bits78=0 & bit9=0 & shortDispCmplt & loadCC & SRRB & SPCBASE & FPRT64 & highlse5 & m=0 {
	addr:$(ADDRSIZE) = SPCBASE + sext(highlse5);
    FPRT64 = zext(*:8 addr);
}

:FLDD^shortDispCmplt^loadCC highlse5^SRRB,FPRT64	is opfam=0x0B & one=1 & bit6=0 & bits78=0 & bit9=0 & shortDispCmplt & loadCC & SRRB & RB & SPCBASE & FPRT64 & highlse5 & m=1 & u=0 {
	addr:$(ADDRSIZE) = SPCBASE;
    FPRT64 = zext(*:8 addr);
    RB = RB + sext(highlse5);
}

:FLDD^shortDispCmplt^loadCC highlse5^SRRB,FPRT64	is opfam=0x0B & one=1 & bit6=0 & bits78=0 & bit9=0 & shortDispCmplt & loadCC & SRRB & RB & SPCBASE & FPRT64 & highlse5 & m=1 & u=1 {
	addr:$(ADDRSIZE) = SPCBASE + sext(highlse5);
    FPRT64 = zext(*:8 addr);
    RB = RB + sext(highlse5);
}

:FSTW^shortDispCmplt^storeCC FPRT32,highlse5^SRRB	is opfam=0x09 & one=1 & bits78=0 & bit9=1 & shortDispCmplt & storeCC & SRRB & SPCBASE & FPRT32 & highlse5 & m=0 {
	addr:$(ADDRSIZE) = SPCBASE + sext(highlse5);
	*addr = FPRT32:4; 
}

:FSTW^shortDispCmplt^storeCC FPRT32,highlse5^SRRB	is opfam=0x09 & one=1 & bits78=0 & bit9=1 & shortDispCmplt & storeCC & SRRB & SPCBASE & RB & FPRT32 & highlse5 & m=1 & u=0 {
	addr:$(ADDRSIZE) = SPCBASE;
	*addr = FPRT32:4;
	RB = RB + sext(highlse5);
}

:FSTW^shortDispCmplt^storeCC FPRT32,highlse5^SRRB	is opfam=0x09 & one=1 & bits78=0 & bit9=1 & shortDispCmplt & storeCC & SRRB & SPCBASE & RB & FPRT32 & highlse5 & m=1 & u=1 {
	addr:$(ADDRSIZE) = SPCBASE + sext(highlse5);
	*addr = FPRT32:4;
	RB = RB + sext(highlse5);
}

:FSTD^shortDispCmplt^storeCC FPRT64,highlse5^SRRB	is opfam=0x0B & one=1 & bit6=0 & bits78=0 & bit9=1 & shortDispCmplt & storeCC & SRRB & SPCBASE & FPRT64 & highlse5 & m=0 {
	addr:$(ADDRSIZE) = SPCBASE + sext(highlse5);
	*addr = FPRT64:8; 
}

:FSTD^shortDispCmplt^storeCC FPRT64,highlse5^SRRB	is opfam=0x0B & one=1 & bit6=0 & bits78=0 & bit9=1 & shortDispCmplt & storeCC & SRRB & RB & SPCBASE & FPRT64 & highlse5 & u=0 & m=1 {
	addr:$(ADDRSIZE) = SPCBASE;
	*addr = FPRT64:8;
	RB = RB + sext(highlse5);
}

:FSTD^shortDispCmplt^storeCC FPRT64,highlse5^SRRB	is opfam=0x0B & one=1 & bit6=0 & bits78=0 & bit9=1 & shortDispCmplt & storeCC & SRRB & RB & SPCBASE & FPRT64 & highlse5 & u=1 & m=1 {
	addr:$(ADDRSIZE) = SPCBASE + sext(highlse5);
	*addr = FPRT64:8;
	RB = RB + sext(highlse5);
}

# Floating Point Format Conversion Instructions
:FCNV^fpsf^fpdf FPR232,FPRT32						is opfam=0x0E & fpclass=1 & fpc1sub=0 & fpc1sub2=0 & FPR232 & FPRT32 & fpsf & fpdf {
	FPRT32 = float2float(FPR232);
}
 
:FCNV^fpsf^fpdf FPR264,FPRT64						is opfam=0x0C & fpclass=1 & fpc1sub=0 & fpc1sub2=0 & sfu=0 & bit5=0 & FPR264 & FPRT64 & fpsf & fpsfraw=0 & fpdf & freg2sgl & fptsgl {
# if src format is sgl, this is sgl to dbl
# if src format is dbl, this is dbl to sgl
# sgl to sgl or dbl to dbl don't make sense
# and we don't support quad right now	
	FPRT64 = float2float(freg2sgl);
}

:FCNV^fpsf^fpdf FPR264,FPRT64						is opfam=0x0C & fpclass=1 & fpc1sub=0 & fpc1sub2=0 & sfu=0 & bit5=0 & FPR264 & FPRT64 & fpsf & fpsfraw=1 & fpdf & freg2sgl & fptsgl {
# if src format is sgl, this is sgl to dbl
# if src format is dbl, this is dbl to sgl
# sgl to sgl or dbl to dbl don't make sense
# and we don't support quad right now	
	fptsgl = float2float(FPR264);
}
 
:FCNVXF^fpsf^fpdf FPR232,FPRT32							is opfam=0x0E & fpclass=1 & fpc1sub=1 & fpc1sub2=0 & FPR232 & FPRT32 & fpsf & fpdf {
	FPRT32 = int2float(FPR232);
} 

# int2float -- support single/double size ints and single/double floats
# so handle 4 different cases
:FCNVXF^fixedsf^fpdf FPR264,FPRT64							is opfam=0x0C & fpclass=1 & fpc1sub=1 & fpc1sub2=0 & FPR264 & FPRT64 & sfu=0 & fixedsf & fpdf & fptsgl & freg2sgl & fpsfraw=0 & fpdfraw=0 {
	fptsgl = int2float(freg2sgl);
}

:FCNVXF^fixedsf^fpdf FPR264,FPRT64							is opfam=0x0C & fpclass=1 & fpc1sub=1 & fpc1sub2=0 & FPR264 & FPRT64 & sfu=0 & fixedsf & fpdf & fptsgl & freg2sgl & fpsfraw=0 & fpdfraw=1 {
	FPRT64 = int2float(freg2sgl);
}

:FCNVXF^fixedsf^fpdf FPR264,FPRT64							is opfam=0x0C & fpclass=1 & fpc1sub=1 & fpc1sub2=0 & FPR264 & FPRT64 & sfu=0 & fixedsf & fpdf & fptsgl & freg2sgl & fpsfraw=1 & fpdfraw=0 {
	fptsgl = int2float(FPR264);
}

:FCNVXF^fixedsf^fpdf FPR264,FPRT64							is opfam=0x0C & fpclass=1 & fpc1sub=1 & fpc1sub2=0 & FPR264 & FPRT64 & sfu=0 & fixedsf & fpdf & fptsgl & freg2sgl & fpsfraw=1 & fpdfraw=1 {
	FPRT64 = int2float(FPR264);
}

:FCNVFX^fpsf^fixeddf FPR232,FPRT32							is opfam=0x0E & fpclass=1 & fpc1sub=2 & fpc1sub2=0 & FPR232 & FPRT32 & fpsf & fixeddf {
	temp:4 = round(FPR232);
	FPRT32 = trunc(temp);
}

:FCNVFX^fpsf^fixeddf FPR264,FPRT64							is opfam=0x0C & fpclass=1 & fpc1sub=2 & fpc1sub2=0 & sfu=0 & FPR264 & FPRT64 & fpsf & fpsfraw=1 & fixeddf & fptsgl & freg2sgl {
	local temp:8 = FPR264; 
	temp = round(temp);
	FPRT64 = trunc(temp);
} 

:FCNVFX^fpsf^fixeddf FPR264,FPRT64							is opfam=0x0C & fpclass=1 & fpc1sub=2 & fpc1sub2=0 & sfu=0 & FPR264 & FPRT64 & fpsf & fpsfraw=0 & fixeddf & fptsgl & freg2sgl {
	local temp:8 = float2float(freg2sgl); # convert single precision to double
	temp = round(temp);
	FPRT64 = trunc(temp);
}
 
:FCNVFXT^fpsf^fixeddf FPR232,FPRT32						is opfam=0x0E & fpclass=1 & fpc1sub=3 & fpc1sub2=0 & FPR232 & FPRT32 & fpsf & fixeddf {
	FPRT32 = trunc(FPR232);
} 

:FCNVFXT^fpsf^fixeddf FPR264,FPRT64						is opfam=0x0C & fpclass=1 & fpc1sub=3 & fpc1sub2=0 & sfu=0 & FPR264 & FPRT64 & fpsf & fpsfraw=1 & fixeddf & fpsfraw & fptsgl & freg2sgl {
	local value:4 = float2float(FPR264); # convert double precision to single
	fptsgl = trunc(value);
}

:FCNVFXT^fpsf^fixeddf FPR264,FPRT64						is opfam=0x0C & fpclass=1 & fpc1sub=3 & fpc1sub2=0 & sfu=0 & FPR264 & FPRT64 & fpsf & fpsfraw=0 & fixeddf & fpsfraw & fptsgl & freg2sgl {
	local value:4 = freg2sgl; # get single precision value from left half of 64 bit register
	fptsgl = trunc(value);
}

 # Floating Point Functions
:FCPY^fpfmt FPR232,FPRT32								is opfam=0x0E & fpclass=0 & fpsub=2 & freg1=0 & FPR232 & FPRT32 & fpfmt {
	FPRT32 = FPR232;
} 

:FCPY^fpfmt FPR264,FPRT64								is opfam=0x0C & fpclass=0 & fpsub=2 & freg1=0 & FPR264 & FPRT64 & fpfmt & fpsfraw=1 & fptsgl & freg2sgl {
	fptsgl = freg2sgl;
}

:FCPY^fpfmt FPR264,FPRT64								is opfam=0x0C & fpclass=0 & fpsub=2 & freg1=0 & FPR264 & FPRT64 & fpfmt & fpsfraw=0 & fptsgl & freg2sgl {
	FPRT64 = FPR264;
}

:FABS^fpfmt FPR232,FPRT32								is opfam=0x0E & fpclass=0 & fpsub=3 & freg1=0 & bit5=0 & bit8=0 & FPR232 & FPRT32 & fpfmt {
	FPRT32 = abs(FPR232);
} 

:FABS^fpfmt FPR264,FPRT64								is opfam=0x0C & fpclass=0 & fpsub=3 & freg1=0 & bits59=0 & bit10=0 & FPR264 & FPRT64 & fpfmt {
	FPRT64 = abs(FPR264);
}

:FSQRT^fpfmt FPR232,FPRT32								is opfam=0x0E & fpclass=0 & fpsub=4 & freg1=0 & FPR232 & FPRT32 & fpfmt {
	FPRT32 = sqrt(FPR232);
} 
:FSQRT^fpfmt FPR264,FPRT64								is opfam=0x0C & fpclass=0 & fpsub=4 & freg1=0 & FPR264 & FPRT64 & fpfmt {
	FPRT64 = sqrt(FPR264);
}

:FRND^fpfmt FPR232,FPRT32								is opfam=0x0E & fpclass=0 & fpsub=5 & FPR232 & FPRT32 & fpfmt {
	FPRT32 = round(FPR232);
 } 

:FRND^fpfmt FPR264,FPRT64								is opfam=0x0C & fpclass=0 & fpsub=5 & FPR264 & FPRT64 & fpfmt {
	FPRT64 = round(FPR264);
}

:FADD^fpfmt FPR232,FPR132,FPRT32							is opfam=0x0E & fpclass=3 & fpsub=0 & FPR232 & FPR132 & FPRT32 & fpfmt {
	FPRT32 = FPR132 f+ FPR232;
} 

:FADD^fpfmt FPR264,FPR164,FPRT64							is opfam=0x0C & fpclass=3 & fpsub=0 & FPR264 & FPRT64 & FPR164 & fpfmt & fpsfraw=0 & freg1sgl & freg2sgl & fptsgl {
	fptsgl = freg1sgl f+ freg2sgl;
}

:FADD^fpfmt FPR264,FPR164,FPRT64							is opfam=0x0C & fpclass=3 & fpsub=0 & FPR264 & FPRT64 & FPR164 & fpfmt & fpsfraw=1 & freg1sgl & freg2sgl & fptsgl {
	FPRT64 = FPR164 f+ FPR264;
}

:FSUB^fpfmt FPR232,FPR132,FPRT32							is opfam=0x0E & fpclass=3 & fpsub=1 & FPR232 & FPR132 & FPRT32 & fpfmt {
	FPRT32 = FPR232 f- FPR132;
} 

:FSUB^fpfmt FPR264,FPR164,FPRT64							is opfam=0x0C & fpclass=3 & fpsub=1 & FPR264 & FPRT64 & FPR164 & fpfmt & fpsfraw=0 & fptsgl & freg1sgl & freg2sgl {
	fptsgl = freg2sgl f- freg1sgl;
}

:FSUB^fpfmt FPR264,FPR164,FPRT64							is opfam=0x0C & fpclass=3 & fpsub=1 & FPR264 & FPRT64 & FPR164 & fpfmt & fpsfraw=1 & fptsgl & freg1sgl & freg2sgl {
	FPRT64 = FPR264 f- FPR164;
}

:FMPY^fpfmt FPR232,FPR132,FPRT32							is opfam=0x0E & fpclass=3 & fpsub=2 & bit8=0 & FPR232 & FPR132 & FPRT32 & fpfmt {
	FPRT32 = FPR132 f* FPR232;
} 

:FMPY^fpfmt FPR264,FPR164,FPRT64							is opfam=0x0C & fpclass=3 & fpsub=2 & bit8=0 & FPR264 & FPRT64 & FPR164 & fpfmt & fpsfraw=0 & fptsgl & freg1sgl & freg2sgl {
	fptsgl = freg1sgl f* freg2sgl;
}

:FMPY^fpfmt FPR264,FPR164,FPRT64							is opfam=0x0C & fpclass=3 & fpsub=2 & bit8=0 & FPR264 & FPRT64 & FPR164 & fpfmt & fpsfraw=1 & fptsgl & freg1sgl & freg2sgl {
	FPRT64 = FPR164 f* FPR264;
}

:FDIV^fpfmt FPR232,FPR132,FPRT32							is opfam=0x0E & fpclass=3 & fpsub=3 & FPR232 & FPR132 & FPRT32 & fpfmt {
	FPRT32 = FPR232 f/ FPR132;
} 

:FDIV^fpfmt FPR264,FPR164,FPRT64							is opfam=0x0C & fpclass=3 & fpsub=3 & FPR264 & FPRT64 & FPR164 & fpfmt & fpsfraw=0 & fptsgl & freg1sgl & freg2sgl {
	fptsgl = freg2sgl f/ freg1sgl;
}

:FDIV^fpfmt FPR264,FPR164,FPRT64							is opfam=0x0C & fpclass=3 & fpsub=3 & FPR264 & FPRT64 & FPR164 & fpfmt & fpsfraw=1 & fptsgl & freg1sgl & freg2sgl {
	FPRT64 = FPR264 f/ FPR164;
}

# 64 bit version
:FMPYADD^fusedfmt FPR264,FPR164,FPRT64,fpra,fpta				is opfam=0x06 & FPR264 & FPR164 & FPRT64 & fusedfmt & fpra & fpta & bit5=0 {
	FPRT64 = FPR164 f* FPR264;
	fpta = fpta f+ fpra;
}

# 32 bit version -- this uses a special encoding of the 32 bit registers and can only use 16-31{LR}, not the lower registers
:FMPYADD^fusedfmt FUSEDR2,FUSEDR1,FUSEDRT,FUSEDRA,FUSEDTA				is opfam=0x06 & FUSEDR2 & FUSEDR1 & FUSEDRT & fusedfmt & FUSEDRA & FUSEDTA & bit5=1 {
	FUSEDRT = FUSEDR1 f* FUSEDR2;
	FUSEDTA = FUSEDTA f+ FUSEDRA;

}

:FMPYSUB^fusedfmt FPR264,FPR164,FPRT64,fpra,fpta				is opfam=0x26 & FPR264 & FPR164 & FPRT64 & fusedfmt & fpra & fpta & bit5=0 {
	FPRT64 = FPR164 f* FPR264;
	fpta = fpta f- fpra;
}

:FMPYSUB^fusedfmt FUSEDR2,FUSEDR1,FUSEDRT,FUSEDRA,FUSEDTA				is opfam=0x26 & FUSEDR2 & FUSEDR1 & FUSEDRT & fusedfmt & FUSEDRA & FUSEDTA & bit5=1 {
	FUSEDRT = FUSEDR1 f* FUSEDR2;
	FUSEDTA = FUSEDTA f- FUSEDRA;
}

# Fixed Point / Integer Multiply
:XMPYU^fpfmt FPR232,FPR132,FPRT64								is opfam=0x0E & fpclass=3 & fpsub=2 & bit8=1 & FPR232 & FPR132 & FPRT64 & fpfmt & fptsgl {
	arg1:8 = zext(FPR232);
	arg2:8 = zext(FPR132);
	prod:8 = arg1 * arg2;
	FPRT64 = prod;
 } 

# Floating Point Compare
# 32 bit register comparison
:FCMP^fpfmt1bit^fpcmp FPR232,FPR132						is opfam=0x0E & fpclass=2 & fpsub=0 & FPR232 & FPR132 & fpfmt1bit & bit11=0 & fpcmp {
	local result:1 = 0:1;
	# shift the previous compareBit onto the compareQueue
	compareQueue = (compareQueue << 1);
	compareQueue = compareQueue | compareBit;
	result = fpcmp;
	compareBit = result;
}

:FCMP^fpfmt1bit^fpcmp64 FPR232,FPR132						is opfam=0x0E & fpclass=2 & fpsub=0 & FPR232 & FPR132 & fpfmt1bit & bit11=1 & fpcmp64 {
	local result:1 = 0:1;
	# shift the previous compareBit onto the compareQueue
	compareQueue = (compareQueue << 1);
	compareQueue = compareQueue | compareBit;
	result = fpcmp64;
	compareBit = result;
}

# 64 bit register comparison 
:FCMP^fpfmt^fpcmp FPR264,FPR164						is opfam=0x0C & fpclass=2 & fpsub=0 & FPR264 & FPR164 & fpfmt & fpsfraw=0 & fpcmp {
	local result:1 = 0:1;
	# shift the previous compareBit onto the compareQueue
	compareQueue = (compareQueue << 1);
	compareQueue = compareQueue | compareBit;
	result = fpcmp;
	compareBit = result;
}

:FCMP^fpfmt^fpcmp64 FPR264,FPR164						is opfam=0x0C & fpclass=2 & fpsub=0 & FPR264 & FPR164 & fpfmt & fpsfraw=1 & fpcmp64 {
	local result:1 = 0:1;
	# shift the previous compareBit onto the compareQueue
	compareQueue = (compareQueue << 1);
	compareQueue = compareQueue | compareBit;
	result = fpcmp64;
	compareBit = result;
}

:FTEST^fptest										is opfam=0x0C & fpclass=2 & fpsub=1 & fptest & $(COMMON)
	[
	  nullifyEnable = 1;
	  globalset(inst_next, nullifyEnable);
	] 
{
	nullifyNextCond = compareBit;
}

# Misc Floating Point Functions
:COPR.0.0											is opfam=0x0C & im26=0x0 { }

###############################################################
# Performance Montioring Unit Instructions
###############################################################
:PMENB												is opfam=0x0C & bit5=0  & sfu=0x2 & pmuop=0x3 { }
:PMDIS												is opfam=0x0C & bit5=0  & sfu=0x2 & pmuop=0x1 { }

} # end with : phase=1
