module lc8951(
	input nRESET,
	input clk_sys,
	input CLK_68KCLK_EN,
	input nWR, nRD,
	input RS,	// Register select, 0=Access address register, 1=Access pointed register
	input [7:0] DIN,
	output reg [7:0] DOUT,

	input [31:0] HEADER_DIN,

	input SECTOR_READY,
	input DMA_RUNNING,

	output reg CDC_nIRQ	// Triggers when SECTOR_READY or DMA_RUNNING rises and IRQ enabled
);

	reg [3:0] AR;		// Address Register
	reg [7:0] REGS_WRITE [15:0];
	
	reg [11:0] DBC;	// Byte counter for transfer
	reg [15:0] DAC;	// Transfer address - Can ignore ? Should always be set to 0000
	//reg [15:0] PT;	// Pointer to start of data block - Can always be 0004 ?
							// System ROM subtracts 4 to ignore MSF/Mode header
	reg [15:0] WA;		// Unused on Neo CD ?
	reg nDTBSY, nSTBSY, nDTEN, nSTEN, nVALST;
	reg [7:0] HEAD [3:0];
	
	// Bunch of decoder and error detection/correction flags which could be hardcoded
	// Can't have CD errors if there's no CD !
	reg CMDI_FLAG, DTEI_FLAG, DECI_FLAG;
	reg CMDIEN, DTEIEN, DECIEN, nCMDBRK, nDTWAI, nSTWAI, DOUTEN, SOUTEN;
	reg DTTRG;
	reg DECEN, EDCRQ, E01RQ, AUTORQ, ERAMRQ, WRRQ, QRQ, PRQ;
	reg SYIEN, SYDEN, DSCREN, COWREN, MODRQ, FORMRQ, SHDREN;
	
	reg nWR_PREV, nRD_PREV;
	reg SECTOR_READY_PREV, DMA_RUNNING_PREV, HEADER_WR_PREV;

	reg [15:0] INT_CYCLE_CNT;

	// 12 x 1800. LC8950 manual says that LC8951 /INT goes low for 1.8ms
	localparam INT_CYCLES = 16'd21600;

	always @(posedge clk_sys)
	begin
		if (!nRESET)
		begin
			AR <= 4'd0;
			nWR_PREV <= 1;
			nRD_PREV <= 1;
			
			CDC_nIRQ <= 1;
			
			DBC <= 12'h000;
			DAC <= 16'h0000;
			//PT <= 16'h0000;
			WA <= 16'h0000;
			
			CMDI_FLAG <= 0;
			DTEI_FLAG <= 0;
			DECI_FLAG <= 0;
			nDTBSY <= 1;
			nSTBSY <= 1;
			nDTEN <= 1;
			nSTEN <= 1;
			
			HEAD[0] <= 8'h00;
			HEAD[1] <= 8'h00;
			HEAD[2] <= 8'h00;
			HEAD[3] <= 8'h00;
			
			nVALST <= 1;
			
			{CMDIEN, DTEIEN, DECIEN, nCMDBRK, nDTWAI, nSTWAI, DOUTEN, SOUTEN} <= 8'b00000000;
			DTTRG <= 0;
			{DECEN, EDCRQ, E01RQ, AUTORQ, ERAMRQ, WRRQ, QRQ, PRQ} <= 8'b00000000;
			{SYIEN, SYDEN, DSCREN, COWREN, MODRQ, FORMRQ, SHDREN} <= 7'b0000000;
			
			SECTOR_READY_PREV <= 0;
			DMA_RUNNING_PREV <= 0;
			HEADER_WR_PREV <= 0;

			INT_CYCLE_CNT <= 0;
		end
		else
		if (CLK_68KCLK_EN) begin

			SECTOR_READY_PREV <= SECTOR_READY;
			DMA_RUNNING_PREV <= DMA_RUNNING;

			// Rising edge of SECTOR_READY: Set decoder IRQ flag
			if (~SECTOR_READY_PREV & SECTOR_READY) begin
				if (DECEN) begin
					DECI_FLAG <= 1;
					nVALST <= 0;
					INT_CYCLE_CNT <= 0;
					HEAD[0] <= HEADER_DIN[ 7: 0];
					HEAD[1] <= HEADER_DIN[15: 8];
					HEAD[2] <= HEADER_DIN[23:16];
					HEAD[3] <= HEADER_DIN[31:24];
				end
			end else if (~nVALST) begin // Use nVALST because DECI can be reset by reading STAT3.
				if (INT_CYCLE_CNT < INT_CYCLES) begin
					INT_CYCLE_CNT <= INT_CYCLE_CNT + 1'b1;
				end else begin // Decoder INT timeout
					DECI_FLAG <= 0;
					nVALST <= 1;
				end
			end

			// Falling edge of DMA_RUNNING: Set transfer end IRQ flag
			if (DMA_RUNNING_PREV & ~DMA_RUNNING) begin
				//DTEI_FLAG <= 1;
				nDTBSY <= 1;
			end

			CDC_nIRQ <= ~|{(CMDI_FLAG & CMDIEN), (DTEI_FLAG & DTEIEN), (DECI_FLAG & DECIEN)};

			nWR_PREV <= nWR;
			nRD_PREV <= nRD;

			if (nWR_PREV & ~nWR)
			begin
				// Write
				if (~RS)
					AR <= DIN[3:0];
				else
				begin
					case(AR)
						4'd0:;	// COMIN - Is the command system used at all ?
						4'd1: {CMDIEN, DTEIEN, DECIEN, nCMDBRK, nDTWAI, nSTWAI, DOUTEN, SOUTEN} <= DIN;	// IFCTRL
						
						4'd2: DBC[7:0] <= DIN;		// DBCL - Data transfer byte counter
						4'd3: DBC[11:8] <= DIN[3:0];	// DBCH
						
						4'd4: DAC[7:0] <= DIN;		// DACL
						4'd5: DAC[15:8] <= DIN;		// DACH
						4'd6: begin
								DTTRG <= 1;
								if (DOUTEN) begin
									nDTBSY <= 0;
								end
						end
						4'd7: DTEI_FLAG <= 0;		// DTACK - Clears the transfer end IRQ flag
						
						4'd8: WA[7:0] <= DIN;		// WAL
						4'd9: WA[15:8] <= DIN;		// WAH
			
						4'd10: {DECEN, EDCRQ, E01RQ, AUTORQ, ERAMRQ, WRRQ, QRQ, PRQ} <= DIN;	// CTRL0
						4'd11: {SYIEN, SYDEN, DSCREN, COWREN, MODRQ, FORMRQ, SHDREN} <= {DIN[7:2], DIN[0]};	// CTRL1
						
						4'd12:; //PT[7:0] <= DIN;		// PTL
						4'd13:; //PT[15:8] <= DIN;		// PTH
						4'd14:;
						4'd15:;	// RESET - Unused ?
					endcase
					
					// Auto-inc if AR is nonzero
					if (|{AR})
						AR <= AR + 1'b1;
				end
			end
			else if (nRD_PREV & ~nRD)
			begin
				// Read
				if (~RS)
					DOUT <= {4'b0000, AR};
				else
				begin
					case(AR)
						4'd0: DOUT <= 8'b00000000;	// SBOUT - Is the command system used at all ?
						4'd1: DOUT <= {~CMDI_FLAG, ~DTEI_FLAG, ~DECI_FLAG, 1'b1, nDTBSY, nSTBSY, nDTEN, nSTEN};	// IFSTAT
						
						4'd2: DOUT <= DBC[7:0];		// DBCL - Data transfer byte counter
						4'd3: DOUT <= {{4{DTEI_FLAG}}, DBC[11:8]};	// DBCH
						
						4'd4: DOUT <= HEAD[0];
						4'd5: DOUT <= HEAD[1];
						4'd6: DOUT <= HEAD[2];
						4'd7: DOUT <= HEAD[3]; // CD-ROM mode, always 1
						
						4'd8: DOUT <= 8'h04;	//PT[7:0];		// PTL
						4'd9: DOUT <= 8'h00;	//PT[15:8];		// PTH
			
						4'd10: DOUT <= WA[7:0];		// WAL - Datasheet says these are undefined after reset
						4'd11: DOUT <= WA[15:8];	// WAH
						
						4'd12: DOUT <= 8'b10000000;	// STAT0 - CRC OK
						4'd13: DOUT <= 8'b00000000;	// STAT1
						4'd14: DOUT <= 8'b00000000;	// STAT2 - MODE, FORM (Mode 1)
						4'd15:
						begin
							DOUT <= {nVALST, 7'b0000000};	// STAT3 - Reading clears the decoder IRQ
							DECI_FLAG <= 0;
						end
					endcase
				
					// Auto-inc if AR is nonzero
					if (|{AR})
						AR <= AR + 1'b1;
				end
			end
		end
	end
	
endmodule