//----- Synthesizable Circuit -----

module LED7_Display (
// Digit display interface for Digilent Digital I/O 1 board offering
// individual control of each LED segment.
//
// - Accepts four 8-bit input values, where the most significant bit
//     corresponds to the decimal point, and the remaining seven bits
//     correspond to the segments "a" through "g". For example, the
//     value 8'b10010101 will activate the decimal point and segments
//     "c", "e" and "g". A "1" lights the segment, and a "0" turns it off.
// - Uses multiplexed display scheme with 100 Hz refresh to minimize flicker.
// - Requires 50MHz master clock
// - Requires active-high master reset (all segments active on reset)
//
// Author: Ed Doering
// Created: 22 Jan 2003
// Revised:

	// Inputs:
	i$Clock50MHz,	// System clock (50 MHz)
	i$MasterReset,	// Master reset (active high)

	i$Right,			// Pattern to display on rightmost digit
	i$MiddleRight,	// Pattern to display on middle right digit
	i$MiddleLeft,	// Pattern to display on middle left digit
	i$Left,			// Pattern to display on leftmost digit

	// Outputs:
	o$Segment_a,	// LED segment a (active low)
	o$Segment_b,	// etc.
	o$Segment_c,
	o$Segment_d,
	o$Segment_e,
	o$Segment_f,
	o$Segment_g,
	o$Segment_dp,	// LED decimal point
	o$Digit_Right,	// Rightmost digit enable (active high)
	o$Digit_MiddleRight,	// etc.
	o$Digit_MiddleLeft,
	o$Digit_Left
);

// User-adjustable constants
parameter p$ClockFrequency = 50;	// Clock frequency in MHz
parameter p$RefreshFrequency = 100;	// Display refresh rate (for entire display) in Hz

// Upper limit for frequency divider counter
parameter p$UpperLimit = (p$ClockFrequency * 1000000) / (4 * p$RefreshFrequency);
//parameter p$UpperLimit = 2; // for simulation only

// Number of bits for frequency divider counter (will accommodate 
// refresh frequencies down to 1 Hz)
parameter p$DividerCounterBits = 24;


// Port mode declarations:
	// Inputs:
input	i$Clock50MHz;
input	i$MasterReset;
input [7:0]	i$Right;	
input [7:0]	i$MiddleRight;
input [7:0]	i$MiddleLeft;
input [7:0]	i$Left;

	// Outputs:
output	o$Segment_a;
output	o$Segment_b;
output	o$Segment_c;
output	o$Segment_d;
output	o$Segment_e;
output	o$Segment_f;
output	o$Segment_g;
output	o$Segment_dp;
output	o$Digit_Right;
output	o$Digit_MiddleRight;
output	o$Digit_MiddleLeft;
output	o$Digit_Left;

// Registered identifiers:
reg	o$Segment_a;
reg	o$Segment_b;
reg	o$Segment_c;
reg	o$Segment_d;
reg	o$Segment_e;
reg	o$Segment_f;
reg	o$Segment_g;
reg	o$Segment_dp;
reg	o$Digit_Right;
reg	o$Digit_MiddleRight;
reg	o$Digit_MiddleLeft;
reg	o$Digit_Left;

reg [p$DividerCounterBits-1:0] r$Cycles;
reg [1:0] r$DigitSelect;
reg [3:0] r$Digit;
reg [7:0] r$Pattern;

// Frequency divider and 2-bit counter for digit selector
always @ (posedge i$Clock50MHz or posedge i$MasterReset)
	if (i$MasterReset) begin
		r$Cycles <= 0;
		r$DigitSelect <= 3;
	end
	else
		if (r$Cycles == p$UpperLimit)	begin
			r$Cycles <= 0;
			r$DigitSelect <= r$DigitSelect - 1;
		end
		else
			r$Cycles <= r$Cycles + 1;

// Decode the digit selector to four control lines
always @ (r$DigitSelect)
	case (r$DigitSelect)
		2'b00 : r$Digit <= 4'b0001;
		2'b01 : r$Digit <= 4'b0010;
		2'b10 : r$Digit <= 4'b0100; 
		2'b11 : r$Digit <= 4'b1000;
	endcase

// MUX the four 8-bit inputs to a single 8-bit value, and bit-wise
// complement to make active low
always @ (r$DigitSelect or i$Right or i$MiddleRight or i$MiddleLeft or i$Left)
	case (r$DigitSelect)
		2'b00 : r$Pattern <= ~i$Right;
		2'b01 : r$Pattern <= ~i$MiddleRight;
		2'b10 : r$Pattern <= ~i$MiddleLeft;
		2'b11 : r$Pattern <= ~i$Left;
	endcase

// Create registered outputs (for glitch-free output)
always @ (posedge i$Clock50MHz or posedge i$MasterReset)
	if (i$MasterReset) begin
		o$Segment_a <= 0;
		o$Segment_b <= 0;
		o$Segment_c <= 0;
		o$Segment_d <= 0;
		o$Segment_e <= 0;
		o$Segment_f <= 0;
		o$Segment_g <= 0;
		o$Segment_dp <= 0;
		o$Digit_Right <= 1;
		o$Digit_MiddleRight <= 1;
		o$Digit_MiddleLeft <= 1;
		o$Digit_Left <= 1;
	end
	else begin
		o$Segment_dp <= r$Pattern[7];
		o$Segment_a <= r$Pattern[6];
		o$Segment_b <= r$Pattern[5];
		o$Segment_c <= r$Pattern[4];
		o$Segment_d <= r$Pattern[3];
		o$Segment_e <= r$Pattern[2];
		o$Segment_f <= r$Pattern[1];
		o$Segment_g <= r$Pattern[0];
		o$Digit_Right <= r$Digit[0];
		o$Digit_MiddleRight <= r$Digit[1];
		o$Digit_MiddleLeft <= r$Digit[2];
		o$Digit_Left <= r$Digit[3];
	end

endmodule