/*************************************************************************************
 i8272 emulation - Floppy Drive Controller + 4 floppy drives connected

 intended to speedup floppy emulation compared to MESS nec765 detailed modelling

   Copyright Matt Knoth 2008
 
   - This source code is released as freeware for non-commercial purposes.
   - You are free to use and redistribute this code in modified or
     unmodified form, provided you list me in the credits.
   - If you modify this source code, you must add a notice to each modified
     source file that it has been changed.
   - The author of this copywritten work reserves the right to change the
     terms of its usage and license at any time, including retroactively
   - This entire notice must remain in the source code.

   TODO: - functionality beyond the P8000EMU requirements (unimplemented commands)

 *************************************************************************************/
#include "driver.h"
#include "machine/i8272_floppies.h"
#include "machine/cqm_image.h"

enum {
        I8272_PHASE_CMD = 0x00,    // command phase
        I8272_PHASE_EXE = 0x01,    // execution phase general
        I8272_PHASE_RD  = 0x02,    // execution phase read access ongoing
        I8272_PHASE_WR  = 0x03,    // execution phase write access ongoing
        I8272_PHASE_FRM = 0x04,    // execution phase format access ongoing
        I8272_PHASE_RES = 0x05,    // result phase

        I8272_STAT_RQM = 0x80,     // Data Ready
        I8272_STAT_DIO = 0x40,     // direction '1'=FDC->CPU, '0'=CPU->FDC
        I8272_STAT_NDM = 0x20,     // no DMA mode
        I8272_STAT_CB  = 0x10,     // busy - read/write in progress
        I8272_STAT_D3B = 0x08,     // drive 3
        I8272_STAT_D2B = 0x04,     // drive 2
        I8272_STAT_D1B = 0x02,     // drive 1
        I8272_STAT_D0B = 0x01,     // drive 0

        I8272_ST3_WP   = 0x40,     // ST3 Write Protected
        I8272_ST3_RDY  = 0x20,     // ST3 Ready
        I8272_ST3_T0   = 0x10,     // ST3 Track Zer0
        I8272_ST3_TS   = 0x08,     // ST3 Two Sided
        I8272_ST3_HD   = 0x04,     // ST3 Head Side
};

struct __i8272_floppy {

   void (*intr)(int state);        // interrupt callback
   void (*dmar)(int state);        // dma request callback

   UINT8 phase;                    // FDC phase
   UINT8 int_state;                // FDC interrupt status
   emu_timer* exe_timer;           // execution timer

   UINT8 data_register[10];        // data receivers, [0] holds command
   UINT8 result_register[10];      // result of operation

   UINT8 dirty;                    // write/format took place
   UINT8 changed;                  // floppy has changed  [3] - changed [2]-status [1:0] drive number

   UINT8 status_reg;               // main status register
   UINT8 cmd_cnt;                  // command data counter
   UINT8 res_cnt;                  // result data counter

   UINT8 SRT;                      // step rate timing
   UINT8 HLT;                      // head load time
   UINT8 HUT;                      // head unload time
   UINT8 ND;                       // no DMA mode

   UINT8 PCN;                      // Present Cylinder Number

   UINT8 ST0;                      // status register 0
   UINT8 ST1;                      // status register 1
   UINT8 ST2;                      // status register 2
   UINT8 ST3;                      // status register 3

   struct cqm_image* images[4];   // drive contents

};
typedef struct __i8272_floppy _i8272_floppy;

static void i8272_cmd_undefined( void );
static void i8272_cmd_read_track( void );
static void i8272_cmd_specify( void );
static void i8272_cmd_sense_drive_status( void );
static void i8272_cmd_write_data( void );
static void i8272_cmd_read_data( void );
static void i8272_cmd_recalibrate( void );
static void i8272_cmd_sense_interrupt_status( void );
static void i8272_cmd_write_deleted_data( void );
static void i8272_cmd_read_id( void );
static void i8272_cmd_read_deleted_data( void );
static void i8272_cmd_format_track( void );
static void i8272_cmd_seek( void );
static void i8272_cmd_scan_equal( void );
static void i8272_cmd_scan_low_or_equal( void );
static void i8272_cmd_scan_high_or_equal( void );

