diff --git a/examples/sdl/src/main.rs b/examples/sdl/src/main.rs
index 584239cb788ae2206d9d2c51ca1fc50e1199a912..e2de571ce8d1a106c96d71e2644c62b0a00476bd 100644
--- a/examples/sdl/src/main.rs
+++ b/examples/sdl/src/main.rs
@@ -83,7 +83,7 @@ fn main() {
     let mut game_boy = GameBoy::new();
     game_boy.load_boot_dmg_bootix();
 
-    //game_boy.load_rom_file("../../res/roms.prop/tetris.gb");
+    game_boy.load_rom_file("../../res/roms.prop/tetris.gb");
     //game_boy.load_rom_file("../../res/roms.prop/alleyway.gb");
 
     //game_boy.load_rom_file("../../res/roms/firstwhite.gb");
@@ -97,7 +97,7 @@ fn main() {
     //game_boy.load_rom_file("../../res/roms/paradius/cpu/06-ld r,r.gb"); // PASSED
     //game_boy.load_rom_file("../../res/roms/paradius/cpu/07-jr,jp,call,ret,rst.gb"); // PASSED
     //game_boy.load_rom_file("../../res/roms/paradius/cpu/08-misc instrs.gb");  // PASSED
-    game_boy.load_rom_file("../../res/roms/paradius/cpu/09-op r,r.gb"); // NO FINISH
+    //game_boy.load_rom_file("../../res/roms/paradius/cpu/09-op r,r.gb"); // NO FINISH
     //game_boy.load_rom_file("../../res/roms/paradius/cpu/11-op a,(hl).gb"); // NO FINISH
 
     'main: loop {
diff --git a/src/cpu.rs b/src/cpu.rs
index ceed42e7a000b49bae2acf29fb157ae185ddf76f..794c1364b4eb85323e468c3de7c2041aef46a739 100644
--- a/src/cpu.rs
+++ b/src/cpu.rs
@@ -18,6 +18,7 @@ pub struct Cpu {
     pub e: u8,
     pub h: u8,
     pub l: u8,
+    ime: bool,
     zero: bool,
     sub: bool,
     half_carry: bool,
@@ -65,6 +66,7 @@ impl Cpu {
             e: 0x0,
             h: 0x0,
             l: 0x0,
+            ime: false,
             zero: false,
             sub: false,
             half_carry: false,
@@ -90,6 +92,19 @@ impl Cpu {
             panic!("Invalid PC area at 0x{:04x}", pc);
         }
 
+        if self.ime {
+            // @todo aggregate all of this interrupts in the MMU
+            if self.mmu.ppu().int_vblank() {
+                println!("VAI FAZER HANDLING VBLANK");
+                let pc = self.pc;
+                self.disable_int();
+                self.push_word(pc);
+                self.pc = 0x40;
+                self.mmu.ppu().ack_vblank();
+                return 16;
+            }
+        }
+
         // fetches the current instruction and increments
         // the PC (program counter) accordingly
         let mut opcode = self.mmu.read(self.pc);
@@ -313,11 +328,11 @@ impl Cpu {
 
     #[inline(always)]
     pub fn enable_int(&mut self) {
-        // @todo implement this one
+        self.ime = true;
     }
 
     #[inline(always)]
     pub fn disable_int(&mut self) {
-        // @todo implement this one
+        self.ime = false;
     }
 }
diff --git a/src/mmu.rs b/src/mmu.rs
index 2d9ace7f3ddcb2dad4deceb1a4297ac7b719ae3d..770a651b261de52a1a2fdd5f0e0a5040c76ab934 100644
--- a/src/mmu.rs
+++ b/src/mmu.rs
@@ -152,7 +152,17 @@ impl Mmu {
                                 _ => println!("Writing to unknown IO control 0x{:04x}", addr),
                             },
                             0x40 | 0x60 | 0x70 => {
-                                self.ppu.write(addr, value);
+                                match addr & 0x00ff {
+                                    0x0046 => {
+                                        // @todo must increment the cycle count by 160
+                                        // and make this a separated dma.rs file
+                                        println!("GOING TO START DMA transfer to 0x{:x}00", value);
+                                        let data = self.read_many((value as u16) << 8, 160);
+                                        self.write_many(0xfe00, &data);
+                                        println!("FINISHED DMA transfer")
+                                    }
+                                    _ => self.ppu.write(addr, value),
+                                }
                             }
                             0x50 => match addr & 0x00ff {
                                 0x50 => self.boot_active = false,
@@ -168,6 +178,23 @@ impl Mmu {
         }
     }
 
+    pub fn write_many(&mut self, addr: u16, data: &Vec<u8>) {
+        for index in 0..data.len() {
+            self.write(addr + index as u16, data[index])
+        }
+    }
+
+    pub fn read_many(&mut self, addr: u16, count: u16) -> Vec<u8> {
+        let mut data: Vec<u8> = vec![];
+
+        for index in 0..count {
+            let byte = self.read(addr + index);
+            data.push(byte);
+        }
+
+        return data;
+    }
+
     pub fn write_boot(&mut self, addr: u16, buffer: &[u8]) {
         self.boot[addr as usize..addr as usize + buffer.len()].clone_from_slice(buffer);
     }
diff --git a/src/ppu.rs b/src/ppu.rs
index d8110299bfd678fd5d094c1d42fb4831d2af8563..a42bd364ade444470de6f92f705e8851496a7839 100644
--- a/src/ppu.rs
+++ b/src/ppu.rs
@@ -84,6 +84,8 @@ pub struct Ppu {
     bg_tile: bool,
     // Controls if the window is meant to be drawn.
     switch_window: bool,
+    // Controls the offset of the map that is going to be drawn
+    // for the window section of the screen.
     window_map: bool,
     /// Flag that controls if the LCD screen is ON and displaying
     /// content.
@@ -92,6 +94,9 @@ pub struct Ppu {
     stat_vblank: bool,
     stat_oam: bool,
     stat_lyc: bool,
+    // Boolean value set when the V-Blank interrupt should be handled
+    // by the next CPU clock.
+    int_vblank: bool,
 }
 
 #[derive(Clone, Copy, PartialEq)]
@@ -130,6 +135,7 @@ impl Ppu {
             stat_vblank: false,
             stat_oam: false,
             stat_lyc: false,
+            int_vblank: false,
         }
     }
 
@@ -166,6 +172,7 @@ impl Ppu {
                     // in case we've reached the end of the
                     // screen we're now entering the v-blank
                     if self.ly == 144 {
+                        self.int_vblank = true;
                         self.mode = PpuMode::VBlank;
                         // self.drawData
                         // @todo implement this one
@@ -289,6 +296,33 @@ impl Ppu {
         }
     }
 
+    pub fn fill_frame_buffer(&mut self, color: Pixel) {
+        for index in (0..self.frame_buffer.len()).step_by(RGB_SIZE) {
+            self.frame_buffer[index] = color[0];
+            self.frame_buffer[index + 1] = color[1];
+            self.frame_buffer[index + 2] = color[2];
+        }
+    }
+
+    pub fn int_vblank(&self) -> bool {
+        self.int_vblank
+    }
+
+    pub fn ack_vblank(&mut self) {
+        self.int_vblank = false;
+    }
+
+    /// Prints the tile data information to the stdout, this is
+    /// useful for debugging purposes.
+    pub fn draw_tile_stdout(&self, tile_index: usize) {
+        for y in 0..8 {
+            for x in 0..8 {
+                print!("{}", self.tiles[tile_index][y as usize][x as usize]);
+            }
+            print!("\n");
+        }
+    }
+
     /// Updates the tile structure with the value that has
     /// just been written to a location on the VRAM associated
     /// with tiles.
@@ -378,25 +412,6 @@ impl Ppu {
         }
     }
 
-    pub fn fill_frame_buffer(&mut self, color: Pixel) {
-        for index in (0..self.frame_buffer.len()).step_by(RGB_SIZE) {
-            self.frame_buffer[index] = color[0];
-            self.frame_buffer[index + 1] = color[1];
-            self.frame_buffer[index + 2] = color[2];
-        }
-    }
-
-    /// Prints the tile data information to the stdout, this is
-    /// useful for debugging purposes.
-    pub fn draw_tile_stdout(&self, tile_index: usize) {
-        for y in 0..8 {
-            for x in 0..8 {
-                print!("{}", self.tiles[tile_index][y as usize][x as usize]);
-            }
-            print!("\n");
-        }
-    }
-
     /// Obtains the current level of the LCD interrupt by
     /// checking the current PPU state in various sections.
     fn interrupt_level(&self) -> bool {