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