module InstructionDecoder(
	//inputs
	input [15:0] instruction,
	
	//outputs
	output reg [2:0] Rn,
	output reg [2:0] Rm,
	output reg [2:0] Rx,
	output reg [2:0] Rd,
	
	//imm-extended
	output reg [15:0] Immediate,
	
	//conditional stuff
	output reg [3:0] cond,
	
	//control signals
	output reg RegEnable,
	output reg UseImm
);

	//deciding what to do
	always @(*) begin
		casez(instruction[15:10])
		// Addition/ Subtraction
			6'b00011?: begin
				case(instruction[15:9])
					// ADDS <Rd>, <Rn>, <Rm>
					// SUBS <Rd>, <Rn>, <Rm>
					7'b0001100, 7'b0001101: begin
						RegEnable = 1'b1;
						Rd = instruction[2:0];
						Rn = instruction[5:3];
						Rm = instruction[8:6];
					end
					// ADDS <Rd>, <Rn>, #<imm3>
					// SUBS <Rd>, <Rn>, #<imm3>
					7'b0001110, 7'b0001111: begin
						UseImm = 1'b1;
						RegEnable = 1'b1;
						Rd = instruction[2:0];
						Rn = instruction[5:3];
						Immediate = {13'b0, instruction[8:6]};
					end
				endcase
			end
			
		// MOVS <Rd>, #<imm8>
			6'b00100?: begin
				UseImm = 1'b1;
				RegEnable = 1'b1;
				Rd = instruction[10:8];
				Immediate = {8'b0, instruction[7:0]};
			end
		
		// CMP <Rn>, #<imm8>
			6'b00101?: begin
				UseImm = 1'b1;
				RegEnable = 1'b0;
				Rn = instruction[10:8];
				Immediate = {8'b0, instruction[7:0]};
			end
		// ADDS <Rdn>, #<imm8> 
			6'b00110?: begin
				UseImm = 1'b1;
				RegEnable = 1'b1;
				// Rdn = Rn = Rd
				Rd = instruction[10:8];
				Rn = instruction[10:8];
				Immediate = {8'b0, instruction[7:0]};
			end
		// SUBS <Rdn>, #<imm8> 
			6'b00111?: begin
				UseImm = 1'b1;
				RegEnable = 1'b1;
				// Rdn = Rn = Rd
				Rd = instruction[10:8];
				Rn = instruction[10:8];
				Immediate = {8'b0, instruction[7:0]};
			end
		
		// Logical OPS
			6'b010000: begin
				
				case(instruction[9:6])
					// ANDS <Rdn>, <Rm>
					4'b0000: begin
						RegEnable = 1'b1;
						Rm = instruction[5:3];
						Rn = instruction[2:0];
					end
					// EORS <Rdn>, <Rm>
					4'b0001: begin
						RegEnable = 1'b1;
						Rm = instruction[5:3];
						Rn = instruction[2:0];
					end
					// CMP <Rn>, <Rm>
					4'b1010: begin
						RegEnable = 1'b0;
						Rm = instruction[5:3];
						Rn = instruction[2:0];
					end
					// ORRS <Rdn>, <Rm>
					4'b1100: begin
						RegEnable = 1'b1;
						Rm = instruction[5:3];
						Rn = instruction[2:0];
					end
					//MVNS <Rd>, <Rm>
					4'b1111: begin
						RegEnable = 1'b1;
						Rm = instruction[5:3];
						Rn = instruction[2:0];
					end
					// don't care
					default: begin
						RegEnable = 1'b0;
					end
				endcase
			end
			
		// Memory Load (PC with offset)
			6'b01001?: begin
				Rd = instruction[10:8];
				Immediate = { 8'b0, instruction[7:0]};
			end
		// Memory Load/ Store
			6'b0101??: begin
				case(instruction[11:9]) // using case incase more ops are needed
					// STR <Rt>, [<Rn>, <Rm>]
					3'b000: begin
						Rm = instruction[8:6];
						Rn = instruction[5:3];
						Rd = instruction[2:0];
					end
					// LDR <Rt>, [<Rn>, <Rm>]
					3'b100: begin
						Rm = instruction[8:6];
						Rn = instruction[5:3];
						Rd = instruction[2:0];
					end
				endcase
			end
			6'b0110??: begin
				Immediate = {11'b0, instruction[10:6]};
				// LDR <Rt>, [<Rn>, #<imm5>]
				if(instruction[11]) begin
					Rd = instruction[2:0];
				end
				// STR <Rt>, [<Rn>, #<imm5>]
				else begin
					Rd = instruction[2:0];
				end
			end
			
		// Conditional Branching
			6'b1101??: begin
				cond = instruction[11:8];
				Immediate = {8'b0, instruction[10:6]};
			end
			
		// UnConditional Branching
			6'b11100?: begin
				Immediate = {5'b0, instruction[10:0]};
			end
		
		// 6'b11111?: Do nothing (by default) AND the following
		// Relative Address calculation*
		// Misc*
		// Memory Load/Store (Blocks)*
			default: begin
				Rn = 3'd0;
				Rm = 3'd0;
				Rx = 3'd0;
				Rd = 3'd0;
				Immediate = 16'b0;
				RegEnable = 1'b0;
				UseImm = 1'b0;
			end
		endcase
	end

endmodule