diff --git a/mmc.c b/mmc.c
index 27d05c0..4d32b1e 100644
--- a/mmc.c
+++ b/mmc.c
@@ -34,6 +34,10 @@
 #define ERASE_SEQ_ERROR_MASK 0x10
 #define PARAMETER_ERROR_MASK 0x40
 
+#define TOKEN_START_BLOCK        0xFE /* 11111110 */
+#define TOKEN_START_MBWR_BLOCK   0xFC /* 11111100 */
+#define TOKEN_STOP_TRAN          0xFD /* 11111101 */
+
 /* The states while a command is being sent to the card */
 enum command_state_t {
   WAITING_FOR_COMMAND,
@@ -54,13 +58,18 @@ enum command_byte {
   SEND_IF_COND = 8,
   SEND_CSD = 9,
   SEND_CID = 10,
+  STOP_TRANSMISSION = 12,
+  SET_BLOCKLEN = 16,
   READ_SINGLE_BLOCK = 17,
+  READ_MULTIPLE_BLOCK = 18,
   WRITE_BLOCK = 24,
+  WRITE_MULTIPLE_BLOCK = 25,
   ERASE_WR_BLK_START = 32,
   ERASE_WR_BLK_END = 33,
   ERASE = 38,
   APP_CMD = 55,
-  READ_OCR = 58
+  READ_OCR = 58,
+  CRC_ON_OFF=59
 };
 
 /* Application specific commands, only some implemented
@@ -135,6 +144,9 @@ struct libspectrum_mmc_card {
 
 };
 
+static void
+mmc_read_multiple_blocks( libspectrum_mmc_card *card );
+
 libspectrum_mmc_card*
 libspectrum_mmc_alloc( void )
 {
@@ -232,9 +244,14 @@ libspectrum_mmc_commit( libspectrum_mmc_card *card )
 libspectrum_byte
 libspectrum_mmc_read( libspectrum_mmc_card *card )
 {
-  libspectrum_byte r = card->response_buffer_next < card->response_buffer_end ?
-    *(card->response_buffer_next)++ :
-    0xff;
+  libspectrum_byte r = 0xff;
+
+  if( card->response_buffer_next < card->response_buffer_end ) {
+    r = *(card->response_buffer_next)++;
+  } else if( READ_MULTIPLE_BLOCK == card->current_command ) {
+    mmc_read_multiple_blocks( card );
+    /* note: even though we've filled the buffer, *this* read request returns 0xff */
+  }
 
   return r;
 }
@@ -252,14 +269,46 @@ parse_command( libspectrum_mmc_card *card, libspectrum_byte b )
   return 1;
 }
 
+/* static void
+reset_response_buffer( libspectrum_mmc_card *card )
+{
+  card->response_buffer_end = card->response_buffer_next = card->response_buffer;
+} */
+
+/* static void
+set_response_buffer_size( libspectrum_mmc_card *card, int size )
+{
+  card->response_buffer_next = card->response_buffer;
+  card->response_buffer_end = card->response_buffer + size;
+} */
+
 static void
-set_response_buffer_r1( libspectrum_mmc_card *card )
+set_response_buffer( libspectrum_mmc_card *card, libspectrum_byte value )
 {
-  card->response_buffer[ 0 ] = card->r1_status;
+  card->response_buffer[ 0 ] = value;
   card->response_buffer_next = card->response_buffer;
   card->response_buffer_end = card->response_buffer + 1;
 }
 
+static void
+set_response_buffer2( libspectrum_mmc_card *card, libspectrum_byte v1, libspectrum_byte v2 )
+{
+  card->response_buffer[ 0 ] = v1;
+  card->response_buffer[ 1 ] = v2;
+  card->response_buffer_next = card->response_buffer;
+  card->response_buffer_end = card->response_buffer + 2;
+}
+
+/* static void
+append_response_buffer( libspectrum_mmc_card *card, libspectrum_byte value )
+{
+  const int pos = card->response_buffer_end - card->response_buffer_next;
+  card->response_buffer[ pos ] = value;
+  card->response_buffer_end++;
+} */
+
+#define set_response_buffer_r1( c ) set_response_buffer( c, c->r1_status )
+
 static void
 set_response_buffer_r7( libspectrum_mmc_card *card, libspectrum_dword value )
 {
@@ -272,6 +321,24 @@ set_response_buffer_r7( libspectrum_mmc_card *card, libspectrum_dword value )
   card->response_buffer_end = card->response_buffer + 5;
 }
 