typedef struct _i8272_cmdlst{
        void (*cmd)( void );   // command callback 
        int  nargs;            // number of cmd arguments
        int  nres;             // number of cmd results
}; 

static struct _i8272_cmdlst i8272_cmdlst[32] = 
{ 
     { i8272_cmd_undefined,              0,    1 }, // 0x00 - undefined cmd
     { i8272_cmd_undefined,              0,    1 }, // 0x01 - undefined cmd
     { i8272_cmd_read_track,             8,    7 }, // 0x02 - read track cmd
     { i8272_cmd_specify,                2,    0 }, // 0x03 - specify cmd
     { i8272_cmd_sense_drive_status,     1,    1 }, // 0x04 - sense drive status cmd
     { i8272_cmd_write_data,             8,    7 }, // 0x05 - write data cmd
     { i8272_cmd_read_data,              8,    7 }, // 0x06 - read data cmd
     { i8272_cmd_recalibrate,            1,    0 }, // 0x07 - recalibrate command
     { i8272_cmd_sense_interrupt_status, 0,    2 }, // 0x08 - sense interrupt status
     { i8272_cmd_write_deleted_data,     8,    7 }, // 0x09 - write deleted data cmd
     { i8272_cmd_read_id,                1,    7 }, // 0x0a - read ID cmd
     { i8272_cmd_undefined,              0,    1 }, // 0x0b - undefined cmd
     { i8272_cmd_read_deleted_data,      8,    7 }, // 0x0c - read deleted data cmd
     { i8272_cmd_format_track,           5,    7 }, // 0x0d - format a track cmd
     { i8272_cmd_undefined,              0,    1 }, // 0x0e - undefined cmd
     { i8272_cmd_seek,                   2,    0 }, // 0x0f - seek cmd
     { i8272_cmd_undefined,              0,    1 }, // 0x10 - undefined cmd
     { i8272_cmd_scan_equal,             8,    7 }, // 0x11 - scan equal cmd
     { i8272_cmd_undefined,              0,    1 }, // 0x12 - undefined cmd
     { i8272_cmd_undefined,              0,    1 }, // 0x13 - undefined cmd
     { i8272_cmd_undefined,              0,    1 }, // 0x14 - undefined cmd
     { i8272_cmd_undefined,              0,    1 }, // 0x15 - undefined cmd
     { i8272_cmd_undefined,              0,    1 }, // 0x16 - undefined cmd
     { i8272_cmd_undefined,              0,    1 }, // 0x17 - undefined cmd
     { i8272_cmd_undefined,              0,    1 }, // 0x18 - undefined cmd
     { i8272_cmd_scan_low_or_equal,      8,    7 }, // 0x19 - scan low or equal cmd
     { i8272_cmd_undefined,              0,    1 }, // 0x1a - undefined cmd
     { i8272_cmd_undefined,              0,    1 }, // 0x1b - undefined cmd
     { i8272_cmd_undefined,              0,    1 }, // 0x1c - undefined cmd
     { i8272_cmd_scan_high_or_equal,     8,    7 }, // 0x1d - scan high or equal cmd
     { i8272_cmd_undefined,              0,    1 }, // 0x1e - undefined cmd
     { i8272_cmd_undefined,              0,    1 }, // 0x1f - undefined cmd
};

static _i8272_floppy i8272_floppy;
static unsigned char* pRead=NULL;  // read pointer

static TIMER_CALLBACK( exec_phase_timer_cb )        // after execution time run out FIXME: also handles data phase in exec
{
//DEBUG fprintf(stderr,"TIMER! param=%d\n",param);
   i8272_floppy.phase = param;
   (*i8272_cmdlst[i8272_floppy.data_register[0] & 0x1f].cmd)();  // goto result phase command handler
}

void i8272_floppy_init( const i8272_floppy_intf *intf )
{

   memset(&i8272_floppy, 0, sizeof(i8272_floppy));

   i8272_floppy.intr = intf->intr;
   i8272_floppy.dmar = intf->dmar;

   i8272_floppy.exe_timer = timer_alloc( exec_phase_timer_cb, NULL );  // get execution timer

   i8272_floppy_reset();

}

