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

module DigitDisplay (
// Digit display interface for Digilent Digital I/O 1 board
//
// - Accepts two 8-bit values on input, and displays the hexadecimal
//     representation of each value on the Digilent DIO1 peripheral board.
// - 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: 21 Jan 2003
// Revised:

	// Inputs:
	i$Clock50MHz,	// System clock (50 MHz)
	i$MasterReset,	// Master reset (active high)
	i$RightByte,	// Value to display on right two digits
	i$LeftByte,	// Value to display on left two digits

	// 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$RightByte;
input	[7:0]	i$LeftByte;

	// 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 [7:0] r$Nybble;
reg [3:0] r$Digit;
wire w$DecimalPoint;
reg [6:0] r$Character;

// 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

// Activate decimal point when left-middle digit is selected
assign w$DecimalPoint = ~(r$DigitSelect == 2'b10);

// MUX the four 4-bit inputs to a single 4-bit value
always @ (r$DigitSelect or i$RightByte or i$LeftByte)
	case (r$DigitSelect)
		2'b00 : r$Nybble <= i$RightByte[3:0];
		2'b01 : r$Nybble <= i$RightByte[7:4];
		2'b10 : r$Nybble <= i$LeftByte[3:0];
		2'b11 : r$Nybble <= i$LeftByte[7:4];
	endcase

// Convert 4-bit value to character
always @ (r$Nybble)
	case (r$Nybble)       //     abcdefg
		4'h0 : r$Character <= ~(7'b1111110);
		4'h1 : r$Character <= ~(7'b0110000);
		4'h2 : r$Character <= ~(7'b1101101);
		4'h3 : r$Character <= ~(7'b1111001);
		4'h4 : r$Character <= ~(7'b0110011);
		4'h5 : r$Character <= ~(7'b1011011);
		4'h6 : r$Character <= ~(7'b1011111);
		4'h7 : r$Character <= ~(7'b1110000);
		4'h8 : r$Character <= ~(7'b1111111);
		4'h9 : r$Character <= ~(7'b1111011);
		4'ha : r$Character <= ~(7'b1110111);
		4'hb : r$Character <= ~(7'b0011111);
		4'hc : r$Character <= ~(7'b1001110);
		4'hd : r$Character <= ~(7'b0111101);
		4'he : r$Character <= ~(7'b1001111);
		4'hf : r$Character <= ~(7'b1000111);
		default : r$Character <= ~(7'b1001001);	
	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_a <= r$Character[6];
		o$Segment_b <= r$Character[5];
		o$Segment_c <= r$Character[4];
		o$Segment_d <= r$Character[3];
		o$Segment_e <= r$Character[2];
		o$Segment_f <= r$Character[1];
		o$Segment_g <= r$Character[0];
		o$Segment_dp <= w$DecimalPoint;
		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