import "RV64IBase.core_desc"
import "RV32A.core_desc"

InsructionSet RV64A extends RV64IBase {
	 
	address_spaces { 
		RES[8]
	}
	
	instructions{
		LR.D {
			encoding: b00010 | aq[0:0] | rl[0:0]  | b00000 | rs1[4:0] | b011 | rd[4:0] | b0101111;
			args_disass: "x%rd$d, x%rs1$d";
			if(rd!=0){
				val offs[XLEN] <= X[rs1];
				X[rd]<= sext(MEM[offs]{64}, XLEN);
				RES[offs]{64}<=sext(-1, 64);
			}		
		}
		SC.D {
			encoding: b00011 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
			args_disass: "x%rd$d, x%rs1$d, x%rs2$d";
			val offs[XLEN] <= X[rs1];
			val res[64] <= RES[offs];
			if(res!=0){
				MEM[offs]{64} <= X[rs2];
				if(rd!=0) X[rd]<=0;
			} else{ 
				if(rd!=0) X[rd]<= 1;
			}
		}
		AMOSWAP.D{
			encoding: b00001 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
			args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)";
			val offs[XLEN] <= X[rs1];
			if(rd!=0) X[rd] <= sext(MEM[offs]{64});
			MEM[offs]{64} <= X[rs2];			
		}
		AMOADD.D{
			encoding: b00000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
			args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)";
			val offs[XLEN] <= X[rs1];
			val res[XLEN] <= sext(MEM[offs]{64});
			if(rd!=0) X[rd]<=res;
			val res2[XLEN] <= res + X[rs2];
			MEM[offs]{64}<=res2;			
		}
		AMOXOR.D{
			encoding: b00100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
			args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)";
			val offs[XLEN] <= X[rs1];
			val res[XLEN] <= sext(MEM[offs]{64});
			if(rd!=0) X[rd] <= res;
			val res2[XLEN] <= res ^ X[rs2];
			MEM[offs]{64} <= res2;			
		}
		AMOAND.D{
			encoding: b01100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
			args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)";
			val offs[XLEN] <= X[rs1];
			val res[XLEN] <= sext(MEM[offs]{64});
			if(rd!=0) X[rd] <= res;
			val res2[XLEN] <= res & X[rs2];
			MEM[offs]{64} <= res2;			
		}
		AMOOR.D {
			encoding: b01000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
			args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)";
			val offs[XLEN] <= X[rs1];
			val res[XLEN] <= sext(MEM[offs]{64});
			if(rd!=0) X[rd] <= res;
			val res2[XLEN] <= res | X[rs2];
			MEM[offs]{64} <= res2;			
		}
		AMOMIN.D{
			encoding: b10000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
			args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)";
			val offs[XLEN] <= X[rs1];
			val res[XLEN] <= sext(MEM[offs]{64});
			if(rd!=0) X[rd] <= res;
			val res2[XLEN] <= choose(res s > X[rs2]s, X[rs2], res);			
			MEM[offs]{64} <= res;			
		}
		AMOMAX.D{
			encoding: b10100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
			args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)";
			val offs[XLEN] <= X[rs1];
			val res[XLEN] <= sext(MEM[offs]{64});
			if(rd!=0) X[rd] <= res;
			val res2[XLEN] <= choose(res s < X[rs2]s, X[rs2], res);			
			MEM[offs]{64} <= res2;			
		}
		AMOMINU.D{
			encoding: b11000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
			args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)";
			val offs[XLEN] <= X[rs1];
			val res[XLEN] <= zext(MEM[offs]{64});
			if(rd!=0) X[rd] <= res;
			val res2[XLEN] <= choose(res > X[rs2], X[rs2], res);			
			MEM[offs]{64} <= res2;			
		}
		AMOMAXU.D{
			encoding: b11100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111;
			args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)";
			val offs[XLEN] <= X[rs1];
			val res[XLEN] <= zext(MEM[offs]{64});
			if(rd!=0) X[rd] <= res;
			val res2[XLEN] <= choose(res < X[rs2], X[rs2], res);			
			MEM[offs]{64} <= res2;			
		}
	}
}