void i8272_floppy_reset( void ) 
{

    if(i8272_floppy.intr) (*i8272_floppy.intr)( 0 );    // reset interrupt
    if(i8272_floppy.dmar) (*i8272_floppy.dmar)( 0 );    // reset dma request

    timer_adjust(i8272_floppy.exe_timer,attotime_zero,0,attotime_zero); // call read_data handler immediately
    i8272_floppy.status_reg = I8272_STAT_RQM;           // ready to receive data
    i8272_floppy.cmd_cnt = 0;                           // reset command argument counter
    i8272_floppy.res_cnt = 0;                           // reset pending result counter

}

READ8_HANDLER( i8272_fdc_r )
{
   UINT8 res;

   if(offset & 0x01) {                                             // data register
      if(i8272_floppy.intr) (*i8272_floppy.intr)(0);               // reset finish interrupt
      i8272_floppy.int_state = 0;      

      if(i8272_floppy.res_cnt) {
         res = i8272_floppy.result_register[i8272_floppy.res_cnt]; // set current result
         i8272_floppy.res_cnt--;                                   // decrement result index
         i8272_floppy.status_reg |= I8272_STAT_CB;                 // set busy for transaction
      } else {
         res = 0xff;                                               // no read data avail
      }

      if(!i8272_floppy.res_cnt) {
         i8272_floppy.status_reg &= 0x0f;                          // reset status flags
         i8272_floppy.status_reg |= I8272_STAT_RQM;                // signal readyness
      }
   } else {                                                        // status register
       res = i8272_floppy.status_reg;                              // return status
   }

//DEBUG fprintf(stderr,"FDC: R[%d]=0x%02x\n",offset,res);
   return res;
}

READ8_HANDLER( i8272_fdc_disk_r )
{
   return *pRead++;  
}

WRITE8_HANDLER( i8272_fdc_disk_w )
{
   if(i8272_floppy.phase==I8272_PHASE_WR)                                 // write data cmd
      *pRead++=data;
   else {                                                                 // format command
    i8272_floppy.data_register[i8272_floppy.cmd_cnt] = data;
    i8272_floppy.cmd_cnt++;   

    if(i8272_floppy.cmd_cnt>9) {                                          // all format bytes received
       cqm_image geometry;                                                // set up geometry
       int which = i8272_floppy.data_register[1] & 0x3;                   // select drive
       geometry.fname[0] = 0;
       geometry.sector_size = (i8272_floppy.data_register[2]+1) << 7;      // set N 
       geometry.sectors_per_track = i8272_floppy.data_register[3];         // set SC
       geometry.heads = 2;
       geometry.tracks = 80;
       geometry.current_track=i8272_floppy.data_register[6];               // set C
       geometry.current_head=i8272_floppy.data_register[7];                // set H
       geometry.current_sector=i8272_floppy.data_register[8];              // set R

//DEBUG fprintf(stderr,"FORMAT: c=%d, bytes=%d, s/t=%d, t=%d, h=%d, s=%d\n",
  //DEBUG geometry.current_track,geometry.sector_size,geometry.sectors_per_track,geometry.current_track,geometry.current_head,geometry.current_sector);

       qm_image_format(which, &geometry, i8272_floppy.data_register[5] );  // format image cylinder (which,geom,databyte)
       i8272_floppy.cmd_cnt=6;                                             // set to next cylinder format data
    }
  }
}


WRITE8_HANDLER( i8272_fdc_w )
{
   UINT8 cmd;

//DEBUG fprintf(stderr,"FDC: W[%d]=0x%02x\n",i8272_floppy.cmd_cnt,data);

   if(i8272_floppy.intr) (*i8272_floppy.intr)(0);            // reset finish interrupt

   i8272_floppy.data_register[i8272_floppy.cmd_cnt] = data;  // receive data
   i8272_floppy.status_reg |= I8272_STAT_CB;                 // set busy
   i8272_floppy.cmd_cnt++;                                   // set for next argument
   cmd = i8272_floppy.data_register[0] & 0x1f;               // evaluate command status

   if(i8272_floppy.cmd_cnt > i8272_cmdlst[cmd].nargs) {      // command phase finished
      i8272_floppy.phase = I8272_PHASE_EXE;                  // execution phase
      i8272_floppy.status_reg &= 0x0f;                       // no rd/wr data ready
      i8272_floppy.cmd_cnt = 0;                              // reset argument counter
      i8272_floppy.res_cnt = i8272_cmdlst[cmd].nres;         // set response data count
      (*i8272_cmdlst[cmd].cmd)();                            // goto command handler
   }
}

