diff --git a/quad/.gitignore b/quad/.gitignore
index 43d04fb118c3ab8c1ea06f84c8a8b11598990756..92bd47f407dc5d75d40fff7c329cb9ba87f3df11 100644
--- a/quad/.gitignore
+++ b/quad/.gitignore
@@ -5,3 +5,4 @@ lib/
 lib-zybo/
 TAGS
 out/
+bin/
\ No newline at end of file
diff --git a/quad/Makefile b/quad/Makefile
index 147ee25067ceb0bae3ffc9295e7a83a9bf37d00d..18875c630eee61348a964b38c0cdac57fc0d2eb5 100644
--- a/quad/Makefile
+++ b/quad/Makefile
@@ -1,13 +1,14 @@
 INCDIR = inc
 LIBDIR = lib
 OUTDIR = out
+EXEDIR = bin
 WS = $(CURDIR)/xsdk_workspace
 
 BOOT = $(OUTDIR)/BOOT.bin
 
 .PHONY: all libs zybo boot test clean deep-clean
 
-all: libs
+all: libs bins
 
 libs:
 	$(MAKE) -C src/test
@@ -16,6 +17,9 @@ libs:
 	$(MAKE) -C src/commands
 	$(MAKE) -C src/quad_app
 
+bins:
+	$(MAKE) -C src/virt_quad
+
 zybo:
 	bash scripts/build_zybo.sh
 
@@ -27,7 +31,7 @@ test:
 	$(MAKE) -C src/quad_app test
 
 clean:
-	rm -rf $(INCDIR) $(LIBDIR) $(OUTDIR)
+	rm -rf $(INCDIR) $(LIBDIR) $(OUTDIR) $(EXEDIR)
 
 deep-clean:
 	make clean
