// EC533: Programmable Logic System Design
// Fall 2000
// Doering (Ed.Doering@Rose-Hulman.Edu)
//
//
// Template for developing an 8031-SRAM-FPGA system on the XS-40 board.
// The 8031/FPGA interface is based on memory-mapped registers inside the
// the FPGA. Examples of 8031-readable and writable registers are included,
// as is a simple 8031-controlled process (blinking LEDs with 8031-defined
// selection of LED segments).
//
// Please use a 12 MHz system clock when using this template as is (adjust 
// the XS-40 programmable oscillator frequency using XSSETCLK).
//
// Descriptions of the 8031 pins are taken from the Winbond W78C32C data
// sheet. As of 10/5/2000, Winbond did not have a data sheet for the W78C31BD
// microcontroller on the XS-40, but the pinouts of the two devices are
// equivalent.

/* -----------------------------------------------------------------------------
	BEGIN MODULE DESCRIPTION
----------------------------------------------------------------------------- */

module Template_8031_SRAM_FPGA (

	// User input/output signals for FPGA
	I$_Reset,
	O$LED,

	// From 8031 to FPGA only
	I$8031_to_FPGA_only$ALE,
	I$8031_to_FPGA_only$_PSEN,
	I$8031_to_FPGA_only$_RD,

	// From 8031 to FPGA and SRAM
	I$8031_to_FPGA_and_SRAM$_WR,
	I$8031_to_FPGA_and_SRAM$AddressHigh,
	
	// Shared bus between 8031, FPGA, and SRAM
	IO$8031_FPGA_SRAM$Data,

	// From FPGA to 8031
	O$FPGA_to_8031$RST,
	O$FPGA_to_8031$XTAL1,
	
	// From FPGA to SRAM
	O$FPGA_to_SRAM$_OE,
	O$FPGA_to_SRAM$_CE,
	O$FPGA_to_SRAM$AddressLow,
	
	// From oscillator to FPGA
	I$Oscillator_to_FPGA$Clock
);	


/* -----------------------------------------------------------------------------
	Declare Port Modes
----------------------------------------------------------------------------- */

// User inputs
input	I$_Reset;
//	Master reset, active low (using XStend board 'RESET' button).

output	[6:0]	O$LED;
//	Seven-segment LED (used as part of an example below)

// Inputs from 8031 to FPGA (these are not connected to SRAM):

input	I$8031_to_FPGA_only$ALE;
//	Address Latch Enable, active high. Indicates that the value on the
// shared address/data bus is the lower eight bits of the address. The data bus
// value is latched on the falling edge of the master clock when enabled by ALE.

input	I$8031_to_FPGA_only$_PSEN;
// 	Program Store Enable, active low. According to the data sheet, "Enables
// the external ROM onto the Port 0 address/data bus during fetch and
// MOVC operations." Put more simply, _PSEN is asserted when the 8031 is reading
// memory to fetch an instruction; _PSEN is not asserted when the 8031 is
// reading memory to fetch data as part of executing an instruction (_RD is
// used for that purpose).

input	I$8031_to_FPGA_only$_RD;
// 	Data Read Strobe, active low. Asserted when the 8031 is reading memory
// as part of executing an instruction. A value should be placed on the data bus
// and held stable until the read strobe is deasserted.


// Inputs from 8031 to FPGA that are also sent to SRAM:

input	I$8031_to_FPGA_and_SRAM$_WR;
//	Data Write Strobe, active low. Asserted when the 8031 is writing memory
// as part of executing an instruction.

input	[7:0]	I$8031_to_FPGA_and_SRAM$AddressHigh;
//	Address bus, high byte. 
// NOTE: Address bit 15 (most significant bit) is not connected to SRAM, because
// the SRAM has only 32K addressable bytes, but the 16-bit address bus of the
// 8031 can access 64K bytes. The FPGA uses bit 15 to determine when the 8031 is
// performing a memory operation beyond the SRAM address space.


// Shared bus between 8031, FPGA, and SRAM:

inout	[7:0]	IO$8031_FPGA_SRAM$Data;
//	Data bus, 8 bits. Carries data OR low byte of address. Address Latch
// Enable (ALE) is used to determine when the data bus is carrying an address
// generated by the 8031.


// From FPGA to 8031:

output	O$FPGA_to_8031$RST;
//	Reset 8031, active high. When asserted, 8031 is held in reset state, and
// all the 8031 pins are weakly pulled high. Must be asserted for at least two
// machine cycles in order to be recognized by the 8031.

