#include <cpu_prog_model.h>
#include <stdio.h>

#define FALSE  0
#define TRUE   1

#define OFF    0
#define ON     1

char   gap_1    [] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
                      0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
                      0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
                      0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
                      0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
                      0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
                      0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
                      0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
       prologue [] = {0xD5,0xAA},
       addfield [] = {0x96},
       datfield [] = {0xAd},
       epilgue  [] = {0xDE,0xAA,0xEB},
       gap_2    [] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
       gap_3    [] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
                      0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
       conv_tab [] = {0x96,0x97,0x9A,0x9B,0x9D,0x9E,0x9F,0xA6,
                      0xA7,0xAB,0xAC,0xAD,0xAE,0xAF,0xB2,0xB3,
                      0xB4,0xB5,0xB6,0xB7,0xB9,0xBA,0xBB,0xBC,
                      0xBD,0xBE,0xBF,0xCB,0xCD,0xCE,0xCF,0xD3,
                      0xD6,0xD7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,
                      0xDF,0xE5,0xE6,0xE7,0xE9,0xEA,0xEB,0xEC,
                      0xED,0xEE,0xEF,0xF2,0xF3,0xF4,0xF5,0xF6,
                      0xF7,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF},
       logi_sec [] = {0x00,0x0D,0x0B,0x09,0x07,0x05,0x03,0x01,
                      0x0E,0x0C,0x0A,0x08,0x06,0x04,0x02,0x0F};

char   sec_secv [][24] = {
/* 00 */                    {0x00,0x09,0x08,0x07,0x06,0x05,0x04,0x03,
                             0x02,0x01,0x00,0x0F,0x0E,0x0D,0x0C,0x0B,
                             0x0A,0xFF},
/* 01 */                    {0x0F,0x0E,0x0D,0x0C,0x0B,0x0A,0x09,0x08,
                             0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,
                             0xFF},
/* 02 */                    {0x04,0x03,0x02,0x01,0x00,0x0F,0x0E,0x0D,
                             0x0C,0x0B,0x0A,0x09,0x08,0x07,0x06,0x05,
                             0xFF},
/* 03 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 04 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 05 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 06 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 07 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 08 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 09 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 10 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 11 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 12 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 13 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 14 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 15 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 16 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 17 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 18 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 19 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 20 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 21 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 22 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 23 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 24 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 25 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 26 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 27 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 28 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 29 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 30 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 31 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 32 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 33 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
/* 34 */                    {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
                             0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
                             0xFF},
                         };


short  trace_flag,
       new_track;


short stepp_motor( address)
short address;
{
   static short  magnet           [4] = {0, 0, 0, 0},
                 prev_magnet      [4] = {0, 0, 0, 0},
                 prev_prev_magnet [4] = {0, 0, 0, 0},
                 prev_number          = 0,
                 prev_prev_number     = 0,
                 track_pos            = 0;

   short         magnet_number;

   magnet_number = address >> 1;

   prev_prev_magnet [prev_prev_number] = prev_magnet [prev_prev_number];
   prev_prev_number = prev_number;

   prev_magnet [prev_number] = magnet [prev_number];
   prev_number = magnet_number;

   if ( (address & 1) == 0)
   {
      magnet [magnet_number] = OFF;
      if (trace_flag)
      {
         printf("\nTrack magnet [%d %d %d %d]\n", magnet [0],
                                                  magnet [1],
                                                  magnet [2],
                                                  magnet [3]);
         switch (magnet_number)
         {
            case 0:
               printf("              ^\n");
               break;

            case 1:
               printf("                ^\n");
               break;

            case 2:
               printf("                  ^\n");
               break;

            case 3:
               printf("                    ^\n");
               break;
         }
         printf("Set to OFF\n");
      }

   }


   if (address & 1)
   {

      if (prev_prev_magnet [(magnet_number + 1) & 3])
      {
         track_pos --;
         if (track_pos < 0)
            track_pos = 0;
      }

      if (prev_prev_magnet [(magnet_number - 1) & 3])
      {
         track_pos ++;
         if (track_pos > 140)
            track_pos = 140;

      }
      magnet [magnet_number] = ON;

      if (trace_flag)
      {
         printf("\nTrack magnet [%d %d %d %d]\n", magnet [0],
                                                  magnet [1],
                                                  magnet [2],
                                                  magnet [3]);
         switch (magnet_number)
         {
            case 0:
               printf("              ^\n");
               break;

            case 1:
               printf("                ^\n");
               break;

            case 2:
               printf("                  ^\n");
               break;

            case 3:
               printf("                    ^\n");
               break;
         }
         printf("Set to ON\n");
      }
   }

   if (!(track_pos & 0x3) )
   {
      static short old_pos = 99;
      if (old_pos != track_pos)

      old_pos = track_pos;
   }

   if (trace_flag)
      printf("Move to track int(%d / 2)\n", track_pos + 1);

   new_track = TRUE;
   return (track_pos + 1) / 2;
}

