/*=========================================================================*/
/*===  DE248 Support Library ==============================================*/
/*=========================================================================*/

/* 
 * FILE: support.v
 * PROGRAMMER: William L. Bahn
 *
 * This file contains just those modules from other, more generic,
 * library files that are needed for the DE248. The purpose for 
 * doing this is to make the distribution files more compact.
 *
 * CONTENTS:
 * From: registers.v
 *       - RSFF(Q, S, R, rst, clk);
 *       - DFFRen(Q, D, en, rst, clk);
 *       - Reg4(Q, D, en, rst, clk);
 *       - Reg8(Q, D, en, rst, clk);
 *       - Reg16(Q, D, en, rst, clk);
 *       - ShiftReg10(Sout, Sin, Q, D, Shift, Load, rst, clk);
 *       - ShiftReg16LSB(Sout, Sin, Q, D, Shift, Load, rst, clk);
 *       - DualPortBlockRAM512x64(WA, Din, WE, RA, Dout, clk);
 * From: counter.v
 *       - Counter12(Q, en, rst, clk);
 *       - PulseGen8(Q, Period, en, rst, clk);
 *       - PulseGen16(Q, Period, en, rst, clk);
 *       - PulseGen24(Q, Period, en, rst, clk);
 *       - Binary2Gray12(Gray, Binary, rst, clk);
 *       - Gray2Binary12(Binary, Gray, rst, clk);
 * From: muxus.v
 *       - MUX2(Q, D1, D0, Sel);
 *       - MUX4(Q, D3, D2, D1, D0, Sel);
 *       - MUX2TAP(Q, D, Sel);
 *       - MUX4TAP(Q, D, Sel);
 *       - MUX2x2(Q, D1, D0, Sel);
 *       - MUX2x8(Q, D1, D0, Sel);
 *       - MUX2x16(Q, D1, D0, Sel);
 *       - MUX4x2(Q, D3, D2, D1, D0, Sel);
 *       - MUX4x8(Q, D3, D2, D1, D0, Sel);
 *       - MUX16x8
 * From: fifos.v
 *       - FIFO16x24(Dout, Din, FF, AF, HF, AE, EF, Push, Pop, Dump, clk);
 *       - FIFO16x32(Dout, Din, FF, AF, HF, AE, EF, Push, Pop, Dump, clk);
 * From: mmv.v
 *       - OneShot(Q, Start, Stop, rst, clk);
 *       - FireAndAcknowledge(Q, Fire, Ack, rst, clk);
 */

/*=========================================================================*/
/*===  From the REGISTERS LIBRARY  ========================================*/
/*=========================================================================*/

module RSFF(Q, S, R, rst, clk);

	output Q;
	input  S, R;
	input rst, clk;

	parameter LO = 1'b0, HI = 1'b1;

	reg Q_int;
	assign Q = Q_int;

	always @ (posedge clk)
	begin
		if ((rst == HI)||(R == HI))
			Q_int <= LO;
		else if (S == HI)
			Q_int <= HI;
		else
			Q_int <= Q_int;
	end

endmodule

module DFFRen(Q, D, en, rst, clk);
	output Q;
	input D, en, rst, clk;

	reg Q_int;

	assign Q = Q_int;

	always @ (posedge clk or posedge rst)
	begin
		if (rst == 1)
			Q_int <= 0;
		else if (en == 1)
			Q_int <= D;
		else
			Q_int <= Q_int;
	 end
endmodule

module Reg4(Q, D, en, rst, clk);

	parameter REGWIDTH = 4;

	input clk, en, rst;
	input [(REGWIDTH-1):0] D;
	output [(REGWIDTH-1):0] Q;

	reg [(REGWIDTH-1):0] Q_int;

	assign Q = (rst == 0)? Q_int : 4'd0;

	always @ (posedge clk)
	begin
		if (rst == 1)
			Q_int <= 4'd0;
		else if (en == 1)
			Q_int <= D;
		else
			Q_int <= Q_int;
	end

endmodule

