HDC.java
     1: //========================================================================================
     2: //  HDC.java
     3: //    en:SASI hard disk controller
     4: //    ja:SASIハードディスクコントローラ
     5: //  Copyright (C) 2003-2026 Makoto Kamada
     6: //
     7: //  This file is part of the XEiJ (X68000 Emulator in Java).
     8: //  You can use, modify and redistribute the XEiJ if the conditions are met.
     9: //  Read the XEiJ License for more details.
    10: //  https://stdkmd.net/xeij/
    11: //========================================================================================
    12: 
    13: //----------------------------------------------------------------------------------------
    14: //  0x00e96020  HDC SASI HDコントローラ
    15: //  0x00e96020  SPC 内蔵SCSIプロトコルコントローラ
    16: //----------------------------------------------------------------------------------------
    17: 
    18: package xeij;
    19: 
    20: import java.awt.event.*;  //ActionEvent,ActionListener,ComponentAdapter,ComponentEvent,ComponentListener,FocusAdapter,FocusEvent,FocusListener,InputEvent,KeyAdapter,KeyEvent,KeyListener,MouseAdapter,MouseEvent,MouseListener,MouseMotionAdapter,MouseWheelEvent,WindowAdapter,WindowEvent,WindowListener,WindowStateListener
    21: import java.io.*;  //BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter,File,FileInputStream,FileNotFoundException,FileReader,InputStream,InputStreamReader,IOException,OutputStreamWriter,RandomAccessFile
    22: import java.lang.*;  //Boolean,Character,Class,Comparable,Double,Exception,Float,IllegalArgumentException,Integer,Long,Math,Number,Object,Runnable,SecurityException,String,StringBuilder,System
    23: import java.util.*;  //ArrayList,Arrays,Calendar,GregorianCalendar,HashMap,Map,Map.Entry,Timer,TimerTask,TreeMap
    24: import java.util.zip.*;  //CRC32,Deflater,GZIPInputStream,GZIPOutputStream,ZipEntry,ZipInputStream
    25: import javax.swing.*;  //AbstractSpinnerModel,Box,ButtonGroup,DefaultListModel,ImageIcon,JButton,JCheckBox,JCheckBoxMenuItem,JDialog,JFileChooser,JFrame,JLabel,JList,JMenu,JMenuBar,JMenuItem,JPanel,JRadioButton,JScrollPane,JSpinner,JTextArea,JTextField,JTextPane,JViewport,ScrollPaneConstants,SpinnerListModel,SpinnerNumberModel,SwingConstants,SwingUtilities,UIManager,UIDefaults,UnsupportedLookAndFeelException
    26: 
    27: public class HDC {
    28: 
    29:   public static final boolean HDC_DEBUG_TRACE = false;
    30:   public static final boolean HDC_DEBUG_COMMAND = false;
    31:   public static final boolean HDC_DEBUG_UNIMPLEMENTED_COMMAND = true;
    32: 
    33:   public static final int HDC_BASE           = 0x00e96000;
    34:   public static final int HDC_DATA_PORT      = 0x00e96001;  //データポート
    35:   public static final int HDC_STATUS_PORT    = 0x00e96003;  //ステータスポート
    36:   public static final int HDC_RESET_PORT     = 0x00e96005;  //リセットポート
    37:   public static final int HDC_SELECTION_PORT = 0x00e96007;  //セレクションポート
    38: 
    39:   public static final int HDC_STATUS_MESSAGE = 0b10000;
    40:   public static final int HDC_STATUS_C_D     = 0b01000;
    41:   public static final int HDC_STATUS_COMMAND = 0b01000;
    42:   public static final int HDC_STATUS_DATA    = 0b00000;
    43:   public static final int HDC_STATUS_I_O     = 0b00100;
    44:   public static final int HDC_STATUS_OUTPUT  = 0b00000;
    45:   public static final int HDC_STATUS_INPUT   = 0b00100;
    46:   public static final int HDC_STATUS_BUSY    = 0b00010;
    47:   public static final int HDC_STATUS_FREE    = 0b00000;
    48:   public static final int HDC_STATUS_REQUEST = 0b00001;
    49: 
    50:   public static final String[] HDC_COMMAND_NAME = (
    51:     "TestDriveReady"                + "," +  //0x00
    52:     "Recalibrate"                   + "," +  //0x01
    53:     ""                              + "," +  //0x02
    54:     "RequestSenseStatus"            + "," +  //0x03
    55:     "FormatDrive"                   + "," +  //0x04
    56:     "CheckTrackFormat"              + "," +  //0x05
    57:     "FormatBlock"                   + "," +  //0x06
    58:     "BadTrackFormat"                + "," +  //0x07
    59:     "Read"                          + "," +  //0x08
    60:     ""                              + "," +  //0x09
    61:     "Write"                         + "," +  //0x0a
    62:     "Seek"                          + "," +  //0x0b
    63:     "InitializeDriveCharacteristic" + "," +  //0x0c
    64:     "LastCorrectedBurstLength"      + "," +  //0x0d
    65:     "AssignTrack"                   + "," +  //0x0e
    66:     "WriteSectorBuffer"             + "," +  //0x0f
    67:     "ReadSectorBuffer"              + "," +  //0x10
    68:     //123456789abcdef0123456789abcdef
    69:     ",,,,,,,,,,,,,,,"                     +  //0x11..0x1f
    70:     ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"    +  //0x20..0x3f
    71:     ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"    +  //0x40..0x5f
    72:     ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"    +  //0x60..0x7f
    73:     ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"    +  //0x80..0x9f
    74:     ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"    +  //0xa0..0xbf
    75:     ",,"                                  +  //0xc0..0xc1
    76:     "AssignDrive"                   + "," +  //0xc2
    77:     ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,"       +  //0xc3..0xdf
    78:     ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"        //0xe0..0xff
    79:     ).split (",", 256);  //splitで末尾の空要素が削除されるのでHDC_COMMAND_NAME[cmd]が存在しないとき""とみなす処理が必要
    80: 
    81:   //転送開始遅延
    82:   //  WRITEコマンドを実行するには、コマンドとデータの両方をデータポートに書き込む。
    83:   //  コマンドをMPUで、データをDMACで書き込むには、その間にDMACを始動しなければならない。
    84:   //  コマンドの6バイト目を受け取った瞬間にデータの1バイト目の外部転送要求を出してしまうと、
    85:   //  DMACがREQの立ち下がりを見逃してしまうので、少し間隔をあける必要がある。
    86:   public static final long HDC_DELAY_TIME = XEiJ.TMR_FREQ * 100 / 1000000;  //100us
    87:   public static final TickerQueue.Ticker hdcDelayTicker = new TickerQueue.Ticker () {
    88:     @Override protected void tick () {
    89:       HD63450.dmaFallREQ (1);
    90:     }
    91:   };
    92: 
    93: 
    94:   //メニュー
    95:   public static JMenu hdcMenu;
    96: 
    97:   //ファイルフィルタ
    98:   public static javax.swing.filechooser.FileFilter hdcFileFilter;  //java.io.FileFilterと紛らわしい
    99: 
   100:   //開くダイアログ
   101:   public static OpenDialog hdcOpenDialog;  //開くダイアログ。null=作る前
   102:   public static int hdcOpenUnit;  //開くユニットの番号
   103:   public static ArrayList<File[]> hdcOpenHistory;  //作る前に追加されたヒストリ
   104: 
   105:   //フォーマットダイアログ
   106:   public static JDialog hdcFormatDialog;  //ダイアログ
   107:   public static JFileChooser2 hdcFormatFileChooser;  //ファイルチューザー
   108:   public static HDMedia hdcFormatMedia;  //フォーマットするメディアの種類
   109:   public static boolean hdcFormatCopySystemFiles;  //true=システムファイルを転送する
   110: 
   111:   //ユニット
   112:   public static final HDUnit[] hdcUnitArray = new HDUnit[16];  //ユニットの配列
   113:   public static int hdcHDMax;  //現在挿入されているユニットのユニット番号の最大値+1。0~16。[0x00ed005a].b=SPC.spcSCSIINOn?0:hdcHDMax
   114: 
   115:   public static int hdcSelectedID;  //セレクションフェーズで選択されたID。0~7=有効,-1=選択されていない
   116:   public static int hdcSelectedLUN;  //コマンドフェーズで選択されたLUN。0~1=有効,-1=選択されていない
   117:   public static HDUnit hdcTargetUnit;  //バスを占有しているターゲットのユニット。hdcUnitArray[hdcSelectedID<<1|hdcSelectedLUN],null=フリー
   118:   public static int hdcBusStatus;  //バスステータス
   119: 
   120:   public static byte[] hdcReadHandle;  //転送(ターゲット→イニシエータ)の対象の配列。hdcStatusBuffer,hdcMessageBuffer,hdcSenseBuffer,hduImage
   121:   public static byte[] hdcWriteHandle;  //転送(イニシエータ→ターゲット)の対象の配列。hdcCommandBuffer,hduImage
   122:   public static int hdcIndex;  //次に転送する位置
   123:   public static int hdcLimit;  //転送を終了する位置
   124:   public static final byte[] hdcCommandBuffer = new byte[6];  //コマンドバッファ
   125:   public static final byte[] hdcStatusBuffer = new byte[1];  //ステータスバッファ
   126:   public static final byte[] hdcMessageBuffer = new byte[1];  //メッセージバッファ
   127:   public static final byte[] hdcSenseBuffer = new byte[4];  //センスバッファ
   128:   public static final byte[] hdcAssignDriveBuffer = new byte[10];  //ドライブパラメータバッファ
   129: 
   130:   public static int hdcLastFormatBlodkEnd;  //最後に実行したFormatBlockコマンドの終了位置(バイト)。-1=最後に実行したコマンドはFormatBlockではない
   131: 
   132:   public static JCheckBoxMenuItem hdcSASIMenuItem;
   133: 
   134:   //hdcInit ()
   135:   //  HDCを初期化する
   136:   public static void hdcInit () {
   137: 
   138:     //ファイルフィルタ
   139:     //  SASIハードディスクのイメージファイルかどうかを調べる
   140:     //  ファイルチューザーとドロップターゲットで使う
   141:     hdcFileFilter = new javax.swing.filechooser.FileFilter () {  //java.io.FileFilterと紛らわしい
   142:       @Override public boolean accept (File file) {
   143:         if (file.isDirectory ()) {  //ディレクトリがある
   144:           return true;
   145:         }
   146:         if (!file.isFile ()) {  //ファイルがない
   147:           return false;
   148:         }
   149:         String path = file.getPath ();
   150:         if (hdcIsInserted (path)) {  //既に挿入されている
   151:           return false;
   152:         }
   153:         long longLength = file.length ();
   154:         for (HDMedia media : HDMedia.HDM_ARRAY) {
   155:           if (media.humDiskEndByte == longLength) {  //ファイルサイズが一致
   156:             return true;
   157:           }
   158:         }
   159:         return false;
   160:       }
   161:       @Override public String getDescription () {
   162:         return (Multilingual.mlnJapanese ?
   163:                 "SASI ハードディスクのイメージファイル (*.HDF)" :
   164:                 "SASI hard disk image files (*.HDF)");
   165:       }
   166:     };
   167: 
   168:     //開くダイアログ
   169:     hdcOpenDialog = null;
   170:     hdcOpenUnit = 0;
   171:     hdcOpenHistory = new ArrayList<File[]> ();
   172:     for (int i = JFileChooser2.MAXIMUM_HISTORY_COUNT - 1; 0 <= i; i--) {
   173:       hdcAddHistory (JFileChooser2.pathsToFiles (Settings.sgsGetString ("sahistory" + i)));
   174:     }
   175: 
   176:     //ユニット
   177:     //  ダイアログが書き込み禁止でもパラメータは:Rを付けなければ書き込み禁止にしない
   178:     //hdcUnitArray = new HDUnit[16];
   179:     hdcHDMax = 0;
   180:     for (int u = 0; u < 16; u++) {
   181:       HDUnit unit = hdcUnitArray[u] = new HDUnit (u);
   182:       if (u == 0) {
   183:         unit.connect (false);  //ID 0は内蔵ドライブとするため切り離せない
   184:       }
   185:       String path = Settings.sgsGetString ("sa" + u);
   186:       String hdN = Settings.sgsGetString ("hd" + u);  //SASIまたはSCSI
   187:       if (!(hdN.equals ("") || hdN.equals ("none"))) {  //hdNが指定されている
   188:         String hdNWithoutR = hdN.endsWith (":R") || hdN.endsWith (":r") ? hdN.substring (0, hdN.length () - 2) : hdN;  //":R"を取り除く
   189:         int dotIndex = hdNWithoutR.lastIndexOf ('.');
   190:         String ext = dotIndex < 0 ? "" : hdNWithoutR.substring (dotIndex + 1);  //最後の'.'の後の文字列、なければ""
   191:         if (ext.equalsIgnoreCase ("HDF") ||
   192:             HDMedia.hdmPathToMedia (hdNWithoutR, null) != null) {  //hdNはSASI HDらしい
   193:           path = hdN;
   194:           Settings.sgsPutString ("hd" + u, "");  //消しておく
   195:         }
   196:       }
   197:       boolean userWriteProtect = false;
   198:       if (path.toUpperCase ().endsWith (":R")) {  //書き込み禁止モードで開く
   199:         path = path.substring (0, path.length () - 2);
   200:         userWriteProtect = true;
   201:       }
   202:       boolean hostWriteProtect = !new File (path).canWrite ();
   203:       if (path.length () != 0) {
   204:         unit.connect (true);  //接続されていなければ接続する
   205:         if (unit.insert (path,
   206:                          userWriteProtect || hostWriteProtect)) {  //挿入できた
   207:           hdcAddHistory (new File (path).getAbsoluteFile ());
   208:         }
   209:       }
   210:     }
   211: 
   212:     //フォーマットダイアログ
   213:     hdcFormatDialog = null;
   214:     hdcFormatFileChooser = null;
   215:     hdcFormatMedia = HDMedia.HDM_40MB;
   216:     hdcFormatCopySystemFiles = true;
   217: 
   218:     hdcSelectedID = -1;
   219:     hdcSelectedLUN = -1;
   220:     hdcTargetUnit = null;
   221:     hdcBusStatus = HDC_STATUS_FREE;
   222: 
   223:     hdcReadHandle = null;
   224:     hdcWriteHandle = null;
   225:     hdcIndex = 0;
   226:     hdcLimit = 0;
   227:     //hdcCommandBuffer = new byte[6];
   228:     //hdcStatusBuffer = new byte[1];
   229:     //hdcMessageBuffer = new byte[1];
   230:     //hdcSenseBuffer = new byte[4];
   231:     //hdcAssignDriveBuffer = new byte[10];
   232: 
   233:     hdcLastFormatBlodkEnd = -1;
   234: 
   235:   }  //hdcInit()
   236: 
   237:   //hdcTini ()
   238:   //  後始末
   239:   public static void hdcTini () {
   240: 
   241:     //イメージファイルに書き出す
   242:     for (HDUnit unit : hdcUnitArray) {
   243:       unit.hduTini ();
   244:     }
   245: 
   246:     //開くダイアログ
   247:     //  開くダイアログを作らなかったときはパラメータを更新しない
   248:     if (hdcOpenDialog != null) {
   249:       Settings.sgsPutOnOff ("sareadonly", hdcOpenDialog.getReadOnly ());
   250:       Settings.sgsPutOnOff ("saappreboot", hdcOpenDialog.getReboot ());
   251:       ArrayList<String> pathsList = hdcOpenDialog.getHistory ();
   252:       int n = pathsList.size ();
   253:       for (int i = 0; i < n; i++) {
   254:         Settings.sgsPutString ("sahistory" + i, pathsList.get (i));
   255:       }
   256:       for (int i = n; i < 16; i++) {
   257:         Settings.sgsPutString ("sahistory" + i, "");
   258:       }
   259:     }
   260: 
   261:     //ユニット
   262:     for (int u = 0; u < 16; u++) {
   263:       AbstractUnit unit = hdcUnitArray[u];
   264:       Settings.sgsPutString (
   265:         "sa" + u,
   266:         unit.abuConnected && unit.abuInserted ?
   267:         unit.abuWriteProtected ? unit.abuPath + ":R" : unit.abuPath :
   268:         "");
   269:     }
   270: 
   271:   }  //hdcTini()
   272: 
   273:   public static void hdcMakeMenu () {
   274: 
   275:     //アクションリスナー
   276:     ActionListener listener = new ActionListener () {
   277:       @Override public void actionPerformed (ActionEvent ae) {
   278:         Object source = ae.getSource ();
   279:         String command = ae.getActionCommand ();
   280:         switch (command) {
   281:         case "Create new SASI hard disk image files":  //SASIハードディスクのイメージファイルの新規作成
   282:           hdcOpenFormatDialog ();
   283:           break;
   284:         }
   285:       }
   286:     };
   287: 
   288:     //SASIメニュー
   289:     hdcMenu = ComponentFactory.createMenu ("SASI");  //横に長いとサブメニューを開きにくいので短くする
   290:     ComponentFactory.addComponents (
   291:       hdcMenu,
   292:       ComponentFactory.createHorizontalBox (
   293:         Multilingual.mlnText (
   294:           ComponentFactory.createLabel ("SASI hard disk"),
   295:           "ja", "SASI ハードディスク")),
   296:       ComponentFactory.createHorizontalSeparator ()
   297:       );
   298:     for (int u = 0; u < 16; u++) {
   299:       hdcMenu.add (hdcUnitArray[u].getMenuBox ());
   300:     }
   301:     ComponentFactory.addComponents (
   302:       hdcMenu,
   303:       ComponentFactory.createHorizontalSeparator (),
   304:       hdcSASIMenuItem = ComponentFactory.setEnabled (
   305:         Multilingual.mlnText (ComponentFactory.createCheckBoxMenuItem (!XEiJ.currentModel.isSCSI (), "Built-in SASI port", listener), "ja", "内蔵 SASI ポート"),
   306:         false),  //機種の指定で内蔵SASIと内蔵SCSIを切り替えるので操作できないことにする
   307:       ComponentFactory.createHorizontalSeparator (),
   308:       Multilingual.mlnText (ComponentFactory.createMenuItem ("Create new SASI hard disk image files", listener),
   309:                             "ja", "SASI ハードディスクのイメージファイルの新規作成")
   310:       );
   311: 
   312:   }
   313: 
   314:   //inserted = hdcIsInserted (path)
   315:   //  パスで指定したファイルが既に挿入されているか調べる
   316:   public static boolean hdcIsInserted (String path) {
   317:     for (HDUnit unit : hdcUnitArray) {
   318:       if (unit != null &&
   319:           unit.abuConnected &&  //接続されている
   320:           unit.abuInserted &&  //挿入されている
   321:           unit.abuPath.equals (path)) {  //パスが一致している
   322:         return true;  //既に挿入されている
   323:       }
   324:     }
   325:     return false;  //まだ挿入されていない
   326:   }  //hdcIsInserted(String)
   327: 
   328:   static class OpenDialog extends AbstractOpenDialog {
   329:     public OpenDialog () {
   330:       super (XEiJ.frmFrame,
   331:              "Open SASI hard disk image files",
   332:              "SASI ハードディスクのイメージファイルを開く",
   333:              false,  //ファイル
   334:              hdcFileFilter);
   335:     }
   336:     @Override public void openFiles (File[] files, boolean reboot) {
   337:       hdcOpenFiles (files, reboot);
   338:     }
   339:   }  //class OpenDialog
   340: 
   341:   //hdcOpenFiles (list, reset)
   342:   //  開くダイアログで選択されたファイルを開く
   343:   public static void hdcOpenFiles (File[] list, boolean reset) {
   344:     boolean success = true;
   345:     for (int u = hdcOpenUnit, k = 0; k < list.length; ) {
   346:       if (16 <= u) {  //ユニットが足りない
   347:         success = false;  //失敗
   348:         break;
   349:       }
   350:       HDUnit unit = hdcUnitArray[u];  //ユニット
   351:       if (!unit.abuConnected) {  //接続されていない
   352:         u++;
   353:         continue;
   354:       }
   355:       File file = list[k++];  //イメージファイル
   356:       if (!file.isFile ()) {  //イメージファイルが存在しない
   357:         success = false;  //失敗
   358:         continue;
   359:       }
   360:       if (!unit.insert (file.getPath (),
   361:                         hdcOpenDialog.getReadOnly () || !file.canWrite ())) {  //挿入できない
   362:         success = false;  //失敗
   363:         continue;
   364:       }
   365:       u++;
   366:     }
   367:     if (success) {  //すべて挿入できた
   368:       hdcAddHistory (list);  //ヒストリに追加する
   369:       if (reset) {  //ここから再起動
   370:         XEiJ.mpuReset (0x8000 | hdcOpenUnit << 8, -1);
   371:       }
   372:     }
   373:   }  //hdcOpenFiles(File[],boolean)
   374: 
   375:   //hdcMakeFormatDialog ()
   376:   //  フォーマットダイアログを作る
   377:   //  コマンドラインのみ
   378:   public static void hdcMakeFormatDialog () {
   379: 
   380:     //アクションリスナー
   381:     ActionListener listener = new ActionListener () {
   382:       @Override public void actionPerformed (ActionEvent ae) {
   383:         switch (ae.getActionCommand ()) {
   384:         case JFileChooser.APPROVE_SELECTION:
   385:         case "Start formatting":  //フォーマットを開始する
   386:           {
   387:             File[] list = hdcFormatFileChooser.getSelectedFiles ();
   388:             if (list.length > 0) {
   389:               hdcFormatDialog.setVisible (false);
   390:               if (!hdcFormatFiles (list)) {
   391:                 //!!! 失敗
   392:               }
   393:             }
   394:           }
   395:           break;
   396:         case JFileChooser.CANCEL_SELECTION:
   397:         case "Cancel":  //キャンセル
   398:           hdcFormatDialog.setVisible (false);
   399:           break;
   400:         case "10MB":
   401:           hdcFormatMedia = HDMedia.HDM_10MB;
   402:           break;
   403:         case "20MB":
   404:           hdcFormatMedia = HDMedia.HDM_20MB;
   405:           break;
   406:         case "40MB":
   407:           hdcFormatMedia = HDMedia.HDM_40MB;
   408:           break;
   409:         case "Copy system files":  //システムファイルを転送する
   410:           hdcFormatCopySystemFiles = ((JCheckBox) ae.getSource ()).isSelected ();
   411:           break;
   412:         }
   413:       }
   414:     };
   415: 
   416:     //ファイルチューザー
   417:     hdcMakeFormatFileChooser ();
   418:     hdcFormatFileChooser.setFileFilter (hdcFileFilter);
   419:     hdcFormatFileChooser.addActionListener (listener);
   420: 
   421:     //ダイアログ
   422:     ButtonGroup mediaGroup = new ButtonGroup ();
   423:     hdcFormatDialog = Multilingual.mlnTitle (
   424:       ComponentFactory.createModalDialog (
   425:         XEiJ.frmFrame,
   426:         "Create new SASI hard disk image files",
   427:         ComponentFactory.createBorderPanel (
   428:           0, 0,
   429:           ComponentFactory.createVerticalBox (
   430:             hdcFormatFileChooser,
   431:             ComponentFactory.createHorizontalBox (
   432:               Box.createHorizontalStrut (12),
   433:               Box.createHorizontalGlue (),
   434:               ComponentFactory.createRadioButtonMenuItem (mediaGroup, hdcFormatMedia == HDMedia.HDM_10MB,  "10MB", listener),
   435:               ComponentFactory.createRadioButtonMenuItem (mediaGroup, hdcFormatMedia == HDMedia.HDM_20MB,  "20MB", listener),
   436:               ComponentFactory.createRadioButtonMenuItem (mediaGroup, hdcFormatMedia == HDMedia.HDM_40MB,  "40MB", listener),
   437:               Box.createHorizontalGlue (),
   438:               Box.createHorizontalStrut (12)
   439:               ),
   440:             Box.createVerticalStrut (12),
   441:             ComponentFactory.createHorizontalBox (
   442:               Box.createHorizontalStrut (12),
   443:               Box.createHorizontalGlue (),
   444:               Multilingual.mlnText (ComponentFactory.createCheckBox (hdcFormatCopySystemFiles, "Copy system files", listener), "ja", "システムファイルを転送する"),
   445:               Box.createHorizontalGlue (),
   446:               Box.createHorizontalStrut (12),
   447:               Multilingual.mlnText (ComponentFactory.createButton ("Start formatting", KeyEvent.VK_F, listener), "ja", "フォーマットを開始する"),
   448:               Box.createHorizontalStrut (12),
   449:               Multilingual.mlnText (ComponentFactory.createButton ("Cancel", KeyEvent.VK_C, listener), "ja", "キャンセル"),
   450:               Box.createHorizontalStrut (12)
   451:               ),
   452:             Box.createVerticalStrut (12)
   453:             )
   454:           )
   455:         ),
   456:       "ja", "SASI ハードディスクのイメージファイルの新規作成");
   457: 
   458:   }  //hdcMakeFormatDialog()
   459: 
   460:   //hdcMakeFormatFileChooser ()
   461:   //  フォーマットファイルチューザーを作る
   462:   public static void hdcMakeFormatFileChooser () {
   463:     if (hdcFormatFileChooser == null) {
   464:       hdcFormatFileChooser = new JFileChooser2 ();
   465:       //hdcFormatFileChooser.setMultiSelectionEnabled (true);  //複数選択可能
   466:       hdcFormatFileChooser.setControlButtonsAreShown (false);  //デフォルトのボタンを消す
   467:     }
   468:   }
   469: 
   470:   //hdcOpenFormatDialog ()
   471:   //  フォーマットダイアログを開く
   472:   public static void hdcOpenFormatDialog () {
   473:     if (hdcFormatDialog == null) {
   474:       hdcMakeFormatDialog ();
   475:     }
   476:     XEiJ.pnlExitFullScreen (true);
   477:     hdcFormatDialog.setVisible (true);
   478:   }  //hdcOpenFormatDialog()
   479: 
   480:   //success = hdcFormatFiles (list)
   481:   //  SASIディスクをフォーマットする
   482:   //  コマンドラインのみ
   483:   public static boolean hdcFormatFiles (File[] list) {
   484:     boolean success = true;
   485:   format:
   486:     {
   487:       //SASIディスクのフォーマットデータを作る
   488:       byte[] bb = new byte[(int) hdcFormatMedia.humDiskEndByte];  //高々40MBなので丸ごと確保する
   489:       if (!hdcFormatMedia.hdmMakeFormatData (bb, hdcFormatCopySystemFiles)) {
   490:         success = false;  //失敗
   491:         break format;
   492:       }
   493:       //書き出す
   494:       int u = 0;
   495:       for (File file : list) {
   496:         String path = file.getPath ();
   497:         if (true) {
   498:           if (!path.toUpperCase ().endsWith (".HDF")) {  //適切な拡張子が指定されていない
   499:             path += path.endsWith (".") ? "hdf" : ".hdf";  //拡張子を付ける
   500:             file = new File (path);
   501:           }
   502:         }
   503:         if (hdcIsInserted (path)) {  //他のユニットに挿入されている
   504:           success = false;  //失敗
   505:           break format;
   506:         }
   507:         if (!XEiJ.rscPutFile (path, bb, 0, bb.length)) {  //書き出せない
   508:           success = false;  //失敗
   509:           break format;
   510:         }
   511:         //空いているユニットがあれば挿入する
   512:         while (u < 16) {
   513:           HDUnit unit = hdcUnitArray[u++];  //ユニット
   514:           if (unit.abuConnected &&  //接続されていて
   515:               !unit.abuInserted &&  //空いていて
   516:               unit.insert (path,
   517:                            false)) {  //挿入できた
   518:             //フォーマットしたディスクの書き込みを禁止しても意味がないのでここでは書き込みを禁止しない
   519:             break;
   520:           }
   521:         }
   522:       }
   523:     }  //format
   524:     if (success) {  //すべてフォーマットできた
   525:       hdcAddHistory (list);  //ヒストリに追加する
   526:     }
   527:     return success;
   528:   }  //hdcFormatFiles(File[])
   529: 
   530: 
   531:   //hdcAddHistory (file)
   532:   //  ファイルをヒストリに追加する
   533:   public static void hdcAddHistory (File file) {
   534:     hdcAddHistory (new File[] { file });
   535:   }
   536: 
   537:   //hdcAddHistory (files)
   538:   //  複数のファイルをヒストリに追加する
   539:   public static void hdcAddHistory (File[] files) {
   540:     if (hdcOpenDialog == null) {
   541:       hdcOpenHistory.add (files);
   542:     } else {
   543:       hdcOpenDialog.addHistory (files);
   544:     }
   545:     hdcMakeFormatFileChooser ();
   546:     hdcFormatFileChooser.addHistory (files);
   547:     hdcFormatFileChooser.selectLastFiles ();
   548:   }
   549: 
   550: 
   551:   //入出力
   552:   //
   553:   //     4   3   2   1   0
   554:   //    MSG C/D I/O BSY REQ | ACK SEL | DATA
   555:   //
   556:   //     0   0   0   0   0  |  0   0  |       バスフリーフェーズ
   557:   //
   558:   //     0   0   0   0   0  |  0   1  |  ID   イニシエータがセレクションフェーズを開始
   559:   //     0   0   0   1   0  |  0   1  |       ターゲットがバスを占有
   560:   //     0   0   0   1   0  |  0   0  |       イニシエータがセレクションフェーズを終了
   561:   //
   562:   //     0   1   0   1   0  |  0   0  |       ターゲットがコマンドフェーズ(イニシエータ→ターゲット)を開始
   563:   //     0   1   0   1   1  |  0   0  |       ターゲットがデータの受信を開始
   564:   //     0   1   0   1   1  |  1   0  |  XX   イニシエータがデータの送信を開始
   565:   //     0   1   0   1   0  |  1   0  |       ターゲットがデータの受信を終了
   566:   //     0   1   0   1   0  |  0   0  |       イニシエータがデータの送信を終了
   567:   //    繰り返す
   568:   //
   569:   //    データ転送フェーズが必要なとき
   570:   //     0   0   0   1   0  |  0   0  |       ターゲットがデータ転送フェーズ(イニシエータ→ターゲット)を開始
   571:   //     0   0   0   1   1  |  0   0  |       ターゲットがデータの受信を開始
   572:   //     0   0   0   1   1  |  1   0  |  XX   イニシエータがデータの送信を開始
   573:   //     0   0   0   1   0  |  1   0  |       ターゲットがデータの受信を終了
   574:   //     0   0   0   1   0  |  0   0  |       イニシエータがデータの送信を終了
   575:   //    繰り返す
   576:   //    または
   577:   //     0   0   1   1   0  |  0   0  |       ターゲットがデータ転送フェーズ(ターゲット→イニシエータ)を開始
   578:   //     0   0   1   1   1  |  0   0  |  XX   ターゲットがデータの送信を開始
   579:   //     0   0   1   1   1  |  1   0  |       イニシエータがデータを受信を開始
   580:   //     0   0   1   1   0  |  1   0  |       ターゲットがデータの送信を終了
   581:   //     0   0   1   1   0  |  0   0  |       イニシエータがデータの受信を終了
   582:   //    繰り返す
   583:   //
   584:   //     0   1   1   1   0  |  0   0  |       ターゲットがステータスフェーズ(ターゲット→イニシエータ)を開始
   585:   //     0   1   1   1   1  |  0   0  |  XX   ターゲットがデータの送信を開始
   586:   //     0   1   1   1   1  |  1   0  |       イニシエータがデータを受信を開始
   587:   //     0   1   1   1   0  |  1   0  |       ターゲットがデータの送信を終了
   588:   //     0   1   1   1   0  |  0   0  |       イニシエータがデータの受信を終了
   589:   //
   590:   //     1   1   1   1   0  |  0   0  |       ターゲットがメッセージフェーズ(ターゲット→イニシエータ)を開始
   591:   //     1   1   1   1   1  |  0   0  |  XX   ターゲットがデータの送信を開始
   592:   //     1   1   1   1   1  |  1   0  |       イニシエータがデータを受信を開始
   593:   //     1   1   1   1   0  |  1   0  |       ターゲットがデータの送信を終了
   594:   //     1   1   1   1   0  |  0   0  |       イニシエータがデータの受信を終了
   595:   //
   596:   //     0   0   0   0   0  |  0   0  |       ターゲットがバスを開放
   597:   //
   598:   //  SELはセレクションポートにIDを書き込むと1になり、ステータスポートに任意のデータを書き込むと0に戻る
   599:   //  ACKはREQ=1のときにデータポートを読み書きすると1になり、REQ=0で0に戻る
   600:   //  ACKはプログラムから見えないので厳密に実装する必要はない
   601:   //  DMAのREQ1はSICILIANのHDREQに接続されている。DMAのACK1はどこにも繋がっておらず、SICILIANがACKを作っている
   602: 
   603:   //d = hdcPeekStatus ()
   604:   //  pbz (0x00e96003)
   605:   public static int hdcPeekStatus () {
   606:     return hdcBusStatus;
   607:   }  //hdcPeekStatus()
   608: 
   609:   //d = hdcReadStatus ()
   610:   //  rbz (0x00e96003)
   611:   public static int hdcReadStatus () {
   612:     int d = hdcBusStatus;
   613:     if (HDC_DEBUG_TRACE) {
   614:       System.out.printf ("%08x hdcReadStatus(%d,%d)=%02x\n", XEiJ.regPC0, hdcSelectedID, hdcSelectedLUN, d);
   615:     }
   616:     return d;
   617:   }  //hdcReadStatus()
   618: 
   619:   //hdcWriteSelect (d)
   620:   //  wb (0x00e96007, d)
   621:   public static void hdcWriteSelect (int d) {
   622:     d &= 255;
   623:     if (HDC_DEBUG_TRACE) {
   624:       System.out.printf ("%08x hdcWriteSelect(%02x)\n", XEiJ.regPC0, d);
   625:     }
   626:     if (d == 0) {  //選択されていない
   627:       return;
   628:     }
   629:     //セレクションフェーズに移行する
   630:     hdcSelectedID = Integer.numberOfTrailingZeros (d);
   631:     hdcSelectedLUN = -1;
   632:     hdcBusStatus = HDC_STATUS_BUSY;
   633:   }  //hdcWriteSelect(int)
   634: 
   635:   //hdcWriteCommand (d)
   636:   //  wb (0x00e96003, d)
   637:   public static void hdcWriteCommand (int d) {
   638:     d &= 255;
   639:     if (HDC_DEBUG_TRACE) {
   640:       System.out.printf ("%08x hdcWriteCommand(%d,%d,%02x)\n", XEiJ.regPC0, hdcSelectedID, hdcSelectedLUN, d);
   641:     }
   642:     //コマンドフェーズに移行する
   643:     hdcWriteHandle = hdcCommandBuffer;
   644:     hdcIndex = 0;
   645:     hdcLimit = 6;
   646:     hdcBusStatus = HDC_STATUS_COMMAND | HDC_STATUS_OUTPUT | HDC_STATUS_BUSY | HDC_STATUS_REQUEST;
   647:     HD63450.dmaFallREQ (1);
   648:   }  //hdcWriteCommand(int)
   649: 
   650:   //hdcWriteReset (d)
   651:   //  wb (0x00e96005, d)
   652:   public static void hdcWriteReset (int d) {
   653:     d &= 255;
   654:     if (HDC_DEBUG_TRACE) {
   655:       System.out.printf ("%08x hdcWriteReset(%d,%d,%02x)\n", XEiJ.regPC0, hdcSelectedID, hdcSelectedLUN, d);
   656:     }
   657:     //バスフリーフェーズに移行する
   658:     hdcBusFreePhase ();
   659:   }  //hdcWriteReset(int)
   660: 
   661:   //d = hdcPeekData ()
   662:   //  pbz (0x00e96001)
   663:   public static int hdcPeekData () {
   664:     return (hdcReadHandle == null ? 0 :  //転送中でなければ無視する
   665:             hdcReadHandle[hdcIndex] & 255);
   666:   }  //hdcPeekData()
   667: 
   668:   //d = hdcReadData ()
   669:   //  rbz (0x00e96001)
   670:   public static int hdcReadData () {
   671:     if (hdcReadHandle == null) {  //転送中でなければ無視する
   672:       if (HDC_DEBUG_TRACE) {
   673:         System.out.printf ("%08x hdcReadData(%d,%d)=%02x\n", XEiJ.regPC0, hdcSelectedID, hdcSelectedLUN, 0);
   674:       }
   675:       return 0;
   676:     }
   677:     int d = hdcReadHandle[hdcIndex++] & 255;
   678:     HD63450.dmaRiseREQ (1);
   679:     if (HDC_DEBUG_TRACE) {
   680:       System.out.printf ("%08x hdcReadData(%d,%d)=%02x\n", XEiJ.regPC0, hdcSelectedID, hdcSelectedLUN, d);
   681:     }
   682:     if (hdcIndex < hdcLimit) {  //継続
   683:       HD63450.dmaFallREQ (1);
   684:     } else if (hdcBusStatus == (HDC_STATUS_INPUT | HDC_STATUS_BUSY | HDC_STATUS_REQUEST)) {  //データ転送フェーズが終了した
   685:       //ステータスフェーズに移行する
   686:       hdcStatusPhase (0, 0);  //センスデータなし
   687:     } else if (hdcBusStatus == (HDC_STATUS_COMMAND | HDC_STATUS_INPUT | HDC_STATUS_BUSY | HDC_STATUS_REQUEST)) {  //ステータスフェーズが終了した
   688:       //メッセージフェーズに移行する
   689:       hdcReadHandle = hdcMessageBuffer;
   690:       hdcWriteHandle = null;
   691:       hdcIndex = 0;
   692:       hdcLimit = 1;
   693:       hdcBusStatus = HDC_STATUS_MESSAGE | HDC_STATUS_COMMAND | HDC_STATUS_INPUT | HDC_STATUS_BUSY | HDC_STATUS_REQUEST;
   694:       HD63450.dmaFallREQ (1);
   695:     } else {  //メッセージフェーズが終了した
   696:       //バスフリーフェーズに移行する
   697:       hdcBusFreePhase ();
   698:       IOInterrupt.ioiHdcFall ();
   699:       IOInterrupt.ioiHdcRise ();
   700:     }
   701:     return d;
   702:   }  //hdcReadData()
   703: 
   704:   //hdcWriteData (d)
   705:   //  wb (0x00e96001)
   706:   public static void hdcWriteData (int d) {
   707:     d &= 255;
   708:     if (HDC_DEBUG_TRACE) {
   709:       System.out.printf ("%08x hdcWriteData(%d,%d,%02x)\n", XEiJ.regPC0, hdcSelectedID, hdcSelectedLUN, d);
   710:     }
   711:     if (hdcWriteHandle == null) {  //転送中でなければ無視する
   712:       return;
   713:     }
   714:     hdcWriteHandle[hdcIndex++] = (byte) d;
   715:     HD63450.dmaRiseREQ (1);
   716:     if (hdcIndex < hdcLimit) {  //継続
   717:       HD63450.dmaFallREQ (1);
   718:     } else if (hdcBusStatus == (HDC_STATUS_OUTPUT | HDC_STATUS_BUSY | HDC_STATUS_REQUEST)) {  //データ転送フェーズが終了した
   719:       if (hdcWriteHandle == hdcAssignDriveBuffer) {  //ASSIGN DRIVEのデータ転送フェーズが終了した
   720:         if (HDC_DEBUG_COMMAND) {
   721:           System.out.printf ("%08x SASI AssignDrive[", XEiJ.regPC0);
   722:           for (int i = 0; i < 10; i++) {
   723:             if (i > 0) {
   724:               System.out.print (',');
   725:             }
   726:             System.out.printf ("0x%02x", hdcAssignDriveBuffer[i] & 255);
   727:           }
   728:           System.out.println (']');
   729:         }
   730:         //!!!
   731:       }
   732:       //ステータスフェーズに移行する
   733:       hdcStatusPhase (0, 0);  //センスデータなし
   734:     } else {  //コマンドフェーズが終了した
   735:       int cmd = hdcCommandBuffer[0] & 255;  //コマンド番号
   736:       if (HDC_DEBUG_COMMAND) {
   737:         String name = cmd < HDC_COMMAND_NAME.length ? HDC_COMMAND_NAME[cmd] : "";
   738:         if (name.length () == 0) {
   739:           name = "???";
   740:         }
   741:         System.out.printf ("%08x SASI %s(", XEiJ.regPC0, name);
   742:         for (int i = 0; i < hdcLimit; i++) {
   743:           if (i > 0) {
   744:             System.out.print (',');
   745:           }
   746:           System.out.printf ("0x%02x", hdcCommandBuffer[i] & 255);
   747:         }
   748:         System.out.println (')');
   749:       }
   750:       hdcSelectedLUN = hdcCommandBuffer[1] >> 5 & 7;
   751:       if (hdcSelectedLUN > 1) {
   752:         //ステータスフェーズに移行する
   753:         hdcSenseBuffer[0] = 0x20;  //INVALID COMMAND
   754:         hdcStatusPhase (2, 0);  //センスデータあり
   755:         return;
   756:       }
   757:       hdcTargetUnit = hdcUnitArray[hdcSelectedID << 1 | hdcSelectedLUN];  //ユニット
   758:       if (!hdcTargetUnit.abuInserted) {  //挿入されていない
   759:         //ステータスフェーズに移行する
   760:         hdcSenseBuffer[0] = 0x20;  //INVALID COMMAND
   761:         hdcStatusPhase (2, 0);  //センスデータあり
   762:         return;
   763:       }
   764:       if (hdcLastFormatBlodkEnd >= 0 && cmd != 0x06) {  //一連のFormatBlockコマンドが終了した
   765:         HDMedia media = HDMedia.hdmLengthToMedia (hdcLastFormatBlodkEnd);
   766:         if (media != null) {
   767:           hdcTargetUnit.hduMedia = media;  //SASIハードディスクの容量を変更する
   768:           //!!! FORMAT.XはFormatBlockを行う前に指定されたサイズまでアクセスできるか確認しようとするので、容量を減らすことはできるが増やすことはできない
   769:         }
   770:         hdcLastFormatBlodkEnd = -1;
   771:       }
   772:       switch (cmd) {
   773:       case 0x00:  //TEST DRIVE READY
   774:         hdcDoTestDriveReady ();
   775:         break;
   776:       case 0x01:  //RECALIBRATE
   777:         hdcDoRecalibrate ();
   778:         break;
   779:       case 0x03:  //REQUEST SENSE STATUS
   780:         hdcDoRequestSenseStatus ();
   781:         break;
   782:       case 0x04:  //FORMAT DRIVE
   783:         hdcDoFormatDrive ();
   784:         break;
   785:       //case 0x05:  //CHECK TRACK FORMAT
   786:       case 0x06:  //FORMAT BLOCK
   787:         hdcDoFormatBlock ();
   788:         break;
   789:       //case 0x07:  //BAD TRACK FORMAT
   790:       case 0x08:  //READ
   791:         hdcDoRead ();
   792:         break;
   793:       case 0x0a:  //WRITE
   794:         hdcDoWrite ();
   795:         break;
   796:       case 0x0b:  //SEEK
   797:         hdcDoSeek ();
   798:         break;
   799:       //case 0x0c:  //INITIALIZE DRIVE CHARACTERISTICS
   800:       //case 0x0d:  //LAST CORRECTED BURST LENGTH
   801:       //case 0x0e:  //ASSIGN TRACK
   802:       //case 0x0f:  //WRITE SECTOR BUFFER
   803:       //case 0x10:  //READ SECTOR BUFFER
   804:       case 0xc2:  //ASSIGN DRIVE
   805:         hdcDoAssignDrive ();
   806:         break;
   807:       default:
   808:         if (HDC_DEBUG_UNIMPLEMENTED_COMMAND) {  //未実装コマンドを表示する
   809:           StringBuilder sb = new StringBuilder ();
   810:           String name = cmd < HDC_COMMAND_NAME.length ? HDC_COMMAND_NAME[cmd] : "";
   811:           if (name.length () == 0) {
   812:             name = "???";
   813:           }
   814:           sb.append (String.format ("%08x SASI %s(", XEiJ.regPC0, name));
   815:           for (int i = 0; i < hdcLimit; i++) {
   816:             if (i > 0) {
   817:               sb.append (',');
   818:             }
   819:             sb.append (String.format ("0x%02x", hdcCommandBuffer[i] & 255));
   820:           }
   821:           sb.append (')');
   822:           System.out.println (sb.toString ());
   823:         }
   824:         //ステータスフェーズに移行する
   825:         hdcSenseBuffer[0] = 0x20;  //INVALID COMMAND
   826:         hdcStatusPhase (2, 0);  //センスデータあり
   827:       }
   828:     }
   829:   }  //hdcWriteData(int)
   830: 
   831:   //hdcDoTestDriveReady ()
   832:   public static void hdcDoTestDriveReady () {
   833:     if (HDC_DEBUG_TRACE) {
   834:       System.out.printf ("%08x hdcDoTestDriveReady(%d,%d)\n", XEiJ.regPC0, hdcSelectedID, hdcSelectedLUN);
   835:     }
   836:     //ステータスフェーズに移行する
   837:     hdcStatusPhase (0, 0);  //センスデータなし
   838:   }  //hdcDoTestDriveReady()
   839: 
   840:   //hdcDoRecalibrate ()
   841:   public static void hdcDoRecalibrate () {
   842:     if (HDC_DEBUG_TRACE) {
   843:       System.out.printf ("%08x hdcDoRecalibrate(%d,%d)\n", XEiJ.regPC0, hdcSelectedID, hdcSelectedLUN);
   844:     }
   845:     //ステータスフェーズに移行する
   846:     hdcStatusPhase (0, 0);  //センスデータなし
   847:   }  //hdcDoRecalibrate()
   848: 
   849:   //hdcDoRequestSenseStatus ()
   850:   public static void hdcDoRequestSenseStatus () {
   851:     if (HDC_DEBUG_TRACE) {
   852:       System.out.printf ("%08x hdcDoRequestSenseStatus(%d,%d)\n", XEiJ.regPC0, hdcSelectedID, hdcSelectedLUN);
   853:     }
   854:     //データ転送フェーズ(ターゲット→イニシエータ)に移行する
   855:     hdcReadHandle = hdcSenseBuffer;
   856:     hdcIndex = 0;
   857:     hdcLimit = 4;
   858:     hdcBusStatus = HDC_STATUS_INPUT | HDC_STATUS_BUSY | HDC_STATUS_REQUEST;
   859:     if (false) {
   860:       HD63450.dmaFallREQ (1);
   861:     } else {
   862:       TickerQueue.tkqAdd (hdcDelayTicker, XEiJ.mpuClockTime + HDC_DELAY_TIME);
   863:     }
   864:   }  //hdcDoRequestSenseStatus()
   865: 
   866:   //hdcDoFormatDrive ()
   867:   public static void hdcDoFormatDrive () {
   868:     if (HDC_DEBUG_TRACE) {
   869:       System.out.printf ("%08x hdcDoFormatDrive(%d,%d)\n", XEiJ.regPC0, hdcSelectedID, hdcSelectedLUN);
   870:     }
   871:     if (!hdcTargetUnit.abuInserted || hdcTargetUnit.hduMedia == null ||  //挿入されていない
   872:         hdcTargetUnit.abuWriteProtected) {  //書き込みが禁止されている
   873:       //ステータスフェーズに移行する
   874:       hdcSenseBuffer[0] = 0x20;  //INVALID COMMAND
   875:       hdcStatusPhase (2, 0);  //センスデータあり
   876:       return;
   877:     }
   878:     hdcTargetUnit.hduWritten = true;
   879:     //ディスクの全体をゼロクリアする
   880:     Arrays.fill (hdcTargetUnit.hduImage, 0, (int) hdcTargetUnit.hduMedia.humDiskEndByte, (byte) 0);
   881:     //ステータスフェーズに移行する
   882:     hdcStatusPhase (0, 0);  //センスデータなし
   883:   }  //hdcDoFormatDrive()
   884: 
   885:   //hdcDoFormatBlock ()
   886:   //  SASIコマンド$06 FormatBlock
   887:   public static void hdcDoFormatBlock () {
   888:     int i = (hdcCommandBuffer[1] & 31) << 16 | (char) (hdcCommandBuffer[2] << 8 | hdcCommandBuffer[3] & 255);  //開始セクタ
   889:     int n = 33;  //セクタ数
   890:     if (HDC_DEBUG_TRACE) {
   891:       System.out.printf ("%08x hdcDoFormatBlock(%d,%d,%d,%d)\n", XEiJ.regPC0, hdcSelectedID, hdcSelectedLUN, i, n);
   892:     }
   893:     if (!hdcTargetUnit.abuInserted || hdcTargetUnit.hduMedia == null ||  //挿入されていない
   894:         hdcTargetUnit.abuWriteProtected) {  //書き込みが禁止されている
   895:       //ステータスフェーズに移行する
   896:       hdcSenseBuffer[0] = 0x20;  //INVALID COMMAND
   897:       hdcStatusPhase (2, 0);  //センスデータあり
   898:       return;
   899:     }
   900:     int l = i + n;  //終了セクタ+1
   901:     if (hdcTargetUnit.hduMedia.hdmDiskEndRecord < l) {
   902:       //ステータスフェーズに移行する
   903:       hdcSenseBuffer[0] = 0x21;  //INVALID SECTOR ADDRESS
   904:       hdcStatusPhase (2, 0);  //センスデータあり
   905:       return;
   906:     }
   907:     int begin = hdcTargetUnit.hduMedia.hdmBytesPerRecord * i;
   908:     int end = hdcTargetUnit.hduMedia.hdmBytesPerRecord * l;
   909:     hdcLastFormatBlodkEnd = end;
   910:     hdcTargetUnit.hduWritten = true;
   911:     //指定されたセクタをゼロクリアする
   912:     Arrays.fill (hdcTargetUnit.hduImage, begin, end, (byte) 0);
   913:     //ステータスフェーズに移行する
   914:     hdcStatusPhase (0, 0);  //センスデータなし
   915:   }  //hdcDoFormatBlock()
   916: 
   917:   //hdcDoRead ()
   918:   public static void hdcDoRead () {
   919:     int i = (hdcCommandBuffer[1] & 31) << 16 | (char) (hdcCommandBuffer[2] << 8 | hdcCommandBuffer[3] & 255);  //開始セクタ
   920:     int n = hdcCommandBuffer[4] & 255;  //セクタ数
   921:     if (n == 0) {
   922:       n = 256;
   923:     }
   924:     if (HDC_DEBUG_TRACE) {
   925:       System.out.printf ("%08x hdcDoRead(%d,%d,%d,%d)\n", XEiJ.regPC0, hdcSelectedID, hdcSelectedLUN, i, n);
   926:     }
   927:     if (!hdcTargetUnit.abuInserted || hdcTargetUnit.hduMedia == null) {  //挿入されていない
   928:       //ステータスフェーズに移行する
   929:       hdcSenseBuffer[0] = 0x20;  //INVALID COMMAND
   930:       hdcStatusPhase (2, 0);  //センスデータあり
   931:       return;
   932:     }
   933:     int l = i + n;  //終了セクタ+1
   934:     if (hdcTargetUnit.hduMedia.hdmDiskEndRecord < l) {
   935:       //ステータスフェーズに移行する
   936:       hdcSenseBuffer[0] = 0x21;  //INVALID SECTOR ADDRESS
   937:       hdcStatusPhase (2, 0);  //センスデータあり
   938:       return;
   939:     }
   940:     //データ転送フェーズ(ターゲット→イニシエータ)に移行する
   941:     hdcReadHandle = hdcTargetUnit.hduImage;
   942:     hdcIndex = hdcTargetUnit.hduMedia.hdmBytesPerRecord * i;
   943:     hdcLimit = hdcTargetUnit.hduMedia.hdmBytesPerRecord * l;
   944:     hdcBusStatus = HDC_STATUS_INPUT | HDC_STATUS_BUSY | HDC_STATUS_REQUEST;
   945:     if (false) {
   946:       HD63450.dmaFallREQ (1);
   947:     } else {
   948:       TickerQueue.tkqAdd (hdcDelayTicker, XEiJ.mpuClockTime + HDC_DELAY_TIME);
   949:     }
   950:   }  //hdcDoRead()
   951: 
   952:   //hdcDoWrite ()
   953:   public static void hdcDoWrite () {
   954:     int i = (hdcCommandBuffer[1] & 31) << 16 | (char) (hdcCommandBuffer[2] << 8 | hdcCommandBuffer[3] & 255);  //開始セクタ
   955:     int n = hdcCommandBuffer[4] & 255;  //セクタ数
   956:     if (n == 0) {
   957:       n = 256;
   958:     }
   959:     if (HDC_DEBUG_TRACE) {
   960:       System.out.printf ("%08x hdcDoWrite(%d,%d,%d,%d)\n", XEiJ.regPC0, hdcSelectedID, hdcSelectedLUN, i, n);
   961:     }
   962:     if (!hdcTargetUnit.abuInserted || hdcTargetUnit.hduMedia == null ||  //挿入されていない
   963:         hdcTargetUnit.abuWriteProtected) {  //書き込みが禁止されている
   964:       //ステータスフェーズに移行する
   965:       hdcSenseBuffer[0] = 0x20;  //INVALID COMMAND
   966:       hdcStatusPhase (2, 0);  //センスデータあり
   967:       return;
   968:     }
   969:     int l = i + n;  //終了セクタ+1
   970:     if (hdcTargetUnit.hduMedia.hdmDiskEndRecord < l) {
   971:       //ステータスフェーズに移行する
   972:       hdcSenseBuffer[0] = 0x21;  //INVALID SECTOR ADDRESS
   973:       hdcStatusPhase (2, 0);  //センスデータあり
   974:       return;
   975:     }
   976:     hdcTargetUnit.hduWritten = true;
   977:     //データ転送フェーズ(イニシエータ→ターゲット)に移行する
   978:     hdcWriteHandle = hdcTargetUnit.hduImage;
   979:     hdcIndex = hdcTargetUnit.hduMedia.hdmBytesPerRecord * i;
   980:     hdcLimit = hdcTargetUnit.hduMedia.hdmBytesPerRecord * l;
   981:     hdcBusStatus = HDC_STATUS_OUTPUT | HDC_STATUS_BUSY | HDC_STATUS_REQUEST;
   982:     if (false) {
   983:       HD63450.dmaFallREQ (1);
   984:     } else {
   985:       TickerQueue.tkqAdd (hdcDelayTicker, XEiJ.mpuClockTime + HDC_DELAY_TIME);
   986:     }
   987:   }  //hdcDoWrite()
   988: 
   989:   //hdcDoSeek ()
   990:   public static void hdcDoSeek () {
   991:     int i = (hdcCommandBuffer[1] & 31) << 16 | (char) (hdcCommandBuffer[2] << 8 | hdcCommandBuffer[3] & 255);  //開始セクタ
   992:     if (HDC_DEBUG_TRACE) {
   993:       System.out.printf ("%08x hdcDoSeek(%d,%d,%d)\n", XEiJ.regPC0, hdcSelectedID, hdcSelectedLUN, i);
   994:     }
   995:     if (!hdcTargetUnit.abuInserted || hdcTargetUnit.hduMedia == null) {  //挿入されていない
   996:       //ステータスフェーズに移行する
   997:       hdcSenseBuffer[0] = 0x20;  //INVALID COMMAND
   998:       hdcStatusPhase (2, 0);  //センスデータあり
   999:       return;
  1000:     }
  1001:     if (hdcTargetUnit.hduMedia.hdmDiskEndRecord <= i) {
  1002:       //ステータスフェーズに移行する
  1003:       hdcSenseBuffer[0] = 0x21;  //INVALID SECTOR ADDRESS
  1004:       hdcStatusPhase (2, 0);  //センスデータあり
  1005:       return;
  1006:     }
  1007:     //ステータスフェーズに移行する
  1008:     hdcStatusPhase (0, 0);  //センスデータなし
  1009:   }  //hdcDoSeek()
  1010: 
  1011:   //hdcDoAssignDrive ()
  1012:   public static void hdcDoAssignDrive () {
  1013:     if (HDC_DEBUG_TRACE) {
  1014:       System.out.printf ("%08x hdcDoAssignDrive(%d,%d)\n", XEiJ.regPC0, hdcSelectedID, hdcSelectedLUN);
  1015:     }
  1016:     //データ転送フェーズ(イニシエータ→ターゲット)に移行する
  1017:     hdcWriteHandle = hdcAssignDriveBuffer;
  1018:     hdcIndex = 0;
  1019:     hdcLimit = 10;
  1020:     hdcBusStatus = HDC_STATUS_OUTPUT | HDC_STATUS_BUSY | HDC_STATUS_REQUEST;
  1021:     if (false) {
  1022:       HD63450.dmaFallREQ (1);
  1023:     } else {
  1024:       TickerQueue.tkqAdd (hdcDelayTicker, XEiJ.mpuClockTime + HDC_DELAY_TIME);
  1025:     }
  1026:   }  //hdcDoAssignDrive()
  1027: 
  1028:   //hdcStatusPhase (status, message)
  1029:   //  ステータスフェーズに移行する
  1030:   //  status   2=センスデータあり。hdcSenseBufferを設定しておくこと
  1031:   //  message  常に0
  1032:   public static void hdcStatusPhase (int status, int message) {
  1033:     hdcStatusBuffer[0] = (byte) status;
  1034:     hdcMessageBuffer[0] = (byte) message;
  1035:     hdcReadHandle = hdcStatusBuffer;
  1036:     hdcWriteHandle = null;
  1037:     hdcIndex = 0;
  1038:     hdcLimit = 1;
  1039:     hdcBusStatus = HDC_STATUS_COMMAND | HDC_STATUS_INPUT | HDC_STATUS_BUSY | HDC_STATUS_REQUEST;
  1040:     HD63450.dmaFallREQ (1);
  1041:   }  //hdcStatusPhase(int,int)
  1042: 
  1043:   //hdcBusFreePhase ()
  1044:   //  バスフリーフェーズに移行する
  1045:   public static void hdcBusFreePhase () {
  1046:     hdcSelectedID = -1;
  1047:     hdcSelectedLUN = -1;
  1048:     hdcTargetUnit = null;
  1049:     hdcBusStatus = HDC_STATUS_FREE;
  1050:     hdcReadHandle = null;
  1051:     hdcWriteHandle = null;
  1052:     hdcIndex = 0;
  1053:     hdcLimit = 0;
  1054:     HD63450.dmaRiseREQ (1);
  1055:   }  //hdcBusFreePhase()
  1056: 
  1057: 
  1058: 
  1059:   //========================================================================================
  1060:   //SASIフォーマットデータ
  1061:   //  無償公開されたHuman68k version 3.02のシステムディスクに入っているFORMAT.Xから抽出したデータを使う
  1062: 
  1063:   //----------------------------------------------------------------------------------------
  1064:   //SASIディスクIPL
  1065: /*
  1066:   public static final int[] HDC_DISK_IPL = {
  1067:     //  perl -e "do'sjdump.pl';$p=0;$m=4;$o=0x8aa;$l=0xcaa-$o;open IN,'HUMAN302.XDF'or die;binmode IN;seek IN,1024*592,0;read IN,$b,64;seek IN,1024*592+vec($b,15,32)+32*$m,0;read IN,$b,32;seek IN,1024*592+vec($b,7,32)+64+$o,0;read IN,$b,$l;close IN;sjdumpcode($b,0,$l,$p)"
  1068:     0x60,0x00,0x00,0xca,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00000000  `..ハ............
  1069:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00000010  ................
  1070:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00000020  ................
  1071:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00000030  ................
  1072:     0x1a,0x1b,0x5b,0x36,0x3b,0x33,0x32,0x48,0x58,0x36,0x38,0x30,0x30,0x30,0x20,0x48,  //00000040  ..[6;32HX68000 H
  1073:     0x41,0x52,0x44,0x20,0x44,0x49,0x53,0x4b,0x20,0x49,0x50,0x4c,0x20,0x4d,0x45,0x4e,  //00000050  ARD DISK IPL MEN
  1074:     0x55,0x1b,0x5b,0x32,0x35,0x3b,0x32,0x32,0x48,0x83,0x4a,0x81,0x5b,0x83,0x5c,0x83,  //00000060  U.[25;22Hカーソル
  1075:     0x8b,0x83,0x4c,0x81,0x5b,0x82,0xc5,0x91,0x49,0x91,0xf0,0x82,0xb5,0x82,0xc4,0x83,  //00000070   キーで選択してリ
  1076:     0x8a,0x83,0x5e,0x81,0x5b,0x83,0x93,0x83,0x4c,0x81,0x5b,0x82,0xf0,0x89,0x9f,0x82,  //00000080   ターンキーを押し
  1077:     0xb5,0x82,0xc4,0x82,0xad,0x82,0xbe,0x82,0xb3,0x82,0xa2,0x00,0x1b,0x5b,0x32,0x36,  //00000090   てください..[26
  1078:     0x3b,0x32,0x38,0x48,0x91,0x49,0x91,0xf0,0x82,0xb5,0x82,0xbd,0x82,0xe0,0x82,0xcc,  //000000a0  ;28H選択したもの
  1079:     0x82,0xf0,0x8e,0xa9,0x93,0xae,0x8b,0x4e,0x93,0xae,0x82,0xc6,0x82,0xb5,0x82,0xc4,  //000000b0  を自動起動として
  1080:     0x93,0x6f,0x98,0x5e,0x82,0xb5,0x82,0xdc,0x82,0xb7,0x00,0x00,0x4f,0xfa,0xff,0x32,  //000000c0  登録します..O..2
  1081:     0x42,0x85,0x20,0x3c,0x00,0x00,0x00,0x8e,0x4e,0x4f,0x1e,0x00,0xe1,0x47,0x74,0x04,  //000000d0  B. <...晒O..瓱t.
  1082:     0x26,0x3c,0x00,0x00,0x01,0x00,0x43,0xfa,0x02,0xc6,0x61,0x00,0x02,0x32,0x4a,0x00,  //000000e0  &<....C..ニa..2J.
  1083:     0x66,0x00,0x01,0x6a,0x43,0xfa,0x02,0xb8,0x47,0xfa,0xff,0x0a,0x0c,0x91,0x58,0x36,  //000000f0  f..jC..クG....噌6
  1084:     0x38,0x4b,0x66,0x00,0x01,0x6c,0x74,0x0e,0x42,0x43,0x42,0x44,0x42,0x86,0x43,0xe9,  //00000100  8Kf..lt.BCBDB.C.
  1085:     0x00,0x10,0x4a,0x11,0x67,0x16,0x52,0x46,0x26,0xc9,0x10,0x29,0x00,0x08,0x08,0x00,  //00000110  ..J.g.RF&ノ.)....
  1086:     0x00,0x00,0x66,0x08,0x52,0x43,0x4a,0x00,0x66,0x02,0x52,0x44,0x51,0xca,0xff,0xe0,  //00000120  ..f.RCJ.f.RDQハ.濳
  1087:     0x4a,0x43,0x67,0x00,0x01,0x42,0x72,0x0a,0x70,0x04,0x4e,0x4f,0x08,0x00,0x00,0x04,  //00000130   Cg..Br.p.NO....
  1088:     0x66,0x12,0x4a,0x44,0x67,0x0e,0x53,0x44,0x67,0x1c,0x43,0xfa,0xfe,0xf4,0x61,0x00,  //00000140  f.JDg.SDg.C...a.
  1089:     0x01,0xc4,0x60,0x28,0x43,0xfa,0xfe,0xea,0x61,0x00,0x01,0xba,0x43,0xfa,0xff,0x3e,  //00000150  .ト`(C..鸞..コC..>
  1090:     0x61,0x00,0x01,0xb2,0x60,0x14,0x47,0xfa,0xfe,0x9c,0x20,0x5b,0x24,0x28,0x00,0x08,  //00000160  a..イ`.G... [$(..
  1091:     0x4a,0x28,0x00,0x08,0x66,0xf4,0x60,0x00,0x00,0xbe,0x7a,0x02,0x42,0x43,0x45,0xfa,  //00000170  J(..f.`..セz.BCE.
  1092:     0xfe,0x84,0x22,0x52,0x10,0x29,0x00,0x08,0x67,0x0a,0xb0,0x05,0x67,0x06,0x72,0x02,  //00000180  .."R.)..g.ー.g.r.
  1093:     0x61,0x00,0x01,0x76,0x61,0x00,0x01,0x16,0x58,0x8a,0x52,0x43,0xb6,0x46,0x65,0xe2,  //00000190  a..va...X崖CカFe秡
  1094:     0x60,0x2a,0x61,0x00,0x01,0x06,0x61,0x00,0x00,0xf2,0xb0,0x3c,0x00,0x1d,0x67,0x3a,  //000001a0   *a...a...ー<..g:
  1095:     0xb0,0x3c,0x00,0x35,0x67,0x0c,0xb0,0x3c,0x00,0x3c,0x67,0x1a,0xb0,0x3c,0x00,0x3e,  //000001b0  ー<.5g.ー<.<g.ー<.>
  1096:     0x66,0xe4,0x61,0x00,0x00,0xe8,0x52,0x43,0xb6,0x46,0x65,0x02,0x42,0x43,0x61,0x00,  //000001c0  f臑..鏗CカFe.BCa.
  1097:     0x00,0xb2,0x66,0xf2,0x60,0xcc,0x61,0x00,0x00,0xd4,0x53,0x43,0x6a,0x04,0x36,0x06,  //000001d0  .イf.`フa..ヤSCj.6.
  1098:     0x53,0x43,0x61,0x00,0x00,0x9e,0x66,0xf2,0x60,0xb8,0x47,0xfa,0xfe,0x18,0xe5,0x43,  //000001e0  SCa..枅.`クG...蕕
  1099:     0x20,0x73,0x30,0x00,0x24,0x28,0x00,0x08,0x4a,0x05,0x67,0x3a,0x43,0xfa,0x01,0xb8,  //000001f0   s0.$(..J.g:C..ク
  1100:     0x72,0x0e,0x43,0xe9,0x00,0x10,0x4a,0x29,0xff,0xf8,0x67,0x12,0x20,0x11,0x08,0x00,  //00000200  r.C...J)..g. ...
  1101:     0x00,0x18,0x66,0x0a,0x42,0x11,0xb4,0x80,0x67,0x04,0x12,0xbc,0x00,0x02,0x51,0xc9,  //00000210  ..f.B.エ.g..シ..Qノ
  1102:     0xff,0xe2,0x2f,0x02,0x74,0x04,0x26,0x3c,0x00,0x00,0x01,0x00,0x43,0xfa,0x01,0x80,  //00000220  ../.t.&<....C...
  1103:     0x61,0x00,0x00,0xe8,0x24,0x1f,0xc4,0xbc,0x00,0xff,0xff,0xff,0x26,0x3c,0x00,0x00,  //00000230  a...$.トシ....&<..
  1104:     0x04,0x00,0x43,0xfa,0xfd,0xbc,0xd3,0xfc,0x00,0x00,0x04,0x00,0x61,0x00,0x00,0xd0,  //00000240  ..C..シモ.....a..ミ
  1105:     0x4a,0x00,0x66,0x08,0x0c,0x11,0x00,0x60,0x66,0x22,0x4e,0xd1,0x45,0xfa,0x00,0xda,  //00000250  J.f....`f"NムE..レ
  1106:     0x43,0xfa,0x00,0xcc,0x61,0x00,0x00,0xae,0x22,0x4a,0x61,0x00,0x00,0xa8,0x60,0xfe,  //00000260  C..フa..ョ"Ja..ィ`.
  1107:     0x45,0xfa,0x00,0xe3,0x60,0xea,0x45,0xfa,0x00,0xfa,0x60,0xe4,0x45,0xfa,0x01,0x11,  //00000270  E..總鵙...`胼...
  1108:     0x60,0xde,0x41,0xfa,0xfd,0x80,0x20,0x03,0xe5,0x40,0x20,0x70,0x00,0x00,0x10,0x28,  //00000280  `゙A... .蕁 p...(
  1109:     0x00,0x08,0xb0,0x05,0x67,0x02,0x4a,0x00,0x4e,0x75,0x42,0x80,0x4e,0x4f,0xe0,0x48,  //00000290  ..ー.g.J.NuB.NO潯
  1110:     0xb0,0x3c,0x00,0x4e,0x66,0x02,0x70,0x1d,0x4e,0x75,0x61,0x5a,0x43,0xfa,0xfd,0x56,  //000002a0  ー<.Nf.p.NuaZC..V
  1111:     0x30,0x03,0xe5,0x40,0x43,0xf1,0x00,0x00,0x72,0x24,0x74,0x09,0xd4,0x43,0x70,0x23,  //000002b0  0.蕁C...r$t.ヤCp#
  1112:     0x4e,0x4f,0x22,0x51,0x72,0x28,0x61,0x46,0x24,0x09,0x41,0xfa,0x00,0xe2,0x94,0x88,  //000002c0  NO"Qr(aF$.A..笏郁
  1113:     0xe8,0x8a,0x84,0xfc,0x00,0x0a,0xd4,0xbc,0x00,0x30,0x00,0x30,0x72,0x20,0xb4,0x7c,  //000002d0   割...ヤシ.0.0r エ|
  1114:     0x00,0x30,0x67,0x02,0x32,0x02,0x61,0x26,0x48,0x42,0x32,0x02,0x61,0x20,0x72,0x29,  //000002e0  .0g.2.a&HB2.a r)
  1115:     0x61,0x1c,0x72,0x20,0x61,0x18,0x74,0x07,0x42,0x41,0x12,0x19,0x61,0x10,0x51,0xca,  //000002f0  a.r a.t.BA..a.Qハ
  1116:     0xff,0xf8,0x72,0x03,0x60,0x02,0x72,0x0b,0x70,0x22,0x4e,0x4f,0x4e,0x75,0x70,0x20,  //00000300  ..r.`.r.p"NONup 
  1117:     0x4e,0x4f,0x4e,0x75,0x70,0x21,0x4e,0x4f,0x4e,0x75,0x70,0x45,0x60,0x02,0x70,0x46,  //00000310  NONup!NONupE`.pF
  1118:     0x48,0xe7,0x78,0x40,0x32,0x07,0x4e,0x4f,0x4c,0xdf,0x02,0x1e,0x4e,0x75,0x1a,0x1b,  //00000320  H輾@2.NOL゚..Nu..
  1119:     0x5b,0x31,0x36,0x3b,0x33,0x33,0x48,0x00,0x20,0x20,0x83,0x6e,0x81,0x5b,0x83,0x68,  //00000330  [16;33H.  ハード
  1120:     0x83,0x66,0x83,0x42,0x83,0x58,0x83,0x4e,0x82,0xaa,0x93,0xc7,0x82,0xdf,0x82,0xdc,  //00000340  ディスクが読めま
  1121:     0x82,0xb9,0x82,0xf1,0x00,0x20,0x20,0x8a,0xc7,0x97,0x9d,0x83,0x75,0x83,0x8d,0x83,  //00000350  せん.  管理ブロッ
  1122:     0x62,0x83,0x4e,0x82,0xaa,0x89,0xf3,0x82,0xea,0x82,0xc4,0x82,0xa2,0x82,0xdc,0x82,  //00000360   クが壊れています
  1123:     0xb7,0x00,0x20,0x20,0x8b,0x4e,0x93,0xae,0x89,0xc2,0x94,0x5c,0x82,0xc8,0x97,0xcc,  //00000370   .  起動可能な領
  1124:     0x88,0xe6,0x82,0xaa,0x82,0xa0,0x82,0xe8,0x82,0xdc,0x82,0xb9,0x82,0xf1,0x00,0x82,  //00000380  域がありません.I
  1125:     0x68,0x82,0x6f,0x82,0x6b,0x83,0x75,0x83,0x8d,0x83,0x62,0x83,0x4e,0x82,0xcc,0x93,  //00000390   PLブロックの内
  1126:     0xe0,0x97,0x65,0x82,0xaa,0x88,0xd9,0x8f,0xed,0x82,0xc5,0x82,0xb7,0x00,0x00,0x00,  //000003a0   容が異常です...
  1127:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000003b0  ................
  1128:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000003c0  ................
  1129:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000003d0  ................
  1130:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000003e0  ................
  1131:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000003f0  ................
  1132:   };
  1133: */
  1134:   //  perl misc/itob.pl xeij/HDC.java HDC_DISK_IPL
  1135:   public static final byte[] HDC_DISK_IPL = "`\0\0\312\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\32\33[6;32HX68000 HARD DISK IPL MENU\33[25;22H\203J\201[\203\\\203\213\203L\201[\202\305\221I\221\360\202\265\202\304\203\212\203^\201[\203\223\203L\201[\202\360\211\237\202\265\202\304\202\255\202\276\202\263\202\242\0\33[26;28H\221I\221\360\202\265\202\275\202\340\202\314\202\360\216\251\223\256\213N\223\256\202\306\202\265\202\304\223o\230^\202\265\202\334\202\267\0\0O\372\3772B\205 <\0\0\0\216NO\36\0\341Gt\4&<\0\0\1\0C\372\2\306a\0\0022J\0f\0\1jC\372\2\270G\372\377\n\f\221X68Kf\0\1lt\16BCBDB\206C\351\0\20J\21g\26RF&\311\20)\0\b\b\0\0\0f\bRCJ\0f\2RDQ\312\377\340JCg\0\1Br\np\4NO\b\0\0\4f\22JDg\16SDg\34C\372\376\364a\0\1\304`(C\372\376\352a\0\1\272C\372\377>a\0\1\262`\24G\372\376\234 [$(\0\bJ(\0\bf\364`\0\0\276z\2BCE\372\376\204\"R\20)\0\bg\n\260\5g\6r\2a\0\1va\0\1\26X\212RC\266Fe\342`*a\0\1\6a\0\0\362\260<\0\35g:\260<\0005g\f\260<\0<g\32\260<\0>f\344a\0\0\350RC\266Fe\2BCa\0\0\262f\362`\314a\0\0\324SCj\0046\6SCa\0\0\236f\362`\270G\372\376\30\345C s0\0$(\0\bJ\5g:C\372\1\270r\16C\351\0\20J)\377\370g\22 \21\b\0\0\30f\nB\21\264\200g\4\22\274\0\2Q\311\377\342/\2t\4&<\0\0\1\0C\372\1\200a\0\0\350$\37\304\274\0\377\377\377&<\0\0\4\0C\372\375\274\323\374\0\0\4\0a\0\0\320J\0f\b\f\21\0`f\"N\321E\372\0\332C\372\0\314a\0\0\256\"Ja\0\0\250`\376E\372\0\343`\352E\372\0\372`\344E\372\1\21`\336A\372\375\200 \3\345@ p\0\0\20(\0\b\260\5g\2J\0NuB\200NO\340H\260<\0Nf\2p\35NuaZC\372\375V0\3\345@C\361\0\0r$t\t\324Cp#NO\"Qr(aF$\tA\372\0\342\224\210\350\212\204\374\0\n\324\274\0000\0000r \264|\0000g\0022\2a&HB2\2a r)a\34r a\30t\7BA\22\31a\20Q\312\377\370r\3`\2r\13p\"NONup NONup!NONupE`\2pFH\347x@2\7NOL\337\2\36Nu\32\33[16;33H\0  \203n\201[\203h\203f\203B\203X\203N\202\252\223\307\202\337\202\334\202\271\202\361\0  \212\307\227\235\203u\203\215\203b\203N\202\252\211\363\202\352\202\304\202\242\202\334\202\267\0  \213N\223\256\211\302\224\\\202\310\227\314\210\346\202\252\202\240\202\350\202\334\202\271\202\361\0\202h\202o\202k\203u\203\215\203b\203N\202\314\223\340\227e\202\252\210\331\217\355\202\305\202\267\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0".getBytes (XEiJ.ISO_8859_1);
  1136: 
  1137:   //----------------------------------------------------------------------------------------
  1138:   //SASIパーティションIPL
  1139: /*
  1140:   public static final int[] HDC_PARTITION_IPL = {
  1141:     //  perl -e "do'sjdump.pl';$p=0x2100;$m=4;$o=0x1126;$l=0x1526-$o;open IN,'HUMAN302.XDF'or die;binmode IN;seek IN,1024*592,0;read IN,$b,64;seek IN,1024*592+vec($b,15,32)+32*$m,0;read IN,$b,32;seek IN,1024*592+vec($b,7,32)+64+$o,0;read IN,$b,$l;close IN;sjdumpcode($b,0,$l,$p)"
  1142:     0x60,0x20,0x48,0x75,0x64,0x73,0x6f,0x6e,0x20,0x73,0x6f,0x66,0x74,0x20,0x32,0x2e,  //00002100  ` Hudson soft 2.
  1143:     0x30,0x30,0x04,0x00,0x01,0x02,0x00,0x01,0x02,0x00,0x27,0x72,0xf8,0x14,0x00,0x00,  //00002110  00........'r....
  1144:     0x00,0x00,0x4f,0xfa,0xff,0xdc,0x43,0xfa,0x01,0x34,0x61,0x00,0x01,0x2a,0x20,0x3c,  //00002120  ..O..ワC..4a..* <
  1145:     0x00,0x00,0x00,0x8e,0x4e,0x4f,0x12,0x00,0xe1,0x41,0x42,0x82,0x14,0x3a,0xff,0xdf,  //00002130  ...晒O..瓣B..:.゚
  1146:     0x42,0x80,0x10,0x3a,0xff,0xd1,0xc4,0xc0,0x42,0x80,0x30,0x3a,0xff,0xca,0xd4,0x80,  //00002140  B..:.ムトタB.0:.ハヤ.
  1147:     0xe5,0x82,0xd4,0xba,0xff,0xca,0x26,0x3c,0x00,0x00,0x04,0x00,0x43,0xfa,0x01,0x9a,  //00002150  蛯ヤコ.ハ&<....C..啾
  1148:     0x61,0x00,0x00,0xc8,0x4a,0x00,0x66,0x00,0x00,0xd0,0x43,0xfa,0x01,0x8c,0x3c,0x3c,  //00002160   ..ネJ.f..ミC...<<
  1149:     0x00,0x1f,0x24,0x49,0x47,0xfa,0x01,0x75,0x7e,0x0a,0x10,0x1a,0x80,0x3c,0x00,0x20,  //00002170  ..$IG..u~....<. 
  1150:     0xb0,0x1b,0x66,0x06,0x51,0xcf,0xff,0xf4,0x60,0x14,0xd3,0xfc,0x00,0x00,0x00,0x20,  //00002180  ー.f.Qマ..`.モ.... 
  1151:     0x51,0xce,0xff,0xe0,0x43,0xfa,0x00,0xc8,0x61,0x00,0x00,0xbc,0x60,0xfe,0x42,0x80,  //00002190  Qホ.澆..ネa..シ`.B.
  1152:     0x30,0x29,0x00,0x1a,0xe1,0x58,0x55,0x40,0x42,0x87,0x1e,0x3a,0xff,0x68,0xc0,0xc7,  //000021a0  0)..畊U@B..:.hタヌ
  1153:     0xe5,0x80,0xd4,0x80,0x42,0x80,0x30,0x3a,0xff,0x60,0xeb,0x80,0xd0,0xbc,0x00,0x00,  //000021b0  蛟ヤ.B.0:.`..ミシ..
  1154:     0x03,0xff,0xe0,0x88,0xe4,0x88,0xe5,0x80,0xd4,0x80,0x48,0xe7,0x60,0x00,0x43,0xfa,  //000021c0  ..煦艾蛟ヤ.H軈.C.
  1155:     0x01,0x28,0x26,0x3c,0x00,0x00,0x01,0x00,0x61,0x50,0x4c,0xdf,0x00,0x06,0x4a,0x00,  //000021d0  .(&<....aPL゚..J.
  1156:     0x66,0x56,0x43,0xfa,0x01,0x14,0x0c,0x59,0x48,0x55,0x66,0x56,0x54,0x89,0x0c,0x99,  //000021e0  fVC....YHUfVT...
  1157:     0x00,0x00,0x68,0x00,0x66,0x56,0x2f,0x19,0x26,0x19,0xd6,0x99,0x2f,0x03,0x2f,0x19,  //000021f0  ..h.fV/.&.ヨ././.
  1158:     0x22,0x7c,0x00,0x00,0x67,0xc0,0xd6,0xbc,0x00,0x00,0x00,0x40,0x61,0x1c,0x22,0x1f,  //00002200  "|..gタヨシ...@a.".
  1159:     0x24,0x1f,0x22,0x5f,0x4a,0x00,0x66,0x20,0x41,0xf9,0x00,0x00,0x68,0x00,0xd1,0xc2,  //00002210  $."_J.f A...h.ムツ
  1160:     0x53,0x81,0x65,0x04,0x42,0x18,0x60,0xf8,0x4e,0xd1,0x48,0xe7,0x78,0x40,0x70,0x46,  //00002220  S‘.B.`.NムH輾@pF
  1161:     0x4e,0x4f,0x4c,0xdf,0x02,0x1e,0x4e,0x75,0x43,0xfa,0x00,0x48,0x61,0x18,0x60,0x00,  //00002230  NOL゚..NuC..Ha.`.
  1162:     0xff,0x5c,0x43,0xfa,0x00,0x5d,0x61,0x0e,0x60,0x00,0xff,0x52,0x43,0xfa,0x00,0x75,  //00002240  .\C..]a.`..RC..u
  1163:     0x61,0x04,0x60,0x00,0xff,0x48,0x70,0x21,0x4e,0x4f,0x4e,0x75,0x1a,0x00,0x1b,0x5b,  //00002250  a.`..Hp!NONu...[
  1164:     0x31,0x36,0x3b,0x33,0x35,0x48,0x48,0x75,0x6d,0x61,0x6e,0x2e,0x73,0x79,0x73,0x20,  //00002260  16;35HHuman.sys 
  1165:     0x82,0xaa,0x20,0x8c,0xa9,0x82,0xc2,0x82,0xa9,0x82,0xe8,0x82,0xdc,0x82,0xb9,0x82,  //00002270  が 見つかりません
  1166:     0xf1,0x00,0x1b,0x5b,0x31,0x36,0x3b,0x33,0x38,0x48,0x83,0x66,0x83,0x42,0x83,0x58,  //00002280   ..[16;38Hディス
  1167:     0x83,0x4e,0x82,0xaa,0x81,0x40,0x93,0xc7,0x82,0xdf,0x82,0xdc,0x82,0xb9,0x82,0xf1,  //00002290  クが 読めません
  1168:     0x00,0x1b,0x5b,0x31,0x36,0x3b,0x33,0x36,0x48,0x48,0x75,0x6d,0x61,0x6e,0x2e,0x73,  //000022a0  ..[16;36HHuman.s
  1169:     0x79,0x73,0x20,0x82,0xaa,0x20,0x89,0xf3,0x82,0xea,0x82,0xc4,0x82,0xa2,0x82,0xdc,  //000022b0  ys が 壊れていま
  1170:     0x82,0xb7,0x00,0x1b,0x5b,0x31,0x36,0x3b,0x33,0x33,0x48,0x48,0x75,0x6d,0x61,0x6e,  //000022c0  す..[16;33HHuman
  1171:     0x2e,0x73,0x79,0x73,0x20,0x82,0xcc,0x20,0x83,0x41,0x83,0x68,0x83,0x8c,0x83,0x58,  //000022d0  .sys の アドレス
  1172:     0x82,0xaa,0x88,0xd9,0x8f,0xed,0x82,0xc5,0x82,0xb7,0x00,0x68,0x75,0x6d,0x61,0x6e,  //000022e0  が異常です.human
  1173:     0x20,0x20,0x20,0x73,0x79,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000022f0     sys..........
  1174:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002300  ................
  1175:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002310  ................
  1176:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002320  ................
  1177:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002330  ................
  1178:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002340  ................
  1179:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002350  ................
  1180:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002360  ................
  1181:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002370  ................
  1182:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002380  ................
  1183:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002390  ................
  1184:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000023a0  ................
  1185:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000023b0  ................
  1186:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000023c0  ................
  1187:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000023d0  ................
  1188:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000023e0  ................
  1189:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000023f0  ................
  1190:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002400  ................
  1191:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002410  ................
  1192:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002420  ................
  1193:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002430  ................
  1194:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002440  ................
  1195:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002450  ................
  1196:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002460  ................
  1197:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002470  ................
  1198:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002480  ................
  1199:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //00002490  ................
  1200:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000024a0  ................
  1201:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000024b0  ................
  1202:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000024c0  ................
  1203:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000024d0  ................
  1204:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000024e0  ................
  1205:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  //000024f0  ................
  1206:   };
  1207: */
  1208:   //  perl misc/itob.pl xeij/HDC.java HDC_PARTITION_IPL
  1209:   public static final byte[] HDC_PARTITION_IPL = "` Hudson soft 2.00\4\0\1\2\0\1\2\0\'r\370\24\0\0\0\0O\372\377\334C\372\0014a\0\1* <\0\0\0\216NO\22\0\341AB\202\24:\377\337B\200\20:\377\321\304\300B\2000:\377\312\324\200\345\202\324\272\377\312&<\0\0\4\0C\372\1\232a\0\0\310J\0f\0\0\320C\372\1\214<<\0\37$IG\372\1u~\n\20\32\200<\0 \260\33f\6Q\317\377\364`\24\323\374\0\0\0 Q\316\377\340C\372\0\310a\0\0\274`\376B\2000)\0\32\341XU@B\207\36:\377h\300\307\345\200\324\200B\2000:\377`\353\200\320\274\0\0\3\377\340\210\344\210\345\200\324\200H\347`\0C\372\1(&<\0\0\1\0aPL\337\0\6J\0fVC\372\1\24\fYHUfVT\211\f\231\0\0h\0fV/\31&\31\326\231/\3/\31\"|\0\0g\300\326\274\0\0\0@a\34\"\37$\37\"_J\0f A\371\0\0h\0\321\302S\201e\4B\30`\370N\321H\347x@pFNOL\337\2\36NuC\372\0Ha\30`\0\377\\C\372\0]a\16`\0\377RC\372\0ua\4`\0\377Hp!NONu\32\0\33[16;35HHuman.sys \202\252 \214\251\202\302\202\251\202\350\202\334\202\271\202\361\0\33[16;38H\203f\203B\203X\203N\202\252\201@\223\307\202\337\202\334\202\271\202\361\0\33[16;36HHuman.sys \202\252 \211\363\202\352\202\304\202\242\202\334\202\267\0\33[16;33HHuman.sys \202\314 \203A\203h\203\214\203X\202\252\210\331\217\355\202\305\202\267\0human   sys\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0".getBytes (XEiJ.ISO_8859_1);
  1210: 
  1211: 
  1212: 
  1213:   //========================================================================================
  1214:   //$$HDU SASI HDユニット
  1215:   //  SASIハードディスクのユニット
  1216:   public static class HDUnit extends AbstractUnit {
  1217: 
  1218:     public HDMedia hduMedia;  //メディアの種類
  1219:     public byte[] hduImage;  //ディスクイメージ
  1220:     public boolean hduWritten;  //true=書き込みがあった
  1221: 
  1222:     //new HDUnit (number)
  1223:     //  コンストラクタ
  1224:     public HDUnit (int number) {
  1225:       super (number);
  1226:       hduImage = null;
  1227:       hduWritten = false;
  1228:     }
  1229: 
  1230:     //hduTini ()
  1231:     //  後始末
  1232:     //  イメージファイルに書き出す
  1233:     public void hduTini () {
  1234:       if (abuInserted) {
  1235:         hduFlush ();
  1236:       }
  1237:     }  //hduTini()
  1238: 
  1239:     //success = unit.hduFlush ()
  1240:     //  イメージファイルに書き出す
  1241:     public boolean hduFlush () {
  1242:       if (!hduWritten) {  //書き込みがない
  1243:         return true;
  1244:       }
  1245:       if (abuWriteProtected) {  //書き込みが許可されていない
  1246:         return false;
  1247:       }
  1248:       if (!XEiJ.rscPutFile (abuPath, hduImage, 0, (int) hduMedia.humDiskEndByte)) {
  1249:         return false;
  1250:       }
  1251:       hduWritten = false;
  1252:       return true;
  1253:     }  //hduFlush()
  1254: 
  1255:     //unit.connect (disconnectable)
  1256:     //  接続する
  1257:     @Override protected void connect (boolean disconnectable) {
  1258:       super.connect (disconnectable);
  1259:       hduImage = new byte[HDMedia.HDM_MAX_BYTES_PER_DISK];
  1260:       hduWritten = false;
  1261:     }
  1262: 
  1263:     //unit.disconnect ()
  1264:     //  切り離す
  1265:     @Override protected void disconnect () {
  1266:       super.disconnect ();
  1267:       hduImage = null;
  1268:     }
  1269: 
  1270:     //success = unit.eject ()
  1271:     //  イジェクトする
  1272:     @Override protected boolean eject () {
  1273:       if (!hduFlush ()) {  //イメージファイルに書き出す
  1274:         return false;
  1275:       }
  1276:       String path = abuPath;  //イジェクトされたイメージファイルのパス。super.eject()を呼び出す前にコピーすること
  1277:       if (!super.eject ()) {  //イジェクトする
  1278:         return false;
  1279:       }
  1280:       if (hduMedia != null) {  //挿入されていたとき
  1281:         hdcAddHistory (new File (path).getAbsoluteFile ());
  1282:         System.out.println (Multilingual.mlnJapanese ?
  1283:                             path + " を sa" + abuNumber + " から切り離しました" :
  1284:                             path + " was removed from sa" + abuNumber);
  1285:       }
  1286:       hduMedia = null;
  1287:       //hdcHDMaxを更新する
  1288:       if (hdcHDMax == abuNumber - 1) {
  1289:         int u = abuNumber - 1;
  1290:         while (u >= 0 && !hdcUnitArray[u].abuInserted) {  //挿入されている最後のユニットまで遡る
  1291:           u--;
  1292:         }
  1293:         hdcHDMax = u + 1;
  1294:       }
  1295:       return true;
  1296:     }
  1297: 
  1298:     //success = unit.open ()
  1299:     //  開くダイアログを開く
  1300:     @Override protected boolean open () {
  1301:       if (!super.open ()) {
  1302:         return false;
  1303:       }
  1304:       hdcOpenUnit = abuNumber;
  1305:       if (hdcOpenDialog == null) {
  1306:         hdcOpenDialog = new OpenDialog ();
  1307:         hdcOpenDialog.setReadOnly (Settings.sgsGetOnOff ("sareadonly"));
  1308:         hdcOpenDialog.setReboot (Settings.sgsGetOnOff ("saappreboot"));
  1309:         for (File[] files : hdcOpenHistory) {
  1310:           hdcOpenDialog.addHistory (files);
  1311:         }
  1312:         hdcOpenHistory.clear ();
  1313:       }
  1314:       hdcOpenDialog.rescanCurrentDirectory ();  //挿入されているファイルが変わると選択できるファイルも変わるのでリストを作り直す
  1315:       XEiJ.pnlExitFullScreen (true);
  1316:       hdcOpenDialog.setVisible (true);
  1317:       return true;
  1318:     }  //unit.open()
  1319: 
  1320:     //success = unit.insert (path, writeProtected)
  1321:     //  挿入する
  1322:     @Override protected boolean insert (String path, boolean writeProtected) {
  1323:       if (hdcIsInserted (path)) {  //既に挿入されている
  1324:         return false;
  1325:       }
  1326:       if (!super.insert (path, writeProtected)) {  //挿入できなかった
  1327:         return false;
  1328:       }
  1329:       //hdcHDMaxを更新する
  1330:       if (hdcHDMax <= abuNumber) {
  1331:         hdcHDMax = abuNumber + 1;
  1332:       }
  1333:       return true;
  1334:     }  //unit.insert(String)
  1335: 
  1336:     //loaded = unit.load (path)
  1337:     //  読み込む
  1338:     @Override protected boolean load (String path) {
  1339:       hduMedia = HDMedia.hdmPathToMedia (path, hduImage);
  1340:       if (hduMedia == null) {  //読み込めない
  1341:         return false;
  1342:       }
  1343:       hduWritten = false;
  1344:       hdcAddHistory (new File (path).getAbsoluteFile ());
  1345:       System.out.println (Multilingual.mlnJapanese ?
  1346:                           path + " を sa" + abuNumber + " に接続しました" :
  1347:                           path + " was connected to sa" + abuNumber);
  1348:       return true;
  1349:     }
  1350: 
  1351:   }  //class HDUnit
  1352: 
  1353: 
  1354: 
  1355: }  //class HDC
  1356: 
  1357: 
  1358: