diff --git a/src/cpu.rs b/src/cpu.rs
index 39bb3c0166ab8b16101557d52d8c592ed92a52a4..983f7109f6ffd94226c9d93311b16b729ce468f0 100644
--- a/src/cpu.rs
+++ b/src/cpu.rs
@@ -136,10 +136,12 @@ impl Cpu {
             self.halted = false;
         }
 
+        // checks the IME (interrupt master flag) is enabled and then checks
+        // if there's any interrupt to be handled, in case there's one, tries
+        // to check which one should be handled and then handles it
+        // this code assumes that the're no more that one interrupt triggered
+        // per clock cycle, this is a limitation of the current implementation
         if self.ime && self.mmu.ie != 0x00 {
-            // @TODO aggregate all of this interrupts in the MMU, as there's
-            // a lot of redundant code involved in here which complicates the
-            // readability and maybe performance of this code
             if (self.mmu.ie & 0x01 == 0x01) && self.mmu.ppu().int_vblank() {
                 debugln!("Going to run V-Blank interrupt handler (0x40)");
 
@@ -158,9 +160,7 @@ impl Cpu {
                 }
 
                 return 24;
-            }
-            // @TODO aggregate the handling of these interrupts
-            else if (self.mmu.ie & 0x02 == 0x02) && self.mmu.ppu().int_stat() {
+            } else if (self.mmu.ie & 0x02 == 0x02) && self.mmu.ppu().int_stat() {
                 debugln!("Going to run LCD STAT interrupt handler (0x48)");
 
                 self.disable_int();
@@ -178,9 +178,7 @@ impl Cpu {
                 }
 
                 return 24;
-            }
-            // @TODO aggregate the handling of these interrupts
-            else if (self.mmu.ie & 0x04 == 0x04) && self.mmu.timer().int_tima() {
+            } else if (self.mmu.ie & 0x04 == 0x04) && self.mmu.timer().int_tima() {
                 debugln!("Going to run Timer interrupt handler (0x50)");
 
                 self.disable_int();
@@ -198,9 +196,7 @@ impl Cpu {
                 }
 
                 return 24;
-            }
-            // @TODO aggregate the handling of these interrupts
-            else if (self.mmu.ie & 0x08 == 0x08) && self.mmu.serial().int_serial() {
+            } else if (self.mmu.ie & 0x08 == 0x08) && self.mmu.serial().int_serial() {
                 debugln!("Going to run Serial interrupt handler (0x58)");
 
                 self.disable_int();
@@ -218,9 +214,7 @@ impl Cpu {
                 }
 
                 return 24;
-            }
-            // @TODO aggregate the handling of these interrupts
-            else if (self.mmu.ie & 0x10 == 0x10) && self.mmu.pad().int_pad() {
+            } else if (self.mmu.ie & 0x10 == 0x10) && self.mmu.pad().int_pad() {
                 debugln!("Going to run JoyPad interrupt handler (0x60)");
 
                 self.disable_int();
diff --git a/src/dma.rs b/src/dma.rs
index df29926ba940ac3e55da3cc75e816d74cc90e063..f477b8607e2d4d8b631138a8acf8670a810adafa 100644
--- a/src/dma.rs
+++ b/src/dma.rs
@@ -1,5 +1,6 @@
 use crate::warnln;
 
+#[derive(Clone, Copy, PartialEq, Eq)]
 pub enum DmaMode {
     General = 0x00,
     HBlank = 0x01,
@@ -8,7 +9,7 @@ pub enum DmaMode {
 pub struct Dma {
     source: u16,
     destination: u16,
-    length: u8,
+    length: u16,
     mode: DmaMode,
     active: bool,
 }
@@ -37,7 +38,7 @@ impl Dma {
     pub fn read(&mut self, addr: u16) -> u8 {
         match addr {
             // 0xFF55 — HDMA5: VRAM DMA length/mode/start (CGB only)
-            0xff45 => self.length | ((self.active as u8) << 7),
+            0xff45 => ((self.length >> 4) - 1) as u8 | ((self.active as u8) << 7),
             _ => {
                 warnln!("Reading from unknown DMA location 0x{:04x}", addr);
                 0xff
@@ -48,29 +49,66 @@ impl Dma {
     pub fn write(&mut self, addr: u16, value: u8) {
         match addr {
             // 0xFF51 — HDMA1: VRAM DMA source high (CGB only)
-            0xff41 => self.source = (self.source & 0x00ff) | ((value as u16) << 8),
+            0xff51 => self.source = (self.source & 0x00ff) | ((value as u16) << 8),
             // 0xFF52 — HDMA2: VRAM DMA source low (CGB only)
-            0xff42 => self.source = (self.source & 0xff00) | (value as u16),
+            0xff52 => self.source = (self.source & 0xff00) | ((value & 0xf0) as u16),
             // 0xFF53 — HDMA3: VRAM DMA destination high (CGB only)
-            0xff43 => self.destination = (self.destination & 0x00ff) | ((value as u16) << 8),
+            0xff53 => self.destination = (self.destination & 0x00ff) | ((value as u16) << 8),
             // 0xFF54 — HDMA4: VRAM DMA destination low (CGB only)
-            0xff44 => self.destination = (self.destination & 0xff00) | (value as u16),
+            0xff54 => self.destination = (self.destination & 0xff00) | ((value & 0xf0) as u16),
             // 0xFF55 — HDMA5: VRAM DMA length/mode/start (CGB only)
-            0xff45 => {
-                self.length = value & 0x7f;
+            0xff55 => {
+                self.length = (((value & 0x7f) + 0x1) as u16) << 4;
                 self.mode = match (value & 80) >> 7 {
                     0 => DmaMode::General,
                     1 => DmaMode::HBlank,
                     _ => DmaMode::General,
                 };
-
-                // @TODO: Implement DMA transfer in a better way
-                //let data = self.mmu.read_many(self.source, self.length as usize);
-                //self.mmu.write_many(self.destination, &data);
+                self.active = true;
             }
             _ => warnln!("Writing to unknown DMA location 0x{:04x}", addr),
         }
     }
+
+    pub fn source(&self) -> u16 {
+        self.source
+    }
+
+    pub fn set_source(&mut self, value: u16) {
+        self.source = value;
+    }
+
+    pub fn destination(&self) -> u16 {
+        self.destination
+    }
+
+    pub fn set_destination(&mut self, value: u16) {
+        self.destination = value;
+    }
+
+    pub fn length(&self) -> u16 {
+        self.length
+    }
+
+    pub fn set_length(&mut self, value: u16) {
+        self.length = value;
+    }
+
+    pub fn mode(&self) -> DmaMode {
+        self.mode
+    }
+
+    pub fn set_mode(&mut self, value: DmaMode) {
+        self.mode = value;
+    }
+
+    pub fn active(&self) -> bool {
+        self.active
+    }
+
+    pub fn set_active(&mut self, value: bool) {
+        self.active = value;
+    }
 }
 
 impl Default for Dma {
diff --git a/src/gb.rs b/src/gb.rs
index 6621d361378c93c9dcd43a13c57a93ea3acf58c5..7339d0e489fa7b57bb5bda8170e783362bd9c556 100644
--- a/src/gb.rs
+++ b/src/gb.rs
@@ -424,7 +424,7 @@ impl GameBoy {
     }
 
     pub fn dma_clock(&mut self, cycles: u8) {
-        self.dma().clock(cycles)
+        self.mmu().clock_dma(cycles);
     }
 
     pub fn timer_clock(&mut self, cycles: u8) {
diff --git a/src/mmu.rs b/src/mmu.rs
index 2b08fb74fc95e4f42d39852a5e864d0f91c64618..2d966791a5bc50418c0a91f2bcee7ac206877b6e 100644
--- a/src/mmu.rs
+++ b/src/mmu.rs
@@ -205,6 +205,17 @@ impl Mmu {
         self.boot_active = value;
     }
 
+    pub fn clock_dma(&mut self, _cycles: u8) {
+        if !self.dma.active() {
+            return;
+        }
+
+        // @TODO: Implement DMA transfer in a better way
+        let data = self.read_many(self.dma.source(), self.dma.length());
+        self.write_many(self.dma.destination(), &data);
+        self.dma.set_active(false);
+    }
+
     pub fn read(&mut self, addr: u16) -> u8 {
         match addr & 0xf000 {
             // BOOT (256 B) + ROM0 (4 KB/16 KB)
@@ -299,7 +310,14 @@ impl Mmu {
                             }
                         },
                         0x10..=0x26 | 0x30..=0x37 => self.apu.read(addr),
-                        0x40 | 0x50 | 0x60 | 0x70 => self.ppu.read(addr),
+                        0x40 | 0x60 | 0x70 => self.ppu.read(addr),
+                        0x50 => match addr & 0x00ff {
+                            0x51..=0x55 => self.dma.read(addr),
+                            _ => {
+                                debugln!("Reading from unknown IO control 0x{:04x}", addr);
+                                0x00
+                            }
+                        },
                         _ => {
                             debugln!("Reading from unknown IO control 0x{:04x}", addr);
                             0x00
@@ -422,12 +440,7 @@ impl Mmu {
                                 }
                             }
                             0x50 => match addr & 0x00ff {
-                                // 0xFF51-0xFF52 - VRAM DMA source (CGB only)
-                                0x51..=0x52 => (),
-
-                                // 0xFF53-0xFF54 - VRAM DMA destination (CGB only)
-                                0x53..=0x54 => (),
-
+                                0x51..=0x55 => self.dma.write(addr, value),
                                 _ => debugln!("Writing to unknown IO control 0x{:04x}", addr),
                             },
                             _ => debugln!("Writing to unknown IO control 0x{:04x}", addr),