/**
 * @file      nios32_isa.ac
 * @author    Renato Herebia
 *
 *            The ArchC Team
 *            http://www.archc.org/
 *
 *            Engenharia de Computação
 *            UCDB
 *
 * @version   1.0
 * @date      Mon, 21 Apr 2008 10:25
 * 
 * @brief     The ArchC Altera/NIOS cycle-accurate model.
 * 
 * @attention Copyright (C) 2002-2006 --- The ArchC Team
 * 
 * This program is free software; you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version. 
 * 
 * This program is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * GNU General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with this program; if not, write to the Free Software 
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

AC_ISA(nios32){


	ac_format Format_RR = "%op6:6 %rb:5 %ra:5 %nu:16";
	ac_format Format_Ri5 = "%op6:6 %imm5:5 %ra:5 %nu:16";
	ac_format Format_Ri4 = "%op6:6 0x00:1 %imm4:4 %ra:5 %nu:16";
	ac_format Format_RPi5 = "%op4:4 %rp:2 %imm5:5 %ra:5 %nu:16";
	ac_format Format_Ri6 = "%op5:5 %imm6:6 %ra:5 %nu:16";
	ac_format Format_Ri8 = "%op3:3 %imm8:8 %ra:5 %nu:16";
	ac_format Format_i9 = "%op6:6 %imm9:9 0x00:1 %nu:16";
	ac_format Format_i10 = "%op6:6 %imm10:10 %nu:16";
	ac_format Format_i11 = "%op5:5 %imm11:11 %nu:16";
	ac_format Format_Ri1u = "%op6:6 %op3u:3 %imm1u:1 0x00:1 %ra:5 %nu:16";
	ac_format Format_Ri2u = "%op6:6 %op3u:3 %imm2u:2 %ra:5 %nu:16";
	ac_format Format_i8v = "%op6:6 %op2v:2 %imm8v:8 %nu:16";
	ac_format Format_i6v = "%op6:6 %op2v:2 0x00:2 %imm6v:6 %nu:16";
	ac_format Format_Rw = "%op6:6 %op5w:5 %ra:5 %nu:16";
	ac_format Format_i4w = "%op6:6 %op5w:5 0x00:1 %imm4w:4 %nu:16";
	ac_format Format_w = "%op6:6 %op5w:5 0x00:5 %nu:16";
	
	ac_instr<Format_RR> add, and1, andn1, asr, cmp, ext16d, ext8d, ld, lsl, lsr, mov, nop, st, sub, usr0, or1, xor1;
	ac_instr<Format_Ri5> addi, and2, andn2, asri, bgen, cmpi, if0, if1, lsli, lsri, movhi, movi, skp0, skp1, subi, or2, xor2;
	//ac_instr<Format_Ri4>
	ac_instr<Format_RPi5> ldp, stp;
	//ac_instr<Format_Ri6>
	ac_instr<Format_Ri8> lds, sts, syscall;
	ac_instr<Format_i9> sts16s;
	ac_instr<Format_i10> sts8s;
	ac_instr<Format_i11> br, bsr, pfx, pfxio;
	ac_instr<Format_Ri1u> ext16s, st16s;
	ac_instr<Format_Ri2u> ext8s, st8s;
	ac_instr<Format_i8v> save; 
	ac_instr<Format_i6v> trap;
	ac_instr<Format_Rw> abs, call, fill16, fill8, ifrnz, ifrz, jmp, lret, mstep, mul, neg, not, rdctl, ret, rlc, rrc, sext16, sext8, skprnz, skprz, st16d, st8d, swap, tret, usr1, usr2, usr3, usr4, wrctl;
	ac_instr<Format_i4w> ifs, skps;
	ac_instr<Format_w> restore;

	ac_asm_map reg {
		"%r"[0..31] = [0..31];
		"%i"[0..7] = [24..31];
		"%L"[0..7] = [16..23];
		"%o"[0..7] = [8..15];
		"%g"[0..7] = [0..7];
		"%sp" = 14;
		"%fp" = 30;
	}

	ISA_CTOR(nios32){

		/* Absolute Value 
		* Format Rw
		*/
		abs.set_asm("abs %reg",ra);
		abs.set_decoder(nu=0x0000,op6=0x1F,op5w=0x02);
		
		/* Add 
		* Format RR
		*/
		add.set_asm("add %reg, %reg",ra,rb);
		add.set_decoder(nu=0x0000,op6=0x00);
		
		/* Add Immediate 
		* Format Ri5
		*/
		addi.set_asm("addi %reg, %imm",ra,imm5);
		addi.set_decoder(nu=0x0000,op6=0x01);
		
		/* Bitwise Logical AND 
		* Format RR (not preceded by PFX)
		*/
		and1.set_asm("and %reg, %reg",ra,rb);
		and1.set_decoder(nu=0x0000,op6=0x0E);
		
		/* Bitwise Logical AND 
		* Format Ri5 (preceded by PFX)
		*/
		and2.set_asm("and %reg, %imm",ra,imm5);
		and2.set_decoder(nu=0x0000,op6=0x20);
		
		/* Bitwise Logical AND NOT 
		* Format RR (not preceded by PFX)
		*/
		andn1.set_asm("andn %reg, %reg",ra,rb);
		andn1.set_decoder(nu=0x0000,op6=0x0F);
		
		/* Bitwise Logical AND NOT 
		* Format Ri5 (preceded by PFX)
		*/
		andn2.set_asm("andn %reg, %imm",ra,imm5);
		andn2.set_decoder(nu=0x0000,op6=0x21);
		
		/* Arithmetic Shift Right 
		* Format RR
		*/
		asr.set_asm("asr %reg, %reg",ra,rb);
		asr.set_decoder(nu=0x0000,op6=0x0A);
		
		/* Arithmetic Shift Right Immediate 
		* Format Ri5
		*/
		asri.set_asm("asri %reg, %imm",ra,imm5);
		asri.set_decoder(nu=0x0000,op6=0x0B);
		
		/* Bit Generate 
		* Format Ri5
		*/
		bgen.set_asm("bgen %reg, %imm",ra,imm5);
		bgen.set_decoder(nu=0x0000,op6=0x12);
		
		/* Branch  
		* Format i11
		*/
		br.set_asm("br %imm",imm11);
		br.set_decoder(nu=0x0000,op5=0x10);
		
		/* Branch To Subroutine  
		* Format i11
		*/
		bsr.set_asm("bsr %imm",imm11);
		bsr.set_decoder(nu=0x0000,op5=0x11);
		
		/* Call Subroutine  
		* Format Rw
		*/
		call.set_asm("call %reg",ra);
		call.set_decoder(nu=0x0000,op6=0x1F,op5w=0x1F);
		
		/* Compare  
		* Format RR
		*/
		cmp.set_asm("cmp %reg, %reg",ra,rb);
		cmp.set_decoder(nu=0x0000,op6=0x04);
		
		/* Compare Immediate  
		* Format Ri5
		*/
		cmpi.set_asm("cmpi %reg, %imm",ra,imm5);
		cmpi.set_decoder(nu=0x0000,op6=0x05);
		
		/* Half-Word Extract (Dynamic)  
		* Format RR
		*/
		ext16d.set_asm("ext16d %reg, %reg",ra,rb);
		ext16d.set_decoder(nu=0x0000,op6=0x1A);
		
		/* Half-Word Extract (Static)  
		* Format Ri1u
		*/
		ext16s.set_asm("ext16s %reg, %imm",ra,imm1u);
		ext16s.set_decoder(nu=0x0000,op6=0x1D,op3u=0x01);
		
		/* Byte-Extract (Dynamic)  
		* Format RR
		*/
		ext8d.set_asm("ext8d %reg, %reg",ra,rb);
		ext8d.set_decoder(nu=0x0000,op6=0x13);
		
		/* Byte-Extract (Static)  
		* Format Ri2u
		*/
		ext8s.set_asm("ext8s %reg, %imm",ra,imm2u);
		ext8s.set_decoder(nu=0x0000,op6=0x1D,op3u=0x00);
		
		/* Half-Word Fill  
		* Format Rw
		*/
		fill16.set_asm("fill16 \%r0, %reg",ra);
		fill16.set_decoder(nu=0x0000,op6=0x1F,op5w=0x13);
		
		/* Byte-Fill  
		* Format Rw
		*/
		fill8.set_asm("fill8 \%r0, %reg",ra);
		fill8.set_decoder(nu=0x0000,op6=0x1F,op5w=0x12);
		
		/* Execute If Register Bit Is 0  
		* Format Ri5
		*/
		if0.set_asm("if0 %reg, %imm",ra,imm5);
		if0.set_decoder(nu=0x0000,op6=0x15);
		
		/* Execute If Register Bit Is 1  
		* Format Ri5
		*/
		if1.set_asm("if1 %reg, %imm",ra,imm5);
		if1.set_decoder(nu=0x0000,op6=0x14);
		
		/* Execute If Register Is Not Zero  
		* Format Rw
		*/
		ifrnz.set_asm("ifrnz %reg",ra);
		ifrnz.set_decoder(nu=0x0000,op6=0x1F,op5w=0x16);
		
		/* Execute If Register Is Zero  
		* Format Rw
		*/
		ifrz.set_asm("ifrz %reg",ra);
		ifrz.set_decoder(nu=0x0000,op6=0x1F,op5w=0x1A);
		
		/* Conditionally Execute Next Instruction  
		* Format i4w
		*/
		ifs.set_asm("ifs %imm",imm4w);
		ifs.set_decoder(nu=0x0000,op6=0x1F,op5w=0x17);
		
		/* Computed Jump   
		* Format Rw
		*/
		jmp.set_asm("jmp %reg",ra);
		jmp.set_decoder(nu=0x0000,op6=0x1F,op5w=0x1E);
		
		/* Load 32-bit Data From Memory  
		* Format RR
		*/
		ld.set_asm("ld %reg, [%reg]",ra,rb);
		ld.set_decoder(nu=0x0000,op6=0x16);
		
		/* Load 32-bit Data From Memory (Pointer Addressing Mode)  
		* Format RPi5
		*/
		ldp.set_asm("ldp %reg, [%reg,%imm]",ra,rp,imm5);
		ldp.set_decoder(nu=0x0000,op4=0x0B);
		
		/* Load 32-bit Data From Memory (Stack Addressing Mode)  
		* Format Ri8
		*/
		lds.set_asm("lds %reg, [sp,%imm]",ra,imm8);
		lds.set_decoder(nu=0x0000,op3=0x07);
		
		/* Equivalent to JMP %o7  
		* Format Rw
		*/
		lret.set_asm("lret");
		lret.set_decoder(nu=0x0000,op6=0x1F,op5w=0x1E,ra=0x0F);
		
		/* Logical Shift Left  
		* Format RR
		*/
		lsl.set_asm("lsl %reg, %reg",ra,rb);
		lsl.set_decoder(nu=0x0000,op6=0x06);
		
		/* Logical Shift Left Immediate  
		* Format Ri5
		*/
		lsli.set_asm("lsli %reg, %imm",ra,imm5);
		lsli.set_decoder(nu=0x0000,op6=0x07);
		
		/* Logical Shift Right  
		* Format RR
		*/
		lsr.set_asm("lsr %reg, %reg",ra,rb);
		lsr.set_decoder(nu=0x0000,op6=0x08);
		
		/* Logical Shift Right Immediate  
		* Format Ri5
		*/
		lsri.set_asm("lsri %reg, %imm",ra,imm5);
		lsri.set_decoder(nu=0x0000,op6=0x09);
		
		/* Register-to-Register Move  
		* Format RR
		*/
		mov.set_asm("mov %reg, %reg",ra,rb);
		mov.set_decoder(nu=0x0000,op6=0x0C);
		
		/* Move Immediate Into High Half-Word  
		* Format Ri5
		*/
		movhi.set_asm("movhi %reg, %imm",ra,imm5);
		movhi.set_decoder(nu=0x0000,op6=0x1B);
		
		/* Move Immediate  
		* Format Ri5
		*/
		movi.set_asm("movi %reg, %imm",ra,imm5);
		movi.set_decoder(nu=0x0000,op6=0x0D);
		
		/* Multiply-Step  
		* Format Rw
		*/
		mstep.set_asm("mstep %reg",ra);
		mstep.set_decoder(nu=0x0000,op6=0x1F,op5w=0x14);
		
		/* Multiply  
		* Format Rw
		*/
		mul.set_asm("mul %reg",ra);
		mul.set_decoder(nu=0x0000,op6=0x1F,op5w=0x15);
		
		/* Arithmetic Negation  
		* Format Rw
		*/
		neg.set_asm("neg %reg",ra);
		neg.set_decoder(nu=0x0000,op6=0x1F,op5w=0x01);
		
		/* Equivalent to MOV %g0, %g0  
		* Format RR
		*/
		nop.set_asm("nop");
		nop.set_decoder(nu=0x0000,op6=0x1F,ra=0x00,rb=0x00);
		
		/* Logical Not  
		* Format Rw
		*/
		not.set_asm("not %reg",ra);
		not.set_decoder(nu=0x0000,op6=0x1F,op5w=0x00);
		
		/* Bitwise Logical OR  
		* Format RR (not preceded by PFX)
		*/
		or1.set_asm("or %reg, %reg",ra,rb);
		or1.set_decoder(nu=0x0000,op6=0x10);
		
		/* Bitwise Logical OR  
		* Format Ri5 (preceded by PFX)
		*/
		or2.set_asm("or %reg, %imm",ra,imm5);
		or2.set_decoder(nu=0x0000,op6=0x10);
		
		/* Prefix  
		* Format i11
		*/
		pfx.set_asm("pfx %imm",imm11);
		pfx.set_decoder(nu=0x0000,op5=0x13);
		
		/* Prefix with Cache Bypass  
		* Format i11
		*/
		pfxio.set_asm("pfxio %imm",imm11);
		pfxio.set_decoder(nu=0x0000,op5=0x12);
		
		/* Read Control Register  
		* Format Rw
		*/
		rdctl.set_asm("rdctl %reg",ra);
		rdctl.set_decoder(nu=0x0000,op6=0x1F,op5w=0x19);
		
		/* Restore Caller's Register Window  
		* Format w
		*/
		restore.set_asm("restore");
		restore.set_decoder(nu=0x0000,op6=0x1F,op5w=0x0D);
		
		/* Equivalent to JMP %i7  
		* Format Rw
		*/
		ret.set_asm("ret");
		ret.set_decoder(nu=0x0000,op6=0x1F,op5w=0x1E,ra=0x1F);
		
		/* Rotate Left Through Carry  
		* Format Rw
		*/
		rlc.set_asm("rlc %reg",ra);
		rlc.set_decoder(nu=0x0000,op6=0x1F,op5w=0x05);
		
		/* Rotate Right Through Carry  
		* Format Rw
		*/
		rrc.set_asm("rrc %reg",ra);
		rrc.set_decoder(nu=0x0000,op6=0x1F,op5w=0x06);
		
		/* Save Caller's Register Window  
		* Format i8v
		*/
		save.set_asm("save sp, -%imm",imm8v);
		save.set_decoder(nu=0x0000,op6=0x1E,op2v=0x00);
		
		/* Sign Extend 16-bit Value  
		* Format Rw
		*/
		sext16.set_asm("sext16 %reg",ra);
		sext16.set_decoder(nu=0x0000,op6=0x1F,op5w=0x04);
		
		/* Sign Extend 8-bit Value  
		* Format Rw
		*/
		sext8.set_asm("sext8 %reg",ra);
		sext8.set_decoder(nu=0x0000,op6=0x1F,op5w=0x03);
		
		/* Skip If Register Bit Is 0  
		* Format Ri5
		*/
		skp0.set_asm("skp0 %reg, %imm",ra,imm5);
		skp0.set_decoder(nu=0x0000,op6=0x14);
		
		/* Skip If Register Bit Is 1  
		* Format Ri5
		*/
		skp1.set_asm("skp1 %reg, %imm",ra,imm5);
		skp1.set_decoder(nu=0x0000,op6=0x15);
		
		/* Skip If Register Not Equal To 0  
		* Format Rw
		*/
		skprnz.set_asm("skprnz %reg",ra);
		skprnz.set_decoder(nu=0x0000,op6=0x1F,op5w=0x1A);
		
		/* Skip If Register Equals 0  
		* Format Rw
		*/
		skprz.set_asm("skprz %reg",ra);
		skprz.set_decoder(nu=0x0000,op6=0x1F,op5w=0x16);
		
		/* Skip On Condition Code  
		* Format i4w
		*/
		skps.set_asm("skps %imm",imm4w);
		skps.set_decoder(nu=0x0000,op6=0x1F,op5w=0x17);
		
		/* Store 32-bit Data To Memory  
		* Format RR
		*/
		st.set_asm("st [%reg], %reg",rb,ra);
		st.set_decoder(nu=0x0000,op6=0x17);
		
		/* Store 16-bit Data To Memory (Computed Half-Word Pointer Address)  
		* Format Rw
		*/
		st16d.set_asm("st16d [%reg], \%r0",ra);
		st16d.set_decoder(nu=0x0000,op6=0x1F,op5w=0x11);
		
		/* Store 16-bit Data To Memory (Static Half-Word-Offset Address)  
		* Format Ri1u
		*/
		st16s.set_asm("st16s [%reg], \%r0, %imm",ra,imm1u);
		st16s.set_decoder(nu=0x0000,op6=0x1D,op3u=0x05);
		
		/* Store 8-bit Data To Memory (Computed Byte-Pointer Address)  
		* Format Rw
		*/
		st8d.set_asm("st8d [%reg], \%r0",ra);
		st8d.set_decoder(nu=0x0000,op6=0x1F,op5w=0x10);
		
		/* Store 8-bit Data To Memory (Static Byte-Offset Address)  
		* Format Ri2u
		*/
		st8s.set_asm("st8s [%reg], \%r0, %imm",ra,imm2u);
		st8s.set_decoder(nu=0x0000,op6=0x1D,op3u=0x04);
		
		/* Store 32-bit Data To Memory (Pointer Addressing Mode)  
		* Format RPi5
		*/
		stp.set_asm("stp [%reg,%imm],%reg",rp,imm5,ra);
		stp.set_decoder(nu=0x0000,op4=0x0A);
		
		/* Store 32-bit Data To Memory (Stack Addressing Mode)  
		* Format Ri8
		*/
		sts.set_asm("sts [sp, %imm], %reg",imm8,ra);
		sts.set_decoder(nu=0x0000,op3=0x06);
		
		/* Store 16-bit Data To Memory (Stack Addressing Mode)  
		* Format i9
		*/
		sts16s.set_asm("sts16s [sp, %imm], \%r0",imm9);
		sts16s.set_decoder(nu=0x0000,op6=0x19);
		
		/* Store 8-bit Data To Memory (Stack Addressing Mode)  
		* Format i10
		*/
		sts8s.set_asm("sts8s [sp, %imm], \%r0",imm10);
		sts8s.set_decoder(nu=0x0000,op6=0x18);
		
		/* Subtract  
		* Format RR
		*/
		sub.set_asm("sub %reg, %reg",ra,rb);
		sub.set_decoder(nu=0x0000,op6=0x02);
		
		/* Subtract Immediate  
		* Format Ri5
		*/
		subi.set_asm("subi %reg, %imm",ra,imm5);
		subi.set_decoder(nu=0x0000,op6=0x03);
		
		/* Swap Register Half-Words  
		* Format Rw
		*/
		swap.set_asm("swap %reg",ra);
		swap.set_decoder(nu=0x0000,op6=0x1F,op5w=0x08);
		
		/* Unconditional Trap  
		* Format i6v
		*/
		trap.set_asm("trap %imm",imm6v);
		trap.set_decoder(nu=0x0000,op6=0x1E,op2v=0x01);
		
		/* Trap Return  
		* Format Rw
		*/
		tret.set_asm("tret %reg",ra);
		tret.set_decoder(nu=0x0000,op6=0x1F,op5w=0x0E);
		
		/* User-defined Instruction  
		* Format RR
		*/
		usr0.set_asm("usr0 %reg, %reg",ra,rb);
		usr0.set_decoder(nu=0x0000,op6=0x1C);
		
		/* User-defined Instruction 1  
		* Format Rw
		*/
		usr1.set_asm("usr1 %reg",ra);
		usr1.set_decoder(nu=0x0000,op6=0x1F,op5w=0x09);
		
		/* User-defined Instruction 2  
		* Format Rw
		*/
		usr2.set_asm("usr2 %reg",ra);
		usr2.set_decoder(nu=0x0000,op6=0x1F,op5w=0x0A);
		
		/* User-defined Instruction 3  
		* Format Rw
		*/
		usr3.set_asm("usr3 %reg",ra);
		usr3.set_decoder(nu=0x0000,op6=0x1F,op5w=0x0B);
		
		/* User-defined Instruction 4  
		* Format Rw
		*/
		usr4.set_asm("usr4 %reg",ra);
		usr4.set_decoder(nu=0x0000,op6=0x1F,op5w=0x0C);
		
		/* Write Control Register  
		* Format Rw
		*/
		wrctl.set_asm("wrctl %reg",ra);
		wrctl.set_decoder(nu=0x0000,op6=0x1F,op5w=0x18);
		
		/* Bitwise Logical Exclusive OR  
		* Format RR (not preceded by PFX)
		*/
		xor1.set_asm("xor %reg, %reg",ra,rb);
		xor1.set_decoder(nu=0x0000,op6=0x11);
		
		/* Bitwise Logical Exclusive OR  
		* Format Ri5 (preceded by PFX)
		*/
		xor2.set_asm("xor %reg, %imm",ra,imm5);
		xor2.set_decoder(nu=0x0000,op6=0x11);

		/* Syscall (not in NIOS)
		* Format Ri8
		*/
		syscall.set_asm("syscall");
		syscall.set_decoder(nu=0x0000,op3=0x5);

		pseudo_instr("nop") {
			"mov \%g0, \%g0";
		}

		pseudo_instr("lret") {
			"jmp \%o7";
		}

		pseudo_instr("ret") {
			"jmp \%i7";
		}

		/*pseudo_instr("if0 %reg,%imm") {
			"skp1 %reg,%imm";
		}
		
		pseudo_instr("if1 %reg,%imm") {
			"skp0 %reg,%imm";
		}

		pseudo_instr("ifrz %reg") {
			"skprnz %reg";
		}

		pseudo_instr("ifrnz %reg") {
			"skprz %reg";
		}

		pseudo_instr("ifs %imm") {
			"skps %imm";
		}*/
	};
};