#include "xbasic_types.h"
#include "xio.h"

#include "xintc_l.h"
#include "xuartlite_l.h"
#include "xparameters.h"

/* Defined in mymicroblaze/xparameters.h */
/* #define XPAR_VGA_BASEADDR 0xFEFF1000 */
/* #define XPAR_VGA_HIGHADDR 0xFEFF1fff */

#define FONT_OFFSET 0xA00

/* Address of a particular character on the screen (rows are 80) */
#define CHAR(r,c) \
   (((unsigned char *)(XPAR_VGA_BASEADDR))[(c) + ((r) << 6) + ((r) << 4)])

/* Start of font memory */
#define FONT ((unsigned char *)XPAR_VGA_BASEADDR + FONT_OFFSET)

int uart_interrupt_count = 0;
char uart_character;
 
/*
 * Interrupt service routine for the UART
 */
void uart_handler(void *callback)
{
  Xuint32 IsrStatus;
   
  Xuint8 incoming_character;

  /* Check the ISR status register so we can identify the interrupt source */
  IsrStatus = XIo_In32(XPAR_MYUART_BASEADDR + XUL_STATUS_REG_OFFSET);
   
  if ((IsrStatus & (XUL_SR_RX_FIFO_FULL | XUL_SR_RX_FIFO_VALID_DATA)) != 0) {
    /* The input FIFO contains data: read it */
    incoming_character =
      (Xuint8) XIo_In32( XPAR_MYUART_BASEADDR + XUL_RX_FIFO_OFFSET );
 
    uart_character = incoming_character;
    ++uart_interrupt_count;
  }
  
  if ((IsrStatus & XUL_SR_TX_FIFO_EMPTY) != 0) {
    /* The output FIFO is empty: we can send another character */
  }
    
}

/* Write a text string on the display */
void put_string(char *string, int row, int column)
{
  char *p = &(CHAR(row, column));
  while (*p++ = *string++)
    ;
}

int main()
{
  volatile unsigned char *p;
  unsigned char v, vv;
  int i, j, k;
  print("Hello World!\r\n");

#if 0
  v = 0;
  for ( p = (unsigned char *) XPAR_VGA_BASEADDR ;
        p <= (unsigned char *) XPAR_VGA_HIGHADDR ;
        ++p ) {
#if 0
    print("writing to ");
    putnum((int) p);
    print(" value ");
    putnum(v);
    print("\r\n");
#endif
    *p = v;
    v += 1;
  }
  print("wrote to memory\r\n");
 
  v = 0;
  for ( p = (unsigned char *) XPAR_VGA_BASEADDR ;
        p <= (unsigned char *) XPAR_VGA_HIGHADDR ;
        ++p ) {
    vv = *p;
    if (vv != v) {
      print("read from ");
      putnum((int) p);
      print(" returned ");
      putnum(vv);
      print(" expected ");
      putnum(v);
      print("\r\n");
    }
    v += 1;
  }
 
  print("memory test completed. from ");
  putnum(XPAR_VGA_BASEADDR);
  print(" to ");
  putnum(XPAR_VGA_HIGHADDR);
  print("\r\n");
#endif


  /* Clear the screen */

  /*
  for ( p = &(CHAR(0,0)) ; p < &(CHAR(29,80)) ; ++p)
     *p = ' ';
   */

  /* Announce ourselves */

  put_string("Welcome to CSEE 4840 Lab 2", 15, 27);

  /* Enable UART interrupts and register uart_handler as the ISR */
  XIntc_RegisterHandler( XPAR_INTC_BASEADDR, XPAR_MYUART_DEVICE_ID,
	 		 (XInterruptHandler)uart_handler, (void *)0);
  XIntc_mEnableIntr( XPAR_INTC_BASEADDR, XPAR_MYUART_INTERRUPT_MASK);
  XIntc_mMasterEnable( XPAR_INTC_BASEADDR );
  XIntc_Out32(XPAR_INTC_BASEADDR + XIN_MER_OFFSET, XIN_INT_MASTER_ENABLE_MASK);
  microblaze_enable_interrupts();
  XUartLite_mEnableIntr(XPAR_MYUART_BASEADDR);

  /* Periodically report the latest character received */
/*  put_string("Latest character received:", 2, 0);
  for (;;) {
    char buf[2];
    buf[1] = '\0';

    print("Character number ");
    putnum(uart_interrupt_count);
    print(" is ");
    buf[0] = uart_character;
    print(buf);
    print("\r\n");

    put_string(buf, 2, 27);
     
    for (i = 0 ; i < 10000000 ; i++ )  ; // delay
  } */

  //int i;
  int addr;
  //int j, k;

  /* test BRAM access */
  /*  print("testing BRAM...\r\n");
  j = 0;
  for ( i = 0 ; i < 512 ; i++ ) {
   addr = XPAR_BRAM_PERIPHERAL_BASEADDR + (i << 2);
    XIo_Out8(addr, j);
    j += 17;
  }

  j = 0;
  for ( i = 0 ; i <512 ; i++) {
    addr = XPAR_BRAM_PERIPHERAL_BASEADDR + (i << 2);
    k = XIo_In8(addr);
    //putnum(addr);
    //print(" got ");
    //putnum(k);
    if ( k != (j & 255) ) {
      putnum(addr);
      print(" got ");
      putnum(k);
      print(" expected ");
      putnum(j & 255);
      print("\r\n");
    }
    //print("\r\n");
    j += 17;
    }*/

  /* test SRAM access */
  print("testing SRAM...\r\n");
  j = 0;
  /*for ( i = 0 ; i < 215 ; i++ ) {
   addr = XPAR_SRAM_PERIPHERAL_BASEADDR + (i << 2);
    XIo_Out16(addr, j);
    j += 17;
    }*/

  j = 0;
  for ( i = 0 ; i <10 ; i++) {
    addr = XPAR_SRAM_PERIPHERAL_BASEADDR + (i << 2);
    k = XIo_In16(addr);
    //putnum(addr);
    //print(" got ");
    //putnum(k);
    //if ( k != j ) {
      putnum(addr);
      print(" got ");
      putnum(k);
      //print(" expected ");
      //putnum(j);
      print("\r\n");
      //}
    //print("\r\n");
    j += 17;
  }

  return 0;
}