void i8272_floppy_tc( void )
{
   UINT8 cmd;
//DEBUG fprintf(stderr,"FDC_TC: phase=%02x, param=%02x\n",i8272_floppy.phase,timer_get_param(i8272_floppy.exe_timer));

   switch(i8272_floppy.phase) {
   case I8272_PHASE_CMD:
   case I8272_PHASE_RES: i8272_floppy.phase=I8272_PHASE_CMD;
                         i8272_floppy.cmd_cnt = 0;                                     // reset argument counter
                         i8272_floppy.res_cnt = 0;                                     // reset response counter
                         i8272_floppy.status_reg = 0x80;                               // no rd/wr data ready, FDC ready
                         i8272_floppy.data_register[0] = 0;                            // invalidate old command word
if(i8272_floppy.intr) (*i8272_floppy.intr)(0);               // set change interrupt
i8272_floppy.int_state = 0;      
                         timer_adjust(i8272_floppy.exe_timer,attotime_zero,0,attotime_zero);
                         break;
   case I8272_PHASE_FRM:
   case I8272_PHASE_WR:
   case I8272_PHASE_RD:  i8272_floppy.phase=I8272_PHASE_RES;                           // go from EXE states to result phase
                         if(i8272_floppy.dmar) (*i8272_floppy.dmar)( 0 );              // reset dma request
                         timer_adjust(i8272_floppy.exe_timer,attotime_zero,0,attotime_zero); // call read_data handler immediately
                         cmd = i8272_floppy.data_register[0] & 0x1f;                   // evaluate command status
                         (*i8272_cmdlst[cmd].cmd)();                                   // goto result phase command handler
                         break;
   default:
                         fprintf(stderr,"ERROR: unimplemented i8272_floppy_tc state\n");
                         exit(1);
   }
//DEBUG fprintf(stderr,"FDC_TC_return\n");
}

void i8272_floppy_change_ready(  UINT8 which, const char* fname, UINT8 wrten )
{
    if(which > 3)
       return;

    if(fname==NULL) {

       if(i8272_floppy.images[which]!=NULL)  {  // remove disk or set write enable

             i8272_floppy.images[which]=NULL;
             if(i8272_floppy.dirty & (1<<which)) {  // check if modified
                qm_image_save( which );
                i8272_floppy.dirty &= ~(1<<which);
             }

//DEBUG fprintf(stderr,"REMOVE FLOPPY %d\n",which);
         qm_image_close( which );
       }
    } else if((int)fname == -1) {                            // create new disk

               if(i8272_floppy.images[which]!=NULL)  {  // remove disk
                  qm_image_close( which );
               }

//DEBUG fprintf(stderr,"New FLOPPY %d\n",which);
               i8272_floppy.images[which]=qm_image_new( which, strcpy(auto_malloc(4),"New"));

    } else {                                                   // open existing disk

         if(i8272_floppy.images[which]!=NULL) {

//DEBUG fprintf(stderr,"REMOVE FLOPPY %d %s\n",which,i8272_floppy.images[which]);
            i8272_floppy.images[which]=NULL;
            if(i8272_floppy.dirty & (1<<which)) {  // check if modified
               qm_image_save( which );
               i8272_floppy.dirty &= ~(1<<which);
            }

            qm_image_close( which );
         }

//DEBUG fprintf(stderr,"INSERT FLOPPY %d %s\n",which,fname);
         i8272_floppy.images[which] = qm_image_open( which, fname);
    }

    i8272_floppy.changed = which | ((i8272_floppy.images[which])? 0x0c : 0x08);  // floppy status
    if(i8272_floppy.intr) (*i8272_floppy.intr)(1);                               // set change interrupt
}

/**************************************************************************************
 internal commands 
 **************************************************************************************/
static void i8272_cmd_undefined( void )
{
//DEBUG fprintf(stderr,"i8272_cmd_undefined\n");

}

static void i8272_cmd_read_track( void )
{
//DEBUG fprintf(stderr,"i8272_cmd_read_track\n");

}