short boot_file( position, track, array, size, mode)
short   position,
        track;
char  * array;
short   size,
        mode;
{
   char        temp_buffer [256];

if (trace_flag)
   printf("boot_file:\n");

   switch (mode)
   {
      case _CLOSE:
if (trace_flag)
   printf("Close drive 1 and volume file\n");
         disk_close();
         break;

      case _OPEN:
         if (disk_open( _READ, 0x60, 0x01, 0x00) )
         {
            printf("Can't open BOOT_DISK\n");
            return -1;
         }
if (trace_flag)
   printf("Open drive 1 and volume file.\n");
         break;

      case _READ:
         disk_seek( track, 0x00, position);
         if (size)
            disk_read( array, size);
         else
         {
            printf("Internasl error No size is defined\n");
            exit( -1);
         }
         break;

      case _WRITE:
printf("You can't write throw the boot strap!\n");
exit(-1);
         break;

   }

   return FALSE;
}

short read_addfield( value, drive, track, sector, reset)
short * value,
        drive,
        track,
        sector,
        reset;
{
   static char   vol_trc_sec_check [7],
                 previous_byte;
   static short  field_pos = 0;
   short         reading_pos,
                 error_code;

   if (reset)
   {
      if (trace_flag)
         printf("Reset Add field_pos\n");
      field_pos = 0;
   }

   switch (field_pos)
   {
      case 0x0:   case 0x1:
if (trace_flag)
   printf("Prologue [%d]\n", field_pos & 3);
         *value = prologue [field_pos & 3];
         break;

      case 0x2:
if (trace_flag)
   printf("addfield\n");
         *value = *addfield;
         break;

      case 0x3:
if (trace_flag)
   printf("Read Addfield\n");
         /* Volume (2), Track (2), Sector (2), Checksum (1)  2+2+2+1=7 */
         *value = 0x50;   /* Dummy */
         reading_pos = field_pos - 3 + sector * 0x104;

         if (drive == 1)
            if (boot_file( reading_pos, track, vol_trc_sec_check, 0x7,
                                                                 _READ) )
            {
                printf("\
Error in reading AddField on pos [$%x] drive %d track %x sector %x\n",
                                   field_pos - 3, drive, track, sector );
               exit(-1);
            }

         if (drive == 2)
         {
            printf("You have tried to use drive II, that is illegal!\n");
            exit (-1);
         }

         previous_byte = 0;
         break;

      /* Volume     Track      Sector */
      case 0x4:   case 0x6:   case 0x8:   /* Even */
      case 0x5:   case 0x7:   case 0x9:   /* Odd  */
         reading_pos = (field_pos - 4) / 2;
         *value = vol_trc_sec_check [reading_pos];

         if ( (field_pos == 8) || (field_pos == 9) )
            *value = logi_sec [*value];

         if (!(field_pos & 1) )
         {
            previous_byte ^= *value;
            if (trace_flag)
               printf("Checksum = %x\n", previous_byte);

            *value >>= 1;
         }

         *value |= 0xAA;
if (trace_flag)
{
   printf("Reading %x from VolTrcSecCheck [%x]\n",
                                       vol_trc_sec_check [reading_pos],
                                       reading_pos                      );
   printf("Convert to %x\n", *value);
}
         break;

      case 0xA:   case 0xB:   /* Check sum */
if (trace_flag)
   printf("check_sum %x\n", previous_byte);
         *value = previous_byte;
         if (!(field_pos & 1) )
            *value >>= 1;

         *value |= 0xAA;
         break;

      case 0xC:   case 0xD:   case 0xE:
if (trace_flag)
   printf("epilgue [%d]   (addfield)\n", field_pos - 12);
         *value = epilgue [field_pos - 12];
         break;

   }

   field_pos ++;
   if (field_pos >= 0xF)
   {
      if (trace_flag)
         printf("Set field_pos = 0   (addfield)\n");

      field_pos = 0;
   }

   if (*value == -1)
      field_pos = -1;

   return (field_pos);
}

