diff --git a/Makefile b/Makefile
index 133228de2a..81240ccc0b 100644
--- a/Makefile
+++ b/Makefile
@@ -53,6 +53,10 @@ ifneq ($(findstring DOS,$(OS)),)
    LDFLAGS += -lemu
 endif
 
+ifneq ($(findstring FPGA,$(OS)),)
+   DEFINES += -DHAVE_FPGA
+endif
+
 ifneq ($(findstring Win32,$(OS)),)
    LDFLAGS += -static-libgcc -lwinmm
 endif
diff --git a/Makefile.common b/Makefile.common
index c935d711e9..a4a967f2ec 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -1912,6 +1912,13 @@ ifeq ($(HAVE_NETWORKING), 1)
    endif
 endif
 
+ifneq ($(findstring FPGA,$(OS)),)
+   OBJ += gfx/drivers/fpga_gfx.o \
+          gfx/drivers_context/fpga_ctx.o \
+          gfx/drivers_font/fpga_font.o \
+          menu/drivers_display/menu_display_fpga.o
+endif
+
 ifneq ($(findstring Win32,$(OS)),)
    OBJ += media/rarch.o \
           gfx/common/win32_common.o \
diff --git a/configuration.c b/configuration.c
index 910112c8ac..ecc6835869 100644
--- a/configuration.c
+++ b/configuration.c
@@ -166,6 +166,7 @@ enum video_driver_enum
    VIDEO_CACA,
    VIDEO_GDI,
    VIDEO_VGA,
+   VIDEO_FPGA,
    VIDEO_NULL
 };
 
@@ -364,6 +365,8 @@ static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_SDL2;
 static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_GDI;
 #elif defined(DJGPP)
 static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_VGA;
+#elif defined(HAVE_FPGA)
+static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_FPGA;
 #elif defined(HAVE_DYLIB) && !defined(ANDROID)
 static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_EXT;
 #else
@@ -827,6 +830,8 @@ const char *config_get_default_video(void)
          return "gdi";
       case VIDEO_VGA:
          return "vga";
+      case VIDEO_FPGA:
+         return "fpga";
       case VIDEO_NULL:
          break;
    }