diff --git a/quad/executable.mk b/quad/executable.mk
new file mode 100644
index 0000000000000000000000000000000000000000..d17244a837c5c785fcf53ffb3f547d110d0be88a
--- /dev/null
+++ b/quad/executable.mk
@@ -0,0 +1,43 @@
+GCC = gcc
+
+INCDIR = $(TOP)/inc
+OBJDIR = obj
+EXEDIR = $(TOP)/bin
+LIBDIR = $(TOP)/lib
+
+SOURCES = $(wildcard *.c)
+HEADERS = $(wildcard *.h)
+INCLUDES = $(addprefix $(INCDIR)/, $(HEADERS))
+OBJECTS = $(patsubst %.c, $(OBJDIR)/%.o, $(SOURCES))
+
+TARGET = $(EXEDIR)/$(NAME)
+
+.PHONY: default run clean
+
+################
+## User Targets
+################
+
+default: $(TARGET)
+
+run: $(TARGET)
+	$(EXEDIR)/$(NAME)
+
+clean:
+	rm -rf $(TARGET) $(OBJDIR)
+
+####################
+## Internal Targets
+####################
+
+$(TARGET): $(OBJECTS) | $(EXEDIR)
+	$(GCC) -g -o $(TARGET) $^ -I$(INCDIR) -L$(LIBDIR) $(REQLIBS)
+
+$(OBJDIR)/%.o : %.c | $(OBJDIR) $(INCDIR)
+	$(GCC) -c -g -o $@ $< -I$(INCDIR)
+
+$(OBJDIR):
+	mkdir $(OBJDIR)
+
+$(EXEDIR):
+	mkdir $(EXEDIR)
diff --git a/quad/src/virt_quad/Makefile b/quad/src/virt_quad/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..47cebc494626a024de63f93c15480f5e4c3ff5a4
--- /dev/null
+++ b/quad/src/virt_quad/Makefile
@@ -0,0 +1,6 @@
+TOP=../..
+
+NAME = virt_quad
+REQLIBS = -lquad_app -lcomputation_graph -lm -lcommands
+
+include $(TOP)/executable.mk
diff --git a/quad/src/virt_quad/hw_impl_unix.c b/quad/src/virt_quad/hw_impl_unix.c
new file mode 100644
index 0000000000000000000000000000000000000000..fea231c35e963f5321b35665e4c3c2feac961383
--- /dev/null
+++ b/quad/src/virt_quad/hw_impl_unix.c
@@ -0,0 +1,70 @@
+#include "hw_impl_unix.h"
+
+struct UARTDriver create_unix_uart() {
+  struct UARTDriver uart;
+  uart.state = NULL;
+  uart.reset = unix_uart_reset;
+  uart.write = unix_uart_write;
+  uart.read = unix_uart_read;
+  return uart;
+}
+
+struct PWMOutputDriver create_unix_pwm_outputs() {
+  struct PWMOutputDriver pwm_outputs;
+  pwm_outputs.state = NULL;
+  pwm_outputs.reset = unix_pwm_output_reset;
+  pwm_outputs.write = unix_pwm_output_write;
+  return pwm_outputs;
+}
+
+struct PWMInputDriver create_unix_pwm_inputs() {
+  struct PWMInputDriver pwm_inputs;
+  pwm_inputs.state = NULL;
+  pwm_inputs.reset = unix_pwm_input_reset;
+  pwm_inputs.read = unix_pwm_input_read;
+  return pwm_inputs;
+}
+
+struct I2CDriver create_unix_i2c() {
+  struct I2CDriver i2c;
+  i2c.state = NULL;
+  i2c.reset = unix_i2c_reset;
+  i2c.write = unix_i2c_write;
+  i2c.read = unix_i2c_read;
+  return i2c;
+}
+
+struct TimerDriver create_unix_global_timer() {
+  struct TimerDriver global_timer;
+  global_timer.state = NULL;
+  global_timer.reset = unix_global_timer_reset;
+  global_timer.restart = unix_global_timer_restart;
+  global_timer.read = unix_global_timer_read;
+  return global_timer;
+}
+
+struct TimerDriver create_unix_axi_timer() {
+  struct TimerDriver axi_timer;
+  axi_timer.state = NULL;
+  axi_timer.reset = unix_axi_timer_reset;
+  axi_timer.restart = unix_axi_timer_restart;
+  axi_timer.read = unix_axi_timer_read;
+  return axi_timer;
+}
+
+struct LEDDriver create_unix_mio7_led() {
+  struct LEDDriver mio7_led;
+  mio7_led.state = NULL;
+  mio7_led.reset = unix_mio7_led_reset;
+  mio7_led.turn_on = unix_mio7_led_turn_on;
+  mio7_led.turn_off = unix_mio7_led_turn_off;
+  return mio7_led;
+}
+
+struct SystemDriver create_unix_system() {
+  struct SystemDriver sys;
+  sys.state = NULL;
+  sys.reset = unix_system_reset;
+  sys.sleep = unix_system_sleep;
+  return sys;
+}
diff --git a/quad/src/virt_quad/hw_impl_unix.h b/quad/src/virt_quad/hw_impl_unix.h
new file mode 100644
index 0000000000000000000000000000000000000000..c7e3659dffcfb0b1094c26f41ffe3b4d792962b8
--- /dev/null
+++ b/quad/src/virt_quad/hw_impl_unix.h
@@ -0,0 +1,61 @@
+#ifndef HW_IMPL_UNIX
+#define HW_IMPL_UNIX
+
+#include "hw_iface.h"
+#include "type_def.h"
+
+#include <sys/time.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+
+int unix_uart_reset(struct UARTDriver *self);
+int unix_uart_write(struct UARTDriver *self, unsigned char c);
+int unix_uart_read(struct UARTDriver *self, unsigned char *c);
+
+int unix_pwm_output_reset(struct PWMOutputDriver *self);
+int unix_pwm_output_write(struct PWMOutputDriver *self, unsigned int channel, unsigned long pulse_width_us);
+
+int unix_pwm_input_reset(struct PWMInputDriver *self);
+int unix_pwm_input_read(struct PWMInputDriver *self, unsigned int channel, unsigned long *pulse_width_us);
+
+int unix_i2c_reset(struct I2CDriver *self);
+int unix_i2c_write(struct I2CDriver *self,
+                   unsigned short device_addr,
+                   unsigned char *data,
+                   unsigned int length);
+int unix_i2c_read(struct I2CDriver *self,
+                  unsigned short device_addr,
+                  unsigned char *buff,
+                  unsigned int length);
+
+int unix_global_timer_reset(struct TimerDriver *self);
+int unix_global_timer_restart(struct TimerDriver *self);
+int unix_global_timer_read(struct TimerDriver *self, u64 *us);
+
+int unix_axi_timer_reset(struct TimerDriver *self);
+int unix_axi_timer_restart(struct TimerDriver *self);
+int unix_axi_timer_read(struct TimerDriver *self, u64 *us);
+
+int unix_mio7_led_reset(struct LEDDriver *self);
+int unix_mio7_led_turn_on(struct LEDDriver *self);
+int unix_mio7_led_turn_off(struct LEDDriver *self);
+
+int unix_system_reset(struct SystemDriver *self);
+int unix_system_sleep(struct SystemDriver *self, unsigned long us);
+
+struct UARTDriver create_unix_uart();
+struct PWMOutputDriver create_unix_pwm_outputs();
+struct PWMInputDriver create_unix_pwm_inputs();
+struct I2CDriver create_unix_i2c();
+struct TimerDriver create_unix_global_timer();
+struct TimerDriver create_unix_axi_timer();
+struct LEDDriver create_unix_mio7_led();
+struct SystemDriver create_unix_system();
+
+int test_unix_i2c();
+int test_unix_mio7_led_and_system();
+int test_unix_pwm_inputs();
+
+#endif
diff --git a/quad/src/virt_quad/hw_impl_unix_axi_timer.c b/quad/src/virt_quad/hw_impl_unix_axi_timer.c
new file mode 100644
index 0000000000000000000000000000000000000000..73e9acc281110e6453bfba625976af852eeac351
--- /dev/null
+++ b/quad/src/virt_quad/hw_impl_unix_axi_timer.c
@@ -0,0 +1,24 @@
+#include "hw_impl_unix.h"
+
+int unix_axi_timer_reset(struct TimerDriver *self) {
+  if (self->state == NULL) {
+    self->state = malloc(sizeof(struct timeval));
+  }
+  return 0;
+}
+
+int unix_axi_timer_restart(struct TimerDriver *self) {
+  struct timeval *start = self->state;
+  struct timezone tz;
+  gettimeofday(start, &tz);
+  return 0;
+}
+
+int unix_axi_timer_read(struct TimerDriver *self, u64 *us) {
+  struct timeval *start = self->state;
+  struct timeval end;
+  struct timezone tz;
+  gettimeofday(&end, &tz);
+  *us = end.tv_usec - start->tv_usec;
+  return 0;
+}
diff --git a/quad/src/virt_quad/hw_impl_unix_global_timer.c b/quad/src/virt_quad/hw_impl_unix_global_timer.c
new file mode 100644
index 0000000000000000000000000000000000000000..be752b774eb55cb17f3c481947f44b76fc2ec124
--- /dev/null
+++ b/quad/src/virt_quad/hw_impl_unix_global_timer.c
@@ -0,0 +1,24 @@
+#include "hw_impl_unix.h"
+
+int unix_global_timer_reset(struct TimerDriver *self) {
+  if (self->state == NULL) {
+    self->state = malloc(sizeof(struct timeval));
+  }
+  return 0;
+}
+
+int unix_global_timer_restart(struct TimerDriver *self) {
+  struct timeval *start = self->state;
+  struct timezone tz;
+  gettimeofday(start, &tz);
+  return 0;
+}
+
+int unix_global_timer_read(struct TimerDriver *self, u64 *us) {
+  struct timeval *start = self->state;
+  struct timeval end;
+  struct timezone tz;
+  gettimeofday(&end, &tz);
+  *us = end.tv_usec - start->tv_usec;
+  return 0;
+}
diff --git a/quad/src/virt_quad/hw_impl_unix_i2c.c b/quad/src/virt_quad/hw_impl_unix_i2c.c
new file mode 100644
index 0000000000000000000000000000000000000000..09ab43c8b83b82d60dff7623a31efb1d29c3fd60
--- /dev/null
+++ b/quad/src/virt_quad/hw_impl_unix_i2c.c
@@ -0,0 +1,19 @@
+#include "hw_impl_unix.h"
+
+int unix_i2c_reset(struct I2CDriver *self) {
+  return 0;
+}
+
+int unix_i2c_write(struct I2CDriver *self,
+                   unsigned short device_addr,
+                   unsigned char *data,
+                   unsigned int length) {
+  return 0;
+}
+
+int unix_i2c_read(struct I2CDriver *self,
+                  unsigned short device_addr,
+                  unsigned char *buff,
+                  unsigned int length) {
+  return 0;
+}
diff --git a/quad/src/virt_quad/hw_impl_unix_mio7_led.c b/quad/src/virt_quad/hw_impl_unix_mio7_led.c
new file mode 100644
index 0000000000000000000000000000000000000000..f96fda029e0c0a9664be8bd81e76a93af606e7ba
--- /dev/null
+++ b/quad/src/virt_quad/hw_impl_unix_mio7_led.c
@@ -0,0 +1,23 @@
+#include "hw_impl_unix.h"
+
+int on;
+
+int unix_mio7_led_reset(struct LEDDriver *self) {
+  return 0;
+}
+
+int unix_mio7_led_turn_on(struct LEDDriver *self) {
+  if (!on) {
+    puts("LED ON");
+    on = 1;
+  }
+  return 0;
+}
+
+int unix_mio7_led_turn_off(struct LEDDriver *self) {
+  if (on) {
+    puts("LED OFF");
+    on = 0;
+  }
+  return 0;
+}
diff --git a/quad/src/virt_quad/hw_impl_unix_pwm_input.c b/quad/src/virt_quad/hw_impl_unix_pwm_input.c
new file mode 100644
index 0000000000000000000000000000000000000000..8881f5f3815f063fb2ce365a6b07c79d7a2eaf44
--- /dev/null
+++ b/quad/src/virt_quad/hw_impl_unix_pwm_input.c
@@ -0,0 +1,50 @@
+#include "hw_impl_unix.h"
+
+int unix_pwm_input_reset(struct PWMInputDriver *self) {
+  return 0;
+}
+
+int unix_pwm_input_read(struct PWMInputDriver *self,
+                        unsigned int channel,
+                        unsigned long *pulse_width_us) {
+  static int inc = 0;
+  unsigned long gear;
+
+  switch (channel) {
+  case 0:
+    *pulse_width_us = 100000;
+    break;
+  case 1:
+    *pulse_width_us = 100000;
+    break;
+  case 2:
+    *pulse_width_us = 100000;
+    break;
+  case 3:
+    *pulse_width_us = 100000;
+    break;
+  case 4:
+    if (inc == 0) {
+      inc += 1;
+      puts("GEAR OFF");
+    }
+    if (inc < 20) {
+      inc += 1;
+      gear = 120000;
+    }
+    else if (inc == 20) {
+      puts("GEAR ON");
+      inc += 1;
+    }
+    else {
+      gear = 140000;
+    }
+    *pulse_width_us = gear;
+    break;
+  case 5:
+    // flap 1
+    *pulse_width_us = 192000;
+    break;
+  }
+  return 0;
+}
diff --git a/quad/src/virt_quad/hw_impl_unix_pwm_output.c b/quad/src/virt_quad/hw_impl_unix_pwm_output.c
new file mode 100644
index 0000000000000000000000000000000000000000..b549cd4367af0a5ebfe8a50cd7af97e94daf16bb
--- /dev/null
+++ b/quad/src/virt_quad/hw_impl_unix_pwm_output.c
@@ -0,0 +1,12 @@
+#include "hw_impl_unix.h"
+
+int unix_pwm_output_reset(struct PWMOutputDriver *self) {
+  return 0;
+}
+
+int unix_pwm_output_write(struct PWMOutputDriver *self,
+                          unsigned int channel,
+                          unsigned long pulse_width_us) {
+  //printf("PWM OUTPUT: %d %d\n", channel, pulse_width_us);
+  return 0;
+}
diff --git a/quad/src/virt_quad/hw_impl_unix_system.c b/quad/src/virt_quad/hw_impl_unix_system.c
new file mode 100644
index 0000000000000000000000000000000000000000..27f1a691ee92f46f6be0e029245dfba51bfb9de0
--- /dev/null
+++ b/quad/src/virt_quad/hw_impl_unix_system.c
@@ -0,0 +1,14 @@
+#include "hw_impl_unix.h"
+
+int unix_system_reset(struct SystemDriver *sys) {
+  return 0;
+}
+
+int unix_system_sleep(struct SystemDriver *sys, unsigned long us) {
+  struct timespec time;
+  struct timespec time2;
+  time.tv_sec = 0;
+  time.tv_nsec = us * 1000;
+  nanosleep(&time, &time2);
+  return 0;
+}
diff --git a/quad/src/virt_quad/hw_impl_unix_uart.c b/quad/src/virt_quad/hw_impl_unix_uart.c
new file mode 100644
index 0000000000000000000000000000000000000000..f4787939832cd38d781643df1c9cd9d801f311b3
--- /dev/null
+++ b/quad/src/virt_quad/hw_impl_unix_uart.c
@@ -0,0 +1,13 @@
+#include "hw_impl_unix.h"
+
+int unix_uart_reset(struct UARTDriver *self) {
+  return 0;
+}
+
+int unix_uart_write(struct UARTDriver *self, unsigned char c) {
+  return 0;
+}
+
+int unix_uart_read(struct UARTDriver *self, unsigned char *c) {
+  return 0;
+}
diff --git a/quad/src/virt_quad/main.c b/quad/src/virt_quad/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..a87b8013f5037d6a2db5badd74c7166f681e3e8c
--- /dev/null
+++ b/quad/src/virt_quad/main.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include "hw_impl_unix.h"
+#include "quad_app.h"
+
+int setup_hardware(hardware_t *hardware) {
+  hardware->i2c = create_unix_i2c();
+  hardware->pwm_inputs = create_unix_pwm_inputs();
+  hardware->pwm_outputs = create_unix_pwm_outputs();
+  hardware->uart = create_unix_uart();
+  hardware->global_timer = create_unix_global_timer();
+  hardware->axi_timer = create_unix_axi_timer();
+  hardware->mio7_led = create_unix_mio7_led();
+  hardware->sys = create_unix_system();
+  return 0;
+}
+
+int main()
+{
+  quad_main(setup_hardware);
+  return 0;
+}