module Reg8(Q, D, en, rst, clk);

	parameter REGWIDTH = 8;

	input clk, en, rst;
	input [(REGWIDTH-1):0] D;
	output [(REGWIDTH-1):0] Q;

	reg [(REGWIDTH-1):0] Q_int;

	assign Q = (rst == 0)? Q_int : 8'd0;

	always @ (posedge clk)
	begin
		if (rst == 1)
			Q_int <= 8'd0;
		else if (en == 1)
			Q_int <= D;
		else
			Q_int <= Q_int;
	end

endmodule

module Reg16(Q, D, en, rst, clk);

	parameter REGWIDTH = 16;

	input clk, en, rst;
	input [(REGWIDTH-1):0] D;
	output [(REGWIDTH-1):0] Q;

	reg [(REGWIDTH-1):0] Q_int;

	assign Q = (rst == 0)? Q_int : 16'd0;

	always @ (posedge clk)
	begin
		if (rst == 1)
			Q_int <= 16'd0;
		else if (en == 1)
			Q_int <= D;
		else
			Q_int <= Q_int;
	end

endmodule

module ShiftReg10(Sout, Sin, Q, D, Shift, Load, rst, clk);
	input Sin;
	output Sout;
	output [9:0] Q;
	input [9:0] D;
	input Shift, Load, rst, clk;

	reg [9:0] Q_int;

	assign Q = (rst == 0)? Q_int: 10'd0;
   assign Sout = Q_int[0];
	
	always @ (posedge clk)
	begin
		if (rst == 1)
			Q_int <= 10'd0;
		else if (Load == 1)
			Q_int <= D;
		else if (Shift == 1)
			Q_int <= {Sin,Q_int[9:1]};
		else
			Q_int <= Q_int;
	end
endmodule

module ShiftReg16DIR(Sout, Sin, Q, D, Shift, Load, Dir, rst, clk);
	input Sin;
	output Sout;
	output [15:0] Q;
	input [15:0] D;
	input Shift, Load, Dir, rst, clk;

	reg [15:0] Q_int;

	assign Q = Q_int;
   assign Sout = (Dir == 0)? Q_int[0] : Q_int[15];
	
	always @ (posedge clk)
	begin
		if (rst == 1)
			Q_int <= 16'd0;
		else if (Load == 1)
			Q_int <= D;
		else if (Shift == 1)
			if (Dir == 0)
				Q_int <= {Sin, Q_int[15:1]};
			else
				Q_int <= {Q_int[14:0], Sin};
		else
			Q_int <= Q_int;
	end
endmodule

module ShiftReg16LSB(Sout, Sin, Q, D, Shift, Load, rst, clk);
	input Sin;
	output Sout;
	output [15:0] Q;
	input [15:0] D;
	input Shift, Load, rst, clk;

	reg [15:0] Q_int;

	assign Q = (rst == 0)? Q_int: 16'd0;
   assign Sout = Q_int[0];
	
	always @ (posedge clk)
	begin
		if (rst == 1)
			Q_int <= 16'd0;
		else if (Load == 1)
			Q_int <= D;
		else if (Shift == 1)
			Q_int <= {Sin,Q_int[15:1]};
		else
			Q_int <= Q_int;
	end
endmodule

module DualPortBlockRAM512x64
	(
		WriteAddress,
		DataIn,
		WriteEnable,
		ReadAddress,
		DataOut,
		clk
	);

	input  [ 8:0] WriteAddress;
	input  [63:0] DataIn;
	input         WriteEnable;
	input  [ 8:0] ReadAddress;
	output [63:0] DataOut;
	input         clk;

	parameter LO = 1'b0, HI = 1'b1;

	reg [63:0] DPRAM[511:0];
	reg [8:0] RA;

	always @ (posedge clk)
	begin
		if (WriteEnable == HI)
			DPRAM[WriteAddress] <= DataIn;
		RA <= ReadAddress;
	end

	assign DataOut = DPRAM[RA];

endmodule

/*=========================================================================*/
/*===  From the COUNTERS LIBRARY  =========================================*/
/*=========================================================================*/

module Counter12(Q, en, rst, clk);
	output [11:0] Q;
	input en, rst, clk;

	reg [11:0] Q_int;

	assign Q = (rst == 0)? Q_int : 11'd0;

	always @(posedge clk)
	begin
		if (rst == 1)
			Q_int <= 11'd0;
		else if (en == 1)
			Q_int <= Q_int + 1;
		else
			Q_int <= Q_int;
	end