short read_datafield( value, drive, track, sector, reset)
short  * value,
         drive,
         track,
         sector,
         reset;
{
   static char   disk_sector   [0x102],
                 previous_byte;
   static short  field_pos = 0,
                 conv_pos;
   short         reading_pos,
                 error_code;
   char          temp_byte;

   if (reset)
      field_pos = 0;

   switch (field_pos)
   {
      case 0:   case 1:
if (trace_flag)
   printf("Prologue [%d]\n", field_pos);
         *value = prologue [field_pos];
         field_pos ++;
         break;

      case 2:
if (trace_flag)
   printf("Datafield\n");
         *value = *datfield;
         field_pos ++;
         break;

      case 3:
         *value  = 0x51;   /* Dummy */
         if (trace_flag)
            printf("Reading one sector [%x] from disk\n", sector);

         reading_pos = field_pos - 3 + 4 + sector * 0x104;

         if (drive == 1)
            if (boot_file( reading_pos, track, disk_sector, 0x100, _READ) )
            {
                printf("\
Error in reading DataField on pos [$%x] drive %d track %x sector %x\n",
                                    field_pos - 3, drive, track, sector );
               exit(-1);
            }

         if (drive == 2)
         {
            printf("You have tried to use drive II, that is illegal!\n");
            exit (-1);
         }

         disk_sector [0x100] = 0x00;
         disk_sector [0x101] = 0x00;
         field_pos    += 1;
         conv_pos      = 0;
         previous_byte = 0;
         break;

      case 4:
         temp_byte  = 0;
         temp_byte |=  disk_sector [conv_pos + 0x56 * 2] & 1;
         temp_byte <<= 1;
         temp_byte |= (disk_sector [conv_pos + 0x56 * 2] >> 1) & 1;
         temp_byte <<= 1;
         temp_byte |=  disk_sector [conv_pos + 0x56 * 1] & 1;
         temp_byte <<= 1;
         temp_byte |= (disk_sector [conv_pos + 0x56 * 1] >> 1) & 1;
         temp_byte <<= 1;
         temp_byte |=  disk_sector [conv_pos + 0x56 * 0] & 1;
         temp_byte <<= 1;
         temp_byte |= (disk_sector [conv_pos + 0x56 * 0] >> 1) & 1;

if (trace_flag)
{
   printf("Take 6bit\n");
   printf("Reading $%02x on [%x]\n", disk_sector [conv_pos], conv_pos);
   printf("Convert to $%02x\n", temp_byte);
}

         previous_byte ^= temp_byte;
         conv_pos ++;
         if (conv_pos >= 0x56)
         {
            conv_pos   = 0;
            field_pos += 1;
         }

         *value = conv_tab [previous_byte];
         previous_byte = temp_byte;
         break;

      case 5:
         temp_byte = (disk_sector [conv_pos] >> 2);
         if (trace_flag)
         {
            printf("Take 6bit\n");
            printf("Reading $%02x on [%x]\n", disk_sector [conv_pos],
                                                             conv_pos );
            printf("Convert to $%02x\n", temp_byte);
         }

         previous_byte ^= temp_byte;
         conv_pos = (conv_pos + 1) & 0xFF;
         if (!conv_pos)
            field_pos ++;
         *value = conv_tab [previous_byte];
         previous_byte = temp_byte;
         break;

      case 6:
         *value = conv_tab [previous_byte];  /* Checksum */
         field_pos    += 1;
         conv_pos      = 0;
         previous_byte = 0;
         break;

      case 7:   case 8:   case 9:
if (trace_flag)
   printf("epilgue [%d]    (datafield)\n", field_pos - 7);
         *value = epilgue [field_pos - 7];
         field_pos ++;
         break;

      default:
         *value = 0x55;
if (trace_flag)
   printf("Recycle\n");
         field_pos = 0;
         break;
   }

   if (*value == -1)
      field_pos = -1;

   return (field_pos);
}

short read_gap_1( value)
short *value;
{
   static short position = 0;

if (trace_flag)
   printf("Gap_1 [%x]\n", position);

   *value = gap_1 [position];
   position = (position + 1) & 0x3F;

   return (position);
}

short read_gap_2( value)
short *value;
{
   static short position;

if (trace_flag)
   printf("Gap_2 [%d]\n", position);

   *value = gap_2 [position];
   position = (position + 1) & 0xF;

   return (position);
}