static void i8272_cmd_specify( void )
{
   i8272_floppy.SRT = i8272_floppy.data_register[1] >> 4;                      // step rate timing
   i8272_floppy.HUT = i8272_floppy.data_register[1] & 0x0f;                    // head unload time
   i8272_floppy.HLT = i8272_floppy.data_register[2] >> 1;                      // head load time
   i8272_floppy.ND  = i8272_floppy.data_register[2] & 0x01;                    // no DMA mode

   i8272_floppy.phase = I8272_PHASE_RES;                                       // result phase
   i8272_floppy.status_reg = I8272_STAT_RQM;                                   // ready to receive data

//DEBUG fprintf(stderr,"i8272_cmd_specify SRT=%d, HUT=%d, HLT=%d, ND=%d\n",i8272_floppy.SRT,i8272_floppy.HUT,i8272_floppy.HLT,i8272_floppy.ND);

}

static void i8272_cmd_sense_drive_status( void )
{
   UINT8 drive;

   drive = i8272_floppy.data_register[1] & 0x03;
   if(i8272_floppy.images[drive]) {
      i8272_floppy.ST3 = I8272_ST3_WP | I8272_ST3_RDY | I8272_ST3_T0 | I8272_ST3_TS;   //FIXME - too simplistic for general purpose
   } else {
      i8272_floppy.ST3 = i8272_floppy.data_register[1] & 0x07;  // drive not ready
   }

   i8272_floppy.result_register[1] = i8272_floppy.ST3;

   i8272_floppy.phase = I8272_PHASE_RES;                                       // result phase
   i8272_floppy.status_reg = I8272_STAT_RQM | I8272_STAT_DIO;                  // data avialable for pickup

//DEBUG fprintf(stderr,"i8272_cmd_sense_drive_status %d - %p\n",drive,i8272_floppy.images[drive]);

}

static void i8272_cmd_write_data( void )
{
   switch(i8272_floppy.phase) {
   case I8272_PHASE_EXE:
                         //DEBUG fprintf(stderr,"i8272_cmd_write_data EXE\n");
                         i8272_floppy.status_reg &= 0x0f;                                         // busy within exec phase
                         timer_set(ATTOTIME_IN_MSEC(100), NULL, I8272_PHASE_WR, exec_phase_timer_cb); // average 1/2 turn
                         return;
   case I8272_PHASE_WR:
                         //DEBUG fprintf(stderr,"i8272_cmd_write_data WRITE\n");
                         i8272_floppy.status_reg &= 0x0f;                                         // busy within exec phase
                         i8272_floppy.dirty |= 1<<(i8272_floppy.data_register[1] & 0x03);         // mark as dirty
                         pRead=qm_image_get_rw_ptr(i8272_floppy.data_register[1] & 0x03,          // which drive
                                                   i8272_floppy.data_register[2],                 // cylinder number
                                                   i8272_floppy.data_register[3],                 // head number
                                                   i8272_floppy.data_register[4]);                // sector number

                //FIXME: consider non-dma behavior /////////////////////////////////////////////////
                         if(i8272_floppy.dmar) (*i8272_floppy.dmar)( 1 );                         // set dma request
                         return;
   case I8272_PHASE_RES:
                         //DEBUG fprintf(stderr,"i8272_cmd_write_data RES\n");
                         i8272_floppy.status_reg = I8272_STAT_RQM | I8272_STAT_DIO  | I8272_STAT_CB; // data avialable for pickup
                         i8272_floppy.result_register[7] = 0x00;                     //FIXME - must assemble ST0 properly
                         i8272_floppy.result_register[6] = 0x00;                     //FIXME - must assemble ST1 properly
                         i8272_floppy.result_register[5] = 0x00;                     //FIXME - must assemble ST2 properly
                         i8272_floppy.result_register[4] = i8272_floppy.data_register[2];         // current cylinder number
                         i8272_floppy.result_register[3] = i8272_floppy.data_register[3];         //FIXME current head number
                         i8272_floppy.result_register[2] = i8272_floppy.data_register[4];         //FIXME current sector number
                         i8272_floppy.result_register[1] = i8272_floppy.data_register[5];         //FIXME byte count
                         if(i8272_floppy.intr) (*i8272_floppy.intr)(1);                           // set finish interrupt
                         return;
   }
}

