   pinMode(snesResetPin, OUTPUT);
 
   //read the rom header
-  readHeader();
+  //readHeader();
 
   //Write byte to indicate device ready
   Serial.write(0x00); 
 }
 
 void loop() {
-  done = true;
-  if (Serial.available() > 0) {
-    int incomingByte = Serial.read();
-    switch(incomingByte) {
-      case HEADRead:
-      {
-        Serial.write(getHeader(), 64);
-        Serial.flush();
-      } 
-      break;
-      
-      case ROMRead:
-      {
-        //Read the header
-        readHeader();
+  int incomingByte = serialReadBlocking();
+  switch(incomingByte) {
+    // set the cartridge control lines
+    case CTRL:
+    {
+      setCtrlLines(serialReadBlocking());
+    }
+    break;
+    
+    // read a section of data from the cart
+    case READSECTION:
+    {
+      byte bank = serialReadBlocking();
+      byte startAddrHi = serialReadBlocking();
+      byte startAddrLow = serialReadBlocking();
+      byte endAddrHi = serialReadBlocking();
+      byte endAddrLow = serialReadBlocking();
 
-        //Write the rom size
-        Serial.write(romSizeCode);
+      unsigned int addr = bytesToInt(startAddrHi, startAddrLow);
+      unsigned int endAddr = bytesToInt(endAddrHi, endAddrLow);
+      setDataBusDir(INPUT);
 
-        //prepare to dump the cart
-        digitalWrite(snesReadPin, LOW);
-        digitalWrite(snesCartPin, LOW);
-        digitalWrite(snesResetPin, HIGH);
-        digitalWrite(snesWritePin, HIGH);
-        setDataBusDirection(INPUT);
+      while (true) {
+        writeAddrBus(bank, addr);
+        Serial.write(readDataBus());
 
-        //dump the cart
-        byte banks = romSize / (bankSize - readOffset);
-        dumpCart(banks);
+        /* We must break out of the loop this way because of the potential case
+         * where addresses 0x0000 - 0xffff (inclusive) must be used. A standard 
+         * loop won't work because it will overflow the 16 bit unsigned int.
+         */
+        if (addr == endAddr) {
+          break;
+        }
+        addr++;
+      }
+      Serial.flush();
+    }
+    break;
+    
+    case WRITESECTION:
+    {
+      byte bank = serialReadBlocking();
+      byte startAddrHi = serialReadBlocking();
+      byte startAddrLow = serialReadBlocking();
+      byte endAddrHi = serialReadBlocking();
+      byte endAddrLow = serialReadBlocking();
 
-        Serial.flush();
+      unsigned int addr = bytesToInt(startAddrHi, startAddrLow);
+      unsigned int endAddr = bytesToInt(endAddrHi, endAddrLow);
+      setDataBusDir(OUTPUT);
+  
+      while (true) {
+        writeAddrBus(bank, addr);
+        writeDataBus(serialReadBlocking());
+
+        /* We must break out of the loop this way because of the potential case
+         * where addresses 0x0000 - 0xffff (inclusive) must be used. A standard 
+         * loop won't work because it will overflow the 16 bit unsigned int.
+         */
+        if (addr == endAddr) {
+          break;
+        }
+        addr++;
       }
-      break;
-      
-      case RAMRead:
-      {
-        //Read the header
-        readHeader();
-
-        //Write the ram size code
-        Serial.write(ramSizeCode);
-
-        //prepare to dump the save data
-        digitalWrite(snesReadPin, LOW);
-        digitalWrite(snesCartPin, (romLayout == HiROM ? HIGH : LOW));
-        digitalWrite(snesResetPin, HIGH);
-        digitalWrite(snesWritePin, HIGH);
-        setDataBusDirection(INPUT);
-
-        //dump the data
-        for (long a = readOffset; a < (readOffset + ramSize); a++) {
-          byte bank = 0x00;
-          int addr = a;
-          
-          //LoROM
-          if (romLayout == LoROM) {
-            bitWrite(bank, 4, 1);
-            bitWrite(bank, 6, 1);
-          } else if (romLayout == HiROM) {
-          //HiROM
-            bitWrite(addr, 13, 1);
-            bitWrite(addr, 14, 1);
-            bitWrite(addr, 15, 0);
-            bitWrite(bank, 6, 0);
-          }
-          //Both
-          bitWrite(bank, 5, 1);
-          
-          address(bank, addr);
-          Serial.write(cartRead());
-        }
-        Serial.flush();
-      }
-      break;
-        
-      case RAMWrite:
-      {
-        //read cart header
-        readHeader();
-        //write ram size code
-        Serial.write(ramSizeCode);
-        //prepare to write save data
-        digitalWrite(snesReadPin, HIGH);
-        digitalWrite(snesCartPin, (romLayout == HiROM ? HIGH : LOW));
-        digitalWrite(snesResetPin, HIGH);
-        digitalWrite(snesWritePin, LOW);
-        setDataBusDirection(OUTPUT);
-
-        //write save data
-        int received = 0;
-        while (received < ramSize) {
-          while (Serial.available()) {
-            byte incomingByte = Serial.read();
-            byte bank = 0x00;
-            unsigned int addr = 0x00;
-            
-            //LoROM
-            if (romLayout == LoROM) {
-              bitWrite(bank, 4, 1);
-              bitWrite(bank, 6, 1);
-            } else if (romLayout == HiROM) {
-            //HiROM
-              bitWrite(addr, 13, 1);
-              bitWrite(addr, 14, 1);
-              bitWrite(addr, 15, 0);
-              bitWrite(bank, 6, 0);
-            }
-            //Both
-            bitWrite(bank, 5, 1);
-            
-            address(bank, addr + received);
-            cartWrite(incomingByte);
-            received++;
-          }
-        }
-      }
-      break;
-
-      case CHUNKRead:
-      {
-        byte bank = serialReadBlocking();
-        byte addr_upper = serialReadBlocking();
-        byte addr_lower = serialReadBlocking();
-
-        if (bank == 0 && addr_upper == 0xFF && addr_lower == 0xC0) {
-          digitalWrite(13, HIGH);
-          delay(1000);
-          digitalWrite(13, LOW);
-          delay(1000);
-          digitalWrite(13, HIGH);
-          delay(1000);
-          digitalWrite(13, LOW);
-        }
-
-        Serial.write(bank);
-        Serial.write(addr_upper);
-        Serial.write(addr_lower);
-
-        //Read the header
-        readHeader();
-
-        digitalWrite(snesReadPin, LOW);
-        digitalWrite(snesCartPin, LOW);
-        digitalWrite(snesResetPin, HIGH);
-        digitalWrite(snesWritePin, HIGH);
-        setDataBusDirection(INPUT);
-        
-
-        unsigned int maddress = 0;
-        maddress |= addr_upper << 8;
-        maddress |= addr_lower;
-
-        byte bread = 0;
-        while (bread < 64) {
-          address(bank, maddress + bread);
-
-          byte bus_data = (PIND & ~0x03) | (PINB & 0x03);
-          Serial.write(bus_data);
-          
-          bread++;
-        }
-          
-        //Serial.flush();
-      }
-      break;
     }
+    break;
   }
-  digitalWrite(snesResetPin, LOW);
-}
-
-void dumpCart(byte banks) {
-  //dump the cart
-  for (byte b = 0; b < banks; b++) {
-    unsigned int a = readOffset;
-    while(true) {
-      address(b, a);
-      
-      // wait for USART to become ready & write byte from data bus
-      while ( !( UCSR0A & (1<<UDRE0)) );
-      UDR0 = (PIND & ~0x03) | (PINB & 0x03);
-
-      if (a == 0xFFFF) {
-        break;
-      }
-      a++;
-    }
-  }
-}
-
-void address(byte b, unsigned int a) {
-  //Set AddressLatchPin (Digital pin 10) low
-  //Digital pin 10 is bit 2 of PORTB
-  PORTB &= ~(B100);
-  
-  //shift out bank address
-  SPDR = b;
-  while(!(SPSR & (1<<SPIF)));
-  
-  //shift out upper address
-  SPDR = a >> 8;
-  while(!(SPSR & (1<<SPIF)));
-  
-  //shift out lower address
-  SPDR = a;
-  while(!(SPSR & (1<<SPIF)));
-  
-  //Set AddressLatchPin (Digital pin 10) high
-  //Digital pin 10 is bit 2 of PORTB
-  PORTB |= (B100);
-
-
-  //Wait 4 cycles for things to settle
-  //One cycle of 16MHz AVR = 62.5ns.
-  //SNES SlowRom access time is 200ns (4 cycles = 250ns).  
-  asm volatile (
-    "nop" "\n\t"
-    "nop" "\n\t"
-    "nop" "\n\t"
-    "nop" "\n\t"
-  );
 }
 
 byte serialReadBlocking() {

  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV2); //8MHz
  
  setDataBusDirection(INPUT);

  //setup cart control pins
  pinMode(snesCartPin, OUTPUT);

const int AddressLatchPin = 10;

const int snesCartPin = A4; //Cart pin 49 - aka /CS, /ROMSEL, /Cart - Goes low when reading ROM
const int snesReadPin = A3; //Cart pin 23 - aka /RD - Address bus read
const int snesWritePin = A2; //Cart pin 54 - aka /WR - Address bus write
const int snesResetPin = A1; //Cart pin 26 - SNES reset pin. Goes high when reading cart

typedef enum COMMANDS {
  CTRL,
  READSECTION,
  WRITESECTION
};

void setup() {
  //begin serial