+static libspectrum_dword
+get_data_address( libspectrum_mmc_card *card )
+{
+  return card->current_argument[ 3 ] +
+    (card->current_argument[ 2 ] << 8) +
+    (card->current_argument[ 1 ] << 16) +
+    (card->current_argument[ 0 ] << 24);
+}
+
+static void
+set_data_address( libspectrum_mmc_card *card, libspectrum_dword sector_number )
+{
+  card->current_argument[ 3 ] = ( sector_number & 0x000000ff );
+  card->current_argument[ 2 ] = ( sector_number & 0x0000ff00 ) >> 8;
+  card->current_argument[ 1 ] = ( sector_number & 0x00ff0000 ) >> 16;
+  card->current_argument[ 0 ] = ( sector_number & 0xff000000 ) >> 24;
+}
+
 static void
 reset_erase_sequence( libspectrum_mmc_card *card )
 {
@@ -298,11 +365,7 @@ erase_wr_blk_start( libspectrum_mmc_card *card )
     return;
   }
 
-  card->erase_block_start =
-    card->current_argument[ 3 ] +
-    (card->current_argument[ 2 ] << 8) +
-    (card->current_argument[ 1 ] << 16) +
-    (card->current_argument[ 0 ] << 24);
+  card->erase_block_start = get_data_address( card );
 
   /* Sector out of range */
   if( card->erase_block_start >= card->total_sectors ) {
@@ -334,11 +397,7 @@ erase_wr_blk_end( libspectrum_mmc_card *card )
     return;
   }
 
-  card->erase_block_end =
-    card->current_argument[ 3 ] +
-    (card->current_argument[ 2 ] << 8) +
-    (card->current_argument[ 1 ] << 16) +
-    (card->current_argument[ 0 ] << 24);
+  card->erase_block_end = get_data_address( card );
 
   /* Sector out of range */
   if( card->erase_block_end >= card->total_sectors ) {
@@ -389,14 +448,41 @@ erase( libspectrum_mmc_card *card )
                                          card->send_buffer );
   }
 
-  card->response_buffer[ 0 ] = card->r1_status; /* R1 command response */
-  card->response_buffer[ 1 ] = 0x01;            /* busy flag */
-  card->response_buffer_next = card->response_buffer;
-  card->response_buffer_end = card->response_buffer + 2;
+  /* R1 command response + busy flag */
+  set_response_buffer2( card, card->r1_status, 0x01 );
 
   reset_erase_sequence( card );
 }
 
+static void
+set_response_buffer_from_sector( libspectrum_mmc_card *card, libspectrum_dword sector_number, int offset )
+{
+  // First byte: Start Block token
+  card->response_buffer[ offset ] = 0xfe;	/* Start Block token */
+  // Bytes 2-513 filled using libspectrum_ide_read_sector_from_hdf
+  int error = libspectrum_ide_read_sector_from_hdf(
+      &card->drive, card->cache, sector_number, &card->response_buffer[ offset + 1 ]
+  );
+
+  /* Data retrieval error */
+  if( error ) {
+    if( offset == 0 ) { /* 2nd and so on packet, data error token only */
+      set_response_buffer( card, 0x01 );		/* data error token */
+    } else { /* First data packet, override command response */
+      /* R1 command response + data error token */
+      set_response_buffer2( card, card->r1_status, 0x01 );
+      // FIXME: change command state to WAIT?
+    }
+    return;
+  }
+
+  // Last two bytes: CRC
+  memset( &card->response_buffer[ offset+1+512 ], 0x00, 2 );
+
+  card->response_buffer_next = card->response_buffer;
+  card->response_buffer_end = card->response_buffer + offset + 1+512+2;
+}
+
 static void
 read_single_block( libspectrum_mmc_card *card )
 {
@@ -409,11 +495,7 @@ read_single_block( libspectrum_mmc_card *card )
     return;
   }
 
