data/full_repos/permissive/476477303/verilog/rtl/ExperiarCore/RV32ICore.v
1: b'%Warning-WIDTH: data/full_repos/permissive/476477303/verilog/rtl/ExperiarCore/RV32ICore.v:103: Logical Operator LOGNOT expects 1 bit on the LHS, but LHS\'s VARREF \'management_registerIndex\' generates 5 bits.\n                                                                                             : ... In instance RV32ICore\n   management_readRegister: management_dataOut <= !management_registerIndex ? registers[management_registerIndex] : 32\'b0;\n                                                  ^\n                ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message.\n%Warning-WIDTH: data/full_repos/permissive/476477303/verilog/rtl/ExperiarCore/RV32ICore.v:124: Operator COND expects 33 bits on the Conditional True, but Conditional True\'s VARREF \'management_writeData\' generates 32 bits.\n                                                                                             : ... In instance RV32ICore\n wire[31:0] csrWriteData = !management_run ? management_writeData : coreCSRWriteData;\n                                           ^\n%Warning-WIDTH: data/full_repos/permissive/476477303/verilog/rtl/ExperiarCore/RV32ICore.v:124: Operator ASSIGNW expects 32 bits on the Assign RHS, but Assign RHS\'s COND generates 33 bits.\n                                                                                             : ... In instance RV32ICore\n wire[31:0] csrWriteData = !management_run ? management_writeData : coreCSRWriteData;\n                         ^\n%Warning-WIDTH: data/full_repos/permissive/476477303/verilog/rtl/ExperiarCore/RV32ICore.v:292: Operator ASSIGNDLY expects 33 bits on the Assign RHS, but Assign RHS\'s VARREF \'csrRS1Data\' generates 32 bits.\n                                                                                             : ... In instance RV32ICore\n   if (isCSRRW) coreCSRWriteData <= csrRS1Data;\n                                 ^~\n%Warning-WIDTH: data/full_repos/permissive/476477303/verilog/rtl/ExperiarCore/RV32ICore.v:293: Operator OR expects 33 bits on the LHS, but LHS\'s VARREF \'csrReadData\' generates 32 bits.\n                                                                                             : ... In instance RV32ICore\n   else if (isCSRRS) coreCSRWriteData <= csrReadData | csrRS1Data;\n                                                     ^\n%Warning-WIDTH: data/full_repos/permissive/476477303/verilog/rtl/ExperiarCore/RV32ICore.v:293: Operator OR expects 33 bits on the RHS, but RHS\'s VARREF \'csrRS1Data\' generates 32 bits.\n                                                                                             : ... In instance RV32ICore\n   else if (isCSRRS) coreCSRWriteData <= csrReadData | csrRS1Data;\n                                                     ^\n%Warning-WIDTH: data/full_repos/permissive/476477303/verilog/rtl/ExperiarCore/RV32ICore.v:294: Operator AND expects 33 bits on the LHS, but LHS\'s VARREF \'csrReadData\' generates 32 bits.\n                                                                                             : ... In instance RV32ICore\n   else if (isCSRRC) coreCSRWriteData <= csrReadData & ~csrRS1Data;\n                                                     ^\n%Warning-WIDTH: data/full_repos/permissive/476477303/verilog/rtl/ExperiarCore/RV32ICore.v:294: Operator NOT expects 33 bits on the LHS, but LHS\'s VARREF \'csrRS1Data\' generates 32 bits.\n                                                                                             : ... In instance RV32ICore\n   else if (isCSRRC) coreCSRWriteData <= csrReadData & ~csrRS1Data;\n                                                       ^\n%Warning-WIDTH: data/full_repos/permissive/476477303/verilog/rtl/ExperiarCore/RV32ICore.v:295: Operator ASSIGNDLY expects 33 bits on the Assign RHS, but Assign RHS\'s CONST \'32\'h0\' generates 32 bits.\n                                                                                             : ... In instance RV32ICore\n   else coreCSRWriteData <= 32\'b0;\n                         ^~\n%Warning-WIDTH: data/full_repos/permissive/476477303/verilog/rtl/ExperiarCore/RV32ICore.v:297: Operator ASSIGNDLY expects 33 bits on the Assign RHS, but Assign RHS\'s CONST \'32\'h0\' generates 32 bits.\n                                                                                             : ... In instance RV32ICore\n   coreCSRWriteData <= 32\'b0;\n                    ^~\n%Warning-WIDTH: data/full_repos/permissive/476477303/verilog/rtl/ExperiarCore/RV32ICore.v:453: Operator ASSIGNDLY expects 2 bits on the Assign RHS, but Assign RHS\'s CONST \'4\'h0\' generates 4 bits.\n                                                                                             : ... In instance RV32ICore\n   currentError <= 4\'b0;\n                ^~\n%Error: data/full_repos/permissive/476477303/verilog/rtl/ExperiarCore/RV32ICore.v:518: Cannot find file containing module: \'CSR\'\n CSR csr(\n ^~~\n        ... Looked in:\n             data/full_repos/permissive/476477303/verilog/rtl/ExperiarCore,data/full_repos/permissive/476477303/CSR\n             data/full_repos/permissive/476477303/verilog/rtl/ExperiarCore,data/full_repos/permissive/476477303/CSR.v\n             data/full_repos/permissive/476477303/verilog/rtl/ExperiarCore,data/full_repos/permissive/476477303/CSR.sv\n             CSR\n             CSR.v\n             CSR.sv\n             obj_dir/CSR\n             obj_dir/CSR.v\n             obj_dir/CSR.sv\n%Error: Exiting due to 1 error(s), 11 warning(s)\n'
module RV32ICore(
`ifdef USE_POWER_PINS
	inout vccd1,
	inout vssd1,
`endif

		input wire clk,
		input wire rst,


		output wire[31:0] memoryAddress,
		output wire[3:0] memoryByteSelect,
		output wire memoryWriteEnable,
		output wire memoryReadEnable,
		output wire[31:0] memoryDataWrite,
		input wire[31:0] memoryDataRead,
		input wire memoryBusy,
		input wire memoryAccessFault,


		input wire management_run,
		input wire management_trapEnable,
		input wire management_interruptEnable,
		input wire management_writeEnable,
		input wire[3:0] management_byteSelect,
		input wire[15:0] management_address,
		input wire[31:0] management_writeData,
		output wire[31:0] management_readData,


		input wire[7:0] coreIndex,
		input wire[10:0] manufacturerID,
		input wire[15:0] partID,
		input wire[3:0] versionID,
		input wire[25:0] extensions,


		input wire isAddressBreakpoint,
		input wire[15:0] userInterrupts,


		output wire[1:0] probe_state,
		output wire[1:0] probe_env,
		output wire[31:0] probe_programCounter,
		output wire[6:0] probe_opcode,
		output wire[1:0] probe_errorCode,
		output wire probe_isBranch,
		output wire probe_takeBranch,
		output wire probe_isStore,
		output wire probe_isLoad,
		output wire probe_isCompressed
    );

	localparam STATE_HALT 	 	= 2'b00;
	localparam STATE_FETCH   	= 2'b10;
	localparam STATE_EXECUTE 	= 2'b11;


	reg[1:0] state = STATE_HALT;
	reg[1:0] currentError = 2'b0;
	reg[31:0] programCounter = 32'b0;
	reg[31:0] currentInstruction = 32'b0;
	reg[31:0] registers [0:31];


	localparam MANAGMENT_ADDRESS_SYSTEM	   = 2'b00;
	localparam MANAGMENT_ADDRESS_REGISTERS = 2'b01;
	localparam MANAGMENT_ADDRESS_CSR 	   = 2'b10;

	wire management_selectProgramCounter      = (management_address[15:14] == MANAGMENT_ADDRESS_SYSTEM) && (management_address[13:4] == 10'h000);
	wire management_selectInstructionRegister = (management_address[15:14] == MANAGMENT_ADDRESS_SYSTEM) && (management_address[13:4] == 10'h001);
	wire management_selectClearError		  = (management_address[15:14] == MANAGMENT_ADDRESS_SYSTEM) && (management_address[13:4] == 10'h002);
	wire management_selectRegister            = (management_address[15:14] == MANAGMENT_ADDRESS_REGISTERS) && (management_address[13:7] == 7'h00);
	wire management_selectCSR 				  = management_address[15:14] == MANAGMENT_ADDRESS_CSR;

	wire management_writeValid = !management_run && management_writeEnable;
	wire management_writeProgramCounter = management_writeValid && management_selectProgramCounter;
	wire management_writeProgramCounter_set = management_writeProgramCounter && (management_address[3:0] == 4'h0);
	wire management_writeProgramCounter_jump = management_writeProgramCounter && (management_address[3:0] == 4'h4);
	wire management_writeProgramCounter_step = management_writeProgramCounter && (management_address[3:0] == 4'h8);
	wire management_writeClearError = management_writeValid && management_selectClearError;
	wire management_writeRegister = management_writeValid && management_selectRegister;
	wire management_writeCSR = management_writeValid && management_selectCSR;

	wire management_readValid = !management_run && !management_writeEnable;
	wire management_readProgramCounter = management_readValid && management_selectProgramCounter;
	wire management_readInstructionRegister = management_readValid && management_selectInstructionRegister;
	wire management_readRegister = management_readValid && management_selectRegister;
	wire management_readCSR = management_readValid && management_selectCSR;

	wire management_allowInstruction = management_run || management_writeProgramCounter_step;

	wire[4:0] management_registerIndex = management_address[6:2];
	wire[11:0] management_csrIndex = management_address[13:2];
	wire[31:0] management_jumpTarget = programCounter + management_writeData;

	reg[31:0] management_dataOut;

	always @(*) begin
		case (1'b1)
			management_readProgramCounter: management_dataOut <= programCounter;
			management_readInstructionRegister : management_dataOut <= currentInstruction;
			management_readRegister: management_dataOut <= !management_registerIndex ? registers[management_registerIndex] : 32'b0;
			management_readCSR: management_dataOut <= csrReadData;
			default: management_dataOut <= 32'b0;
		endcase
	end

	assign management_readData = {
		management_byteSelect[3] ? management_dataOut[31:24] : 8'h00,
		management_byteSelect[2] ? management_dataOut[23:16] : 8'h00,
		management_byteSelect[1] ? management_dataOut[15:8]  : 8'h00,
		management_byteSelect[0] ? management_dataOut[7:0]   : 8'h00
	};


	wire coreCSRWrite;
	wire coreCSRRead;
	wire[11:0] coreCSRIndex = currentInstruction[31:20];
	reg[32:0] coreCSRWriteData;
	wire csrWriteEnable = management_writeCSR || (management_run && coreCSRWrite && (state == STATE_EXECUTE));
	wire csrReadEnable = management_readCSR || (management_run && coreCSRRead && (state == STATE_EXECUTE));
	wire[11:0] csrAddress = !management_run ? management_csrIndex : coreCSRIndex;
	wire[31:0] csrWriteData = !management_run ? management_writeData : coreCSRWriteData;
	wire[31:0] csrReadData;

	wire[31:0] trapVector;
	wire[31:0] trapReturnVector;
	wire inTrap;


	wire[31:0] imm_I = {currentInstruction[31] ? 21'h1F_FFFF : 21'h00_0000, currentInstruction[30:25], currentInstruction[24:21], currentInstruction[20]};
	wire[31:0] imm_S = {currentInstruction[31] ? 21'h1F_FFFF : 21'h00_0000, currentInstruction[30:25], currentInstruction[11:8] , currentInstruction[7]};
	wire[31:0] imm_B = {currentInstruction[31] ? 20'hF_FFFF  : 20'h0_0000 , currentInstruction[7]    , currentInstruction[30:25], currentInstruction[11:8] , 1'b0};
	wire[31:0] imm_U = {currentInstruction[31]							  , currentInstruction[30:20], currentInstruction[19:12], 12'h000};
	wire[31:0] imm_J = {currentInstruction[31] ? 12'hFFF : 12'h000 		  , currentInstruction[19:12], currentInstruction[20]	, currentInstruction[30:25], currentInstruction[24:21], 1'b0};


	wire[6:0] opcode = currentInstruction[6:0];
	wire[4:0] rdIndex = currentInstruction[11:7];
	wire[4:0] rs1Index = currentInstruction[19:15];
	wire[4:0] rs2Index = currentInstruction[24:20];
	wire[2:0] funct3 = currentInstruction[14:12];
	wire[6:0] funct7 = currentInstruction[31:25];
	wire isCompressed = opcode[1:0] != 2'b11;


	wire isLUI 	  = (opcode == 7'b0110111);
	wire isAUIPC  = (opcode == 7'b0010111);
	wire isJAL 	  = (opcode == 7'b1101111);
	wire isJALR   = (opcode == 7'b1100111) && (funct3 == 3'b000);
	wire isBranch = (opcode == 7'b1100011) && (funct3 != 3'b010) && (funct3 != 3'b011);
	wire isLoad   = (opcode == 7'b0000011) && (funct3 == 3'b000 || funct3 == 3'b001 || funct3 == 3'b010 || funct3 == 3'b100 || funct3 == 3'b101);
	wire isStore  = (opcode == 7'b0100011) && (funct3 == 3'b000 || funct3 == 3'b001 || funct3 == 3'b010);
	wire isALUImmBase = (opcode == 7'b0010011);
	wire isALUImmNormal = isALUImmBase && funct3 != 3'b001 && funct3 != 3'b101;
	wire isALUImmShift = isALUImmBase && ((funct3 == 3'b001 && funct7 == 7'b0000000) || (funct3 == 3'b101 && (funct7 == 7'b0000000 || funct7 == 7'b0100000)));
	wire isALUImm = isALUImmShift || isALUImmNormal;
	wire isALU 	  = (opcode == 7'b0110011) && (funct7 == 7'b0000000 || ((funct7 == 7'b0100000) && (funct3 == 3'b000 || funct3 == 3'b101)));
	wire isFENCE  = (opcode == 7'b0001111) && (funct3 == 3'b000);
	wire isSystem = (opcode == 7'b1110011);
	

	wire isCSR = isSystem && (funct3 != 3'b000);
	wire isCSRIMM = isCSR && funct3[2];
	wire isCSRRW = isCSR && (funct3[1:0] == 2'b01);
	wire isCSRRS = isCSR && (funct3[1:0] == 2'b10);
	wire isCSRRC = isCSR && (funct3[1:0] == 2'b11);
	wire isECALL  = isSystem && (currentInstruction[31:7] == 25'b0000000000000000000000000);
	wire isEBREAK = isSystem && (currentInstruction[31:7] == 25'b0000000000010000000000000);
	wire isRET    = isSystem && (currentInstruction[31:7] == 25'b0011000000100000000000000);

	wire validSystemCommand = isCSR || isECALL || isEBREAK || isRET;

	reg invalidInstruction;
	always @(*) begin
		case ({ isLUI, isAUIPC, isJAL, isJALR, isBranch, isLoad, isStore, isALUImm, isALU, isFENCE, isSystem })
			'b00000000001: invalidInstruction <= 1'b0;
			'b00000000010: invalidInstruction <= 1'b0;
			'b00000000100: invalidInstruction <= 1'b0;
			'b00000001000: invalidInstruction <= 1'b0;
			'b00000010000: invalidInstruction <= 1'b0;
			'b00000100000: invalidInstruction <= 1'b0;
			'b00001000000: invalidInstruction <= 1'b0;
			'b00010000000: invalidInstruction <= 1'b0;
			'b00100000000: invalidInstruction <= 1'b0;
			'b01000000000: invalidInstruction <= 1'b0;
			'b10000000000: invalidInstruction <= validSystemCommand;
			default: invalidInstruction <= 1'b1;
		endcase
	end

	wire isInvalidInstruction = invalidInstruction && state == STATE_EXECUTE;


	wire[31:0] rs1 = |rs1Index ? registers[rs1Index] : 32'b0;
	wire[31:0] rs2 = |rs2Index ? registers[rs2Index] : 32'b0;


	wire[31:0] inputA = isAUIPC ? programCounter : rs1;
	wire[31:0] inputB = isAUIPC  ? imm_U : 
						isALUImm ? imm_I :
						isLoad   ? imm_I : 
						isStore  ? imm_S :
								   rs2;


	wire[31:0] aluAPlusB = inputA + inputB;
	wire[32:0] aluACompareB = { 1'b0, inputA } - { 1'b0, inputB };
	wire[31:0] aluAMinusB = aluACompareB[31:0];
	wire aluAEqualsB = aluAMinusB == 32'b0;
	wire aluALessThanB = inputA[31] ^ inputB[31] ? inputA[31] : aluACompareB[32];
	wire aluALessThanBUnsigned = aluACompareB[32];


	reg takeBranch;
	always @(*) begin
		if (isBranch) begin
			case (funct3)
3'b000: takeBranch <= aluAEqualsB;
3'b001: takeBranch <= !aluAEqualsB;
				/3'b010: takeBranch <= 1'b0;
				/3'b011: takeBranch <= 1'b0;
3'b100: takeBranch <= aluALessThanB;
3'b101: takeBranch <= !aluALessThanB;
3'b110: takeBranch <= aluALessThanBUnsigned;
3'b111: takeBranch <= !aluALessThanBUnsigned;
						default: takeBranch <= 1'b0;
			endcase
		end else begin
			takeBranch <= 1'b0;
		end
	end

	wire[31:0] programCounterLink = programCounter + (isCompressed ? 2 : 4);
	wire[31:0] nextProgramCounterBase = isJAL 					 ? programCounter :
										isJALR		  			 ? rs1 			  :
										takeBranch 				 ? programCounter :
																   programCounterLink;
	wire[31:0] nextProgramCounterOffset = isJAL 				   ? imm_J :
										  isJALR		  		   ? imm_I :
										  takeBranch 			   ? imm_B :
																     32'b0;
	wire[31:0] nextProgramCounterWord = nextProgramCounterBase + nextProgramCounterOffset;
	wire[31:0] nextProgramCounterCompressed = programCounterLink;
	wire[31:0] nextProgramCounterFull = isCompressed ? nextProgramCounterCompressed : nextProgramCounterWord;
	wire[31:0] nextProgramCounter = { nextProgramCounterFull[31:1] , 1'b0};
	wire jumpMissaligned = !isCompressed && |nextProgramCounter[1:0] && state == STATE_EXECUTE && (isJAL || isJALR || takeBranch);


	wire aluAlt = funct7 == 7'b0100000 && (isALU || isALUImmShift);
	


	function [31:0] flipBits32 (input [31:0] x);
		flipBits32 = { x[ 0], x[ 1], x[ 2], x[ 3], x[ 4], x[ 5], x[ 6], x[ 7], 
					   x[ 8], x[ 9], x[10], x[11], x[12], x[13], x[14], x[15], 
					   x[16], x[17], x[18], x[19], x[20], x[21], x[22], x[23],
					   x[24], x[25], x[26], x[27], x[28], x[29], x[30], x[31] };
	endfunction

	wire isLeftShift = funct3 == 3'b001;
	wire[31:0] shiftInput = isLeftShift ? flipBits32(inputA) : inputA;
	wire signed[32:0] signedShiftInput = { aluAlt && shiftInput[31] && !isLeftShift, shiftInput };
	wire[32:0] aluShifter = $signed(signedShiftInput >>> inputB[4:0]);
	wire[31:0] rightShift = aluShifter[31:0];
	wire[31:0] leftShift = flipBits32(rightShift);

	reg[31:0] aluValue;
	always @(*) begin
		case (funct3)
3'b000: aluValue <= aluAlt ? aluAMinusB : aluAPlusB;
3'b001: aluValue <= leftShift;
3'b010: aluValue <= {31'b0, aluALessThanB};
3'b011: aluValue <= {31'b0, aluALessThanBUnsigned};
3'b100: aluValue <= inputA ^ inputB;
3'b101: aluValue <= rightShift;
3'b110: aluValue <= inputA | inputB;
3'b111: aluValue <= inputA & inputB;
					default: aluValue <= 32'b0;
		endcase
	end


	assign coreCSRWrite = isCSRRW || (isCSR && |rs1Index);
	assign coreCSRRead = isCSRRC || isCSRRS || (isCSR && |rdIndex);

	wire[31:0] csrRS1Data = isCSRIMM ? { 27'b0, rs1Index} : rs1;

	always @(*) begin
		if (isCSR) begin			
			if (isCSRRW) coreCSRWriteData <= csrRS1Data;
			else if (isCSRRS) coreCSRWriteData <= csrReadData | csrRS1Data;
			else if (isCSRRC) coreCSRWriteData <= csrReadData & ~csrRS1Data;
			else coreCSRWriteData <= 32'b0;
		end else begin
			coreCSRWriteData <= 32'b0;
		end 
	end


	wire[31:0] targetMemoryAddress = state == STATE_FETCH   ? programCounter : 
									 state == STATE_EXECUTE ? aluAPlusB:
									 						  32'b0;
	wire loadSigned    = (funct3 == 3'b000) || (funct3 == 3'b001);
	wire loadStoreByte = funct3[1:0] == 2'b00;
	wire loadStoreHalf = funct3[1:0] == 2'b01;
	wire loadStoreWord = funct3 == 3'b010;
	reg[3:0] baseByteMask;
	always @(*) begin
		if (state == STATE_FETCH) baseByteMask <= 4'b1111;
		else if ((isLoad || isStore) && state == STATE_EXECUTE) begin
			if (loadStoreWord) baseByteMask <= 4'b1111;
			else if (loadStoreHalf) baseByteMask <= 4'b0011;
			else if (loadStoreByte) baseByteMask <= 4'b0001;
			else baseByteMask <= 4'b0000;
		end else baseByteMask <= 4'b0000;
	end

	reg signExtend;
	always @(*) begin
		if (loadSigned) begin
			if (loadStoreByte) begin
				case (targetMemoryAddress[1:0])
					2'b00: signExtend <= memoryDataRead[7];
					2'b01: signExtend <= memoryDataRead[15];
					2'b10: signExtend <= memoryDataRead[23];
					2'b11: signExtend <= memoryDataRead[31];
				endcase
			end else if (loadStoreHalf) begin
				case (targetMemoryAddress[1:0])
					2'b00: signExtend <= memoryDataRead[15];
					2'b01: signExtend <= memoryDataRead[23];
					2'b10: signExtend <= memoryDataRead[31];
					2'b11: signExtend <= 1'b0;
				endcase
			end else begin
				signExtend <= 1'b0;
			end
		end else begin
			signExtend <= 1'b0;
		end
	end

	wire[7:0] signExtendByte = signExtend ? 8'hFF : 8'h00;

	wire[6:0] loadStoreByteMask = {3'b0, baseByteMask} << targetMemoryAddress[1:0];
	wire loadStoreByteMaskValid = |(loadStoreByteMask[3:0]);
	wire addressMissaligned = |loadStoreByteMask[6:4];
	wire isAddressMisaligned = addressMissaligned && ((state == STATE_FETCH) || ((state == STATE_EXECUTE) && (isLoad || isStore)));
	wire shouldLoad  = loadStoreByteMaskValid && !addressMissaligned && ((state == STATE_FETCH) || ((state == STATE_EXECUTE) && isLoad));
	wire shouldStore = loadStoreByteMaskValid && !addressMissaligned && ((state == STATE_EXECUTE) && isStore);
	assign memoryAddress = shouldLoad || shouldStore ? { targetMemoryAddress[31:2], 2'b00 } : 32'b0;

	assign memoryByteSelect = shouldStore || shouldLoad  ? loadStoreByteMask[3:0] : 4'b0000;

	wire[31:0] loadData  = shouldLoad && !shouldStore ? dataIn : 32'b0;
	wire[31:0] storeData = shouldStore && !shouldLoad ? rs2    : 32'b0;
	
	reg[31:0] dataIn;
	always @(*) begin
		case (targetMemoryAddress[1:0])
			2'b00: dataIn = {
					loadStoreByteMask[3] ? memoryDataRead[31:24] : signExtendByte,
					loadStoreByteMask[2] ? memoryDataRead[23:16] : signExtendByte,
					loadStoreByteMask[1] ? memoryDataRead[15:8]  : signExtendByte,
					loadStoreByteMask[0] ? memoryDataRead[7:0]   : 8'h00
				};

			2'b01: dataIn = {
					signExtendByte,
					loadStoreByteMask[3] ? memoryDataRead[31:24] : signExtendByte,
					loadStoreByteMask[2] ? memoryDataRead[23:16] : signExtendByte,
					loadStoreByteMask[1] ? memoryDataRead[15:8]  : 8'h00
				};

			2'b10: dataIn = {
					signExtendByte,
					signExtendByte,
					loadStoreByteMask[3] ? memoryDataRead[31:24] : signExtendByte,
					loadStoreByteMask[2] ? memoryDataRead[23:16] : 8'h00
				};

			2'b11: dataIn = {
					signExtendByte,
					signExtendByte,
					signExtendByte,
					loadStoreByteMask[3] ? memoryDataRead[31:24] : 8'h00
				};
		endcase
	end

	reg[31:0] dataOut;
	always @(*) begin
		case (targetMemoryAddress[1:0])
			2'b00: dataOut = {
					baseByteMask[3] ? storeData[31:24] : 8'h00,
					baseByteMask[2] ? storeData[23:16] : 8'h00,
					baseByteMask[1] ? storeData[15:8]  : 8'h00,
					baseByteMask[0] ? storeData[7:0]   : 8'h00
				};

			2'b01: dataOut = {
					baseByteMask[2] ? storeData[23:16] : 8'h00,
					baseByteMask[1] ? storeData[15:8]  : 8'h00,
					baseByteMask[0] ? storeData[7:0]   : 8'h00,
					8'h00
				};

			2'b10: dataOut = {
					baseByteMask[1] ? storeData[15:8]  : 8'h00,
					baseByteMask[0] ? storeData[7:0]   : 8'h00,
					8'h00,
					8'h00
				};

			2'b11: dataOut = {
					baseByteMask[0] ? storeData[7:0]   : 8'h00,
					8'h00,
					8'h00,
					8'h00
				};
		endcase
	end

	assign memoryDataWrite = dataOut;

	assign memoryWriteEnable = shouldStore;
	assign memoryReadEnable = shouldLoad;

	wire memoryReadReady = shouldLoad ? !memoryBusy : 1'b0;
	wire memoryWriteDone = shouldStore ? !memoryBusy : 1'b0;


	wire integerRegisterWriteEn = isLUI || isAUIPC || isJAL || isJALR || isALU || isALUImm || isLoad || csrReadEnable;
	wire[31:0] integerRegisterWriteData = isLUI 			  ? imm_U			   :
										  isAUIPC 			  ? aluAPlusB 		   :
										  isJAL 			  ? programCounterLink :
										  isJALR 			  ? programCounterLink :
										  isLoad 			  ? loadData		   :
										  (isALU || isALUImm) ? aluValue 		   :
										  csrReadEnable		  ? csrReadData 	   :
																32'b0;

	wire progressExecute = isStore ? memoryWriteDone :
						   isLoad  ? memoryReadReady : 
							 		 1'b1;

	always @(posedge clk) begin
		if (rst) begin
			state <= STATE_HALT;
			programCounter <= 32'b0;
			currentError <= 4'b0;
			programCounter <= 32'b0;
			currentInstruction <= 32'b0;
		end else begin
			case (state)
				STATE_HALT: begin
					if (management_allowInstruction && !(|currentError)) state <= STATE_FETCH;
					else begin
						if (management_writeProgramCounter_set) programCounter <= { management_writeData[31:1] , 1'b0};
						else if (management_writeProgramCounter_jump) programCounter <= { management_jumpTarget[31:1] , 1'b0};
						else if (management_writeRegister) registers[management_registerIndex] <= management_writeData;
						else if (management_writeClearError) currentError <= 2'b0;
					end
				end

				STATE_FETCH: begin
					if (|currentError) begin
						state <= STATE_HALT;
					end else begin
						if (inTrap) programCounter <= trapVector;
						else if (memoryReadReady) begin
							currentInstruction <= dataIn;
							state <= STATE_EXECUTE;
						end
					end
				end

				STATE_EXECUTE: begin
					if (!management_trapEnable && (isAddressMisaligned || isInvalidInstruction)) begin
						currentError <= { isAddressMisaligned, isInvalidInstruction };
						state <= STATE_HALT;
					end else begin
						if (progressExecute) begin
							if (integerRegisterWriteEn && |rdIndex) registers[rdIndex] <= integerRegisterWriteData;

							if (management_trapEnable) begin
								if (inTrap) programCounter <= trapVector;
								else if (isRET) programCounter <= trapReturnVector;
								else programCounter <= nextProgramCounter;
							end else begin
								programCounter <= nextProgramCounter;
							end
							
							if (management_allowInstruction) state <= STATE_FETCH;
							else state <= STATE_HALT;
						end
					end
				end

				default: state <= STATE_HALT;
			endcase
		end
	end


	wire eCall = isECALL && (state == STATE_EXECUTE);
	wire eBreak = isEBREAK && (state == STATE_EXECUTE);
	wire trapReturn = isRET && (state == STATE_EXECUTE);

	wire isMachineTimerInterrupt = 1'b0;
	wire isMachineExternalInterrupt = 1'b0;
	wire isMachineSoftwareInterrupt = 1'b0;


	wire instructionCompleted = (state == STATE_EXECUTE) && progressExecute;
	CSR csr(
		.clk(clk),
		.rst(rst),
		.csrWriteEnable(csrWriteEnable),
		.csrReadEnable(csrReadEnable),
		.csrAddress(csrAddress),
		.csrWriteData(csrWriteData),
		.csrReadData(csrReadData),
		.coreIndex(coreIndex),
		.manufacturerID(manufacturerID),
		.partID(partID),
		.versionID(versionID),
		.extensions(extensions),
		.instructionCompleted(instructionCompleted),
		.coreState(state),
		.programCounter(programCounter),
		.currentInstruction(currentInstruction),
		.isLoad(isLoad),
		.isStore(isStore),
		.isMachineTimerInterrupt(isMachineTimerInterrupt),
		.isMachineExternalInterrupt(isMachineExternalInterrupt),
		.isMachineSoftwareInterrupt(isMachineSoftwareInterrupt),
		.isAddressMisaligned(isAddressMisaligned),
		.isJumpMissaligned(jumpMissaligned),
		.isAccessFault(memoryAccessFault),
		.isInvalidInstruction(isInvalidInstruction),
		.isEBREAK(eBreak),
		.isECALL(eCall),
		.isAddressBreakpoint(isAddressBreakpoint),
		.userInterrupts(management_interruptEnable ? userInterrupts : 16'b0),
		.trapReturn(trapReturn),
		.inTrap(inTrap),
		.trapVector(trapVector),
		.trapReturnVector(trapReturnVector));


	assign probe_state = state;
	assign probe_env = { eCall, eBreak };
	assign probe_programCounter = programCounter;
	assign probe_opcode = opcode;
	assign probe_errorCode = currentError;
	assign probe_isBranch = isBranch;
	assign probe_takeBranch = takeBranch;
	assign probe_isStore = isStore;
	assign probe_isLoad = isLoad;
	assign probe_isCompressed = isCompressed;

endmodule
module RV32ICore(
`ifdef USE_POWER_PINS
	inout vccd1,
	inout vssd1,
`endif

		input wire clk,
		input wire rst,


		output wire[31:0] memoryAddress,
		output wire[3:0] memoryByteSelect,
		output wire memoryWriteEnable,
		output wire memoryReadEnable,
		output wire[31:0] memoryDataWrite,
		input wire[31:0] memoryDataRead,
		input wire memoryBusy,
		input wire memoryAccessFault,


		input wire management_run,
		input wire management_trapEnable,
		input wire management_interruptEnable,
		input wire management_writeEnable,
		input wire[3:0] management_byteSelect,
		input wire[15:0] management_address,
		input wire[31:0] management_writeData,
		output wire[31:0] management_readData,


		input wire[7:0] coreIndex,
		input wire[10:0] manufacturerID,
		input wire[15:0] partID,
		input wire[3:0] versionID,
		input wire[25:0] extensions,


		input wire isAddressBreakpoint,
		input wire[15:0] userInterrupts,


		output wire[1:0] probe_state,
		output wire[1:0] probe_env,
		output wire[31:0] probe_programCounter,
		output wire[6:0] probe_opcode,
		output wire[1:0] probe_errorCode,
		output wire probe_isBranch,
		output wire probe_takeBranch,
		output wire probe_isStore,
		output wire probe_isLoad,
		output wire probe_isCompressed
    );


	localparam STATE_HALT 	 	= 2'b00;
	localparam STATE_FETCH   	= 2'b10;
	localparam STATE_EXECUTE 	= 2'b11;


	reg[1:0] state = STATE_HALT;
	reg[1:0] currentError = 2'b0;
	reg[31:0] programCounter = 32'b0;
	reg[31:0] currentInstruction = 32'b0;
	reg[31:0] registers [0:31];


	localparam MANAGMENT_ADDRESS_SYSTEM	   = 2'b00;
	localparam MANAGMENT_ADDRESS_REGISTERS = 2'b01;
	localparam MANAGMENT_ADDRESS_CSR 	   = 2'b10;

	wire management_selectProgramCounter      = (management_address[15:14] == MANAGMENT_ADDRESS_SYSTEM) && (management_address[13:4] == 10'h000);
	wire management_selectInstructionRegister = (management_address[15:14] == MANAGMENT_ADDRESS_SYSTEM) && (management_address[13:4] == 10'h001);
	wire management_selectClearError		  = (management_address[15:14] == MANAGMENT_ADDRESS_SYSTEM) && (management_address[13:4] == 10'h002);
	wire management_selectRegister            = (management_address[15:14] == MANAGMENT_ADDRESS_REGISTERS) && (management_address[13:7] == 7'h00);
	wire management_selectCSR 				  = management_address[15:14] == MANAGMENT_ADDRESS_CSR;

	wire management_writeValid = !management_run && management_writeEnable;
	wire management_writeProgramCounter = management_writeValid && management_selectProgramCounter;
	wire management_writeProgramCounter_set = management_writeProgramCounter && (management_address[3:0] == 4'h0);
	wire management_writeProgramCounter_jump = management_writeProgramCounter && (management_address[3:0] == 4'h4);
	wire management_writeProgramCounter_step = management_writeProgramCounter && (management_address[3:0] == 4'h8);
	wire management_writeClearError = management_writeValid && management_selectClearError;
	wire management_writeRegister = management_writeValid && management_selectRegister;
	wire management_writeCSR = management_writeValid && management_selectCSR;

	wire management_readValid = !management_run && !management_writeEnable;
	wire management_readProgramCounter = management_readValid && management_selectProgramCounter;
	wire management_readInstructionRegister = management_readValid && management_selectInstructionRegister;
	wire management_readRegister = management_readValid && management_selectRegister;
	wire management_readCSR = management_readValid && management_selectCSR;

	wire management_allowInstruction = management_run || management_writeProgramCounter_step;

	wire[4:0] management_registerIndex = management_address[6:2];
	wire[11:0] management_csrIndex = management_address[13:2];
	wire[31:0] management_jumpTarget = programCounter + management_writeData;

	reg[31:0] management_dataOut;

	always @(*) begin
		case (1'b1)
			management_readProgramCounter: management_dataOut <= programCounter;
			management_readInstructionRegister : management_dataOut <= currentInstruction;
			management_readRegister: management_dataOut <= !management_registerIndex ? registers[management_registerIndex] : 32'b0;
			management_readCSR: management_dataOut <= csrReadData;
			default: management_dataOut <= 32'b0;
		endcase
	end

	assign management_readData = {
		management_byteSelect[3] ? management_dataOut[31:24] : 8'h00,
		management_byteSelect[2] ? management_dataOut[23:16] : 8'h00,
		management_byteSelect[1] ? management_dataOut[15:8]  : 8'h00,
		management_byteSelect[0] ? management_dataOut[7:0]   : 8'h00
	};


	wire coreCSRWrite;
	wire coreCSRRead;
	wire[11:0] coreCSRIndex = currentInstruction[31:20];
	reg[32:0] coreCSRWriteData;
	wire csrWriteEnable = management_writeCSR || (management_run && coreCSRWrite && (state == STATE_EXECUTE));
	wire csrReadEnable = management_readCSR || (management_run && coreCSRRead && (state == STATE_EXECUTE));
	wire[11:0] csrAddress = !management_run ? management_csrIndex : coreCSRIndex;
	wire[31:0] csrWriteData = !management_run ? management_writeData : coreCSRWriteData;
	wire[31:0] csrReadData;

	wire[31:0] trapVector;
	wire[31:0] trapReturnVector;
	wire inTrap;


	wire[31:0] imm_I = {currentInstruction[31] ? 21'h1F_FFFF : 21'h00_0000, currentInstruction[30:25], currentInstruction[24:21], currentInstruction[20]};
	wire[31:0] imm_S = {currentInstruction[31] ? 21'h1F_FFFF : 21'h00_0000, currentInstruction[30:25], currentInstruction[11:8] , currentInstruction[7]};
	wire[31:0] imm_B = {currentInstruction[31] ? 20'hF_FFFF  : 20'h0_0000 , currentInstruction[7]    , currentInstruction[30:25], currentInstruction[11:8] , 1'b0};
	wire[31:0] imm_U = {currentInstruction[31]							  , currentInstruction[30:20], currentInstruction[19:12], 12'h000};
	wire[31:0] imm_J = {currentInstruction[31] ? 12'hFFF : 12'h000 		  , currentInstruction[19:12], currentInstruction[20]	, currentInstruction[30:25], currentInstruction[24:21], 1'b0};


	wire[6:0] opcode = currentInstruction[6:0];
	wire[4:0] rdIndex = currentInstruction[11:7];
	wire[4:0] rs1Index = currentInstruction[19:15];
	wire[4:0] rs2Index = currentInstruction[24:20];
	wire[2:0] funct3 = currentInstruction[14:12];
	wire[6:0] funct7 = currentInstruction[31:25];
	wire isCompressed = opcode[1:0] != 2'b11;


	wire isLUI 	  = (opcode == 7'b0110111);
	wire isAUIPC  = (opcode == 7'b0010111);
	wire isJAL 	  = (opcode == 7'b1101111);
	wire isJALR   = (opcode == 7'b1100111) && (funct3 == 3'b000);
	wire isBranch = (opcode == 7'b1100011) && (funct3 != 3'b010) && (funct3 != 3'b011);
	wire isLoad   = (opcode == 7'b0000011) && (funct3 == 3'b000 || funct3 == 3'b001 || funct3 == 3'b010 || funct3 == 3'b100 || funct3 == 3'b101);
	wire isStore  = (opcode == 7'b0100011) && (funct3 == 3'b000 || funct3 == 3'b001 || funct3 == 3'b010);
	wire isALUImmBase = (opcode == 7'b0010011);
	wire isALUImmNormal = isALUImmBase && funct3 != 3'b001 && funct3 != 3'b101;
	wire isALUImmShift = isALUImmBase && ((funct3 == 3'b001 && funct7 == 7'b0000000) || (funct3 == 3'b101 && (funct7 == 7'b0000000 || funct7 == 7'b0100000)));
	wire isALUImm = isALUImmShift || isALUImmNormal;
	wire isALU 	  = (opcode == 7'b0110011) && (funct7 == 7'b0000000 || ((funct7 == 7'b0100000) && (funct3 == 3'b000 || funct3 == 3'b101)));
	wire isFENCE  = (opcode == 7'b0001111) && (funct3 == 3'b000);
	wire isSystem = (opcode == 7'b1110011);
	

	wire isCSR = isSystem && (funct3 != 3'b000);
	wire isCSRIMM = isCSR && funct3[2];
	wire isCSRRW = isCSR && (funct3[1:0] == 2'b01);
	wire isCSRRS = isCSR && (funct3[1:0] == 2'b10);
	wire isCSRRC = isCSR && (funct3[1:0] == 2'b11);
	wire isECALL  = isSystem && (currentInstruction[31:7] == 25'b0000000000000000000000000);
	wire isEBREAK = isSystem && (currentInstruction[31:7] == 25'b0000000000010000000000000);
	wire isRET    = isSystem && (currentInstruction[31:7] == 25'b0011000000100000000000000);

	wire validSystemCommand = isCSR || isECALL || isEBREAK || isRET;

	reg invalidInstruction;
	always @(*) begin
		case ({ isLUI, isAUIPC, isJAL, isJALR, isBranch, isLoad, isStore, isALUImm, isALU, isFENCE, isSystem })
			'b00000000001: invalidInstruction <= 1'b0;
			'b00000000010: invalidInstruction <= 1'b0;
			'b00000000100: invalidInstruction <= 1'b0;
			'b00000001000: invalidInstruction <= 1'b0;
			'b00000010000: invalidInstruction <= 1'b0;
			'b00000100000: invalidInstruction <= 1'b0;
			'b00001000000: invalidInstruction <= 1'b0;
			'b00010000000: invalidInstruction <= 1'b0;
			'b00100000000: invalidInstruction <= 1'b0;
			'b01000000000: invalidInstruction <= 1'b0;
			'b10000000000: invalidInstruction <= validSystemCommand;
			default: invalidInstruction <= 1'b1;
		endcase
	end

	wire isInvalidInstruction = invalidInstruction && state == STATE_EXECUTE;


	wire[31:0] rs1 = |rs1Index ? registers[rs1Index] : 32'b0;
	wire[31:0] rs2 = |rs2Index ? registers[rs2Index] : 32'b0;


	wire[31:0] inputA = isAUIPC ? programCounter : rs1;
	wire[31:0] inputB = isAUIPC  ? imm_U : 
						isALUImm ? imm_I :
						isLoad   ? imm_I : 
						isStore  ? imm_S :
								   rs2;


	wire[31:0] aluAPlusB = inputA + inputB;
	wire[32:0] aluACompareB = { 1'b0, inputA } - { 1'b0, inputB };
	wire[31:0] aluAMinusB = aluACompareB[31:0];
	wire aluAEqualsB = aluAMinusB == 32'b0;
	wire aluALessThanB = inputA[31] ^ inputB[31] ? inputA[31] : aluACompareB[32];
	wire aluALessThanBUnsigned = aluACompareB[32];


	reg takeBranch;
	always @(*) begin
		if (isBranch) begin
			case (funct3)
3'b000: takeBranch <= aluAEqualsB;
3'b001: takeBranch <= !aluAEqualsB;
				/3'b010: takeBranch <= 1'b0;
				/3'b011: takeBranch <= 1'b0;
3'b100: takeBranch <= aluALessThanB;
3'b101: takeBranch <= !aluALessThanB;
3'b110: takeBranch <= aluALessThanBUnsigned;
3'b111: takeBranch <= !aluALessThanBUnsigned;
						default: takeBranch <= 1'b0;
			endcase
		end else begin
			takeBranch <= 1'b0;
		end
	end

	wire[31:0] programCounterLink = programCounter + (isCompressed ? 2 : 4);
	wire[31:0] nextProgramCounterBase = isJAL 					 ? programCounter :
										isJALR		  			 ? rs1 			  :
										takeBranch 				 ? programCounter :
																   programCounterLink;
	wire[31:0] nextProgramCounterOffset = isJAL 				   ? imm_J :
										  isJALR		  		   ? imm_I :
										  takeBranch 			   ? imm_B :
																     32'b0;
	wire[31:0] nextProgramCounterWord = nextProgramCounterBase + nextProgramCounterOffset;
	wire[31:0] nextProgramCounterCompressed = programCounterLink;
	wire[31:0] nextProgramCounterFull = isCompressed ? nextProgramCounterCompressed : nextProgramCounterWord;
	wire[31:0] nextProgramCounter = { nextProgramCounterFull[31:1] , 1'b0};
	wire jumpMissaligned = !isCompressed && |nextProgramCounter[1:0] && state == STATE_EXECUTE && (isJAL || isJALR || takeBranch);


	wire aluAlt = funct7 == 7'b0100000 && (isALU || isALUImmShift);
	


	function [31:0] flipBits32 (input [31:0] x);
		flipBits32 = { x[ 0], x[ 1], x[ 2], x[ 3], x[ 4], x[ 5], x[ 6], x[ 7], 
					   x[ 8], x[ 9], x[10], x[11], x[12], x[13], x[14], x[15], 
					   x[16], x[17], x[18], x[19], x[20], x[21], x[22], x[23],
					   x[24], x[25], x[26], x[27], x[28], x[29], x[30], x[31] };
	endfunction

	wire isLeftShift = funct3 == 3'b001;
	wire[31:0] shiftInput = isLeftShift ? flipBits32(inputA) : inputA;
	wire signed[32:0] signedShiftInput = { aluAlt && shiftInput[31] && !isLeftShift, shiftInput };
	wire[32:0] aluShifter = $signed(signedShiftInput >>> inputB[4:0]);
	wire[31:0] rightShift = aluShifter[31:0];
	wire[31:0] leftShift = flipBits32(rightShift);

	reg[31:0] aluValue;
	always @(*) begin
		case (funct3)
3'b000: aluValue <= aluAlt ? aluAMinusB : aluAPlusB;
3'b001: aluValue <= leftShift;
3'b010: aluValue <= {31'b0, aluALessThanB};
3'b011: aluValue <= {31'b0, aluALessThanBUnsigned};
3'b100: aluValue <= inputA ^ inputB;
3'b101: aluValue <= rightShift;
3'b110: aluValue <= inputA | inputB;
3'b111: aluValue <= inputA & inputB;
					default: aluValue <= 32'b0;
		endcase
	end


	assign coreCSRWrite = isCSRRW || (isCSR && |rs1Index);
	assign coreCSRRead = isCSRRC || isCSRRS || (isCSR && |rdIndex);

	wire[31:0] csrRS1Data = isCSRIMM ? { 27'b0, rs1Index} : rs1;

	always @(*) begin
		if (isCSR) begin			
			if (isCSRRW) coreCSRWriteData <= csrRS1Data;
			else if (isCSRRS) coreCSRWriteData <= csrReadData | csrRS1Data;
			else if (isCSRRC) coreCSRWriteData <= csrReadData & ~csrRS1Data;
			else coreCSRWriteData <= 32'b0;
		end else begin
			coreCSRWriteData <= 32'b0;
		end 
	end


	wire[31:0] targetMemoryAddress = state == STATE_FETCH   ? programCounter : 
									 state == STATE_EXECUTE ? aluAPlusB:
									 						  32'b0;
	wire loadSigned    = (funct3 == 3'b000) || (funct3 == 3'b001);
	wire loadStoreByte = funct3[1:0] == 2'b00;
	wire loadStoreHalf = funct3[1:0] == 2'b01;
	wire loadStoreWord = funct3 == 3'b010;
	reg[3:0] baseByteMask;
	always @(*) begin
		if (state == STATE_FETCH) baseByteMask <= 4'b1111;
		else if ((isLoad || isStore) && state == STATE_EXECUTE) begin
			if (loadStoreWord) baseByteMask <= 4'b1111;
			else if (loadStoreHalf) baseByteMask <= 4'b0011;
			else if (loadStoreByte) baseByteMask <= 4'b0001;
			else baseByteMask <= 4'b0000;
		end else baseByteMask <= 4'b0000;
	end

	reg signExtend;
	always @(*) begin
		if (loadSigned) begin
			if (loadStoreByte) begin
				case (targetMemoryAddress[1:0])
					2'b00: signExtend <= memoryDataRead[7];
					2'b01: signExtend <= memoryDataRead[15];
					2'b10: signExtend <= memoryDataRead[23];
					2'b11: signExtend <= memoryDataRead[31];
				endcase
			end else if (loadStoreHalf) begin
				case (targetMemoryAddress[1:0])
					2'b00: signExtend <= memoryDataRead[15];
					2'b01: signExtend <= memoryDataRead[23];
					2'b10: signExtend <= memoryDataRead[31];
					2'b11: signExtend <= 1'b0;
				endcase
			end else begin
				signExtend <= 1'b0;
			end
		end else begin
			signExtend <= 1'b0;
		end
	end

	wire[7:0] signExtendByte = signExtend ? 8'hFF : 8'h00;

	wire[6:0] loadStoreByteMask = {3'b0, baseByteMask} << targetMemoryAddress[1:0];
	wire loadStoreByteMaskValid = |(loadStoreByteMask[3:0]);
	wire addressMissaligned = |loadStoreByteMask[6:4];
	wire isAddressMisaligned = addressMissaligned && ((state == STATE_FETCH) || ((state == STATE_EXECUTE) && (isLoad || isStore)));
	wire shouldLoad  = loadStoreByteMaskValid && !addressMissaligned && ((state == STATE_FETCH) || ((state == STATE_EXECUTE) && isLoad));
	wire shouldStore = loadStoreByteMaskValid && !addressMissaligned && ((state == STATE_EXECUTE) && isStore);
	assign memoryAddress = shouldLoad || shouldStore ? { targetMemoryAddress[31:2], 2'b00 } : 32'b0;

	assign memoryByteSelect = shouldStore || shouldLoad  ? loadStoreByteMask[3:0] : 4'b0000;

	wire[31:0] loadData  = shouldLoad && !shouldStore ? dataIn : 32'b0;
	wire[31:0] storeData = shouldStore && !shouldLoad ? rs2    : 32'b0;
	
	reg[31:0] dataIn;
	always @(*) begin
		case (targetMemoryAddress[1:0])
			2'b00: dataIn = {
					loadStoreByteMask[3] ? memoryDataRead[31:24] : signExtendByte,
					loadStoreByteMask[2] ? memoryDataRead[23:16] : signExtendByte,
					loadStoreByteMask[1] ? memoryDataRead[15:8]  : signExtendByte,
					loadStoreByteMask[0] ? memoryDataRead[7:0]   : 8'h00
				};

			2'b01: dataIn = {
					signExtendByte,
					loadStoreByteMask[3] ? memoryDataRead[31:24] : signExtendByte,
					loadStoreByteMask[2] ? memoryDataRead[23:16] : signExtendByte,
					loadStoreByteMask[1] ? memoryDataRead[15:8]  : 8'h00
				};

			2'b10: dataIn = {
					signExtendByte,
					signExtendByte,
					loadStoreByteMask[3] ? memoryDataRead[31:24] : signExtendByte,
					loadStoreByteMask[2] ? memoryDataRead[23:16] : 8'h00
				};

			2'b11: dataIn = {
					signExtendByte,
					signExtendByte,
					signExtendByte,
					loadStoreByteMask[3] ? memoryDataRead[31:24] : 8'h00
				};
		endcase
	end

	reg[31:0] dataOut;
	always @(*) begin
		case (targetMemoryAddress[1:0])
			2'b00: dataOut = {
					baseByteMask[3] ? storeData[31:24] : 8'h00,
					baseByteMask[2] ? storeData[23:16] : 8'h00,
					baseByteMask[1] ? storeData[15:8]  : 8'h00,
					baseByteMask[0] ? storeData[7:0]   : 8'h00
				};

			2'b01: dataOut = {
					baseByteMask[2] ? storeData[23:16] : 8'h00,
					baseByteMask[1] ? storeData[15:8]  : 8'h00,
					baseByteMask[0] ? storeData[7:0]   : 8'h00,
					8'h00
				};

			2'b10: dataOut = {
					baseByteMask[1] ? storeData[15:8]  : 8'h00,
					baseByteMask[0] ? storeData[7:0]   : 8'h00,
					8'h00,
					8'h00
				};

			2'b11: dataOut = {
					baseByteMask[0] ? storeData[7:0]   : 8'h00,
					8'h00,
					8'h00,
					8'h00
				};
		endcase
	end

	assign memoryDataWrite = dataOut;

	assign memoryWriteEnable = shouldStore;
	assign memoryReadEnable = shouldLoad;

	wire memoryReadReady = shouldLoad ? !memoryBusy : 1'b0;
	wire memoryWriteDone = shouldStore ? !memoryBusy : 1'b0;


	wire integerRegisterWriteEn = isLUI || isAUIPC || isJAL || isJALR || isALU || isALUImm || isLoad || csrReadEnable;
	wire[31:0] integerRegisterWriteData = isLUI 			  ? imm_U			   :
										  isAUIPC 			  ? aluAPlusB 		   :
										  isJAL 			  ? programCounterLink :
										  isJALR 			  ? programCounterLink :
										  isLoad 			  ? loadData		   :
										  (isALU || isALUImm) ? aluValue 		   :
										  csrReadEnable		  ? csrReadData 	   :
																32'b0;

	wire progressExecute = isStore ? memoryWriteDone :
						   isLoad  ? memoryReadReady : 
							 		 1'b1;

	always @(posedge clk) begin
		if (rst) begin
			state <= STATE_HALT;
			programCounter <= 32'b0;
			currentError <= 4'b0;
			programCounter <= 32'b0;
			currentInstruction <= 32'b0;
		end else begin
			case (state)
				STATE_HALT: begin
					if (management_allowInstruction && !(|currentError)) state <= STATE_FETCH;
					else begin
						if (management_writeProgramCounter_set) programCounter <= { management_writeData[31:1] , 1'b0};
						else if (management_writeProgramCounter_jump) programCounter <= { management_jumpTarget[31:1] , 1'b0};
						else if (management_writeRegister) registers[management_registerIndex] <= management_writeData;
						else if (management_writeClearError) currentError <= 2'b0;
					end
				end

				STATE_FETCH: begin
					if (|currentError) begin
						state <= STATE_HALT;
					end else begin
						if (inTrap) programCounter <= trapVector;
						else if (memoryReadReady) begin
							currentInstruction <= dataIn;
							state <= STATE_EXECUTE;
						end
					end
				end

				STATE_EXECUTE: begin
					if (!management_trapEnable && (isAddressMisaligned || isInvalidInstruction)) begin
						currentError <= { isAddressMisaligned, isInvalidInstruction };
						state <= STATE_HALT;
					end else begin
						if (progressExecute) begin
							if (integerRegisterWriteEn && |rdIndex) registers[rdIndex] <= integerRegisterWriteData;

							if (management_trapEnable) begin
								if (inTrap) programCounter <= trapVector;
								else if (isRET) programCounter <= trapReturnVector;
								else programCounter <= nextProgramCounter;
							end else begin
								programCounter <= nextProgramCounter;
							end
							
							if (management_allowInstruction) state <= STATE_FETCH;
							else state <= STATE_HALT;
						end
					end
				end

				default: state <= STATE_HALT;
			endcase
		end
	end


	wire eCall = isECALL && (state == STATE_EXECUTE);
	wire eBreak = isEBREAK && (state == STATE_EXECUTE);
	wire trapReturn = isRET && (state == STATE_EXECUTE);

	wire isMachineTimerInterrupt = 1'b0;
	wire isMachineExternalInterrupt = 1'b0;
	wire isMachineSoftwareInterrupt = 1'b0;


	wire instructionCompleted = (state == STATE_EXECUTE) && progressExecute;
	CSR csr(
		.clk(clk),
		.rst(rst),
		.csrWriteEnable(csrWriteEnable),
		.csrReadEnable(csrReadEnable),
		.csrAddress(csrAddress),
		.csrWriteData(csrWriteData),
		.csrReadData(csrReadData),
		.coreIndex(coreIndex),
		.manufacturerID(manufacturerID),
		.partID(partID),
		.versionID(versionID),
		.extensions(extensions),
		.instructionCompleted(instructionCompleted),
		.coreState(state),
		.programCounter(programCounter),
		.currentInstruction(currentInstruction),
		.isLoad(isLoad),
		.isStore(isStore),
		.isMachineTimerInterrupt(isMachineTimerInterrupt),
		.isMachineExternalInterrupt(isMachineExternalInterrupt),
		.isMachineSoftwareInterrupt(isMachineSoftwareInterrupt),
		.isAddressMisaligned(isAddressMisaligned),
		.isJumpMissaligned(jumpMissaligned),
		.isAccessFault(memoryAccessFault),
		.isInvalidInstruction(isInvalidInstruction),
		.isEBREAK(eBreak),
		.isECALL(eCall),
		.isAddressBreakpoint(isAddressBreakpoint),
		.userInterrupts(management_interruptEnable ? userInterrupts : 16'b0),
		.trapReturn(trapReturn),
		.inTrap(inTrap),
		.trapVector(trapVector),
		.trapReturnVector(trapReturnVector));


	assign probe_state = state;
	assign probe_env = { eCall, eBreak };
	assign probe_programCounter = programCounter;
	assign probe_opcode = opcode;
	assign probe_errorCode = currentError;
	assign probe_isBranch = isBranch;
	assign probe_takeBranch = takeBranch;
	assign probe_isStore = isStore;
	assign probe_isLoad = isLoad;
	assign probe_isCompressed = isCompressed;

endmodule