// codec2.v -- Codec interface
// Ed Doering
// 07/20/2000
//
// Based on codec.v, but uses single shift register and two output data registers.
// Valid data indicators are now register outputs.
//
/*
Codec DUT (
	// Inputs: 
	.I$Clock	( 12MHz clock ),
	.I$Reset	( active high async reset ),
	.I$LeftChannel	( left channel to codec, 20 bits, 2's complement format ),
	.I$RightChannel	( right channel to codec, 20 bits, 2's complement format ),
	.I$SerialDataFromCodec	( connect to 'SDOUT' of codec ),

	// Outputs: 
	.O$LeftChannel	( left channel from codec, 20 bits, 2's complement format ),
	.O$RightChannel	( right channel from codec, 20 bits, 2's complement format ),
	.O$LeftChannelDataValid	( indicates when left channel data is valid, active high),
	.O$RightChannelDataValid (indicates when right channel data is valid, active high),
	.O$MasterClock	( connect to 'MCLK' of codec ),
	.O$LeftRightClock ( connect to 'LRCK' of codec ),
	.O$SerialClock	( connect to 'SCLK' of codec ),
	.O$SerialDataToCodec ( connect to 'SDIN' of codec )
);
*/

//-------------------------------------------------------------------------------



module Codec ( 
	// Stereo codec interface for the XSV board 

	// Inputs: 
	I$Clock	// Master clock (must be approximately 12MHz)
,
	I$Reset	// Master reset, active high
,
	I$LeftChannel	// Left channel data to send to codec
,
	I$RightChannel	// Right channel data to send to codec
,
	I$SerialDataFromCodec	// Serial data from codec ('sdout')
,

	// Outputs: 
	O$LeftChannel	// Left channel data from codec
,
	O$RightChannel	// Right channel data from codec
,
	O$LeftChannelDataValid	// 'H' => left channel data is valid
,
	O$RightChannelDataValid	// 'H' => right channel data is valid
,
	O$MasterClock	// Master clock for codec ('mclk')
,
	O$LeftRightClock	// Left/right indicator for codec ('lrck')
,
	O$SerialClock	// Serial clock for codec ('sclk')
,
	O$SerialDataToCodec	// Serial data to codec ('sdin')
); 

// Port mode declarations:
input	I$Clock;
input	I$Reset;
input	[19:0]	I$LeftChannel;
input	[19:0]	I$RightChannel;
input	I$SerialDataFromCodec;
output	[19:0]	O$LeftChannel;
output	[19:0]	O$RightChannel;
output	O$LeftChannelDataValid;
output	O$RightChannelDataValid;
output	O$MasterClock;
output	O$LeftRightClock;
output	O$SerialClock;
output	O$SerialDataToCodec;

// Registered variable declarations:
reg	[19:0]	O$LeftChannel;
reg	[19:0]	O$RightChannel;
reg	O$LeftChannelDataValid;
reg	O$RightChannelDataValid;
reg	O$SerialDataToCodec;

reg	[7:0]	r$CycleCounter;
reg	[19:0]	r$ShiftRegister;

// Constant parameter definitions:
parameter	p$LeftIsInvalid	= 8'd127;
parameter	p$LeftIsValid		= 8'd208;
parameter	p$RightIsInvalid	= 8'd255;
parameter	p$RightIsValid		= 8'd80;
		


//
// Timing signals:
//

// All timing signals derived from an 8-bit up-counter
always @ (posedge I$Clock or posedge I$Reset)
	if (I$Reset == 1)
		r$CycleCounter <= 0;
	else
		r$CycleCounter <= r$CycleCounter + 1;

// Timing signals applied to codec chip
assign O$MasterClock = I$Clock;
assign O$SerialClock = r$CycleCounter[1];
assign O$LeftRightClock = r$CycleCounter[7];


//
// Valid output data indicator signals:
//

always @ (posedge I$Clock or posedge I$Reset)
	if (I$Reset == 1) begin
		O$LeftChannelDataValid <= 0;
		O$RightChannelDataValid <= 0;
	end
	else begin
		O$LeftChannelDataValid <= (r$CycleCounter < p$LeftIsInvalid)
			|| (r$CycleCounter >= p$LeftIsValid);
		O$RightChannelDataValid <= (r$CycleCounter >= p$RightIsValid)
			&& (r$CycleCounter < p$RightIsInvalid);

	end


//
// Shift register:
//

always @ (posedge I$Clock or posedge I$Reset)
	if (I$Reset == 1)
		r$ShiftRegister <= 0;
	else 
		if (r$CycleCounter == p$LeftIsInvalid) 
			r$ShiftRegister <= I$LeftChannel;
		else if (r$CycleCounter == p$RightIsInvalid)
			r$ShiftRegister <= I$RightChannel;
		else if (r$CycleCounter[1:0] == 2'b11)
			r$ShiftRegister <= { r$ShiftRegister[18:0], I$SerialDataFromCodec };

// Connect MSB of shift register to serial output to codec
// NOTE: Use flip-flip triggered on positive edge to guarantee stable data
// when serial clock does falling edge transition (codec data sheet says that it
// latches data on falling edge)
always @ (posedge I$Clock or posedge I$Reset)
	if (I$Reset == 1)
		O$SerialDataToCodec <= 0;
	else
		O$SerialDataToCodec <= r$ShiftRegister[19];


//
// Output data registers:
//

always @ (posedge I$Clock or posedge I$Reset)
	if (I$Reset == 1) begin
		O$LeftChannel <= 0;
		O$RightChannel <= 0;
	end
	else begin
		if (r$CycleCounter == p$LeftIsValid) O$LeftChannel <= r$ShiftRegister;
		if (r$CycleCounter == p$RightIsValid) O$RightChannel <= r$ShiftRegister;
	end


//
// End of description!
//

endmodule