-  sector_number =
-    card->current_argument[ 3 ] +
-    (card->current_argument[ 2 ] << 8) +
-    (card->current_argument[ 1 ] << 16) +
-    (card->current_argument[ 0 ] << 24);
+  sector_number = get_data_address( card );
 
   /* Sector out of range */
   if( sector_number >= card->total_sectors ) {
@@ -422,27 +504,59 @@ read_single_block( libspectrum_mmc_card *card )
     return;
   }
 
-  int error = libspectrum_ide_read_sector_from_hdf(
-      &card->drive, card->cache, sector_number, &card->response_buffer[ 2 ]
-  );
+  // Command Response
+  card->response_buffer[ 0 ] = card->r1_status;
+  /* offset=1 since we already have command response in the buffer */
+  set_response_buffer_from_sector( card, sector_number, 1 );
+}
 
-  /* Data retrieval error */
-  if( error ) {
-    card->response_buffer[ 0 ] = card->r1_status; /* R1 command response */
-    card->response_buffer[ 1 ] = 0x01;            /* data error token */
+static void
+mmc_read_multiple_blocks( libspectrum_mmc_card *card )
+{
+#ifdef MMC_SIMULATE_MULTI_BLOCK_DELAY
+  if( card->response_buffer_end > (card->response_buffer+256) ) {
+    memset( &card->response_buffer, 0xff, 16 );
     card->response_buffer_next = card->response_buffer;
-    card->response_buffer_end = card->response_buffer + 2;
+    card->response_buffer_end = card->response_buffer + 16;
     return;
   }
+#endif
 
-  card->response_buffer[ 0 ] = card->r1_status;
-  card->response_buffer[ 1 ] = 0xfe;
+  libspectrum_dword sector_number;
+  /* both single and multiple block read start with read_single_block(...) */
+  /* thus we need to advance to the next sector first */
+  sector_number = get_data_address( card ) + 1;
 
-  /* CRC */
-  memset( &card->response_buffer[ 514 ], 0x00, 2 );
+  /* Sector out of range */
+  if( sector_number >= card->total_sectors ) {
+    set_response_buffer( card, 0x08 );	/* data error token: out of range */
+    card->command_state = WAITING_FOR_COMMAND;
+    return;
+  }
 
+  set_data_address( card, sector_number );
+  /* offset=0 - sector data starts from the beginning of the buffer */
+  set_response_buffer_from_sector( card, sector_number, 0 );
+}
+
+static void
+stop_transmission( libspectrum_mmc_card *card )
+{
+  int i = 0;
+  // typically card may send at least one more byte of the data packet
+  if( card->response_buffer_next < card->response_buffer_end ) {
+    card->response_buffer[ i++ ] = *(card->response_buffer_next);
+    // technically, there may be up to Ncr clock cycles BUSY (0xff)
+    // but we always transfer full bytes, so things are naturally
+    // Ncr aligned
+  }
+
+  card->response_buffer[ i ] = card->r1_status;
+  // for write op the response should have trailing busy (0x00) bytes
   card->response_buffer_next = card->response_buffer;
-  card->response_buffer_end = card->response_buffer + 516;
+  card->response_buffer_end = card->response_buffer + i;
+
+  card->command_state = WAITING_FOR_COMMAND;
 }
 
 static void
@@ -529,6 +643,34 @@ send_cid( libspectrum_mmc_card *card )
   card->response_buffer_end = card->response_buffer + 20;
 }
 
