/*
 * Input_Port_C.c
 *
 *  Created: 6/18/2013 12:49:46 PM
 *  Author:  Josh Weaver, Dr. Schwartz
 *  Purpose: A modification to the original Assembly IOPORT Example in C.
 *			 Using a mix of C and Assembly to perform the desired IOPORT setup
 *			 and test reading from IOPORT.  This example requires a single C file
 *           using inline assembly commands.
 *
 *			 This is the bare minimum code required to setup an input port
 *			 with ADDRESS DECODING in the CPLD. This solution assumes the user is
 *			 providing their own output enable, OE(L), to the input port's 
 *		     tri-state buffer and will not be using the CS0(L). 
 */ 
#define F_CPU 2000000 // ATxmega runs at 2MHz on Reset. This is needed for _delay
					  // functions to work
#include <avr/io.h>

/*********************************INITIALIZATIONS***********************************/
asm(".set IOPORT, 0x6000");			// Define the Starting Address for the IOPort
asm(".set IOPORTEND, 0x7FFF");		// Define the expected end Address for IOPORT

/*******************************PRIMARY CODE****************************************/
// Main function required in primary C file of project
int main(void)
{
	// Configure PORTH bits 1 and 2 as outputs.
	// Bit 1 is RE(L), 2 is ALE1
	asm("LDI R18, 0x06");
	asm volatile ("STS %0,r18" : "=m" (PORTH_DIRSET));
	
	// Given that RE(L) is active low, it must be initially set to H=false
	asm("LDI R18, 0x02");
	asm volatile ("STS %0,r18" : "=m" (PORTH_OUTSET));
	
	// Set all PORTJ pins (D7-D0) to be outputs as required from datasheet.
	asm("LDI R18, 0xFF");
	asm volatile ("STS %0,r18" : "=m" (PORTJ_DIRSET));

	// Set all PORTK pins (A15-A0) to be outputs as required from datasheet.
	asm("LDI R18, 0xFF");
	asm volatile ("STS %0,r18" : "=m" (PORTK_DIRSET));
	
	// Set EBI_CTRL to select 3 PORT EBI(H,J,K) mode and SRAM ALE1 mode.
	asm("LDI R18, 0x01");
	asm volatile ("STS %0,r18" : "=m" (EBI_CTRL));
	
	// Reserve a chip select zone for our input port.
	// The base address register is made of 12 bits for the address, with the 
	// lower 4 bits being reserved.  The lower 12 bits of the address are
	// assumed to be zero.  This limits the our choice of the base address 
	// for our zone since we can only choose A23:A12
	asm volatile("LDI R31, hi8(%0)" :: "i" (&EBI_CS0_BASEADDR));
	asm volatile("LDI R30, lo8(%0)" :: "i" (&EBI_CS0_BASEADDR));
	
	// Store BASEADDRL.  We shift 8 bits to store the lowest nibble of our
	// user specified address lines (A23:A12) into the upper nibble of the
	// base address reg.  The lower 4 bits are reserved and not used.  We
	// then increment the Z register so we can load the upper byte of the
	// base address.
	asm("LDI R18, (IOPORT>>8)");
	asm("ST Z+, R18");
	
	// Place the upper byte (A23:A16) into the upper byte of the base
	// address BASEADDRH.
	asm("LDI R18, (IOPORT>>16)");
	asm("ST Z, R18");
	
	// Set to 8K chp select space and turn on SRAM mode
	asm("LDI R18, 0x15");
	asm("STS %0, R18" : "=m" (EBI_CS0_CTRLA));

	// Load X to point to the IOPORT addresses.
	// Notice that we cannot access XH or XL and have to use the exact
	// register name.
	asm("LDI R27, hi8(IOPORT)");
	asm("LDI R26, lo8(IOPORT)");

	// Read the input port into R18 and check
	asm("TEST: LD R18, X");
	asm("RJMP TEST");
	
    while(1)
    {
		asm("nop");			// NOP for breakpoint (should never get here)
    }
}