short read_gap_3( value)
short *value;
{
   static short position;

if (trace_flag)
   printf("Gap_3 [%d]\n", position);

   *value = gap_3 [position];
   position = (position + 1) & 0x1F;

   return (position);
}

short data_strob( value, drive, track, direction)
short  * value,
         drive,
         track,
         direction;
{
   static short  info_type  = 0,
                 sector     = 0,
                 sector_pos = 0,
                 reset_addf = FALSE,
                 reset_datf = FALSE;
   short         error_code;

   if (new_track)
   {
      if (trace_flag)
         printf("Set sector_pointer to 0 on track %x\n", track);
      new_track = FALSE;
      sector_pos = 0;
      sector     = sec_secv [track][sector_pos];
      info_type  = 0;
      reset_addf = TRUE;
      reset_datf = TRUE;
      printf("T\b");
   }

if (trace_flag)
   printf("Sector %x  track %x Info type %x\n", sector, track, info_type);

   error_code = FALSE;
   switch (direction)
   {
      case _READ:
         switch (info_type)
         {
            case 0x0:
               *value = 0x50;
if (trace_flag)
   printf("Start of sector %d\n", sector);

               info_type = 0x1;
               break;

            case 0x1:
               if (sector == 0x0)
               {
                  if (!read_gap_1( value) )
                     info_type = 0x2;
               }

               else
               {
                  if (!read_gap_3( value) )
                     info_type = 0x2;
               }
               break;

            case 0x2:
               error_code = read_addfield( value, drive, track, sector,
                                                             reset_addf );
               reset_addf = FALSE;
               if (error_code == -1)
                  return (error_code);

               if (!error_code)
                  info_type = 0x3;
               break;

            case 0x3:
               if (!read_gap_2( value) )
                  info_type = 0x4;
               break;

            case 0x4:
               error_code = read_datafield( value, drive, track, sector,
                                                                 reset_datf);
               reset_datf = FALSE;
               if (error_code == -1)
                  return (error_code);
if (trace_flag)
   printf("Read %x from data_field at sequence %x\n", *value, error_code);

               if (!error_code)
                  info_type = 0x5;
               break;

            default:
               info_type = 0x0;
               sector_pos ++;
               printf("%x\b", sector);
               if (sec_secv [track][sector_pos] == 0xFF)
                  sector_pos = 0;

               sector = sec_secv [track][sector_pos];
               break;
         }
         break;   /* End of case _READ */

   }
   return (info_type);
}

dos_io( address, value, code, mode)
short    address,
       * value;
PM     * code;
short    mode;
{
   static short  track,
                 drive;
short slask;
trace_flag = code->Tr;
   switch (address)
   {
      case 0x0:   case 0x1:   case 0x2:   case 0x3:
      case 0x4:   case 0x5:   case 0x6:   case 0x7:
         track = stepp_motor( address & 7);
         break;

      case 0x8:   /* Motor OFF */
         if (drive == 1)
            if (boot_file( 0, 0, "", 0, _CLOSE) )
            {
               printf("Can't close drive 1\n");
               code->Qu = TRUE;
               code->Er = TRUE;
            }

         if (drive == 2)
         {
            printf("You have tried to use drive II, that is illegal!\n");
            exit (-1);
         }
         printf(" \b");
         break;

      case 0x9:   /* Motor ON */
         if (drive == 1)
            if (boot_file( 0, 0, "", 0, _OPEN) )
            {
               printf("Can't open drive 1.\n");
               code->Qu = TRUE;
               code->Ex = TRUE;
            }

         if (drive == 2)
         {
            printf("You have tried to use drive II, that is illegal!\n");
            exit (-1);
         }
         break;

      case 0xA:
         drive = 1;
         break;

      case 0xB:
         drive = 2;
         break;

      case 0xC:
         slask = data_strob( value, drive, track, mode);

if (trace_flag)
   if (code->Tr)
      printf("Read %02x  on pos %d\n", *value, slask);

         if (slask == -1)
         {
printf("Slask == -1\n");
            code->Qu = TRUE;
            code->Er = TRUE;
         }

         if (!slask && trace_flag)
            printf("Ended One Sector on track %d.\n", track);

         break;

      case 0xD:
if (trace_flag)
   printf("Load Data latch.\n");
         break;

      case 0xE:
if (trace_flag)
   printf("Prepare latch for input.\n");
         break;

      case 0xF:
if (trace_flag)
   printf("Prepare latch for output.\n");
         break;

      default:
         printf("Cant read $C0E%x\n", address);
         exit( -1);
   }
}