+static void
+send_write_command_response( libspectrum_mmc_card *card )
+{
+  libspectrum_dword sector_number;
+
+  /* Card initialised? */
+  if( card->r1_status & IN_IDLE_STATE_MASK ) {
+    card->r1_status |= ILLEGAL_COMMAND_MASK;
+    set_response_buffer_r1( card );
+    /* and skip 'waiting for token' state */
+    card->command_state = WAITING_FOR_COMMAND;
+    return;
+  }
+
+  sector_number = get_data_address( card );
+
+  /* Sector out of range */
+  if( sector_number >= card->total_sectors ) {
+    card->r1_status |= PARAMETER_ERROR_MASK;
+    set_response_buffer_r1( card );
+    /* and skip 'waiting for token' state */
+    card->command_state = WAITING_FOR_COMMAND;
+    return;
+  }
+
+  set_response_buffer_r1( card );
+}
+
 static int
 do_application_command( libspectrum_mmc_card *card )
 {
@@ -590,11 +732,21 @@ do_standard_command( libspectrum_mmc_card *card )
     case SEND_CID:
       send_cid( card );
       break;
+    case STOP_TRANSMISSION:
+      stop_transmission( card );
+      break;
+    case SET_BLOCKLEN:
+      /* SDHC: LOCK_UNLOCK length only (we do not support it yet) */
+      /* e.g. card->lock_length = get_data_address( card ); */
+      set_response_buffer_r1( card );
+      break;
     case READ_SINGLE_BLOCK:
+    case READ_MULTIPLE_BLOCK:
       read_single_block( card );
       break;
     case WRITE_BLOCK:
-      set_response_buffer_r1( card );
+    case WRITE_MULTIPLE_BLOCK:
+      send_write_command_response( card );
       break;
     case ERASE_WR_BLK_START:
       erase_wr_blk_start( card );
@@ -614,6 +766,15 @@ do_standard_command( libspectrum_mmc_card *card )
          status bits (bit 31). CCS set indicates an SDHC card. */
       set_response_buffer_r7( card, 0xc0000000 );
       break;
+    case CRC_ON_OFF: /* [31:1] stuff bits; [0:0] CRC option '1' - ON, '0' - OFF */
+      if( 0 != ( card->current_argument[3] & 0x01 ) ) {
+        card->r1_status |= ILLEGAL_COMMAND_MASK;
+        libspectrum_print_error(
+            LIBSPECTRUM_ERROR_UNKNOWN, "MMC command %d (CRC ON) not implemented",
+            card->current_command );
+      }
+      set_response_buffer_r1( card );
+      break;
     default:
       /* Command not implemented or illegal command */
       card->r1_status |= ILLEGAL_COMMAND_MASK;
@@ -659,38 +820,48 @@ do_command( libspectrum_mmc_card *card )
   do_standard_command( card );
 }
 
+static void
+write_sector_from_send_buffer( libspectrum_mmc_card *card, libspectrum_dword sector_number )
+{
+  libspectrum_ide_write_sector_to_hdf( &card->drive, card->cache, sector_number,
+									   card->send_buffer );
+
+  set_response_buffer2( card, 0x05, 0x01 );	/* data response + busy flag (end of programming) */
+}
+
 static void
 write_single_block( libspectrum_mmc_card *card )
 {
+  /* Note: command response sent earlier by send_write_command_response(...) */
+  /* we only write the data block and return data response token */
   libspectrum_dword sector_number;
 
-  /* Card initialised? */
-  if( card->r1_status & IN_IDLE_STATE_MASK ) {
-    card->r1_status |= ILLEGAL_COMMAND_MASK;
-    set_response_buffer_r1( card );
-    return;
-  }
+  sector_number = get_data_address( card );
+  /* sector_number is validated by the send_write_command_response(...) */
+  write_sector_from_send_buffer( card, sector_number );
+}
 
-  sector_number =
-    card->current_argument[ 3 ] +
-    (card->current_argument[ 2 ] << 8) +
-    (card->current_argument[ 1 ] << 16) +
-    (card->current_argument[ 0 ] << 24);
+static void
+write_multiple_block( libspectrum_mmc_card *card )
+{
+  /* unlike read op we have two distinct paths for single and multiple blocks */
+  /* all sectors of multi-block sequence are handled here */
+  libspectrum_dword sector_number = get_data_address( card );
 
-  /* Sector out of range */
   if( sector_number >= card->total_sectors ) {
-    card->r1_status |= PARAMETER_ERROR_MASK;
-    set_response_buffer_r1( card );
+    /*                           xxx0SSS1 */
+    set_response_buffer( card, 0b00001101U ); /* Data Response token: Data Rejected due to a Write Error */
+    /* In case of any error (CRC or Write Error) during Write Multiple Block operation, the host shall stop the
+    data transmission using CMD12. In case of a Write Error (response '110'), the host may send CMD13
+    (SEND_STATUS) in order to get the cause of the write problem. ACMD22 can be used to find the number
+    of well written write blocks. */
+    card->command_state = WAITING_FOR_COMMAND;
     return;
   }
 
-  libspectrum_ide_write_sector_to_hdf( &card->drive, card->cache, sector_number,
-                                       card->send_buffer );
+  set_data_address( card, sector_number + 1 );	/* keep data address for the next iteration */
 
-  card->response_buffer[ 0 ] = 0x05; /* data response */
-  card->response_buffer[ 1 ] = 0x01; /* busy flag (end of programming) */
-  card->response_buffer_next = card->response_buffer;
-  card->response_buffer_end = card->response_buffer + 2;
+  write_sector_from_send_buffer( card, sector_number );
 }
 
 static void