output	O$FPGA_to_8031$XTAL1;
//	Crystal oscillator input #1 (may also be driven by an external clock).
// The XS-40 board is wired to allow the FPGA to determine the clock signal sent
// to the 8031. This flexibility makes it possible to clock the 8031 at a
// different rate than the FPGA system, or even to pause the 8031 clock entirely
// while FPGA processing continues. The 8031 is a fully static device, meaning
// that its clock can be slowed down or stopped without causing problems with
// loss of internal data.
//
// The 8031 frequency is limited to about 30 MHz (I do not know the precise
// maximum frequency, since I have not been able to find the data sheet for the
// W78C31BD processor on our XS-40 boards). The XS-40 oscillator frequency can
// be as high as 100 MHz (see comment below on "I$Oscillator_to_FPGA$Clock"),
// and your FPGA system can use this high frequency clock, but take care to send
// a reduced-frequency signal to the 8031, e.g., by using a divide-by-four
// counter.
	

// From FPGA to SRAM:

output	O$FPGA_to_SRAM$_OE;
//	Output Enable, active low. This signal enables the tri-state drivers on
// the SRAM data bus.

output	O$FPGA_to_SRAM$_CE;
//	Chip Enable, active low. This signal must be asserted for the SRAM core
// to be active. The SRAM will only respond to the output enable and write
// enable when the chip enable is asserted. The FPGA can decode the address
// produced by the 8031 to determine when to enable the SRAM. The most common
// method is to use bit 15 of the address bus as the SRAM chip enable to place
// the SRAM in the lower 32K of the 8031's address space, and the FPGA in the
// upper 32K of address space.

output	[7:0]	O$FPGA_to_SRAM$AddressLow;
//	Address, low byte. The FPGA must include a register to capture the low
// byte of the address generated by the 8031 during the instruction fetch cycle,
// and present the result to the SRAM.


// From oscillator to FPGA:

input	I$Oscillator_to_FPGA$Clock;
//	From oscillator on the XS-40 board. Note that the oscillator frequency
// is programmable (see the "XSSETCLCK" application), and can be as high as
// 100 MHz.


/* -----------------------------------------------------------------------------
	Declare Register-Type Identifiers
----------------------------------------------------------------------------- */

reg	[7:0]	r$AddressLow;
//	Internal storage for low-byte of address

reg	[7:0]	r$DataOut;
//	Multiplexes 8031-readable registers onto a single bus that can be
// connected to bidirectional data bus port.

reg	[7:0]	r$ByteRegisterA;
reg	[7:0]	r$ByteRegisterB;
reg	[16:0]	r$IntegerRegisterA;
reg	[16:0]	r$IntegerRegisterB;
//	Registers to demonstrate memory mapping technique

reg	[22:0]	r$ClockDividerCounter;
//	Counter for clock divider (part of "controllable process" example below)

/* -----------------------------------------------------------------------------
	Declare Wire-Type Identifiers
----------------------------------------------------------------------------- */

wire	[15:0]	w$Address = {I$8031_to_FPGA_and_SRAM$AddressHigh,r$AddressLow};
//	Combines high-byte and low-byte of address into a single value. More
// convenient for address decoding within FPGA system.

wire	w$Clock = I$Oscillator_to_FPGA$Clock;
//	Abbreviated name for master clock signal

wire	w$Reset = ~I$_Reset;
//	Internal master reset signal

/* -----------------------------------------------------------------------------
	Basic 8031-SRAM-FPGA Interface
----------------------------------------------------------------------------- */

// Register to hold low byte of address
always @ (negedge w$Clock or posedge w$Reset)
	if (w$Reset)
		r$AddressLow <= 0;
	else if (I$8031_to_FPGA_only$ALE)
		r$AddressLow <= IO$8031_FPGA_SRAM$Data;

// Connect internal address low-byte register to output port
assign O$FPGA_to_SRAM$AddressLow = r$AddressLow;

// Create SRAM output enable signal to make SRAM appear in lower 32K of the
// 8031's 64K address space; do this by ORing the 8031 _PSEN and _RD signals
assign O$FPGA_to_SRAM$_OE = !(!I$8031_to_FPGA_only$_PSEN |
	!I$8031_to_FPGA_only$_RD);

// Connect SRAM chip enable to most significant bit of address bus
assign O$FPGA_to_SRAM$_CE = w$Address[15];

// Create tri-stateable output port; set up decoding so FPGA will only drive the
// output for addresses in the upper 32K of address space.
assign IO$8031_FPGA_SRAM$Data = 
	(w$Address[15] == 1 && I$8031_to_FPGA_only$_RD == 0) ? r$DataOut : 8'hzz;

// Generate the 8031 reset signal. In this template the reset is simply a
// pass-through from the master reset, but you could make a more elaborate
// circuit to generate the reset.
assign O$FPGA_to_8031$RST = w$Reset;

// Generate the 8031 clock signal. A pass-through is also used in this template,
// but you can create additional circuitry to produce some other type of clock
// signal.
assign O$FPGA_to_8031$XTAL1 = I$Oscillator_to_FPGA$Clock;


/* -----------------------------------------------------------------------------
	Examples: 8031-Writable Registers
----------------------------------------------------------------------------- */

// Following are some examples of registers that are writable by the
// 8031.

