diff --git a/CHANGELOG.md b/CHANGELOG.md
index d769a34fbf61d2a1015db9e1cdb6c54d2d09d1ee..3f2b41f641926786a69f6c0b73accda78945171d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added
 
-*
+* Support for sprite drawing, works wit Tetris
 
 ### Changed
 
diff --git a/examples/sdl/src/main.rs b/examples/sdl/src/main.rs
index d9abec788d2d4e14225208178ad5096d85d259a7..2c916122b4e30b75f89b4b75335f7aae23769f08 100644
--- a/examples/sdl/src/main.rs
+++ b/examples/sdl/src/main.rs
@@ -118,12 +118,18 @@ fn main() {
                 Event::KeyDown {
                     keycode: Some(keycode),
                     ..
-                } => game_boy.key_press(key_to_pad(keycode)),
+                } => match key_to_pad(keycode) {
+                    Some(key) => game_boy.key_press(key),
+                    None => (),
+                },
 
                 Event::KeyUp {
                     keycode: Some(keycode),
                     ..
-                } => game_boy.key_lift(key_to_pad(keycode)),
+                } => match key_to_pad(keycode) {
+                    Some(key) => game_boy.key_lift(key),
+                    None => (),
+                },
 
                 _ => (),
             }
@@ -160,17 +166,17 @@ fn main() {
     }
 }
 