diff --git a/gfx/drivers/fpga_gfx.c b/gfx/drivers/fpga_gfx.c
new file mode 100644
index 0000000000..0f7c82ae6d
--- /dev/null
+++ b/gfx/drivers/fpga_gfx.c
@@ -0,0 +1,584 @@
+/*  RetroArch - A frontend for libretro.
+ *  Copyright (C) 2010-2014 - Hans-Kristian Arntzen
+ *  Copyright (C) 2011-2017 - Daniel De Matteis
+ *  Copyright (C) 2016-2017 - Brad Parker
+ *
+ *  RetroArch is free software: you can redistribute it and/or modify it under the terms
+ *  of the GNU General Public License as published by the Free Software Found-
+ *  ation, either version 3 of the License, or (at your option) any later version.
+ *
+ *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ *  PURPOSE.  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with RetroArch.
+ *  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <retro_miscellaneous.h>
+
+#ifdef HAVE_CONFIG_H
+#include "../../config.h"
+#endif
+
+#ifdef HAVE_MENU
+#include "../../menu/menu_driver.h"
+#endif
+
+#include "../font_driver.h"
+
+#include "../../driver.h"
+#include "../../configuration.h"
+#include "../../verbosity.h"
+#include "../common/fpga_common.h"
+
+typedef struct RegOp
+{
+   int fd;
+   void *ptr;
+   int only_mmap;
+   int only_munmap;
+} RegOp;
+
+static unsigned char *fpga_menu_frame = NULL;
+static unsigned fpga_menu_width       = 0;
+static unsigned fpga_menu_height      = 0;
+static unsigned fpga_menu_pitch       = 0;
+static unsigned fpga_video_width      = 0;
+static unsigned fpga_video_height     = 0;
+static unsigned fpga_video_pitch      = 0;
+static unsigned fpga_video_bits       = 0;
+static unsigned fpga_menu_bits        = 0;
+static bool fpga_rgb32                = false;
+static bool fpga_menu_rgb32           = false;
+static RegOp regOp;
+
+static unsigned int get_memory_size(void)
+{
+   FILE *size_fp;
+   unsigned int size;
+
+   /* this file holds the memory range needed to map the framebuffer into
+    * kernel address space, it is specified in the device tree
+    */
+   size_fp = fopen("/sys/class/uio/uio0/maps/map0/size", "r");
+
+   if (!size_fp)
+   {
+      RARCH_ERR("unable to open the uio size file\n");
+      exit(1);
+   }
+
+   fscanf(size_fp, "0x%08X", &size);
+   fclose(size_fp);
+
+   return size;
+}
+
+static void do_mmap_op(RegOp *regOp)
+{
+   if (regOp->only_munmap == 0)
+   {
+      regOp->fd = open("/dev/uio0", O_RDWR);
+
+      if (regOp->fd < 1)
+         return;
+
+      regOp->ptr = mmap(NULL, get_memory_size(), PROT_READ|PROT_WRITE, MAP_SHARED, regOp->fd, 0);
+
+      if (regOp->ptr == MAP_FAILED)
+      {
+         RARCH_ERR("could not mmap() memory\n");
+         exit(1);
+      }
+   }
+
+   if (regOp->only_mmap == 0)
+   {
+      if (munmap(regOp->ptr, get_memory_size()) == -1)
+      {
+         RARCH_ERR("could not munmap() memory\n");
+         exit(1);
+      }
+
+      close(regOp->fd);
+   }
+
+   return;
+}
+
+static void fpga_gfx_create(fpga_t *fpga)
+{
+   memset(&regOp, 0, sizeof(regOp));
+
+   regOp.only_mmap = 1;
+
+   do_mmap_op(&regOp);
+
+   fpga->framebuffer = ((volatile unsigned*)regOp.ptr);
+}
+
+static void *fpga_gfx_init(const video_info_t *video,
+      const input_driver_t **input, void **input_data)
+{
+   unsigned full_x, full_y;
+   gfx_ctx_input_t inp;
+   gfx_ctx_mode_t mode;
+   const gfx_ctx_driver_t *ctx_driver   = NULL;
+   unsigned win_width = 0, win_height   = 0;
+   unsigned temp_width = 0, temp_height = 0;
+   settings_t *settings                 = config_get_ptr();
+   fpga_t *fpga                         = (fpga_t*)calloc(1, sizeof(*fpga));
+
+   *input                               = NULL;
+   *input_data                          = NULL;
+
+   fpga_video_width                      = video->width;
+   fpga_video_height                     = video->height;
+   fpga_rgb32                            = video->rgb32;
+
+   fpga_video_bits                       = video->rgb32 ? 32 : 16;
+
+   if (video->rgb32)
+      fpga_video_pitch = video->width * 4;
+   else
+      fpga_video_pitch = video->width * 2;
+
+   fpga_gfx_create(fpga);
+
+   ctx_driver = video_context_driver_init_first(fpga,
+         settings->arrays.video_context_driver,
+         GFX_CTX_FPGA_API, 1, 0, false);
+   if (!ctx_driver)
+      goto error;
+
+   video_context_driver_set((const gfx_ctx_driver_t*)ctx_driver);
+
+   RARCH_LOG("[FPGA]: Found FPGA context: %s\n", ctx_driver->ident);
+
+   video_context_driver_get_video_size(&mode);
+
+   full_x      = mode.width;
+   full_y      = mode.height;
+   mode.width  = 0;
+   mode.height = 0;
+
+   RARCH_LOG("[FPGA]: Detecting screen resolution %ux%u.\n", full_x, full_y);
+
+   win_width   = video->width;
+   win_height  = video->height;
+
+   if (video->fullscreen && (win_width == 0) && (win_height == 0))
+   {
+      win_width  = full_x;
+      win_height = full_y;
+   }
+
+   mode.width      = win_width;
+   mode.height     = win_height;
+   mode.fullscreen = video->fullscreen;
+
+   if (!video_context_driver_set_video_mode(&mode))
+      goto error;
+
+   mode.width     = 0;
+   mode.height    = 0;
+
+   video_context_driver_get_video_size(&mode);
+
+   temp_width     = mode.width;
+   temp_height    = mode.height;
+   mode.width     = 0;
+   mode.height    = 0;
+
+   /* Get real known video size, which might have been altered by context. */
+
+   if (temp_width != 0 && temp_height != 0)
+      video_driver_set_size(&temp_width, &temp_height);
+
+   video_driver_get_size(&temp_width, &temp_height);
+
+   RARCH_LOG("[FPGA]: Using resolution %ux%u\n", temp_width, temp_height);
+
+   inp.input      = input;
+   inp.input_data = input_data;
+
+   video_context_driver_input_driver(&inp);
+
+   if (settings->bools.video_font_enable)
+      font_driver_init_osd(NULL, false,
+            video->is_threaded,
+            FONT_DRIVER_RENDER_FPGA);
+
+   RARCH_LOG("[FPGA]: Init complete.\n");
+
+   return fpga;
+
+error:
+   video_context_driver_destroy();
+   if (fpga)
+      free(fpga);
+   return NULL;
+}
+
+static bool fpga_gfx_frame(void *data, const void *frame,
+      unsigned frame_width, unsigned frame_height, uint64_t frame_count,
+      unsigned pitch, const char *msg, video_frame_info_t *video_info)
+{
+   gfx_ctx_mode_t mode;
+   const void *frame_to_copy = frame;
+   unsigned width            = 0;
+   unsigned height           = 0;
+   unsigned bits             = fpga_video_bits;
+   bool draw                 = true;
+   fpga_t *fpga                = (fpga_t*)data;
+
+   if (!frame || !frame_width || !frame_height)
+      return true;
+
+#ifdef HAVE_MENU
+   menu_driver_frame(video_info);
+#endif
+
+   if (fpga_video_width != frame_width || fpga_video_height != frame_height || fpga_video_pitch != pitch)
+   {
+      if (frame_width > 4 && frame_height > 4)
+      {
+         fpga_video_width = frame_width;
+         fpga_video_height = frame_height;
+         fpga_video_pitch = pitch;
+      }
+   }
+
+   if (fpga_menu_frame && video_info->menu_is_alive)
+   {
+      frame_to_copy = fpga_menu_frame;
+      width         = fpga_menu_width;
+      height        = fpga_menu_height;
+      pitch         = fpga_menu_pitch;
+      bits          = fpga_menu_bits;
+   }
+   else
+   {
+      width         = fpga_video_width;
+      height        = fpga_video_height;
+      pitch         = fpga_video_pitch;
+
+      if (frame_width == 4 && frame_height == 4 && (frame_width < width && frame_height < height))
+         draw = false;
+
+      if (video_info->menu_is_alive)
+         draw = false;
+   }
+
+   video_context_driver_get_video_size(&mode);
+
+   if (draw)
+   {
+      if (bits == 16)
+      {
+         if (frame_to_copy == fpga_menu_frame)
+         {
+            /* RGBX4444 color bits for RGUI */
+            unsigned x, y;
+
+            for (y = 0; y < FB_HEIGHT; y++)
+            {
+               for (x = 0; x < FB_WIDTH; x++)
+               {
+                  /* scale incoming frame to fit the screen */
+                  unsigned scaled_x    = (width * x) / FB_WIDTH;
+                  unsigned scaled_y    = (height * y) / FB_HEIGHT;
+                  unsigned short pixel = ((unsigned short*)frame_to_copy)[width * scaled_y + scaled_x];
+
+                  /* convert RGBX444 to XRGB8888 */
+                  unsigned r = ((pixel & 0xF000) >> 12);
+                  unsigned g = ((pixel & 0x0F00) >> 8);
+                  unsigned b = ((pixel & 0x00F0) >> 4);
+
+                  fpga->framebuffer[FB_WIDTH * y + x] = (r << 20) | (b << 12) | (g << 4);
+               }
+            }
+         }
+         else
+         {
+            /* RGB565 color bits for core */
+            unsigned x, y;
+
+            for (y = 0; y < FB_HEIGHT; y++)
+            {
+               for (x = 0; x < FB_WIDTH; x++)
+               {
+                  /* scale incoming frame to fit the screen */
+                  unsigned scaled_x    = (width * x) / FB_WIDTH;
+                  unsigned scaled_y    = (height * y) / FB_HEIGHT;
+                  unsigned short pixel = ((unsigned short*)frame_to_copy)[width * scaled_y + scaled_x];
+
+                  /* convert RGB565 to XRBG8888 */
+                  unsigned r = ((pixel & 0xF800) >> 11);
+                  unsigned g = ((pixel & 0x07E0) >> 5);
+                  unsigned b = ((pixel & 0x001F) >> 0);
+
+                  fpga->framebuffer[FB_WIDTH * y + x] = (r << 19) | (b << 11) | (g << 2);
+               }
+            }
+         }
+      }
+      else
+      {
+         /* TODO/FIXME: handle 32-bit core output */
+      }
+   }
+
+   if (msg)
+      font_driver_render_msg(video_info, NULL, msg, NULL);
+
+   return true;
+}
+
+static void fpga_gfx_set_nonblock_state(void *data, bool toggle)
+{
+   (void)data;
+   (void)toggle;
+}
+
+static bool fpga_gfx_alive(void *data)
+{
+   gfx_ctx_size_t size_data;
+   unsigned temp_width  = 0;
+   unsigned temp_height = 0;
+   bool quit            = false;
+   bool resize          = false;
+ 
+   /* Needed because some context drivers don't track their sizes */
+   video_driver_get_size(&temp_width, &temp_height);
+
+   size_data.quit       = &quit;
+   size_data.resize     = &resize;
+   size_data.width      = &temp_width;
+   size_data.height     = &temp_height;
+
+   video_context_driver_check_window(&size_data);
+
+   if (temp_width != 0 && temp_height != 0)
+      video_driver_set_size(&temp_width, &temp_height);
+
+   return true;
+}
+
+static bool fpga_gfx_focus(void *data)
+{
+   (void)data;
+   return true;
+}
+
+static bool fpga_gfx_suppress_screensaver(void *data, bool enable)
+{
+   (void)data;
+   (void)enable;
+   return false;
+}
+
+static bool fpga_gfx_has_windowed(void *data)
+{
+   (void)data;
+   return true;
+}
+
+static void fpga_gfx_free(void *data)
+{
+   fpga_t *fpga = (fpga_t*)data;
+
+   if (fpga_menu_frame)
+   {
+      free(fpga_menu_frame);
+      fpga_menu_frame = NULL;
+   }
+
+   if (!fpga)
+      return;
+
+   font_driver_free_osd();
+   video_context_driver_free();
+
+   free(fpga);
+
+   regOp.only_mmap = 0;
+   regOp.only_munmap = 1;
+
+   do_mmap_op(&regOp);
+}
+
+static bool fpga_gfx_set_shader(void *data,
+      enum rarch_shader_type type, const char *path)
+{
+   (void)data;
+   (void)type;
+   (void)path;
+
+   return false;
+}
+
+static void fpga_gfx_set_rotation(void *data,
+      unsigned rotation)
+{
+   (void)data;
+   (void)rotation;
+}
+
+static void fpga_gfx_viewport_info(void *data,
+      struct video_viewport *vp)
+{
+   (void)data;
+   (void)vp;
+}
+
+static bool fpga_gfx_read_viewport(void *data, uint8_t *buffer, bool is_idle)
+{
+   (void)data;
+   (void)buffer;
+
+   return true;
+}
+
+static void fpga_set_texture_frame(void *data,
+      const void *frame, bool rgb32, unsigned width, unsigned height,
+      float alpha)
+{
+   unsigned pitch = width * 2;
+
+   if (rgb32)
+      pitch = width * 4;
+
+   if (fpga_menu_frame)
+   {
+      free(fpga_menu_frame);
+      fpga_menu_frame = NULL;
+   }
+
+   if (!fpga_menu_frame || fpga_menu_width != width || fpga_menu_height != height || fpga_menu_pitch != pitch)
+      if (pitch && height)
+         fpga_menu_frame = (unsigned char*)malloc(pitch * height);
+
+   if (fpga_menu_frame && frame && pitch && height)
+   {
+      memcpy(fpga_menu_frame, frame, pitch * height);
+      fpga_menu_width  = width;
+      fpga_menu_height = height;
+      fpga_menu_pitch  = pitch;
+      fpga_menu_bits   = rgb32 ? 32 : 16;
+   }
+}
+
+static void fpga_set_osd_msg(void *data, 
+      video_frame_info_t *video_info,
+      const char *msg,
+      const void *params, void *font)
+{
+   font_driver_render_msg(video_info, font, msg, params);
+}
+
+static void fpga_get_video_output_size(void *data,
+      unsigned *width, unsigned *height)
+{
+   gfx_ctx_size_t size_data;
+   size_data.width  = width;
+   size_data.height = height;
+   video_context_driver_get_video_output_size(&size_data);
+}
+
+static void fpga_get_video_output_prev(void *data)
+{
+   video_context_driver_get_video_output_prev();
+}
+
+static void fpga_get_video_output_next(void *data)
+{
+   video_context_driver_get_video_output_next();
+}
+
+static void fpga_set_video_mode(void *data, unsigned width, unsigned height,
+      bool fullscreen)
+{
+   gfx_ctx_mode_t mode;
+
+   mode.width      = width;
+   mode.height     = height;
+   mode.fullscreen = fullscreen;
+
+   video_context_driver_set_video_mode(&mode);
+}
+
+static const video_poke_interface_t fpga_poke_interface = {
+   NULL,
+   NULL,
+   fpga_set_video_mode,
+   NULL,
+   fpga_get_video_output_size,
+   fpga_get_video_output_prev,
+   fpga_get_video_output_next,
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+#if defined(HAVE_MENU)
+   fpga_set_texture_frame,
+   NULL,
+   fpga_set_osd_msg,
+   NULL,
+#else
+   NULL,
+   NULL,
+   NULL,
+   NULL,
+#endif
+
+   NULL,
+#ifdef HAVE_MENU
+   NULL,
+#endif
+};
+
+static void fpga_gfx_get_poke_interface(void *data,
+      const video_poke_interface_t **iface)
+{
+   (void)data;
+   *iface = &fpga_poke_interface;
+}
+
+static void fpga_gfx_set_viewport(void *data, unsigned viewport_width,
+      unsigned viewport_height, bool force_full, bool allow_rotate)
+{
+}
+
+bool fpga_has_menu_frame(void)
+{
+   return (fpga_menu_frame != NULL);
+}
+
+video_driver_t video_fpga = {
+   fpga_gfx_init,
+   fpga_gfx_frame,
+   fpga_gfx_set_nonblock_state,
+   fpga_gfx_alive,
+   fpga_gfx_focus,
+   fpga_gfx_suppress_screensaver,
+   fpga_gfx_has_windowed,
+   fpga_gfx_set_shader,
+   fpga_gfx_free,
+   "fpga",
+   fpga_gfx_set_viewport,
+   fpga_gfx_set_rotation,
+   fpga_gfx_viewport_info,
+   fpga_gfx_read_viewport,
+   NULL, /* read_frame_raw */
+
+#ifdef HAVE_OVERLAY
+  NULL, /* overlay_interface */
+#endif
+  fpga_gfx_get_poke_interface,
+};
diff --git a/gfx/drivers_context/fpga_ctx.c b/gfx/drivers_context/fpga_ctx.c
new file mode 100644
index 0000000000..d83417a356
--- /dev/null
+++ b/gfx/drivers_context/fpga_ctx.c
@@ -0,0 +1,198 @@
+/*  RetroArch - A frontend for libretro.
+ *  Copyright (C) 2010-2014 - Hans-Kristian Arntzen
+ *  Copyright (C) 2011-2017 - Daniel De Matteis
+ *  Copyright (C) 2016-2017 - Brad Parker
+ * 
+ *  RetroArch is free software: you can redistribute it and/or modify it under the terms
+ *  of the GNU General Public License as published by the Free Software Found-
+ *  ation, either version 3 of the License, or (at your option) any later version.
+ *
+ *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ *  PURPOSE.  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with RetroArch.
+ *  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* FPGA context. */
+
+#include <string.h>
+#include <math.h>
+
+#include <string/stdstring.h>
+
+#ifdef HAVE_CONFIG_H
+#include "../../config.h"
+#endif
+
+#include "../../configuration.h"
+#include "../../dynamic.h"
+#include "../../verbosity.h"
+#include "../video_driver.h"
+#include "../common/fpga_common.h"
+
+static unsigned g_resize_width  = FB_WIDTH;
+static unsigned g_resize_height = FB_HEIGHT;
+
+static void gfx_ctx_fpga_check_window(void *data, bool *quit,
+      bool *resize, unsigned *width, unsigned *height, bool is_shutdown)
+{
+}
+
+static bool gfx_ctx_fpga_set_resize(void *data,
+      unsigned width, unsigned height)
+{
+   (void)data;
+   (void)width;
+   (void)height;
+
+   return false;
+}
+
+static void gfx_ctx_fpga_update_window_title(void *data, void *data2)
+{
+   char title[128];
+
+   title[0] = '\0';
+
+   video_driver_get_window_title(title, sizeof(title));
+}
+
+static void gfx_ctx_fpga_get_video_size(void *data,
+      unsigned *width, unsigned *height)
+{
+   (void)data;
+
+    *width  = g_resize_width;
+    *height = g_resize_height;
+}
+
+static void *gfx_ctx_fpga_init(video_frame_info_t *video_info, void *video_driver)
+{
+   (void)video_driver;
+
+   return (void*)"fpga";
+}
+
+static void gfx_ctx_fpga_destroy(void *data)
+{
+   (void)data;
+}
+
+static bool gfx_ctx_fpga_set_video_mode(void *data,
+      video_frame_info_t *video_info,
+      unsigned width, unsigned height,
+      bool fullscreen)
+{
+   if (false)
+      goto error;
+
+   return true;
+
+error:
+   gfx_ctx_fpga_destroy(data);
+   return false;
+}
+
+
+static void gfx_ctx_fpga_input_driver(void *data,
+      const char *joypad_name,
+      const input_driver_t **input, void **input_data)
+{
+   (void)data;
+   settings_t *settings = config_get_ptr();
+}
+
+static bool gfx_ctx_fpga_has_focus(void *data)
+{
+   return true;
+}
+
+static bool gfx_ctx_fpga_suppress_screensaver(void *data, bool enable)
+{
+   return true;
+}
+
+static bool gfx_ctx_fpga_has_windowed(void *data)
+{
+   (void)data;
+
+   return true;
+}
+
+static bool gfx_ctx_fpga_get_metrics(void *data,
+	enum display_metric_types type, float *value)
+{
+   return true;
+}
+
+static bool gfx_ctx_fpga_bind_api(void *data,
+      enum gfx_ctx_api api, unsigned major, unsigned minor)
+{
+   (void)data;
+
+   return true;
+}
+
+static void gfx_ctx_fpga_show_mouse(void *data, bool state)
+{
+   (void)data;
+}
+
+static void gfx_ctx_fpga_swap_interval(void *data, unsigned interval)
+{
+   (void)data;
+   (void)interval;
+}
+
+static void gfx_ctx_fpga_set_flags(void *data, uint32_t flags)
+{
+   (void)data;
+   (void)flags;
+}
+
+static uint32_t gfx_ctx_fpga_get_flags(void *data)
+{
+   uint32_t flags = 0;
+   BIT32_SET(flags, GFX_CTX_FLAGS_NONE);
+   return flags;
+}
+
+static void gfx_ctx_fpga_swap_buffers(void *data, void *data2)
+{
+   (void)data;
+}
+
+const gfx_ctx_driver_t gfx_ctx_fpga = {
+   gfx_ctx_fpga_init,
+   gfx_ctx_fpga_destroy,
+   gfx_ctx_fpga_bind_api,
+   gfx_ctx_fpga_swap_interval,
+   gfx_ctx_fpga_set_video_mode,
+   gfx_ctx_fpga_get_video_size,
+   NULL, /* get_video_output_size */
+   NULL, /* get_video_output_prev */
+   NULL, /* get_video_output_next */
+   gfx_ctx_fpga_get_metrics,
+   NULL,
+   gfx_ctx_fpga_update_window_title,
+   gfx_ctx_fpga_check_window,
+   gfx_ctx_fpga_set_resize,
+   gfx_ctx_fpga_has_focus,
+   gfx_ctx_fpga_suppress_screensaver,
+   gfx_ctx_fpga_has_windowed,
+   gfx_ctx_fpga_swap_buffers,
+   gfx_ctx_fpga_input_driver,
+   NULL,
+   NULL,
+   NULL,
+   gfx_ctx_fpga_show_mouse,
+   "fpga",
+   gfx_ctx_fpga_get_flags,
+   gfx_ctx_fpga_set_flags,
+   NULL,
+   NULL,
+   NULL
+};
+
diff --git a/gfx/drivers_font/fpga_font.c b/gfx/drivers_font/fpga_font.c
new file mode 100644
index 0000000000..33e7caffeb
--- /dev/null
+++ b/gfx/drivers_font/fpga_font.c
@@ -0,0 +1,153 @@
+/*  RetroArch - A frontend for libretro.
+ *  Copyright (C) 2010-2014 - Hans-Kristian Arntzen
+ *  Copyright (C) 2011-2017 - Daniel De Matteis
+ *  Copyright (C) 2016-2017 - Brad Parker
+ * 
+ *  RetroArch is free software: you can redistribute it and/or modify it under the terms
+ *  of the GNU General Public License as published by the Free Software Found-
+ *  ation, either version 3 of the License, or (at your option) any later version.
+ *
+ *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ *  PURPOSE.  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with RetroArch.
+ *  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string/stdstring.h>
+#include <encodings/utf.h>
+
+#ifdef HAVE_CONFIG_H
+#include "../../config.h"
+#endif
+
+#include "../font_driver.h"
+#include "../video_driver.h"
+#include "../../configuration.h"
+#include "../../verbosity.h"
+#include "../common/fpga_common.h"
+
+typedef struct
+{
+   const font_renderer_driver_t *fpga_font_driver;
+   void *fpga_font_data;
+   fpga_t *fpga;
+} fpga_raster_t;
+
+static void *fpga_init_font(void *data,
+      const char *font_path, float font_size,
+      bool is_threaded)
+{
+   fpga_raster_t *font  = (fpga_raster_t*)calloc(1, sizeof(*font));
+
+   if (!font)
+      return NULL;
+
+   font->fpga = (fpga_t*)data;
+
+   font_size = 1;
+
+   if (!font_renderer_create_default((const void**)&font->fpga_font_driver,
+            &font->fpga_font_data, font_path, font_size))
+   {
+      RARCH_WARN("Couldn't initialize font renderer.\n");
+      return NULL;
+   }
+
+   return font;
+}
+
+static void fpga_render_free_font(void *data, bool is_threaded)
+{
+   (void)data;
+   (void)is_threaded;
+}
+
+static int fpga_get_message_width(void *data, const char *msg,
+      unsigned msg_len, float scale)
+{
+   return 0;
+}
+
+static const struct font_glyph *fpga_font_get_glyph(
+      void *data, uint32_t code)
+{
+   return NULL;
+}
+
+static void fpga_render_msg(
+      video_frame_info_t *video_info,
+      void *data, const char *msg,
+      const void *userdata)
+{
+   float x, y, scale;
+   fpga_raster_t *font = (fpga_raster_t*)data;
+   unsigned newX, newY, len;
+   unsigned align;
+   const struct font_params *params = (const struct font_params*)userdata;
+   unsigned width                   = video_info->width;
+   unsigned height                  = video_info->height;
+
+   if (!font || string_is_empty(msg))
+      return;
+
+   if (params)
+   {
+      x = params->x;
+      y = params->y;
+      scale = params->scale;
+      align = params->text_align;
+   }
+   else
+   {
+      x = video_info->font_msg_pos_x;
+      y = video_info->font_msg_pos_y;
+      scale = 1.0f;
+      align = TEXT_ALIGN_LEFT;
+   }
+
+   if (!font->fpga)
+      return;
+
+   len  = utf8len(msg);
+
+   switch (align)
+   {
+      case TEXT_ALIGN_LEFT:
+         newX = x * width * scale;
+         break;
+      case TEXT_ALIGN_RIGHT:
+         newX = (x * width * scale) - len;
+         break;
+      case TEXT_ALIGN_CENTER:
+         newX = (x * width * scale) - (len / 2);
+         break;
+      default:
+         break;
+   }
+
+   /* TODO: draw osd msg */
+}
+
+static void fpga_font_flush_block(unsigned width, unsigned height, void* data)
+{
+   (void)data;
+}
+
+static void fpga_font_bind_block(void* data, void* userdata)
+{
+   (void)data;
+}
+
+font_renderer_t fpga_font = {
+   fpga_init_font,
+   fpga_render_free_font,
+   fpga_render_msg,
+   "fpga font",
+   fpga_font_get_glyph,       /* get_glyph */
+   fpga_font_bind_block,      /* bind_block */
+   fpga_font_flush_block,     /* flush */
+   fpga_get_message_width     /* get_message_width */
+};
diff --git a/gfx/font_driver.h b/gfx/font_driver.h
index bea9809a15..780905ac5d 100644
--- a/gfx/font_driver.h
+++ b/gfx/font_driver.h
@@ -177,6 +177,7 @@ extern font_renderer_t d3d12_font;
 extern font_renderer_t caca_font;
 extern font_renderer_t gdi_font;
 extern font_renderer_t vga_font;