// 8-bit register at address 0x83BC (demonstrates full decoding... the register
// will only appear at the exact address). The 8031 C program must declare a
// byte-wide variable ('char' or 'unsigned char') whose address is 0x83BC.
always @ (posedge w$Clock or posedge w$Reset)
	if (w$Reset)
		r$ByteRegisterA <= 0;
	else if (I$8031_to_FPGA_and_SRAM$_WR == 0)  	// only respond when write
							// strobe is enabled!
		if (w$Address == 16'h83BC)
			r$ByteRegisterA <= IO$8031_FPGA_SRAM$Data;


// 8-bit register at address 0x9xxx (demonstrates partial decoding... the
// register will appear at all addresses between 0x9000 and 0x9FFF). The 8031 C
// program must declare a byte-wide variable ('char' or 'unsigned char') whose
// address is anywhere in the range 0x9000 to 0x9FFF.
always @ (posedge w$Clock or posedge w$Reset)
	if (w$Reset)
		r$ByteRegisterB <= 0;
	else if (I$8031_to_FPGA_and_SRAM$_WR == 0)  	// only respond when write
							// strobe is enabled!
		if (w$Address[15:12] == 4'h9)
			r$ByteRegisterB <= IO$8031_FPGA_SRAM$Data;

// 16-bit register at address 0xA000. The 8031 has only an 8-bit bus, so 
// accessing memory for a variable that has been declared as an 'int' or
// 'unsigned int' requires two write operations. The first byte will be written
// at the address of the variable (0xA000) and the second byte will be written
// at the next byte up (0xA001).
// NEED TO FIND OUT... MS byte at 0xA000 or LS byte??
always @ (posedge w$Clock or posedge w$Reset)
	if (w$Reset)
		r$IntegerRegisterA <= 0;
	else if (I$8031_to_FPGA_and_SRAM$_WR == 0)  	// only respond when write
							// strobe is enabled!
		if (w$Address == 16'hA000)
			r$IntegerRegisterA[15:8] <= IO$8031_FPGA_SRAM$Data;
		else if (w$Address == 16'hA001)
			r$IntegerRegisterA[7:0] <= IO$8031_FPGA_SRAM$Data;
	

/* -----------------------------------------------------------------------------
	Examples: 8031-Readable Registers
----------------------------------------------------------------------------- */

// Following are some examples of registers that are readable by the
// 8031. Note that all readable registers are multiplexed onto a single bus
// r$DataOut. This way, only a single tri-statable output port need be
// described, thereby avoiding problems trying to create an internal
// bidirectional bus. 

always @ (w$Address or r$ByteRegisterA or r$IntegerRegisterA)
	casez (w$Address)

// 8-bit register at address 0x83BC (demonstrates full decoding... the register
// will only appear at the exact address). The 8031 C program must declare a
// byte-wide variable ('char' or 'unsigned char') whose address is 0x83BC.
// Note that this is the same register that is writable at the address 0x83BC
// (see first example of writable register above).

		16'h83BC :  r$DataOut <= r$ByteRegisterA;

// 8-bit register at address 0x8CFE with constant value... 8031 will always
// get the same value when it reads from address 0x8CFE. This technique can
// be used to make a "chip identification" number, for example.

		16'h8CFE :  r$DataOut <= 8'h42;

// 16-bit register at address 0xBxxx. This register is the 1's complement
// of the writable register at 0xA000. Note how the partial decoding can
// produce the MSB for an even address in the range 0xB000 to 0xBFFE, and
// the LSB for an odd address in the range 0xB001 to 0xBFFF.

		16'b1011_????_????_???0 : r$DataOut <= ~r$IntegerRegisterA[15:8];
		
		16'b1011_????_????_???1 : r$DataOut <= ~r$IntegerRegisterA[7:0];
		
		default : r$DataOut <= 8'h00;
	endcase
		

/* -----------------------------------------------------------------------------
	Example: 8031-Controllable Process in FPGA
----------------------------------------------------------------------------- */

// This example illustrates how the 8031 microcontroller can initiate a
// process that runs in the FPGA. The process in this example is simple -- blink
// an LED on the XS-40 board while a particular bit in a writable register is
// set to one, and stop blinking the LED when the bit is set to zero. The seven
// individual segments of the 7-segment LED display will be individually
// controlled by the lower seven bits of a single writable 8-bit register mapped
// to address 0x9xxx (this is the same register as used in the second example
// of writable registers above).

// Clock divider (use MSB as the low frequency signal to control blinking
// frequency)
always @ (posedge w$Clock or posedge w$Reset)
	if (w$Reset)
		r$ClockDividerCounter <= 0;
	else
		r$ClockDividerCounter <= r$ClockDividerCounter + 1;

// Create logical 'AND' of low frequency signal and the contents of the 
// writable register, then connect these to the output LED display
assign O$LED = {7{r$ClockDividerCounter[22]}} & r$ByteRegisterB[6:0];


/* -----------------------------------------------------------------------------
	END OF MODULE DESCRIPTION
----------------------------------------------------------------------------- */

endmodule