text: #include "gpio.h"
  #include "mbox.h"
  #include "sprintf.h"
  
  /* PL011 UART registers */
  #define UART0_DR        ((volatile unsigned int*)(MMIO_BASE+0x00201000))
  #define UART0_FR        ((volatile unsigned int*)(MMIO_BASE+0x00201018))
  #define UART0_IBRD      ((volatile unsigned int*)(MMIO_BASE+0x00201024))
  #define UART0_FBRD      ((volatile unsigned int*)(MMIO_BASE+0x00201028))
  #define UART0_LCRH      ((volatile unsigned int*)(MMIO_BASE+0x0020102C))
  #define UART0_CR        ((volatile unsigned int*)(MMIO_BASE+0x00201030))
  #define UART0_IMSC      ((volatile unsigned int*)(MMIO_BASE+0x00201038))
  #define UART0_ICR       ((volatile unsigned int*)(MMIO_BASE+0x00201044))
  
  // get address from linker
  extern volatile unsigned char _end;
  
  /**
   * Set baud rate and characteristics (115200 8N1) and map to GPIO
   */
  void uart_init()
  {
      register unsigned int r;
  
      /* initialize UART */
      *UART0_CR = 0;         // turn off UART0
  
      /* set up clock for consistent divisor values */
      mbox[0] = 9*4;
      mbox[1] = MBOX_REQUEST;
      mbox[2] = MBOX_TAG_SETCLKRATE; // set clock rate
      mbox[3] = 12;
      mbox[4] = 8;
      mbox[5] = 2;           // UART clock
      mbox[6] = 4000000;     // 4Mhz
      mbox[7] = 0;           // clear turbo
      mbox[8] = MBOX_TAG_LAST;
      mbox_call(MBOX_CH_PROP);
  
      /* map UART0 to GPIO pins */
      r=*GPFSEL1;
      r&=~((7<<12)|(7<<15)); // gpio14, gpio15
      r|=(4<<12)|(4<<15);    // alt0
      *GPFSEL1 = r;
      *GPPUD = 0;            // enable pins 14 and 15
      r=150; while(r--) { asm volatile("nop"); }
      *GPPUDCLK0 = (1<<14)|(1<<15);
      r=150; while(r--) { asm volatile("nop"); }
      *GPPUDCLK0 = 0;        // flush GPIO setup
  
      *UART0_ICR = 0x7FF;    // clear interrupts
      *UART0_IBRD = 2;       // 115200 baud
      *UART0_FBRD = 0xB;
      *UART0_LCRH = 0b11<<5; // 8n1
      *UART0_CR = 0x301;     // enable Tx, Rx, FIFO
  }
  
  /**
   * Send a character
   */
  void uart_send(unsigned int c) {
      /* wait until we can send */
      do{asm volatile("nop");}while(*UART0_FR&0x20);
      /* write the character to the buffer */
      *UART0_DR=c;
  }
  
  /**
   * Receive a character
   */
  char uart_getc() {
      char r;
      /* wait until something is in the buffer */
      do{asm volatile("nop");}while(*UART0_FR&0x10);
      /* read it and return */
      r=(char)(*UART0_DR);
      /* convert carrige return to newline */
      return r=='\r'?'\n':r;
  }
  
  /**
   * Display a string
   */
  void printf(char *fmt, ...) {
      __builtin_va_list args;
      __builtin_va_start(args, fmt);
      // we don't have memory allocation yet, so we
      // simply place our string after our code
      char *s = (char*)&_end;
      // use sprintf to format our string
      vsprintf(s,fmt,args);
      // print out as usual
      while(*s) {
          /* convert newline to carrige return + newline */
          if(*s=='\n')
              uart_send('\r');
          uart_send(*s++);
      }
  }
  
  int strcpy(const char *ct, const char *cs) 
  {
      char* dst = ct;
      char* src = cs;
      while (*src != 0) {
          *dst++ = *src++;
      }
  }
  
  int strcmp(const char *ct, const char *cs)
  {
      unsigned char c1, c2;
      while (*cs != 0) {
          c1 = *cs++;
          c2 = *ct++;
          if (c1 != c2) return c1 < c2 ? -1 : 1;
          if (!c1) break;
      }
      return 0;
  }
  
  /**
   * Compare two string and return 0 if they are identical
   */ 
  int strncmp(const char *ct, const char *cs, int len)
  {
      unsigned char c1, c2;
      while (len--) {
          c1 = *cs++;
          c2 = *ct++;
          if (c1 != c2) return c1 < c2 ? -1 : 1;
          if (!c1) break;
      }
      return 0;
  }