+extern font_renderer_t fpga_font;
 extern font_renderer_t sixel_font;
 extern font_renderer_t switch_font;
 
diff --git a/gfx/video_defines.h b/gfx/video_defines.h
index edecf11233..a460c17556 100644
--- a/gfx/video_defines.h
+++ b/gfx/video_defines.h
@@ -101,6 +101,7 @@ enum font_driver_render_api
    FONT_DRIVER_RENDER_NETWORK_VIDEO,
    FONT_DRIVER_RENDER_GDI,
    FONT_DRIVER_RENDER_VGA,
+   FONT_DRIVER_RENDER_FPGA,
    FONT_DRIVER_RENDER_SWITCH
 };
 
diff --git a/menu/drivers_display/menu_display_fpga.c b/menu/drivers_display/menu_display_fpga.c
new file mode 100644
index 0000000000..2249e4c9f3
--- /dev/null
+++ b/menu/drivers_display/menu_display_fpga.c
@@ -0,0 +1,106 @@
+/*  RetroArch - A frontend for libretro.
+ *  Copyright (C) 2011-2017 - Daniel De Matteis
+ *  Copyright (C) 2016-2017 - Brad Parker
+ *
+ *  RetroArch is free software: you can redistribute it and/or modify it under the terms
+ *  of the GNU General Public License as published by the Free Software Found-
+ *  ation, either version 3 of the License, or (at your option) any later version.
+ *
+ *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ *  PURPOSE.  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with RetroArch.
+ *  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <time.h>
+
+#include <queues/message_queue.h>
+#include <retro_miscellaneous.h>
+
+#include "../../config.def.h"
+#include "../../gfx/font_driver.h"
+#include "../../gfx/video_driver.h"
+
+#include "../menu_driver.h"
+
+static void *menu_display_fpga_get_default_mvp(void)
+{
+   return NULL;
+}
+
+static void menu_display_fpga_blend_begin(void)
+{
+}
+
+static void menu_display_fpga_blend_end(void)
+{
+}
+
+static void menu_display_fpga_draw(void *data)
+{
+   (void)data;
+}
+
+static void menu_display_fpga_draw_pipeline(void *data)
+{
+   (void)data;
+}
+
+static void menu_display_fpga_viewport(void *data)
+{
+   (void)data;
+}
+
+static void menu_display_fpga_restore_clear_color(void)
+{
+}
+
+static void menu_display_fpga_clear_color(menu_display_ctx_clearcolor_t *clearcolor)
+{
+   (void)clearcolor;
+
+   menu_display_fpga_restore_clear_color();
+}
+
+static bool menu_display_fpga_font_init_first(
+      void **font_handle, void *video_data,
+      const char *font_path, float font_size,
+      bool is_threaded)
+{
+   font_data_t **handle = (font_data_t**)font_handle;
+   *handle = font_driver_init_first(video_data,
+         font_path, font_size, true,
+         is_threaded,
+         FONT_DRIVER_RENDER_FPGA);
+   return *handle;
+}
+
+static const float *menu_display_fpga_get_default_vertices(void)
+{
+   static float dummy[16] = {0.0f};
+   return &dummy[0];
+}
+
+static const float *menu_display_fpga_get_default_tex_coords(void)
+{
+   static float dummy[16] = {0.0f};
+   return &dummy[0];
+}
+
+menu_display_ctx_driver_t menu_display_ctx_fpga = {
+   menu_display_fpga_draw,
+   menu_display_fpga_draw_pipeline,
+   menu_display_fpga_viewport,
+   menu_display_fpga_blend_begin,
+   menu_display_fpga_blend_end,
+   menu_display_fpga_restore_clear_color,
+   menu_display_fpga_clear_color,
+   menu_display_fpga_get_default_mvp,
+   menu_display_fpga_get_default_vertices,
+   menu_display_fpga_get_default_tex_coords,
+   menu_display_fpga_font_init_first,
+   MENU_VIDEO_DRIVER_FPGA,
+   "menu_display_fpga",
+};
diff --git a/menu/menu_defines.h b/menu/menu_defines.h
index 50e2dca678..47de53f339 100644
--- a/menu/menu_defines.h
+++ b/menu/menu_defines.h
@@ -228,7 +228,8 @@ enum menu_display_driver_type
    MENU_VIDEO_DRIVER_SIXEL,
    MENU_VIDEO_DRIVER_GDI,
    MENU_VIDEO_DRIVER_SWITCH,
-   MENU_VIDEO_DRIVER_VGA
+   MENU_VIDEO_DRIVER_VGA,
+   MENU_VIDEO_DRIVER_FPGA
 };
 
 enum rgui_thumbnail_scaler
diff --git a/menu/menu_driver.c b/menu/menu_driver.c
index 40b74a84fc..b43857937d 100644
--- a/menu/menu_driver.c
+++ b/menu/menu_driver.c
@@ -166,6 +166,9 @@ static menu_display_ctx_driver_t *menu_display_ctx_drivers[] = {
 #endif
 #ifdef HAVE_CACA
    &menu_display_ctx_caca,
+#endif
+#ifdef HAVE_FPGA
+   &menu_display_ctx_fpga,
 #endif
    &menu_display_ctx_null,
    NULL,
@@ -1641,6 +1644,10 @@ static bool menu_display_check_compatibility(
          if (string_is_equal(video_driver, "vga"))
             return true;
          break;
+      case MENU_VIDEO_DRIVER_FPGA:
+         if (string_is_equal(video_driver, "fpga"))
+            return true;
+         break;
       case MENU_VIDEO_DRIVER_SWITCH:
          if (string_is_equal(video_driver, "switch"))
             return true;
diff --git a/menu/menu_driver.h b/menu/menu_driver.h
index 426efe47a1..8e11b61b0a 100644
--- a/menu/menu_driver.h
+++ b/menu/menu_driver.h
@@ -711,6 +711,7 @@ extern menu_display_ctx_driver_t menu_display_ctx_wiiu;
 extern menu_display_ctx_driver_t menu_display_ctx_caca;
 extern menu_display_ctx_driver_t menu_display_ctx_gdi;
 extern menu_display_ctx_driver_t menu_display_ctx_vga;
+extern menu_display_ctx_driver_t menu_display_ctx_fpga;
 extern menu_display_ctx_driver_t menu_display_ctx_switch;
 extern menu_display_ctx_driver_t menu_display_ctx_sixel;
 extern menu_display_ctx_driver_t menu_display_ctx_null;
diff --git a/retroarch.c b/retroarch.c
index a3472e9cad..2cade385bd 100644
--- a/retroarch.c
+++ b/retroarch.c
@@ -431,6 +431,9 @@ static const video_driver_t *video_drivers[] = {
 #ifdef DJGPP
    &video_vga,
 #endif
+#ifdef HAVE_FPGA
+   &video_fpga,
+#endif
 #ifdef HAVE_SIXEL
    &video_sixel,
 #endif
@@ -517,6 +520,9 @@ static const gfx_ctx_driver_t *gfx_ctx_drivers[] = {
 #endif
 #ifdef HAVE_NETWORK_VIDEO
    &gfx_ctx_network,
+#endif
+#if defined(HAVE_FPGA)
+   &gfx_ctx_fpga,
 #endif
    &gfx_ctx_null,
    NULL
diff --git a/retroarch.h b/retroarch.h
index 62071faed5..b10d7bbb42 100644
--- a/retroarch.h
+++ b/retroarch.h
@@ -839,6 +839,7 @@ enum gfx_ctx_api
    GFX_CTX_NETWORK_VIDEO_API,
    GFX_CTX_METAL_API,
    GFX_CTX_GDI_API,
+   GFX_CTX_FPGA_API,
    GFX_CTX_GX_API,
    GFX_CTX_GX2_API
 };
@@ -1942,6 +1943,7 @@ extern video_driver_t video_xshm;
 extern video_driver_t video_caca;
 extern video_driver_t video_gdi;
 extern video_driver_t video_vga;
+extern video_driver_t video_fpga;
 extern video_driver_t video_sixel;
 extern video_driver_t video_network;
 extern video_driver_t video_null;
@@ -1965,6 +1967,7 @@ extern const gfx_ctx_driver_t gfx_ctx_emscripten;
 extern const gfx_ctx_driver_t gfx_ctx_opendingux_fbdev;
 extern const gfx_ctx_driver_t gfx_ctx_khr_display;
 extern const gfx_ctx_driver_t gfx_ctx_gdi;
+extern const gfx_ctx_driver_t gfx_ctx_fpga;
 extern const gfx_ctx_driver_t gfx_ctx_sixel;
 extern const gfx_ctx_driver_t gfx_ctx_network;
 extern const gfx_ctx_driver_t switch_ctx;