static void i8272_cmd_read_data( void )
{
   switch(i8272_floppy.phase) {
   case I8272_PHASE_EXE:
                         //DEBUG fprintf(stderr,"i8272_cmd_read_data EXE\n");
                         i8272_floppy.status_reg &= 0x0f;                                         // busy within exec phase
                         timer_set(ATTOTIME_IN_MSEC(100), NULL, I8272_PHASE_RD, exec_phase_timer_cb); // average 1/2 turn
                         return;
   case I8272_PHASE_RD:
                         //DEBUG fprintf(stderr,"i8272_cmd_read_data READ\n");
                         i8272_floppy.status_reg &= 0x0f;                                         // busy within exec phase
                         pRead=qm_image_get_rw_ptr(i8272_floppy.data_register[1] & 0x03,          // which drive
                                                   i8272_floppy.data_register[2],                 // cylinder number
                                                   i8272_floppy.data_register[3],                 // head number
                                                   i8272_floppy.data_register[4]);                // sector number
                //FIXME: consider non-dma behavior /////////////////////////////////////////////////
                         if(i8272_floppy.dmar) (*i8272_floppy.dmar)( 1 );                         // set dma request
                         return;
   case I8272_PHASE_RES:
                         //DEBUG fprintf(stderr,"i8272_cmd_read_data RES\n");
                         i8272_floppy.status_reg = I8272_STAT_RQM | I8272_STAT_DIO  | I8272_STAT_CB; // data avialable for pickup
                         i8272_floppy.result_register[7] = 0x00;                     //FIXME - must assemble ST0 properly
                         i8272_floppy.result_register[6] = 0x00;                     //FIXME - must assemble ST1 properly
                         i8272_floppy.result_register[5] = 0x00;                     //FIXME - must assemble ST2 properly
                         i8272_floppy.result_register[4] = i8272_floppy.data_register[2];         // current cylinder number
                         i8272_floppy.result_register[3] = i8272_floppy.data_register[3];         //FIXME current head number
                         i8272_floppy.result_register[2] = i8272_floppy.data_register[4];         //FIXME current sector number
                         i8272_floppy.result_register[1] = i8272_floppy.data_register[5];         //FIXME byte count
                         if(i8272_floppy.intr) (*i8272_floppy.intr)(1);                           // set finish interrupt
                         return;
   }

}

static void i8272_cmd_recalibrate( void )
{
   if(i8272_floppy.phase == I8272_PHASE_EXE) {                                 // in execution phase
//DEBUG fprintf(stderr,"i8272_cmd_recalibrate EXE\n");
      i8272_floppy.status_reg &= 0x0f;                                         // busy within exec phase
      timer_set(ATTOTIME_IN_MSEC(250), NULL, I8272_PHASE_RES, exec_phase_timer_cb); //FIXME correct timing value
      return;
   }

   i8272_floppy.status_reg = I8272_STAT_RQM;                                   // ready to receive data
   i8272_floppy.PCN = 0;

//DEBUG fprintf(stderr,"i8272_cmd_recalibrate RES\n");

   i8272_floppy.int_state = 1;                      // FIXME - set proper SEEK define
   if(i8272_floppy.intr) (*i8272_floppy.intr)(1);                              // set finish interrupt
}

static void i8272_cmd_sense_interrupt_status( void )
{
   i8272_floppy.phase = I8272_PHASE_RES;                                       // result phase
   i8272_floppy.status_reg = I8272_STAT_RQM | I8272_STAT_DIO;                  // data avialable for pickup
   if(i8272_floppy.changed) {
      i8272_floppy.result_register[2] = 0xc0;                                       // ready changed
      i8272_floppy.result_register[2]|= i8272_floppy.changed & 0x03;                // drive number
      i8272_floppy.result_register[2]|= (i8272_floppy.changed & 0x04)? 0x00 : 0x08; // NOT READY flag
      i8272_floppy.changed=0;
   } else
      i8272_floppy.result_register[2] = 0x00; //0x20;                     //FIXME - must assemble ST0 properly at previous command phase
   i8272_floppy.result_register[1] = i8272_floppy.PCN;                         // current cylinder number
//DEBUG fprintf(stderr,"i8272_cmd_sense_interrupt_status\n");
//  if(i8272_floppy.intr) (*i8272_floppy.intr)(1);                              // set finish interrupt
}