@@ -700,6 +871,9 @@ do_command_data( libspectrum_mmc_card *card )
     case WRITE_BLOCK:
       write_single_block( card );
       break;
+    case WRITE_MULTIPLE_BLOCK:
+      write_multiple_block( card );
+      break;
     default:
       /* This should never happen as it indicates a failure in our state machine */
       libspectrum_print_error(
@@ -710,6 +884,36 @@ do_command_data( libspectrum_mmc_card *card )
   }
 }
 
+static void
+do_data_token( libspectrum_mmc_card *card, libspectrum_byte data )
+{
+  /* make sure this function handles transition to the next state */
+  switch( data ) {
+    case TOKEN_START_BLOCK: /* Read, Write single: Start Block token */
+      card->command_state = WAITING_FOR_DATA;
+      card->data_count = 0;
+      break;
+    case TOKEN_START_MBWR_BLOCK: /* Write multiple: Start Block token */
+      card->command_state = WAITING_FOR_DATA;
+      card->data_count = 0;
+      break;
+    case TOKEN_STOP_TRAN: /* Stop Tran token */
+       // TODO: add busy ?
+      card->command_state = WAITING_FOR_COMMAND;
+      break;
+    default:
+      /* per 7.3.3.1 a CMD12 may be received in case of error instead of control token (?) */
+      /* for now we re-set command_state after sending Data Response token with error */
+      libspectrum_print_error(
+		LIBSPECTRUM_ERROR_LOGIC,
+		"Received unexpected MMC control token %d (cmd %d)\n",
+		data, card->current_command );
+      set_response_buffer( card, 0b00000001U ); /* Data Response token: Error */
+      card->command_state = WAITING_FOR_COMMAND;
+      break;
+  }
+}
+
 void
 libspectrum_mmc_write( libspectrum_mmc_card *card, libspectrum_byte data )
 {
@@ -735,15 +939,17 @@ libspectrum_mmc_write( libspectrum_mmc_card *card, libspectrum_byte data )
       /* reset command error flags except in_idle */
       card->r1_status &= IN_IDLE_STATE_MASK;
 
-      card->command_state = card->current_command == WRITE_BLOCK ?
-        WAITING_FOR_DATA_TOKEN :
-        WAITING_FOR_COMMAND;
+      /* Let do_command(...) override the next state, if necessary */
+      if( card->command_state == WAITING_FOR_CRC ) {
+        card->command_state =
+          card->current_command == WRITE_BLOCK
+              || card->current_command == WRITE_MULTIPLE_BLOCK ?
+          WAITING_FOR_DATA_TOKEN :
+          WAITING_FOR_COMMAND;
+      }
       break;
     case WAITING_FOR_DATA_TOKEN:
-      if( data == 0xfe ) {
-        card->command_state = WAITING_FOR_DATA;
-        card->data_count = 0;
-      }
+      do_data_token( card, data );
       break;
     case WAITING_FOR_DATA:
       card->send_buffer[ card->data_count++ ] = data;
@@ -756,7 +962,12 @@ libspectrum_mmc_write( libspectrum_mmc_card *card, libspectrum_byte data )
       break;
     case WAITING_FOR_DATA_CRC2:
       do_command_data( card );
-      card->command_state = WAITING_FOR_COMMAND;
+      /* Let do_command_data(...) override the next state, if necessary */
+      if( card->command_state == WAITING_FOR_DATA_CRC2 ) {
+        card->command_state = card->current_command == WRITE_MULTIPLE_BLOCK ?
+          WAITING_FOR_DATA_TOKEN :
+          WAITING_FOR_COMMAND;
+      }
       break;
     }
 }
