/*********************************************************************************
*
*	SID oscillator hardware emulation
*
*	Just messing around with what's described in the intervew here:
*	http://sid.kubarth.com/articles/interview_bob_yannes.html
*
*	Code not to be copied without giving adequate props of the "hella mad" variety. 
*
**********************************************************************************/

module SID(
	input				[15:0]		FREQ,		//Frequency control - accumulator increment value
	output		wire	[11:0]		TRI,		//Triangle wave output
	output		wire	[11:0]		SAW,		//Saw wave output
	output		wire	[11:0]		TRI_AND_SAW,//Saw and Triangle wave combined output
	output		wire	[11:0]		PULSE,		//Pulse wave output
	output		wire	[11:0]		NOISE,		//Noiser wave output
	input							CLK,		//Master clock input
	input							RES,		//Master reset
	input				[11:0]		DUTY		//Pulse wave duty cycle input
);

wire [23:0] accum_out;
accum my_accum(						//Accumulator instantiation
	.CLK			(CLK),
	.INC_VAL		(FREQ),
	.OUT_VAL		(accum_out),
	.RES			(RES)
);

assign SAW = accum_out[23:12];	//"upper 12-bits of the accumulator"

assign TRI = {{11{accum_out[23]}}^(accum_out[22:12]), 1'b0};
//"using the MSB of the accumulator to invert the remaining upper 11 accumulator bits 
//using EXOR gates. These 11 bits were then left-shifted (throwing away the MSB)"

assign TRI_AND_SAW = SAW & TRI;
//"combination was actually a logical ANDing of the bits of each waveform"

wire comparator = (accum_out[23:12]>=DUTY); //"12-bit digital comparator"
assign PULSE = {12{comparator}};			//"single output... to all 12 bits"

LFSR m_lfsr(
	.CLK			(accum_out[16]),	
	//"clocked by one of the intermediate bits of the accumulator"
	//I'm not sure which intermediate bit he used, so I just grabbed one that made for
	//pretty graphs.
	.RES			(RES),
	.NOISE_OUT		(NOISE)
);

endmodule

//Linear feedback shift register is put into separate module
module LFSR(
	input							CLK,
	input							RES,
	output		wire	[11:0]		NOISE_OUT
);

reg	[22:0]	lfsr;	//"23-bit pseudo-random sequence generator..."
//"...a shift register with specific outputs fed back to the input through combinatorial logic"
wire feedback = lfsr[22] ^ lfsr[17];
//Interview doesn't say which taps are used in the SID. These are grabbed from a Xilinx
//app note on linear feedback shift registers.

assign NOISE_OUT = lfsr[22:11];			//"The upper 12-bits of the shift register"

always @(posedge CLK or posedge RES)
	if(RES)
		lfsr <= 23'd1;					//lfsr must never contain all zeros
	else
		lfsr <= (lfsr<<1) + feedback;	//shift!

endmodule

//Accumulator is in separate module to act as a wrapper. In a Spartan 6, for example,
//this could be done in a DSP48A1 block. 
module accum(
	output		reg		[23:0]		OUT_VAL,	//"24-bit phase-accumulating design"
	input				[15:0]		INC_VAL,	//"of which the lower 16-bits are programmable for pitch control"
	input							CLK,
	input							RES
);

always @(posedge CLK)
	if(RES)
		OUT_VAL <= 'b0;					//Reset Accumulator
	else
		OUT_VAL <= OUT_VAL + INC_VAL;	//Increment Accumulator

endmodule

//	Copyright 2010 - Analog Bytes, LLC