module apb3_slave #(
	// user parameter starts here
	//
	parameter	ADDR_WIDTH	= 12,
	parameter	DATA_WIDTH	= 31,
	parameter	NUM_REG		= 4
) (
	// user logic starts here
	output [1:0] 			apb3LED,
	output				apb3Interrupt,
	//
	input				clk,
	input				resetn,
	input	[ADDR_WIDTH-1:0]	PADDR,
	input				PSEL,
	input				PENABLE,
	output				PREADY,
	input				PWRITE,
	input 	[DATA_WIDTH-1:0] 	PWDATA,
	output	[DATA_WIDTH-1:0] 	PRDATA,
	output				PSLVERROR

);


///////////////////////////////////////////////////////////////////////////////

localparam [1:0]	IDLE   = 2'b00,
			SETUP  = 2'b01,
			ACCESS = 2'b10;

reg [1:0] 		busState, 
			busNext;
reg [DATA_WIDTH-1:0]	slaveReg [0:NUM_REG-1];
reg [DATA_WIDTH-1:0]	slaveRegOut;
reg			slaveReady;
wire	 		actWrite,
			actRead;
integer			byteIndex;


///////////////////////////////////////////////////////////////////////////////

	always@(posedge clk or negedge resetn)
	begin
		if(!resetn) 
			busState <= IDLE; 
		else
			busState <= busNext; 
	end

	always@(*)
	begin
		busNext = busState;

		case(busState)
			IDLE:
			begin
				if(PSEL && !PENABLE)
					busNext = SETUP;
				else
					busNext = IDLE;
			end
			SETUP:
			begin
				if(PENABLE)
					busNext = ACCESS;
				else
					busNext = IDLE;
			end
			ACCESS:
			begin
				if(PENABLE)
					busNext = ACCESS;
				else
					busNext = IDLE;
			end
			default:
			begin
				busNext = IDLE;
			end
		endcase
	end


	assign actWrite = PWRITE  & (busNext == ACCESS);
	assign actRead  = !PWRITE & (busNext == SETUP);
	assign PSLVERROR = 1'b0; //FIXME
	assign PRDATA = slaveRegOut;
	assign PREADY = slaveReady;

	always@ (posedge clk)
	begin
		slaveReady <= (busState == IDLE);
	end

	always@ (posedge clk or negedge resetn)
	begin
		if(!resetn)
			for(byteIndex = 0; byteIndex < NUM_REG; byteIndex = byteIndex + 1)
			slaveReg[byteIndex] <= {{DATA_WIDTH}{1'b0}};
		else begin
			for(byteIndex = 0; byteIndex < NUM_REG; byteIndex = byteIndex + 1)
			if(actWrite && PADDR[3:0] == (byteIndex*4))
				slaveReg[byteIndex] <= PWDATA;
			else
				slaveReg[byteIndex] <= slaveReg[byteIndex];
				
		end

	end

	always@ (posedge clk or negedge resetn)
	begin
		if(!resetn)
			slaveRegOut <= {{DATA_WIDTH}{1'b0}};
		else begin
			if(actRead)
				slaveRegOut <= slaveReg[PADDR[7:2]];
			else
				slaveRegOut <= slaveRegOut;
				
		end

	end

	//custom logic starts here
	assign apb3LED 		= slaveReg[0][1:0];
	assign apb3Interrupt 	= slaveReg[0][2];
	//
endmodule