-fn key_to_pad(keycode: Keycode) -> PadKey {
+fn key_to_pad(keycode: Keycode) -> Option<PadKey> {
     match keycode {
-        Keycode::Up => PadKey::Up,
-        Keycode::Down => PadKey::Down,
-        Keycode::Left => PadKey::Left,
-        Keycode::Right => PadKey::Right,
-        Keycode::Return => PadKey::Start,
-        Keycode::Return2 => PadKey::Start,
-        Keycode::Space => PadKey::Select,
-        Keycode::A => PadKey::A,
-        Keycode::S => PadKey::B,
-        _ => PadKey::A, //@todo this does not make sence, make it an Option
+        Keycode::Up => Some(PadKey::Up),
+        Keycode::Down => Some(PadKey::Down),
+        Keycode::Left => Some(PadKey::Left),
+        Keycode::Right => Some(PadKey::Right),
+        Keycode::Return => Some(PadKey::Start),
+        Keycode::Return2 => Some(PadKey::Start),
+        Keycode::Space => Some(PadKey::Select),
+        Keycode::A => Some(PadKey::A),
+        Keycode::S => Some(PadKey::B),
+        _ => None,
     }
 }
diff --git a/src/inst.rs b/src/inst.rs
index 4062d8d28e858d9d56e9b8e9760af52b9e4e8bca..5f4df2cfac9733508ed2485da8f8e29ed32bdff3 100644
--- a/src/inst.rs
+++ b/src/inst.rs
@@ -555,12 +555,6 @@ pub const EXTENDED: [(fn(&mut Cpu), u8, &'static str); 256] = [
 
 fn nop(_cpu: &mut Cpu) {}
 
-fn noimpl(_cpu: &mut Cpu) {
-    let ten_millis = time::Duration::from_millis(10000);
-    thread::sleep(ten_millis); // @todo remove this hack
-    todo!("Instruction not implemented");
-}
-
 fn illegal(_cpu: &mut Cpu) {
     panic!("Illegal instruction");
 }
diff --git a/src/mmu.rs b/src/mmu.rs
index 342928043ac038f4a0fd4fa8a591c4be487da70d..a64f6a6aca548f381c13b93907e3d366ab6ed516 100644
--- a/src/mmu.rs
+++ b/src/mmu.rs
@@ -155,7 +155,10 @@ impl Mmu {
                 | 0xa00 | 0xb00 | 0xc00 | 0xd00 => {
                     self.ram[(addr & 0x1fff) as usize] = value;
                 }
-                0xe00 => self.ppu.oam[(addr & 0x009f) as usize] = value,
+                0xe00 => {
+                    self.ppu.oam[(addr & 0x009f) as usize] = value;
+                    self.ppu.update_object(addr, value);
+                }
                 0xf00 => {
                     if addr == 0xffff {
                         self.ie = value;
@@ -172,10 +175,9 @@ impl Mmu {
                                     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);
+                                        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),
                                 }
diff --git a/src/ppu.rs b/src/ppu.rs
index cfa871f70d0a030386cfb93dddff8180c12e6257..6cb2b802f9487f591eea7ee7747c0d94afd69bfa 100644
--- a/src/ppu.rs
+++ b/src/ppu.rs
@@ -12,22 +12,33 @@ pub const HRAM_SIZE: usize = 128;
 pub const OAM_SIZE: usize = 260;
 pub const PALETTE_SIZE: usize = 4;
 pub const RGB_SIZE: usize = 3;
+pub const TILE_WIDTH: usize = 8;
+pub const TILE_HEIGHT: usize = 8;
 
 /// The number of tiles that can be store in Game Boy's
 /// VRAM memory according to specifications.
 pub const TILE_COUNT: usize = 384;
 
+/// The number of objects/sprites that can be handled at
+/// the same time by the Game Boy.
+pub const OBJ_COUNT: usize = 40;
+
 /// The width of the Game Boy screen in pixels.
 pub const DISPLAY_WIDTH: usize = 160;
 
 /// The height of the Game Boy screen in pixels.
 pub const DISPLAY_HEIGHT: usize = 144;
 
-// The size of the RGB frame buffer in bytes.
+/// The size to be used by the buffer of colors
+/// for the Game Boy screen the values there should
+/// range from 0 to 3.
+pub const COLOR_BUFFER_SIZE: usize = DISPLAY_WIDTH * DISPLAY_HEIGHT;
+
+/// The size of the RGB frame buffer in bytes.
 pub const FRAME_BUFFER_SIZE: usize = DISPLAY_WIDTH * DISPLAY_HEIGHT * RGB_SIZE;
 
-// Defines the Game Boy pixel type as a buffer
-// with the size of RGB (3 bytes).
+/// Defines the Game Boy pixel type as a buffer
+/// with the size of RGB (3 bytes).
 pub type Pixel = [u8; RGB_SIZE];
 
 /// Defines a type that represents a color palette
@@ -45,11 +56,11 @@ pub struct Tile {
 #[cfg_attr(feature = "wasm", wasm_bindgen)]
 impl Tile {
     pub fn get(&self, x: usize, y: usize) -> u8 {
-        self.buffer[y * 8 + x]
+        self.buffer[y * TILE_WIDTH + x]
     }
 
     pub fn set(&mut self, x: usize, y: usize, value: u8) {
-        self.buffer[y * 8 + x] = value;
+        self.buffer[y * TILE_WIDTH + x] = value;
     }
 
     pub fn buffer(&self) -> Vec<u8> {
@@ -57,6 +68,12 @@ impl Tile {
     }
 }
 
+impl Tile {
+    pub fn get_row(&self, y: usize) -> &[u8] {
+        &self.buffer[y * TILE_WIDTH..(y + 1) * TILE_WIDTH]
+    }
+}
+
 impl Tile {
     pub fn palette_buffer(&self, palette: Palette) -> Vec<u8> {
         self.buffer
@@ -79,6 +96,29 @@ impl Display for Tile {
     }
 }
 
+#[cfg_attr(feature = "wasm", wasm_bindgen)]
+#[derive(Clone, Copy, PartialEq)]
+pub struct ObjectData {
+    x: i16,
+    y: i16,
+    tile: u8,
+    palette: u8,
+    xflip: bool,
+    yflip: bool,
+    priority: bool,
+    index: u8,
+}
+
+impl Display for ObjectData {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "Index => {} X => {} Y => {} Tile => {}",
+            self.index, self.x, self.y, self.tile
+        )
+    }
+}
+
 /// Represents the Game Boy PPU (Pixel Processing Unit) and controls
 /// all of the logic behind the graphics processing and presentation.
 /// Should store both the VRAM and HRAM together with the internal
@@ -91,6 +131,10 @@ impl Display for Tile {
 /// ppu.clock();
 /// ```
 pub struct Ppu {
+    /// The color buffer that is going to store the colors
+    /// (from 0 to 3) for all the pixels in the screen.
+    pub color_buffer: Box<[u8; COLOR_BUFFER_SIZE]>,
+
     /// The 8 bit based RGB frame buffer with the
     /// processed set of pixels ready to be displayed on screen.
     pub frame_buffer: Box<[u8; FRAME_BUFFER_SIZE]>,
@@ -111,6 +155,10 @@ pub struct Ppu {
     /// PPU related structures.
     tiles: [Tile; TILE_COUNT],
 
+    /// The meta information about the sprites/objects that are going
+    /// to be drawn to the screen,
+    obj_data: [ObjectData; OBJ_COUNT],
+
     /// The palette of colors that is currently loaded in Game Boy
     /// and used for background (tiles).
     palette: Palette,
@@ -196,11 +244,22 @@ pub enum PpuMode {
 impl Ppu {
     pub fn new() -> Self {
         Self {
-            frame_buffer: Box::new([0u8; DISPLAY_WIDTH * DISPLAY_HEIGHT * RGB_SIZE]),
+            color_buffer: Box::new([0u8; COLOR_BUFFER_SIZE]),
+            frame_buffer: Box::new([0u8; FRAME_BUFFER_SIZE]),
             vram: [0u8; VRAM_SIZE],
             hram: [0u8; HRAM_SIZE],
             oam: [0u8; OAM_SIZE],
             tiles: [Tile { buffer: [0u8; 64] }; TILE_COUNT],
+            obj_data: [ObjectData {
+                x: 0,
+                y: 0,
+                tile: 0,
+                palette: 0,
+                xflip: false,
+                yflip: false,
+                priority: false,
+                index: 0,
+            }; OBJ_COUNT],
             palette: [[0u8; RGB_SIZE]; PALETTE_SIZE],
             palette_obj_0: [[0u8; RGB_SIZE]; PALETTE_SIZE],
             palette_obj_1: [[0u8; RGB_SIZE]; PALETTE_SIZE],
@@ -227,7 +286,8 @@ impl Ppu {
     }
 
     pub fn reset(&mut self) {
-        self.frame_buffer = Box::new([0u8; DISPLAY_WIDTH * DISPLAY_HEIGHT * RGB_SIZE]);
+        self.color_buffer = Box::new([0u8; COLOR_BUFFER_SIZE]);
+        self.frame_buffer = Box::new([0u8; FRAME_BUFFER_SIZE]);
         self.vram = [0u8; VRAM_SIZE];
         self.hram = [0u8; HRAM_SIZE];
         self.tiles = [Tile { buffer: [0u8; 64] }; TILE_COUNT];
@@ -273,9 +333,7 @@ impl Ppu {
             }
             PpuMode::VramRead => {
                 if self.mode_clock >= 172 {
-                    if self.switch_bg {
-                        self.render_line();
-                    }
+                    self.render_line();
 
                     self.mode_clock = 0;
                     self.mode = PpuMode::HBlank;
@@ -283,6 +341,8 @@ impl Ppu {
             }
             PpuMode::HBlank => {
                 if self.mode_clock >= 204 {
+                    // increments the register that holds the
+                    // information about the current line in drawign
                     self.ly += 1;
 
                     // in case we've reached the end of the
@@ -446,6 +506,7 @@ impl Ppu {
     /// this method must represent the fastest way of achieving
     /// the fill background with color operation.
     pub fn fill_frame_buffer(&mut self, color: Pixel) {
+        self.color_buffer.fill(0);
         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];
@@ -476,7 +537,7 @@ impl Ppu {
 
         let mut mask;
 
-        for x in 0..8 {
+        for x in 0..TILE_WIDTH {
             mask = 1 << (7 - x);
             tile.set(
                 x,
@@ -491,7 +552,38 @@ impl Ppu {
         }
     }
 
+    pub fn update_object(&mut self, addr: u16, value: u8) {
+        let addr = (addr & 0x01ff) as usize;
+        let obj_index = addr >> 2;
+        if obj_index >= OBJ_COUNT {
+            return;
+        }
+        let mut obj = self.obj_data[obj_index].borrow_mut();
+        match addr & 0x03 {
+            0x00 => obj.y = value as i16 - 16,
+            0x01 => obj.x = value as i16 - 8,
+            0x02 => obj.tile = value,
+            0x03 => {
+                obj.palette = if value & 0x10 == 0x10 { 1 } else { 0 };
+                obj.xflip = if value & 0x20 == 0x20 { true } else { false };
+                obj.yflip = if value & 0x40 == 0x40 { true } else { false };
+                obj.priority = if value & 0x80 == 0x80 { false } else { true };
+                obj.index = obj_index as u8;
+            }
+            _ => (),
+        }
+    }
+
     fn render_line(&mut self) {
+        if self.switch_bg {
+            self.render_background();
+        }
+        if self.switch_obj {
+            self.render_objects();
+        }
+    }
+
+    fn render_background(&mut self) {
         // obtains the base address of the background map using the bg map flag
         // that control which background map is going to be used
         let mut map_offset: usize = if self.bg_map { 0x1c00 } else { 0x1800 };
@@ -516,6 +608,10 @@ impl Ppu {
             tile_index += 256;
         }
 
+        // calculates the offset that is going to be used in the update of the color buffer
+        // which stores Game Boy colors from 0 to 3
+        let mut color_offset = self.ly as usize * DISPLAY_WIDTH;
+
         // calculates the frame buffer offset position assuming the proper
         // Game Boy screen width and RGB pixel (3 bytes) size
         let mut frame_offset = self.ly as usize * DISPLAY_WIDTH * RGB_SIZE;
@@ -526,11 +622,17 @@ impl Ppu {
             let pixel = self.tiles[tile_index].get(x, y);
             let color = self.palette[pixel as usize];
 
+            // updates the pixel in the color buffer
+            self.color_buffer[color_offset] = pixel;
+
             // set the color pixel in the frame buffer
             self.frame_buffer[frame_offset] = color[0];
             self.frame_buffer[frame_offset + 1] = color[1];
             self.frame_buffer[frame_offset + 2] = color[2];
 
+            // increments the color offset by one
+            color_offset += 1;
+
             // increments the offset of the frame buffer by the
             // size of an RGB pixel (which is 3 bytes)
             frame_offset += RGB_SIZE;
@@ -540,7 +642,7 @@ impl Ppu {
 
             // in case the end of tile width has been reached then
             // a new tile must be retrieved for plotting
-            if x == 8 {
+            if x == TILE_WIDTH {
                 // resets the tile X position to the base value
                 // as a new tile is going to be drawn
                 x = 0;
@@ -559,6 +661,74 @@ impl Ppu {
         }
     }
 
+    fn render_objects(&mut self) {
+        for index in 0..OBJ_COUNT {
+            // obtains the meta data of the object that is currently
+            // under iteration to be checked for drawing
+            let obj = self.obj_data[index];
+
+            // verifies if the sprite is currently located at the
+            // current line that is going to be drawn and skips it
+            // in case it's not
+            let is_contained =
+                (obj.y <= self.ly as i16) && ((obj.y + TILE_HEIGHT as i16) > self.ly as i16);
+            if !is_contained {
+                continue;
+            }
+
+            let palette = if obj.palette == 0 {
+                self.palette_obj_0
+            } else {
+                self.palette_obj_1
+            };
+
+            let mut color_offset = self.ly as usize * DISPLAY_WIDTH + obj.x as usize;
+
+            // calculates the offset in the frame buffer for the sprite
+            // that is going to be drawn, this is going to be the starting
+            // point for the draw operation to be performed
+            let mut frame_offset = (self.ly as usize * DISPLAY_WIDTH + obj.x as usize) * RGB_SIZE;
+
+            let tile_offset = self.ly as i16 - obj.y;
+
+            let tile_row: &[u8];
+            if obj.yflip {
+                tile_row = self.tiles[obj.tile as usize].get_row((7 - tile_offset) as usize);
+            } else {
+                tile_row = self.tiles[obj.tile as usize].get_row((tile_offset) as usize);
+            }
+
+            for x in 0..TILE_WIDTH {
+                let is_contained =
+                    (obj.x + x as i16 >= 0) && ((obj.x + x as i16) < DISPLAY_WIDTH as i16);
+                if is_contained {
+                    // the object is only considered visible if it's a priority
+                    // or if the underlying pixel is transparent (zero value)
+                    let is_visible = obj.priority || self.color_buffer[color_offset] == 0;
+                    if is_visible {
+                        // obtains the current pixel data from the tile row and
+                        // re-maps it according to the object palette
+                        let pixel = tile_row[if obj.xflip { 7 - x } else { x }];
+                        let color = palette[pixel as usize];
+
+                        // set the color pixel in the frame buffer
+                        self.frame_buffer[frame_offset] = color[0];
+                        self.frame_buffer[frame_offset + 1] = color[1];
+                        self.frame_buffer[frame_offset + 2] = color[2];
+                    }
+                }
+
+                // increment the color offset by one as this represents
+                // the advance of one color pixel
+                color_offset += 1;
+
+                // increments the offset of the frame buffer by the
+                // size of an RGB pixel (which is 3 bytes)
+                frame_offset += RGB_SIZE;
+            }
+        }
+    }
+
     /// Obtains the current level of the LCD interrupt by
     /// checking the current PPU state in various sections.
     fn interrupt_level(&self) -> bool {