static void i8272_cmd_write_deleted_data( void )
{
//DEBUG fprintf(stderr,"i8272_cmd_write_deleted_data\n");

}

static void i8272_cmd_read_id( void )
{
//DEBUG fprintf(stderr,"i8272_cmd_read_id\n");

}

static void i8272_cmd_read_deleted_data( void )
{
//DEBUG fprintf(stderr,"i8272_cmd_read_deleted_data\n");

}

static void i8272_cmd_format_track( void )
{
   switch(i8272_floppy.phase) {
   case I8272_PHASE_EXE:
                         //DEBUG fprintf(stderr,"i8272_cmd_format_track EXE\n");
                         i8272_floppy.status_reg &= 0x0f;                                              // busy within exec phase
                         timer_set(ATTOTIME_IN_MSEC(300), NULL, I8272_PHASE_FRM, exec_phase_timer_cb); // average 1/2 turn + 200ms per cylinder/300rpm
                         return;
   case I8272_PHASE_FRM:
                         //DEBUG fprintf(stderr,"i8272_cmd_format_track FORMAT\n");
                         i8272_floppy.status_reg &= 0x0f;                                         // busy within exec phase
                         i8272_floppy.cmd_cnt=6;                                                  // space after regular command data
                //FIXME: consider non-dma behavior /////////////////////////////////////////////////
                         i8272_floppy.dirty |= 1<<(i8272_floppy.data_register[1] & 0x03);         // mark as dirty
                         if(i8272_floppy.dmar) (*i8272_floppy.dmar)( 1 );                         // set dma request
                         return;
   case I8272_PHASE_RES:
                         //DEBUG fprintf(stderr,"i8272_cmd_format_track RES\n");
                         i8272_floppy.status_reg = I8272_STAT_RQM | I8272_STAT_DIO  | I8272_STAT_CB; // data avialable for pickup
                         i8272_floppy.result_register[7] = 0x00;                     //FIXME - must assemble ST0 properly
                         i8272_floppy.result_register[6] = 0x00;                     //FIXME - must assemble ST1 properly
                         i8272_floppy.result_register[5] = 0x00;                     //FIXME - must assemble ST2 properly
                         i8272_floppy.result_register[4] = i8272_floppy.data_register[6];         // current cylinder number
                         i8272_floppy.result_register[3] = i8272_floppy.data_register[7];         // current head number
                         i8272_floppy.result_register[2] = i8272_floppy.data_register[8] +1;      // current sector number
                         i8272_floppy.result_register[1] = i8272_floppy.data_register[9];         // byte count
                         i8272_floppy.cmd_cnt=0;                                                  // reset dma target
                         if(i8272_floppy.intr) (*i8272_floppy.intr)(1);                           // set finish interrupt
                         return;
   }
}

static void i8272_cmd_seek( void )
{
   if(i8272_floppy.phase == I8272_PHASE_EXE) {                                 // in execution phase
//DEBUG fprintf(stderr,"i8272_cmd_seek EXE\n");
      i8272_floppy.status_reg &= 0x0f;                                         // busy within exec phase
      timer_set(ATTOTIME_IN_MSEC(50), NULL, I8272_PHASE_RES, exec_phase_timer_cb); //FIXME correct timing value
      return;
   }

   i8272_floppy.status_reg = I8272_STAT_RQM;       // ready after seek
//DEBUG fprintf(stderr,"i8272_cmd_seek RES\n");

  //FIXME:::: SEEK!!!!!!!!

   i8272_floppy.int_state = 1;                      // FIXME - set proper SEEK define
   if(i8272_floppy.intr) (*i8272_floppy.intr)(1);                              // set finish interrupt
}

static void i8272_cmd_scan_equal( void )
{
//DEBUG fprintf(stderr,"i8272_cmd_scan_equal\n");

}

static void i8272_cmd_scan_low_or_equal( void )
{
//DEBUG fprintf(stderr,"i8272_cmd_scan_low_or_equal\n");

}

static void i8272_cmd_scan_high_or_equal( void )
{
//DEBUG fprintf(stderr,"i8272_cmd_scan_high_or_equal\n");

}