endmodule

/*=========================================================================*/
/* Programmable Pulse Pattern Generator
	NOTE: This is NOT an arbitrary pattern generator. 
	
	Scale : This is a clock prescaler. The pattern generator logic
	        is only active every Nth master clock if Scale is N. This
			  is the rate at which the pattern generator 'ticks'.

	Period: The period of the waverform in pattern generator ticks.

	Rise  : The output goes HI 'Rise' ticks after rollover or reset.
	 
	Fall  : The output goes LO 'Fall' ticks after rollover or reset.

	The pattern generator resets to LO upon an active reset, but
	remains unchanged upon a rollover.
*/
/*=========================================================================*/

/* MODULE: PulseGen16
 * DESCRIPTION: Programmable Pulse Generator
 * This module produces a single HI pulse once every 'Period' system clocks.
 * This range may be arbitrarily extended by gating the 'en' input as only
 * those clocks that occur while enabled are counted.
 *
 * The output is only asserted when the module is enabled.
 */

module PulseGen8(Q, Period, en, rst, clk);
	output Q;
	input [7:0] Period;
	input en, rst, clk;

	parameter HI = 1'b1, LO = 1'b0;

	wire D;
	reg [7:0] count, newcount;

	always @(posedge clk)
	begin
		count <= newcount;
	end

	assign D = (newcount == 8'd0)? HI : LO;
	DFFRen DFF (.Q(Q), .D(D), .en(HI), .rst(rst), .clk(clk));
		
	always @(count or Period or rst or en)
	begin
		if (rst == HI)
			newcount <= Period;
		else if (en == 1)
			if (count == 8'd0)
				newcount <= Period;
			else
				newcount <= count - 1;
		else
			begin
				newcount <= count;
			end
	end

endmodule

module PulseGen16(Q, Period, en, rst, clk);
	output Q;
	input [15:0] Period;
	input en, rst, clk;

	parameter HI = 1'b1, LO = 1'b0;

	wire D;
	reg [15:0] count, newcount;

	always @(posedge clk)
	begin
		count <= newcount;
	end

	assign D = (newcount == 16'd0)? HI : LO;
	DFFRen DFF (.Q(Q), .D(D), .en(HI), .rst(rst), .clk(clk));
		
	always @(count or Period or rst or en)
	begin
		if (rst == HI)
			newcount <= Period;
		else if (en == 1)
			if (count == 16'd0)
				newcount <= Period;
			else
				newcount <= count - 1;
		else
			begin
				newcount <= count;
			end
	end

endmodule

module PulseGen24(Q, Period, en, rst, clk);
	output Q;
	input [23:0] Period;
	input en, rst, clk;

	parameter HI = 1'b1, LO = 1'b0;

	wire D;
	reg [23:0] count, newcount;

	always @(posedge clk)
	begin
		count <= newcount;
	end

	assign D = (newcount == 24'd0)? HI : LO;
	DFFRen DFF (.Q(Q), .D(D), .en(HI), .rst(rst), .clk(clk));
		
	always @(count or Period or rst or en)
	begin
		if (rst == HI)
			newcount <= Period;
		else if (en == 1)
			if (count == 24'd0)
				newcount <= Period;
			else
				newcount <= count - 1;
		else
			begin
				newcount <= count;
			end
	end

endmodule

module Binary2Gray12(Gray, Binary, rst, clk);
	output [11:0] Gray;
	input  [11:0] Binary;
	input  rst, clk;

	assign Gray[11] = Binary[11];
	assign Gray[10:0] = Binary[11:1]^Binary[10:0];

endmodule

module Gray2Binary12(Binary, Gray, rst, clk);
	output [11:0] Binary;
	input  [11:0] Gray;
	input  rst, clk;

	wire [11:0] Binary_int;
	assign Binary = Binary_int;

	assign Binary_int[11] = Gray[11];
	assign Binary_int[10:0] = Binary_int[11:1]^Gray[10:0];

endmodule

/*=========================================================================*/
/*===  From the MUXES LIBRARY  ============================================*/
/*=========================================================================*/

module MUX2(Q, D1, D0, Sel);
	output Q;
	input D1, D0;
	input Sel;

	wire [1:0] D;

	assign D = {D1,D0};

	MUX2TAP MUX (.Q(Q), .D(D), .Sel(Sel));

endmodule

module MUX4(Q, D3, D2, D1, D0, Sel);
	output Q;
	input D3, D2, D1, D0;
	input [1:0] Sel;

	wire [3:0] D;

	assign D = {D3,D2,D1,D0};

	MUX4TAP MUX (.Q(Q), .D(D), .Sel(Sel));

endmodule

module MUX2TAP(Q, D, Sel);
	output Q;
	input [1:0] D;
	input Sel;

	reg Q_int;

	assign Q = Q_int;

	always @ (D or Sel)
	begin
		case (Sel)
			0: Q_int = D[0];
			1: Q_int = D[1];
			default : Q_int = 1'd0;
		endcase
	end
endmodule

module MUX4TAP(Q, D, Sel);
	output Q;
	input [3:0] D;
	input [1:0] Sel;

	reg Q_int;

	assign Q = Q_int;

	always @ (D or Sel)
	begin
		case (Sel)
			0: Q_int = D[0];
			1: Q_int = D[1];
			2: Q_int = D[2];
			3: Q_int = D[3];
			default : Q_int = 1'd0;
		endcase
	end
endmodule

module MUX2x2(Q, D1, D0, Sel);
	output [1:0] Q;
	input [1:0] D1, D0;
	input Sel;

	MUX2 B1 (.Q(Q[1]), .D1(D1[1]), .D0(D0[1]), .Sel(Sel));
	MUX2 B0 (.Q(Q[0]), .D1(D1[0]), .D0(D0[0]), .Sel(Sel));

endmodule

module MUX2x8(Q, D1, D0, Sel);
	output [7:0] Q;
	input [7:0] D1, D0;
	input Sel;

	MUX2 B7 (.Q(Q[7]), .D1(D1[7]), .D0(D0[7]), .Sel(Sel));
	MUX2 B6 (.Q(Q[6]), .D1(D1[6]), .D0(D0[6]), .Sel(Sel));
	MUX2 B5 (.Q(Q[5]), .D1(D1[5]), .D0(D0[5]), .Sel(Sel));
	MUX2 B4 (.Q(Q[4]), .D1(D1[4]), .D0(D0[4]), .Sel(Sel));
	MUX2 B3 (.Q(Q[3]), .D1(D1[3]), .D0(D0[3]), .Sel(Sel));
	MUX2 B2 (.Q(Q[2]), .D1(D1[2]), .D0(D0[2]), .Sel(Sel));
	MUX2 B1 (.Q(Q[1]), .D1(D1[1]), .D0(D0[1]), .Sel(Sel));
	MUX2 B0 (.Q(Q[0]), .D1(D1[0]), .D0(D0[0]), .Sel(Sel));

endmodule

module MUX2x16(Q, D1, D0, Sel);
	output [15:0] Q;
	input [15:0] D1, D0;
	input Sel;

	MUX2 B15 (.Q(Q[15]), .D1(D1[15]), .D0(D0[15]), .Sel(Sel));
	MUX2 B14 (.Q(Q[14]), .D1(D1[14]), .D0(D0[14]), .Sel(Sel));
	MUX2 B13 (.Q(Q[13]), .D1(D1[13]), .D0(D0[13]), .Sel(Sel));
	MUX2 B12 (.Q(Q[12]), .D1(D1[12]), .D0(D0[12]), .Sel(Sel));
	MUX2 B11 (.Q(Q[11]), .D1(D1[11]), .D0(D0[11]), .Sel(Sel));
	MUX2 B10 (.Q(Q[10]), .D1(D1[10]), .D0(D0[10]), .Sel(Sel));
	MUX2 B9  (.Q(Q[ 9]), .D1(D1[ 9]), .D0(D0[ 9]), .Sel(Sel));
	MUX2 B8  (.Q(Q[ 8]), .D1(D1[ 8]), .D0(D0[ 8]), .Sel(Sel));
	MUX2 B7  (.Q(Q[ 7]), .D1(D1[ 7]), .D0(D0[ 7]), .Sel(Sel));
	MUX2 B6  (.Q(Q[ 6]), .D1(D1[ 6]), .D0(D0[ 6]), .Sel(Sel));
	MUX2 B5  (.Q(Q[ 5]), .D1(D1[ 5]), .D0(D0[ 5]), .Sel(Sel));
	MUX2 B4  (.Q(Q[ 4]), .D1(D1[ 4]), .D0(D0[ 4]), .Sel(Sel));
	MUX2 B3  (.Q(Q[ 3]), .D1(D1[ 3]), .D0(D0[ 3]), .Sel(Sel));
	MUX2 B2  (.Q(Q[ 2]), .D1(D1[ 2]), .D0(D0[ 2]), .Sel(Sel));
	MUX2 B1  (.Q(Q[ 1]), .D1(D1[ 1]), .D0(D0[ 1]), .Sel(Sel));
	MUX2 B0  (.Q(Q[ 0]), .D1(D1[ 0]), .D0(D0[ 0]), .Sel(Sel));

endmodule

module MUX4x2(Q, D3, D2, D1, D0, Sel);
	output [1:0] Q;
	input [1:0] D3, D2, D1, D0;
	input [1:0] Sel;

	MUX4 B1  (.Q(Q[ 1]), .D3(D3[ 1]), .D2(D2[ 1]), .D1(D1[ 1]), .D0(D0[ 1]), .Sel(Sel));
	MUX4 B0  (.Q(Q[ 0]), .D3(D3[ 0]), .D2(D2[ 0]), .D1(D1[ 0]), .D0(D0[ 0]), .Sel(Sel));

endmodule

module MUX4x8(Q, D3, D2, D1, D0, Sel);
	output [7:0] Q;
	input [7:0] D3, D2, D1, D0;
	input [1:0] Sel;

	MUX4 B7  (.Q(Q[ 7]), .D3(D3[ 7]), .D2(D2[ 7]), .D1(D1[ 7]), .D0(D0[ 7]), .Sel(Sel));
	MUX4 B6  (.Q(Q[ 6]), .D3(D3[ 6]), .D2(D2[ 6]), .D1(D1[ 6]), .D0(D0[ 6]), .Sel(Sel));
	MUX4 B5  (.Q(Q[ 5]), .D3(D3[ 5]), .D2(D2[ 5]), .D1(D1[ 5]), .D0(D0[ 5]), .Sel(Sel));
	MUX4 B4  (.Q(Q[ 4]), .D3(D3[ 4]), .D2(D2[ 4]), .D1(D1[ 4]), .D0(D0[ 4]), .Sel(Sel));

	MUX4 B3  (.Q(Q[ 3]), .D3(D3[ 3]), .D2(D2[ 3]), .D1(D1[ 3]), .D0(D0[ 3]), .Sel(Sel));
	MUX4 B2  (.Q(Q[ 2]), .D3(D3[ 2]), .D2(D2[ 2]), .D1(D1[ 2]), .D0(D0[ 2]), .Sel(Sel));
	MUX4 B1  (.Q(Q[ 1]), .D3(D3[ 1]), .D2(D2[ 1]), .D1(D1[ 1]), .D0(D0[ 1]), .Sel(Sel));
	MUX4 B0  (.Q(Q[ 0]), .D3(D3[ 0]), .D2(D2[ 0]), .D1(D1[ 0]), .D0(D0[ 0]), .Sel(Sel));

endmodule

module MUX16x8
	(
		Q, 
		DF, DE, DD, DC, DB, DA, D9, D8, 
		D7, D6, D5, D4, D3, D2, D1, D0, 
		Sel
	);

	output [7:0] Q;
	input [7:0] DF, DE, DD, DC, DB, DA, D9, D8; 
	input [7:0] D7, D6, D5, D4, D3, D2, D1, D0; 
	input [3:0] Sel;

	reg [7:0] Q_int;
	assign Q = Q_int;

	always @ 
	(
		Sel or
		DF or DE or DD or DC or DB or DA or D9 or D8 or 
		D7 or D6 or D5 or D4 or D3 or D2 or D1 or D0 
	)
	begin
		case (Sel)		  
			 0: Q_int = D0;
			 1: Q_int = D1;
			 2: Q_int = D2;
			 3: Q_int = D3;
			 4: Q_int = D4;
			 5: Q_int = D5;
			 6: Q_int = D6;
			 7: Q_int = D7;
			 8: Q_int = D8;
			 9: Q_int = D9;
			10: Q_int = DA;
			11: Q_int = DB;
			12: Q_int = DC;
			13: Q_int = DD;
			14: Q_int = DE;
			15: Q_int = DF;
			default : Q_int = 8'd0;
		endcase
	end

endmodule

/*=========================================================================*/
/*===  From the FIFOS LIBRARY  ============================================*/
/*=========================================================================*/

module FIFO16x8(DataOut, DataIn, FF, AF, HF, AE, EF, Push, Pop, Dump, Clk);
	parameter WIDTH = 8;
	parameter DEPTH = 16;
	parameter LOG2DEPTH = 4;

	input [(WIDTH-1):0] DataIn;
	output [(WIDTH-1):0] DataOut;
	output FF, AF, HF, AE, EF;
	input Push, Pop, Dump, Clk;
	
	wire WE, RE;

	reg [(LOG2DEPTH-1):0] Contents, ReadPointer, WritePointer;
	reg [(WIDTH-1):0] queue[(DEPTH-1):0];

	assign FF = (Contents == (DEPTH-1))? 1 : 0;
	assign AF = (Contents > (DEPTH-3))? 1 : 0;
	assign HF = (Contents > (DEPTH/2))? 1 : 0;
	assign AE = (Contents < 3)? 1 : 0;
	assign EF = (Contents == 0)? 1 : 0;

	assign WE = Push && ~FF;
	assign RE = Pop && ~EF;

	assign DataOut = queue[ReadPointer];

	always @ (posedge Clk)
	begin
		if (Dump == 1)
			Contents <= 0;
		else
			if ((WE == 1) && (RE == 0))
				Contents <= Contents + 1;
			else
				if ((WE == 0) && (RE == 1))
					Contents <= Contents - 1;
				else
					Contents <= Contents;
	end

	always @ (posedge Clk)
	begin
		if (Dump == 1)
			begin
				ReadPointer <= 0;
				WritePointer <= 0;
			end
		else
			begin
				if (RE == 1)
					begin
						ReadPointer <= ReadPointer + 1;
					end
				if (WE == 1)
					begin
						queue[WritePointer] <= DataIn;
						WritePointer <= WritePointer + 1;
					end
			end
	end

endmodule

module FIFO16x24(DataOut, DataIn, FF, AF, HF, AE, EF, Push, Pop, Dump, Clk);
	parameter WIDTH = 24;
	parameter DEPTH = 16;
	parameter LOG2DEPTH = 4;

	input [(WIDTH-1):0] DataIn;
	output [(WIDTH-1):0] DataOut;
	output FF, AF, HF, AE, EF;
	input Push, Pop, Dump, Clk;
	
	wire WE, RE;

	reg [(LOG2DEPTH-1):0] Contents, ReadPointer, WritePointer;
	reg [(WIDTH-1):0] queue[(DEPTH-1):0];

	assign FF = (Contents == (DEPTH-1))? 1 : 0;
	assign AF = (Contents > (DEPTH-3))? 1 : 0;
	assign HF = (Contents > (DEPTH/2))? 1 : 0;
	assign AE = (Contents < 3)? 1 : 0;
	assign EF = (Contents == 0)? 1 : 0;

	assign WE = Push && ~FF;
	assign RE = Pop && ~EF;

	assign DataOut = queue[ReadPointer];

	always @ (posedge Clk)
	begin
		if (Dump == 1)
			Contents <= 0;
		else
			if ((WE == 1) && (RE == 0))
				Contents <= Contents + 1;
			else
				if ((WE == 0) && (RE == 1))
					Contents <= Contents - 1;
				else
					Contents <= Contents;
	end

	always @ (posedge Clk)
	begin
		if (Dump == 1)
			begin
				ReadPointer <= 0;
				WritePointer <= 0;
			end
		else
			begin
				if (RE == 1)
					begin
						ReadPointer <= ReadPointer + 1;
					end
				if (WE == 1)
					begin
						queue[WritePointer] <= DataIn;
						WritePointer <= WritePointer + 1;
					end
			end
	end

endmodule

module FIFO16x32(DataOut, DataIn, FF, AF, HF, AE, EF, Push, Pop, Dump, Clk);
	parameter WIDTH = 32;
	parameter DEPTH = 16;
	parameter LOG2DEPTH = 4;

	input [(WIDTH-1):0] DataIn;
	output [(WIDTH-1):0] DataOut;
	output FF, AF, HF, AE, EF;
	input Push, Pop, Dump, Clk;
	
	wire WE, RE;

	reg [(LOG2DEPTH-1):0] Contents, ReadPointer, WritePointer;
	reg [(WIDTH-1):0] queue[(DEPTH-1):0];

	assign FF = (Contents == (DEPTH-1))? 1 : 0;
	assign AF = (Contents > (DEPTH-3))? 1 : 0;
	assign HF = (Contents > (DEPTH/2))? 1 : 0;
	assign AE = (Contents < 3)? 1 : 0;
	assign EF = (Contents == 0)? 1 : 0;

	assign WE = Push && ~FF;
	assign RE = Pop && ~EF;

	assign DataOut = queue[ReadPointer];

	always @ (posedge Clk)
	begin
		if (Dump == 1)
			Contents <= 0;
		else
			if ((WE == 1) && (RE == 0))
				Contents <= Contents + 1;
			else
				if ((WE == 0) && (RE == 1))
					Contents <= Contents - 1;
				else
					Contents <= Contents;
	end

	always @ (posedge Clk)
	begin
		if (Dump == 1)
			begin
				ReadPointer <= 0;
				WritePointer <= 0;
			end
		else
			begin
				if (RE == 1)
					begin
						ReadPointer <= ReadPointer + 1;
					end
				if (WE == 1)
					begin
						queue[WritePointer] <= DataIn;
						WritePointer <= WritePointer + 1;
					end
			end
	end

endmodule

/*
 * MODULE: PacketBuffer16()
 *
 * This module is a FIFO with and additional wrapper to keep track of packets
 * in the buffer. The packet can be anything and it is the responsibility of
 * the Pushing and Popping entitities to determine when a packet has been
 * pushed and when it has been popped - generally via some artifact of the 
 * packet itself such as a terminating NULL.
 */

module PacketBuffer16(DataOut, DataIn, PacketIn, PacketOut, Lines, FF, AF, HF, AE, EF, Push, Pop, Dump, Clk);
	parameter WIDTH = 8;
	parameter DEPTH = 16;
	parameter LOG2DEPTH = 4;

	input [(WIDTH-1):0] DataIn;
	output [(WIDTH-1):0] DataOut;
	input PacketIn, PacketOut;
	output [(LOG2DEPTH-1):0] Lines;
	output FF, AF, HF, AE, EF;
	input Push, Pop, Dump, Clk;

	reg [(LOG2DEPTH-1):0] Lines;

	FIFO16x8 FIFO
	(
		.DataOut(DataOut), .DataIn(DataIn), 
		.FF(FF), .AF(AF), .HF(HF), .AE(AE), .EF(EF), 
		.Push(Push), .Pop(Pop), .Dump(Dump), .Clk(Clk)
	);

	always @ (posedge Clk)
	begin
		if (Dump == 1)
			Lines <= 0;
		else
			if ((PacketIn == 1) && (PacketOut == 0))
				Lines <= Lines + 1;
			else
				if ((PacketIn == 0) && (PacketOut == 1))
					Lines <= Lines - 1;
				else
					Lines <= Lines;
	end

endmodule

/*=========================================================================*/
/*===  From the MMV LIBRARY  ==============================================*/
/*=========================================================================*/

/* MODULE: OneShot
 * This module asserts an output based on two inputs as follows:
 * STATE: Q0 - Quiescent (output is LO), waiting for Start signal to deassert.
 *        Q1 - Armed     (output is LO), waiting for Start signal to assert.
 *        Q2 - Triggered (output is HI), waiting for Stop signal to assert.
 *        Q3 - Stopped   (output is LO), waiting for Stop signal to deassert.
 *
 * This circuit behaves similarly to a nonretriggerable monostable 
 * multivibrator. 
 *
 * 1) In order to Trigger, the machine MUST be in the armed state. In order
 *    to get into that state, the trigger signal that started the previous 
 *    cycle must be relaxed.
 *
 * 2) Once triggered, the output will remain asserted until the Stop signal is
 *    asserted, at which point the machine will stop and deassert its output.
 *    
 * 3) The Stop signal must be deasserted in order for the machine to move back
 *    into the quiescent state.
 *
 * The main application of this module is to detect events and create a HI 
 * output pulse that is just long enough to catch a single master clock pulse
 * while preventing multiple triggers due to long asserted signals. In order
 * to achieve this behavior it is only necessary to use the Q output as the 
 * Stop input
 *
 */

module OneShot(Q, Start, Stop, rst, clk);
	output Q;
	input Start, Stop;
	input rst, clk;

	reg [1:0] cstate, nstate;
	reg Q;

	parameter LO = 1'b0, HI = 1'b1,
	          QUIESCENT = {LO,LO},
	          ARMED     = {LO,HI},
				 RUNNING   = {HI,LO},
				 STOPPED   = {HI,HI};

	always @ (posedge clk)
	begin
		if (rst == HI)
			cstate <= STOPPED;
		else
			cstate <= nstate;
   end

	always @ (cstate or Start or Stop)
	begin
		case (cstate)
			QUIESCENT:	begin
								Q <= LO;
								if (Start == LO)
									nstate <= ARMED;
								else
									nstate <= QUIESCENT;
							end
			ARMED:		begin
								Q <= LO;
								if (Start == HI)
									nstate <= RUNNING;
								else
									nstate <= ARMED;
							end
			RUNNING:		begin
								Q <= HI;
								if (Stop == HI)
									nstate <= STOPPED;
								else
									nstate <= RUNNING;
							end
			STOPPED:		begin
								Q <= LO;
								if (Stop == LO)
									nstate <= QUIESCENT;
								else
									nstate <= STOPPED;
							end
			default:    begin
								Q <= LO;
								nstate <= STOPPED;
							end
		endcase
	end

endmodule

module FireAndAcknowledge(Q, Fire, Ack, rst, clk);
	output Q;
	input Fire, Ack;
	input rst, clk;

	reg Q;

	parameter LO = 1'b0, HI = 1'b1;

	reg [1:0] State, Next_State;
	reg Q_next;

	parameter
		S_IDLE  = 2'd0,
		S_ARMED = 2'd1,
		S_FIRED = 2'd2;

	always @ (posedge clk)
	begin
		if (rst == HI)
			begin
				Q <= LO;
				State <= S_IDLE;
			end
		else
			begin
				Q <= Q_next;
				State <= Next_State;
			end
	end

	// FSM State Transition Definitions
	always @ (State or Fire or Ack)
	begin
		case (State)
			S_IDLE:   // Hold until Fire flag is relaxed
				begin
					Q_next = LO;
					if (Fire == LO)
						begin
							Next_State = S_ARMED;
						end
					else
						begin
							Next_State = State;
						end
				end
			S_ARMED:  // Waiting for Fire flag
				begin
					if (Fire == HI)
						begin
							Q_next = HI;
							Next_State = S_FIRED;
						end
					else
						begin
							Q_next = LO;
							Next_State = State;
						end
				end
			S_FIRED:  // Hold Output HI until acknowledged
				begin
					if (Ack == HI)
						begin
							Q_next = LO;
							Next_State = S_IDLE;
						end
					else
						begin
							Q_next = HI;
							Next_State = State;
						end
				end
			default:
				begin
					Q_next = LO;
					Next_State = S_IDLE;
				end
		endcase
	end

endmodule

/*=========================================================================*/
/*===  END OF LIBRARY  ====================================================*/
/*=========================================================================*/