SRAM.java
     1: //========================================================================================
     2: //  SRAM.java
     3: //    en:SRAM
     4: //    ja:SRAM
     5: //  Copyright (C) 2003-2025 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: package xeij;
    14: 
    15: import java.awt.event.*;  //ActionEvent,ActionListener
    16: import java.io.*;  //File
    17: import java.util.*;  //Arrays
    18: import javax.swing.*;  //JMenu,JRadioButtonMenuItem
    19: 
    20: public class SRAM {
    21: 
    22:   public static int smrSramSizeRequest;  //SRAMのサイズ。16384,32768,65536のいずれか
    23:   public static int smrSramCurrentSize;  //現在のSRAMのサイズ。16384,32768,65536のいずれか
    24: 
    25:   public static String smrSramName;  //SRAMイメージファイル名
    26: 
    27:   public static int smrBootDevice;  //起動デバイス。0x00ed0018。0x0000=STD,0x9070~0x9370=FDn,0x8000~0x8f00=HDn,0xa000=ROM,0xb000=RAM,-1=設定しない
    28:   public static int smrROMBootHandle;  //ROM起動ハンドル。0x00ed000c。-1=設定しない
    29:   public static int smrRAMBootAddress;  //RAM起動アドレス。0x00ed0010。-1=設定しない
    30: 
    31:   public static int smrRepeatDelay;  //リピート開始。0x00ed003a。-1=設定しない,0..15=200+100*n(ms)
    32:   public static int smrRepeatInterval;  //リピート間隔。0x00ed003b。-1=設定しない,0..15=30+5*n^2(ms)
    33:   public static boolean smrWriteEnableOn;  //true=SRAM書き込み可
    34: 
    35:   //-romdb
    36:   public static int smrRomdbFlag;  //ROMデバッガ起動フラグ。0x00ed0058。-1=設定しない,0=OFF,255=AUX,1=CON(IPLROM 1.6のみ)
    37: 
    38:   //起動時のキャッシュモード
    39:   public static int smrCacheMode;
    40: 
    41:   //起動音
    42:   public static int smrStupsndMode;
    43: 
    44:   //-setmemorysize
    45:   public static boolean smrModifyMemorySizeOn;  //SRAMにあるメモリサイズを修正する
    46: 
    47:   //-srambuserror
    48:   public static boolean smrSRAMBusErrorOn;  //SRAMへの書き込み時のバスエラー
    49: 
    50:   public static JMenu smrRepeatDelayMenu;  //リピート開始メニュー
    51:   public static JMenu smrRepeatIntervalMenu;  //リピート間隔メニュー
    52:   public static JMenu smrRomdbMenu;  //ROMデバッガ起動フラグメニュー
    53:   public static JMenu smrCacheMenu;  //キャッシュメニュー
    54:   public static JMenu smrStupsndMenu;  //起動音
    55:   public static JMenuItem smrModifyMemorySizeMenuItem;  //メモリサイズ修正
    56:   public static JMenu smrMenu;  //SRAMメニュー
    57:   public static JMenu smrBootMenu;  //起動デバイスメニュー
    58:   public static JRadioButtonMenuItem smrSTDMenuItem;
    59: 
    60:   //smrInit ()
    61:   //  SRAMを初期化する
    62:   public static void smrInit () {
    63: 
    64:     //-sramsize
    65:     int sizeKB = Settings.sgsGetInt ("sramsize");  //SRAMのサイズ
    66:     smrSramSizeRequest = (sizeKB == 16 ||
    67:                           sizeKB == 32 ||
    68:                           sizeKB == 64 ? sizeKB << 10 : 16 << 10);
    69:     smrSramCurrentSize = smrSramSizeRequest;
    70:     System.out.printf (Multilingual.mlnJapanese ?
    71:                        "SRAM のサイズは %dKB です\n" :
    72:                        "SRAM size is %dKB\n",
    73:                        smrSramSizeRequest >> 10);
    74: 
    75:     boolean initialized = false;
    76: 
    77:     //-sram
    78:     smrSramName = "";
    79:     if (!initialized) {
    80:       smrSramName = Settings.sgsGetString ("sram");  //SRAMイメージファイル名
    81:       if (smrSramName.length () != 0) {
    82:         byte[] array = XEiJ.rscGetFile (smrSramName, smrSramSizeRequest);
    83:         if (array != null) {
    84:           System.arraycopy (array, 0, MainMemory.mmrM8, 0x00ed0000, smrSramSizeRequest);
    85:           if (smrSramSizeRequest < 64 << 10) {
    86:             Arrays.fill (MainMemory.mmrM8, 0x00ed0000 + smrSramSizeRequest, 0x00ed0000 + (64 << 10), (byte) 0);  //範囲外をゼロクリアする
    87:           }
    88:           initialized = true;
    89:         }
    90:       }
    91:     }
    92: 
    93:     //-sramdata
    94:     //  マジックの有無に関係なく復元する
    95:     if (!initialized) {
    96:       byte[] array = Settings.sgsGetData ("sramdata");  //SRAMの内容(gzip+base64)
    97:       if (array.length != 0) {  //復元するデータがある
    98:         System.out.println (Multilingual.mlnJapanese ?
    99:                             "SRAM のデータを復元します" :
   100:                             "SRAM data is restored");
   101:         System.arraycopy (array, 0, MainMemory.mmrM8, 0x00ed0000, Math.min (array.length, smrSramSizeRequest));
   102:         if (array.length < smrSramSizeRequest) {
   103:           Arrays.fill (MainMemory.mmrM8, 0x00ed0000 + array.length, 0x00ed0000 + smrSramSizeRequest, (byte) 0);  //復元されなかった部分をゼロクリアする
   104:         }
   105:         if (smrSramSizeRequest < 64 << 10) {
   106:           Arrays.fill (MainMemory.mmrM8, 0x00ed0000 + smrSramSizeRequest, 0x00ed0000 + (64 << 10), (byte) 0);  //範囲外をゼロクリアする
   107:         }
   108:         initialized = true;
   109:       }
   110:     }
   111: 
   112:     if (!initialized) {
   113:       System.out.println (Multilingual.mlnJapanese ?
   114:                           "SRAM をゼロクリアします" :
   115:                           "SRAM is zero-cleared");
   116:       Arrays.fill (MainMemory.mmrM8, 0x00ed0000, 0x00ed0000 + (64 << 10), (byte) 0);  //ゼロクリアする
   117:       initialized = true;
   118:     }
   119: 
   120:     //-keydly
   121:     int repeatDelay = Settings.sgsGetInt ("keydly");
   122:     smrRepeatDelay = -1 <= repeatDelay && repeatDelay <= 15 ? repeatDelay : -1;
   123: 
   124:     //-keyrep
   125:     int repeatInterval = Settings.sgsGetInt ("keyrep");
   126:     smrRepeatInterval = -1 <= repeatInterval && repeatInterval <= 15 ? repeatInterval : -1;
   127: 
   128:     //-romdb
   129:     {
   130:       String s = Settings.sgsGetString ("romdb").toLowerCase ();
   131:       smrRomdbFlag = (s.equals ("off") ? 0 :
   132:                       s.equals ("on") || s.equals ("aux") ? 255 :
   133:                       s.equals ("con") ? 1 :
   134:                       -1);
   135:     }
   136: 
   137:     //起動時のキャッシュモード
   138:     smrCacheMode = smrStringToCache (Settings.sgsGetString ("cache"));
   139: 
   140:     //起動音
   141:     smrStupsndMode = smrStringToStupsnd (Settings.sgsGetString ("stupsnd"));
   142: 
   143:     //-modifymemorysize
   144:     smrModifyMemorySizeOn = Settings.sgsGetOnOff ("modifymemorysize");
   145: 
   146:     //-srambuserror
   147:     smrSRAMBusErrorOn = Settings.sgsGetOnOff ("srambuserror");
   148: 
   149:     //-boot
   150:     smrParseBootDevice (Settings.sgsGetString ("boot"));
   151: 
   152:   }  //smrInit
   153: 
   154:   //smrTini ()
   155:   //  SRAMの後始末
   156:   public static void smrTini () {
   157: 
   158:     //-sramsize
   159:     Settings.sgsPutInt ("sramsize", smrSramSizeRequest >> 10);
   160: 
   161:     //-sram
   162:     Settings.sgsPutString ("sram", smrSramName);
   163: 
   164:     //-sramdata
   165:     //  マジックの有無に関係なく保存する
   166:     //  常に64KB保存する
   167:     Settings.sgsPutData ("sramdata", MainMemory.mmrM8, 0x00ed0000, 64 << 10);
   168: 
   169:     //-keydly
   170:     Settings.sgsPutInt ("keydly", smrRepeatDelay);  //リピート開始
   171: 
   172:     //-keyrep
   173:     Settings.sgsPutInt ("keyrep", smrRepeatInterval);  //リピート間隔
   174: 
   175:     //-romdb
   176:     Settings.sgsPutString ("romdb",
   177:                            smrRomdbFlag == 0 ? "off" :
   178:                            smrRomdbFlag == 255 ? "aux" :
   179:                            smrRomdbFlag == 1 ? "con" :
   180:                            "");
   181: 
   182:     //起動時のキャッシュモード
   183:     Settings.sgsPutString ("cache", smrCacheToString (smrCacheMode));
   184: 
   185:     //起動音
   186:     Settings.sgsPutString ("stupsnd", smrStupsndToString (smrStupsndMode));
   187: 
   188:     //-modifymemorysize
   189:     Settings.sgsPutOnOff ("modifymemorysize", smrModifyMemorySizeOn);
   190: 
   191:     //-srambuserror
   192:     Settings.sgsPutOnOff ("srambuserror", smrSRAMBusErrorOn);
   193: 
   194:     //-boot
   195:     Settings.sgsPutString ("boot",
   196:                            smrBootDevice == -1 ? "default" :
   197:                            smrBootDevice == 0x0000 ? "std" :
   198:                            (smrBootDevice & 0xf000) == 0x9000 ? "fd" + (smrBootDevice >> 8 & 3) :
   199:                            (smrBootDevice & 0xf000) == 0x8000 ? "hd" + (smrBootDevice >> 8 & 15) :
   200:                            smrBootDevice == 0xa000 ?
   201:                            (smrROMBootHandle & ~(7 << 2)) == SPC.SPC_HANDLE_EX ? "sc" + (smrROMBootHandle >> 2 & 7) :
   202:                            (smrROMBootHandle & ~(7 << 2)) == SPC.SPC_HANDLE_IN ? "sc" + (smrROMBootHandle >> 2 & 7) :
   203:                            smrROMBootHandle == HFS.HFS_BOOT_HANDLE ? "hf" + HFS.hfsBootUnit :
   204:                            String.format ("rom$%08X", smrROMBootHandle) :
   205:                            smrBootDevice == 0xb000 ? String.format ("ram$%08X", smrRAMBootAddress) :
   206:                            "");
   207: 
   208:   }
   209: 
   210:   //smrMakeMenu ()
   211:   //  mnbMakeMenuより前
   212:   //  mpuMakeMenuより前
   213:   public static void smrMakeMenu () {
   214: 
   215:     //アクションリスナー
   216:     ActionListener listener = new ActionListener () {
   217:       @Override public void actionPerformed (ActionEvent ae) {
   218:         Object source = ae.getSource ();
   219:         String command = ae.getActionCommand ();
   220:         switch (command) {
   221:           //メモリサイズ修正
   222:         case "Modify the memory size in SRAM":  //SRAM にあるメモリサイズを修正する
   223:           smrModifyMemorySizeOn = ((JCheckBoxMenuItem) source).isSelected ();
   224:           break;
   225:           //SRAMメニュー
   226:         case "Zero-clear":  //SRAM をゼロクリア
   227:           smrClear ();
   228:           break;
   229:         case "Import":  //SRAM をインポート
   230:           smrLoad ();
   231:           break;
   232:         case "Export":  //SRAM をエクスポート
   233:           smrSave ();
   234:           break;
   235:         case "16KB":
   236:           smrSramSizeRequest = 16384;
   237:           break;
   238:         case "32KB":
   239:           smrSramSizeRequest = 32768;
   240:           break;
   241:         case "64KB":
   242:           smrSramSizeRequest = 65536;
   243:           break;
   244:         case "Bus error when writing to SRAM":  //SRAM への書き込み時のバスエラー
   245:           smrSRAMBusErrorOn = ((JCheckBoxMenuItem) source).isSelected ();
   246:           break;
   247:         default:
   248:           System.out.println ("unknown action command " + command);
   249:         }
   250:       }
   251:     };
   252: 
   253:     //リピート開始メニュー
   254:     ActionListener delayListener = new ActionListener () {
   255:       @Override public void actionPerformed (ActionEvent ae) {
   256:         String command = ae.getActionCommand ();
   257:         switch (command) {
   258:         case "Follow settings in SWITCH.X":  //SWITCH.X の設定に従う
   259:           smrRepeatDelay = -1;
   260:           Keyboard.kbdSetRepeatDelay (MainMemory.mmrRbs (0x00ed003a));
   261:           break;
   262:         case (200 + 100 *  0) + "ms":
   263:         case (200 + 100 *  1) + "ms":
   264:         case (200 + 100 *  2) + "ms":
   265:         case (200 + 100 *  3) + "ms":
   266:         case (200 + 100 *  4) + "ms":
   267:         case (200 + 100 *  5) + "ms":
   268:         case (200 + 100 *  6) + "ms":
   269:         case (200 + 100 *  7) + "ms":
   270:         case (200 + 100 *  8) + "ms":
   271:         case (200 + 100 *  9) + "ms":
   272:         case (200 + 100 * 10) + "ms":
   273:         case (200 + 100 * 11) + "ms":
   274:         case (200 + 100 * 12) + "ms":
   275:         case (200 + 100 * 13) + "ms":
   276:         case (200 + 100 * 14) + "ms":
   277:         case (200 + 100 * 15) + "ms":
   278:           {
   279:             int ms = Integer.parseInt (command.substring (0, command.length () - 2));  //200..1700
   280:             //perl optdiv.pl 1500 100
   281:             //  x/100==x*1311>>>17 (0<=x<=4698) [1500*1311==1966500]
   282:             smrRepeatDelay = (ms - 200) * 1311 >>> 17;  //0..15
   283:             Keyboard.kbdSetRepeatDelay (smrRepeatDelay);
   284:             MainMemory.mmrWb (0x00ed003a, smrRepeatDelay);
   285:           }
   286:           break;
   287:         default:
   288:           System.out.println ("unknown action command " + command);
   289:         }
   290:       }
   291:     };
   292:     ButtonGroup delayGroup = new ButtonGroup ();
   293:     smrRepeatDelayMenu =
   294:       Multilingual.mlnText (
   295:         ComponentFactory.createMenu (
   296:           "Repeat delay",
   297:           Multilingual.mlnText (
   298:             ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay == -1, "Follow settings in SWITCH.X", delayListener),
   299:             "ja", "SWITCH.X の設定に従う"),
   300:           ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay ==  0, (200 + 100 *  0) + "ms", delayListener),
   301:           ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay ==  1, (200 + 100 *  1) + "ms", delayListener),
   302:           ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay ==  2, (200 + 100 *  2) + "ms", delayListener),
   303:           ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay ==  3, (200 + 100 *  3) + "ms", delayListener),
   304:           ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay ==  4, (200 + 100 *  4) + "ms", delayListener),
   305:           ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay ==  5, (200 + 100 *  5) + "ms", delayListener),
   306:           ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay ==  6, (200 + 100 *  6) + "ms", delayListener),
   307:           ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay ==  7, (200 + 100 *  7) + "ms", delayListener),
   308:           ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay ==  8, (200 + 100 *  8) + "ms", delayListener),
   309:           ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay ==  9, (200 + 100 *  9) + "ms", delayListener),
   310:           ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay == 10, (200 + 100 * 10) + "ms", delayListener),
   311:           ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay == 11, (200 + 100 * 11) + "ms", delayListener),
   312:           ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay == 12, (200 + 100 * 12) + "ms", delayListener),
   313:           ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay == 13, (200 + 100 * 13) + "ms", delayListener),
   314:           ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay == 14, (200 + 100 * 14) + "ms", delayListener),
   315:           ComponentFactory.createRadioButtonMenuItem (delayGroup, smrRepeatDelay == 15, (200 + 100 * 15) + "ms", delayListener)
   316:           ),
   317:         "ja", "リピート開始");
   318: 
   319:     //リピート間隔メニュー
   320:     ActionListener intervalListener = new ActionListener () {
   321:       @Override public void actionPerformed (ActionEvent ae) {
   322:         String command = ae.getActionCommand ();
   323:         switch (command) {
   324:         case "Follow settings in SWITCH.X":  //SWITCH.X の設定に従う
   325:           smrRepeatInterval =  -1;
   326:           Keyboard.kbdSetRepeatInterval (MainMemory.mmrRbs (0x00ed003b));
   327:           break;
   328:         case (30 + 5 *  0 *  0) + "ms":
   329:         case (30 + 5 *  1 *  1) + "ms":
   330:         case (30 + 5 *  2 *  2) + "ms":
   331:         case (30 + 5 *  3 *  3) + "ms":
   332:         case (30 + 5 *  4 *  4) + "ms":
   333:         case (30 + 5 *  5 *  5) + "ms":
   334:         case (30 + 5 *  6 *  6) + "ms":
   335:         case (30 + 5 *  7 *  7) + "ms":
   336:         case (30 + 5 *  8 *  8) + "ms":
   337:         case (30 + 5 *  9 *  9) + "ms":
   338:         case (30 + 5 * 10 * 10) + "ms":
   339:         case (30 + 5 * 11 * 11) + "ms":
   340:         case (30 + 5 * 12 * 12) + "ms":
   341:         case (30 + 5 * 13 * 13) + "ms":
   342:         case (30 + 5 * 14 * 14) + "ms":
   343:         case (30 + 5 * 15 * 15) + "ms":
   344:           {
   345:             int ms = Integer.parseInt (command.substring (0, command.length () - 2));  //30..1155
   346:             //perl optdiv.pl 1125 5
   347:             //  x/5==x*1639>>>13 (0<=x<=2733) [1125*1639==1843875]
   348:             smrRepeatInterval = (int) Math.sqrt ((double) ((ms - 30) * 1639 >>> 13));  //0..15
   349:             Keyboard.kbdSetRepeatInterval (smrRepeatInterval);
   350:             MainMemory.mmrWb (0x00ed003b, smrRepeatInterval);
   351:           }
   352:           break;
   353:         default:
   354:           System.out.println ("unknown action command " + command);
   355:         }
   356:       }
   357:     };
   358:     ButtonGroup intervalGroup = new ButtonGroup ();
   359:     smrRepeatIntervalMenu =
   360:       Multilingual.mlnText (
   361:         ComponentFactory.createMenu (
   362:           "Repeat interval",
   363:           Multilingual.mlnText (
   364:             ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval == -1, "Follow settings in SWITCH.X", intervalListener),
   365:             "ja", "SWITCH.X の設定に従う"),
   366:           ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval ==  0, (30 + 5 *  0 *  0) + "ms", intervalListener),
   367:           ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval ==  1, (30 + 5 *  1 *  1) + "ms", intervalListener),
   368:           ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval ==  2, (30 + 5 *  2 *  2) + "ms", intervalListener),
   369:           ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval ==  3, (30 + 5 *  3 *  3) + "ms", intervalListener),
   370:           ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval ==  4, (30 + 5 *  4 *  4) + "ms", intervalListener),
   371:           ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval ==  5, (30 + 5 *  5 *  5) + "ms", intervalListener),
   372:           ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval ==  6, (30 + 5 *  6 *  6) + "ms", intervalListener),
   373:           ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval ==  7, (30 + 5 *  7 *  7) + "ms", intervalListener),
   374:           ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval ==  8, (30 + 5 *  8 *  8) + "ms", intervalListener),
   375:           ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval ==  9, (30 + 5 *  9 *  9) + "ms", intervalListener),
   376:           ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval == 10, (30 + 5 * 10 * 10) + "ms", intervalListener),
   377:           ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval == 11, (30 + 5 * 11 * 11) + "ms", intervalListener),
   378:           ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval == 12, (30 + 5 * 12 * 12) + "ms", intervalListener),
   379:           ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval == 13, (30 + 5 * 13 * 13) + "ms", intervalListener),
   380:           ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval == 14, (30 + 5 * 14 * 14) + "ms", intervalListener),
   381:           ComponentFactory.createRadioButtonMenuItem (intervalGroup, smrRepeatInterval == 15, (30 + 5 * 15 * 15) + "ms", intervalListener)
   382:           ),
   383:         "ja", "リピート間隔");
   384: 
   385:     //ROMデバッガ起動フラグメニュー
   386:     ActionListener romdbListener = new ActionListener () {
   387:       @Override public void actionPerformed (ActionEvent ae) {
   388:         String command = ae.getActionCommand ();
   389:         switch (command) {
   390:         case "Follow settings in SWITCH.X":  //SWITCH.X の設定に従う
   391:           smrRomdbFlag = -1;
   392:           break;
   393:         case "OFF":
   394:           smrRomdbFlag = 0;
   395:           break;
   396:         case "AUX":
   397:           smrRomdbFlag = 255;
   398:           break;
   399:         case "CON (when using IPLROM 1.6)":  //CON (IPLROM 1.6 使用時)
   400:           smrRomdbFlag = 1;
   401:           break;
   402:         default:
   403:           System.out.println ("unknown action command " + command);
   404:         }
   405:       }
   406:     };
   407:     ButtonGroup romdbGroup = new ButtonGroup ();
   408:     smrRomdbMenu =
   409:       Multilingual.mlnText (
   410:         ComponentFactory.createMenu (
   411:           "ROM debugger start flag",
   412:           Multilingual.mlnText (
   413:             ComponentFactory.createRadioButtonMenuItem (romdbGroup, smrRomdbFlag == -1, "Follow settings in SWITCH.X", romdbListener),
   414:             "ja", "SWITCH.X の設定に従う"),
   415:           ComponentFactory.createRadioButtonMenuItem (romdbGroup, smrRomdbFlag == 0, "OFF", romdbListener),
   416:           ComponentFactory.createRadioButtonMenuItem (romdbGroup, smrRomdbFlag == 255, "AUX", romdbListener),
   417:           Multilingual.mlnText (
   418:             ComponentFactory.createRadioButtonMenuItem (romdbGroup, smrRomdbFlag == 1, "CON (when using IPLROM 1.6)", romdbListener),
   419:             "ja", "CON (IPLROM 1.6 使用時)")
   420:           ),
   421:         "ja", "ROM デバッガ起動フラグ");
   422: 
   423:     //起動時のキャッシュモード
   424:     //  SRAM_CACHE  $00ED0090
   425:     //  cache
   426:     //    -1  none     CACHE.X の設定に従う
   427:     //     0  off-off  データキャッシュと命令キャッシュは無効
   428:     //     1  off-on   データキャッシュは無効、命令キャッシュは有効
   429:     //     2  on-off   データキャッシュは有効、命令キャッシュは無効
   430:     //     3  on-on    データキャッシュと命令キャッシュは有効
   431:     ActionListener cacheListener = new ActionListener () {
   432:       @Override public void actionPerformed (ActionEvent ae) {
   433:         String command = ae.getActionCommand ();
   434:         switch (command) {
   435:         case "Follow settings in CACHE.X":
   436:           smrCacheMode = -1;
   437:           break;
   438:         case "Disabled":
   439:           smrCacheMode = 0;
   440:           break;
   441:         case "Data cache disabled and instruction cache enabled":
   442:           smrCacheMode = 1;
   443:           break;
   444:         case "Data cache enabled and instruction cache disabled":
   445:           smrCacheMode = 2;
   446:           break;
   447:         case "Enabled":
   448:           smrCacheMode = 3;
   449:           break;
   450:         }
   451:       }
   452:     };
   453:     ButtonGroup cacheGroup = new ButtonGroup ();
   454:     smrCacheMenu =
   455:       Multilingual.mlnText (
   456:         ComponentFactory.createMenu (
   457:           "Cache mode at startup",
   458:           Multilingual.mlnText (
   459:             ComponentFactory.createRadioButtonMenuItem (
   460:               cacheGroup,
   461:               smrCacheMode == -1, "Follow settings in CACHE.X",
   462:               cacheListener),
   463:             "ja", "CACHE.X の設定に従う"),
   464:           Multilingual.mlnText (
   465:             ComponentFactory.createRadioButtonMenuItem (
   466:               cacheGroup,
   467:               smrCacheMode == 0, "Disabled",
   468:               cacheListener),
   469:             "ja", "無効"),
   470:           Multilingual.mlnText (
   471:             ComponentFactory.createRadioButtonMenuItem (
   472:               cacheGroup,
   473:               smrCacheMode == 1, "Data cache disabled and instruction cache enabled",
   474:               cacheListener),
   475:             "ja", "データキャッシュは無効、命令キャッシュは有効"),
   476:           Multilingual.mlnText (
   477:             ComponentFactory.createRadioButtonMenuItem (
   478:               cacheGroup,
   479:               smrCacheMode == 2, "Data cache enabled and instruction cache disabled",
   480:               cacheListener),
   481:             "ja", "データキャッシュは有効、命令キャッシュは無効"),
   482:           Multilingual.mlnText (
   483:             ComponentFactory.createRadioButtonMenuItem (
   484:               cacheGroup,
   485:               smrCacheMode == 3, "Enabled",
   486:               cacheListener),
   487:             "ja", "有効")
   488:           ),
   489:         "ja", "起動時のキャッシュモード");
   490: 
   491:     //起動音
   492:     //  SRAM_STARTUP_SOUND  $00ED0091
   493:     //  stupsnd
   494:     //    -1  none  stupsnd.x の設定に従う
   495:     //     0  off
   496:     //     1  on
   497:     //              12 o1c   28 o2c   44 o3c   60 o4c   76 o5c    92 o6c   108 o7c   124 o8c
   498:     //              13 o1c#  29 o2c#  45 o3c#  61 o4c#  77 o5c#   93 o6c#  109 o7c#  125 o8c#
   499:     //              14 o1d   30 o2d   46 o3d   62 o4d   78 o5d    94 o6d   110 o7d   126 o8d
   500:     //              16 o1d#  32 o2d#  48 o3d#  64 o4d#  80 o5d#   96 o6d#  112 o7d#
   501:     //              17 o1e   33 o2e   49 o3e   65 o4e   81 o5e    97 o6e   113 o7e
   502:     //     2  o0f   18 o1f   34 o2f   50 o3f   66 o4f   82 o5f    98 o6f   114 o7f
   503:     //     4  o0f#  20 o1f#  36 o2f#  52 o3f#  68 o4f#  84 o5f#  100 o6f#  116 o7f#
   504:     //     5  o0g   21 o1g   37 o2g   53 o3g   69 o4g   85 o5g   101 o6g   117 o7g
   505:     //     6  o0g#  22 o1g#  38 o2g#  54 o3g#  70 o4g#  86 o5g#  102 o6g#  118 o7g#
   506:     //     8  o0a   24 o1a   40 o2a   56 o3a   72 o4a   88 o5a   104 o6a   120 o7a
   507:     //     9  o0a#  25 o1a#  41 o2a#  57 o3a#  73 o4a#  89 o5a#  105 o6a#  121 o7a#
   508:     //    10  o0b   26 o1b   42 o2b   58 o3b   74 o4b   90 o5b   106 o6b   122 o7b
   509:     ActionListener stupsndListener = new ActionListener () {
   510:       @Override public void actionPerformed (ActionEvent ae) {
   511:         String command = ae.getActionCommand ();
   512:         switch (command) {
   513:         case "Follow settings in stupsnd.x":
   514:           smrStupsndMode = -1;
   515:           break;
   516:         case "Disabled":
   517:           smrStupsndMode = 0;
   518:           break;
   519:         case "Enabled (o5c)":
   520:           smrStupsndMode = 1;
   521:           break;
   522:         default:
   523:           smrStupsndMode = smrStringToStupsnd (command);
   524:         }
   525:       }
   526:     };
   527:     ButtonGroup stupsndGroup = new ButtonGroup ();
   528:     smrStupsndMenu =
   529:       Multilingual.mlnText (
   530:         ComponentFactory.createMenu (
   531:           "Startup sound",
   532:           Multilingual.mlnText (
   533:             ComponentFactory.createRadioButtonMenuItem (
   534:               stupsndGroup,
   535:               smrStupsndMode == -1, "Follow settings in stupsnd.x",
   536:               stupsndListener),
   537:             "ja", "stupsnd.x の設定に従う"),
   538:           Multilingual.mlnText (
   539:             ComponentFactory.createRadioButtonMenuItem (
   540:               stupsndGroup,
   541:               smrStupsndMode == 0, "Disabled",
   542:               stupsndListener),
   543:             "ja", "無効"),
   544:           Multilingual.mlnText (
   545:             ComponentFactory.createRadioButtonMenuItem (
   546:               stupsndGroup,
   547:               smrStupsndMode == 1, "Enabled (o5c)",
   548:               stupsndListener),
   549:             "ja", "有効 (o5c)")
   550:           ),
   551:         "ja", "起動音");
   552:     JMenu stupsndSubMenu = null;
   553:     for (int mode = 2; mode <= 126; mode++) {  //127は不可
   554:       if (mode % 4 == 3) {
   555:         continue;
   556:       }
   557:       if (mode == 2 || (mode + 4) % 16 == 0) {
   558:         stupsndSubMenu = ComponentFactory.createMenu ("o" + (mode + 4) / 16);
   559:         smrStupsndMenu.add (stupsndSubMenu);
   560:       }
   561:       stupsndSubMenu.add (
   562:         ComponentFactory.createRadioButtonMenuItem (
   563:           stupsndGroup,
   564:           smrStupsndMode == mode, smrStupsndToString (mode),
   565:           stupsndListener)
   566:         );
   567:     }
   568: 
   569:     //メモリサイズ修正
   570:     smrModifyMemorySizeMenuItem =
   571:       Multilingual.mlnText (
   572:         ComponentFactory.createCheckBoxMenuItem (smrModifyMemorySizeOn, "Modify the memory size in SRAM", listener),
   573:         "ja", "SRAM にあるメモリサイズを修正する");
   574: 
   575:     //SRAMメニュー
   576:     ButtonGroup sizeGroup = new ButtonGroup ();
   577:     smrMenu =
   578:       ComponentFactory.createMenu (
   579:         "SRAM",
   580:         Multilingual.mlnText (
   581:           ComponentFactory.createMenuItem ("Zero-clear", listener),
   582:           "ja", "ゼロクリア"),
   583:         Multilingual.mlnText (
   584:           ComponentFactory.createMenuItem ("Import", listener),
   585:           "ja", "インポート"),
   586:         Multilingual.mlnText (
   587:           ComponentFactory.createMenuItem ("Export", listener),
   588:           "ja", "エクスポート"),
   589:         ComponentFactory.createHorizontalSeparator (),
   590:         Multilingual.mlnText (
   591:           ComponentFactory.createRadioButtonMenuItem (sizeGroup, smrSramSizeRequest >> 10 == 16, "16KB", listener),
   592:           "ja", "16KB"),
   593:         Multilingual.mlnText (
   594:           ComponentFactory.createRadioButtonMenuItem (sizeGroup, smrSramSizeRequest >> 10 == 32, "32KB", listener),
   595:           "ja", "32KB"),
   596:         Multilingual.mlnText (
   597:           ComponentFactory.createRadioButtonMenuItem (sizeGroup, smrSramSizeRequest >> 10 == 64, "64KB", listener),
   598:           "ja", "64KB"),
   599:         ComponentFactory.createHorizontalSeparator (),
   600:         Multilingual.mlnText (
   601:           ComponentFactory.createCheckBoxMenuItem (smrSRAMBusErrorOn, "Bus error when writing to SRAM", listener),
   602:           "ja", "SRAM への書き込み時のバスエラー")
   603:         );
   604: 
   605:     //起動デバイスメニュー
   606:     ButtonGroup bootGroup = new ButtonGroup ();
   607:     ActionListener bootListener = new ActionListener () {
   608:       @Override public void actionPerformed (ActionEvent ae) {
   609:         String command = ae.getActionCommand ();
   610:         smrParseBootDevice (
   611:           command.startsWith ("FDD ") ? "fd" + command.substring (4) :
   612:           command.startsWith ("SASI ") ? "hd" + command.substring (5) :
   613:           command.startsWith ("SCSI ") ? "sc" + command.substring (5) :
   614:           command.startsWith ("HFS ") ? "hf" + command.substring (4) :
   615:           command.equals ("STD") ? "std" :
   616:           "default");
   617:         if (smrBootDevice != -1) {  //メニューで起動デバイスが既定以外に設定されたとき
   618:           XEiJ.mpuSavedBootDevice = -1;  //保存されている起動デバイスを消す
   619:           XEiJ.mpuSavedROMBootHandle = -1;
   620:         }
   621:       }
   622:     };
   623:     JMenu bootMenuFDD = ComponentFactory.createMenu ("FDD");
   624:     for (int u = 0; u < FDC.FDC_MAX_UNITS; u++) {
   625:       bootMenuFDD.add (ComponentFactory.createRadioButtonMenuItem (
   626:         bootGroup, smrBootDevice == 0x9070 + (u << 8),
   627:         "FDD " + u, bootListener));
   628:     }
   629:     JMenu bootMenuSASI = ComponentFactory.createMenu ("SASI");
   630:     for (int u = 0; u < 16; u++) {
   631:       bootMenuSASI.add (ComponentFactory.createRadioButtonMenuItem (
   632:         bootGroup, smrBootDevice == 0x8000 + (u << 8),
   633:         "SASI " + u, bootListener));
   634:     }
   635:     JMenu bootMenuSCSI = ComponentFactory.createMenu ("SCSI");
   636:     for (int u = 0; u < 8; u++) {
   637:       bootMenuSCSI.add (ComponentFactory.createRadioButtonMenuItem (
   638:         bootGroup, smrBootDevice == 0xa000 && (smrROMBootHandle == SPC.SPC_HANDLE_EX + (u << 2) ||
   639:                                                smrROMBootHandle == SPC.SPC_HANDLE_IN + (u << 2)), "SCSI " + u, bootListener));
   640:     }
   641:     JMenu bootMenuHFS = ComponentFactory.createMenu ("HFS");
   642:     for (int u = 0; u < HFS.HFS_MAX_UNITS; u++) {
   643:       bootMenuHFS.add (ComponentFactory.createRadioButtonMenuItem (
   644:         bootGroup, smrBootDevice == 0xa000 && smrROMBootHandle == HFS.HFS_BOOT_HANDLE && HFS.hfsBootUnit == u,
   645:         "HFS " + u, bootListener));
   646:     }
   647:     smrBootMenu =
   648:       Multilingual.mlnText (
   649:         ComponentFactory.createMenu (
   650:           "Boot device",
   651:           Multilingual.mlnText (
   652:             ComponentFactory.createRadioButtonMenuItem (bootGroup, smrBootDevice == -1, "Follow settings in SWITCH.X", bootListener),
   653:             "ja", "SWITCH.X の設定に従う"),
   654:           smrSTDMenuItem = ComponentFactory.createRadioButtonMenuItem (bootGroup, smrBootDevice == 0x0000, "STD", bootListener),
   655:           bootMenuFDD,
   656:           bootMenuSASI,
   657:           bootMenuSCSI,
   658:           bootMenuHFS
   659:           ),
   660:         "ja", "起動デバイス");
   661: 
   662:   }  //smrInit()
   663: 
   664:   //smrParseBootDevice ()
   665:   //  起動デバイスの設定を読み取る
   666:   public static void smrParseBootDevice (String boot) {
   667:     smrBootDevice = -1;  //起動デバイス
   668:     smrROMBootHandle = -1;  //ROM起動ハンドル
   669:     smrRAMBootAddress = -1;  //RAM起動アドレス
   670:     boot = boot.toLowerCase ();
   671:     if (boot.equals ("std")) {  //std
   672:       smrBootDevice = 0x0000;  //STD 起動
   673:     } else if (boot.startsWith ("fd")) {  //fdN
   674:       int u = XEiJ.fmtParseInt (boot, 2, 0, FDC.FDC_MAX_UNITS - 1, FDC.FDC_MAX_UNITS);  //起動ユニット番号
   675:       if (u < FDC.FDC_MAX_UNITS) {
   676:         smrBootDevice = 0x9070 + (u << 8);  //FDD起動
   677:       }
   678:     } else if (boot.startsWith ("hd")) {  //hdN
   679:       int u = XEiJ.fmtParseInt (boot, 2, 0, 15, 16);  //起動ユニット番号
   680:       if (u < 16) {
   681:         smrBootDevice = 0x8000 + (u << 8);  //SASI起動
   682:       }
   683:     } else if (boot.startsWith ("sc")) {  //scN
   684:       int u = XEiJ.fmtParseInt (boot, 2, 0, 7, 8);
   685:       if (u < 8) {
   686:         smrBootDevice = 0xa000;  //ROM起動
   687:         smrROMBootHandle = SPC.SPC_HANDLE_EX + ((u & 7) << 2);  //仮に拡張SCSI起動にしておく。リセットしたとき拡張SCSIがなければ内蔵SCSIに読み替えられる
   688:       }
   689:     } else if (boot.startsWith ("hf")) {  //hfN
   690:       int u = XEiJ.fmtParseInt (boot, 2, 0, HFS.HFS_MAX_UNITS - 1, HFS.HFS_MAX_UNITS);  //起動ユニット番号
   691:       if (u < HFS.HFS_MAX_UNITS) {
   692:         HFS.hfsBootUnit = u;
   693:         smrBootDevice = 0xa000;  //ROM起動
   694:         smrROMBootHandle = HFS.HFS_BOOT_HANDLE;  //IPL起動ハンドル
   695:       }
   696:     } else if (boot.startsWith ("rom$")) {  //rom$X
   697:       int handle = XEiJ.fmtParseIntRadix (boot, 3, 0, 0x00ffffff, 0x01000000, 16);  //起動ハンドル
   698:       if (handle < 0x01000000) {
   699:         smrBootDevice = 0xa000;  //ROM起動
   700:         smrROMBootHandle = handle;
   701:       }
   702:     } else if (boot.startsWith ("ram$")) {  //ram$X
   703:       int handle = XEiJ.fmtParseIntRadix (boot, 3, 0, 0x00ffffff, 0x01000000, 16);  //起動ハンドル
   704:       if (handle < 0x01000000) {
   705:         smrBootDevice = 0xb000;  //RAM起動
   706:         smrRAMBootAddress = handle;
   707:       }
   708:     }
   709:   }  //smrParseBootDevice(String)
   710: 
   711:   //smrReset ()
   712:   //  SRAMリセット
   713:   //  ここでROMも上書きする
   714:   //  ROMを初期化してから呼び出すこと
   715:   //  SPC.spcReset()よりも後であること
   716:   public static void smrReset () {
   717:     smrWriteEnableOn = false;
   718: 
   719:     //SRAMの容量を変更する
   720:     {
   721:       smrSramCurrentSize = smrSramSizeRequest;
   722:       XEiJ.busSuper (MemoryMappedDevice.MMD_SMR, 0x00ed0000, 0x00ed0000 + smrSramSizeRequest);  //SMR SRAM
   723:       if (smrSramSizeRequest < 65536) {
   724:         XEiJ.busSuper (MemoryMappedDevice.MMD_NUL, 0x00ed0000 + smrSramSizeRequest, 0x00ed0000 + 65536);  //空き
   725:       }
   726:       System.out.printf (Multilingual.mlnJapanese ?
   727:                          "SRAM の容量は %dKB ($%08X-$%08X) です\n" :
   728:                          "Capacity of SRAM is %dKB ($%08X-$%08X)\n",
   729:                          smrSramCurrentSize >> 10, 0x00ed0000, 0x00ed0000 + smrSramCurrentSize - 1);
   730:     }
   731: 
   732:     //ROM起動ハンドルを調整する
   733:     //  ROM起動ハンドルが内蔵SCSIを指しているが内蔵SCSIがないとき
   734:     //    拡張SCSIがあるとき
   735:     //      ROM起動ハンドルを拡張SCSIにする
   736:     //    拡張SCSIがないとき
   737:     //      ROM起動ハンドルを消す
   738:     //      ROM起動のとき
   739:     //        STD起動にする
   740:     //  ROM起動ハンドルが拡張SCSIを指しているが拡張SCSIがないとき
   741:     //    内蔵SCSIがあるとき
   742:     //      ROM起動ハンドルを内蔵SCSIにする
   743:     //    内蔵SCSIがないとき
   744:     //      ROM起動ハンドルを消す
   745:     //      ROM起動のとき
   746:     //        STD起動にする
   747:     //  ROM起動ハンドルがHFSを指しているがHFSのディレクトリが設定されていないとき
   748:     //    ROM起動ハンドルを消す
   749:     //    ROM起動のとき
   750:     //      STD起動にする
   751:     //起動デバイス
   752:     if ((smrROMBootHandle & ~(7 << 2)) == SPC.SPC_HANDLE_IN && !SPC.spcSCSIINOn) {  //ROM起動ハンドルが内蔵SCSIを指しているが内蔵SCSIがないとき
   753:       if (SPC.spcSCSIEXOn) {  //拡張SCSIがあるとき
   754:         smrROMBootHandle = SPC.SPC_HANDLE_EX + (smrROMBootHandle & (7 << 2));  //ROM起動ハンドルを拡張SCSIにする
   755:         //MainMemory.mmrWb (0x00ed0070, MainMemory.mmrRbs (0x00ed0070) | 0x08);  //拡張フラグをセットする
   756:       } else {  //拡張SCSIがないとき
   757:         smrROMBootHandle = 0x00e80400;  //ROM起動ハンドルを消す
   758:         if (smrBootDevice == 0xa000) {  //ROM起動のとき
   759:           smrBootDevice = 0x0000;  //STD起動にする
   760:           smrSTDMenuItem.setSelected (true);
   761:         }
   762:       }
   763:     }
   764:     if ((smrROMBootHandle & ~(7 << 2)) == SPC.SPC_HANDLE_EX && !SPC.spcSCSIEXOn) {  //ROM起動ハンドルが拡張SCSIを指しているが拡張SCSIがないとき
   765:       if (SPC.spcSCSIINOn) {  //内蔵SCSIがあるとき
   766:         smrROMBootHandle = SPC.SPC_HANDLE_IN + (smrROMBootHandle & (7 << 2));  //ROM起動ハンドルを内蔵SCSIにする
   767:         //MainMemory.mmrWb (0x00ed0070, MainMemory.mmrRbs (0x00ed0070) & ~0x08);  //拡張フラグをクリアする
   768:       } else {  //内蔵SCSIがないとき
   769:         smrROMBootHandle = 0x00e80400;  //ROM起動ハンドルを消す
   770:         if (smrBootDevice == 0xa000) {  //ROM起動のとき
   771:           smrBootDevice = 0x0000;  //STD起動にする
   772:           smrSTDMenuItem.setSelected (true);
   773:         }
   774:       }
   775:     }
   776:     if (smrROMBootHandle == HFS.HFS_BOOT_HANDLE &&  //ROM起動ハンドルがHFSを指しているが
   777:         (!HFS.hfsUnitArray[HFS.hfsBootUnit].abuConnected ||
   778:          !HFS.hfsUnitArray[HFS.hfsBootUnit].abuInserted)) {  //HFSのディレクトリが設定されていないとき
   779:       smrROMBootHandle = 0x00e80400;  //ROM起動ハンドルを消す
   780:       if (smrBootDevice == 0xa000) {  //ROM起動のとき
   781:         smrBootDevice = 0x0000;  //STD起動にする
   782:         smrSTDMenuItem.setSelected (true);
   783:       }
   784:     }
   785:     //ここから再起動
   786:     if ((XEiJ.mpuROMBootHandle & ~(7 << 2)) == SPC.SPC_HANDLE_IN && !SPC.spcSCSIINOn) {  //ROM起動ハンドルが内蔵SCSIを指しているが内蔵SCSIがないとき
   787:       if (SPC.spcSCSIEXOn) {  //拡張SCSIがあるとき
   788:         XEiJ.mpuROMBootHandle = SPC.SPC_HANDLE_EX + (XEiJ.mpuROMBootHandle & (7 << 2));  //ROM起動ハンドルを拡張SCSIにする
   789:         //MainMemory.mmrWb (0x00ed0070, MainMemory.mmrRbs (0x00ed0070) | 0x08);  //拡張フラグをセットする
   790:       } else {  //拡張SCSIがないとき
   791:         XEiJ.mpuROMBootHandle = 0x00e80400;  //ROM起動ハンドルを消す
   792:         if (XEiJ.mpuBootDevice == 0xa000) {  //ROM起動のとき
   793:           XEiJ.mpuBootDevice = 0x0000;  //STD起動にする
   794:         }
   795:       }
   796:     }
   797:     if ((XEiJ.mpuROMBootHandle & ~(7 << 2)) == SPC.SPC_HANDLE_EX && !SPC.spcSCSIEXOn) {  //ROM起動ハンドルが拡張SCSIを指しているが拡張SCSIがないとき
   798:       if (SPC.spcSCSIINOn) {  //内蔵SCSIがあるとき
   799:         XEiJ.mpuROMBootHandle = SPC.SPC_HANDLE_IN + (XEiJ.mpuROMBootHandle & (7 << 2));  //ROM起動ハンドルを内蔵SCSIにする
   800:         //MainMemory.mmrWb (0x00ed0070, MainMemory.mmrRbs (0x00ed0070) & ~0x08);  //拡張フラグをクリアする
   801:       } else {  //内蔵SCSIがないとき
   802:         XEiJ.mpuROMBootHandle = 0x00e80400;  //ROM起動ハンドルを消す
   803:         if (XEiJ.mpuBootDevice == 0xa000) {  //ROM起動のとき
   804:           XEiJ.mpuBootDevice = 0x0000;  //STD起動にする
   805:         }
   806:       }
   807:     }
   808:     if (XEiJ.mpuROMBootHandle == HFS.HFS_BOOT_HANDLE &&  //ROM起動ハンドルがHFSを指しているが
   809:         (!HFS.hfsUnitArray[HFS.hfsBootUnit].abuConnected ||
   810:          !HFS.hfsUnitArray[HFS.hfsBootUnit].abuInserted)) {  //HFSのディレクトリが設定されていないとき
   811:       XEiJ.mpuROMBootHandle = 0x00e80400;  //ROM起動ハンドルを消す
   812:       if (XEiJ.mpuBootDevice == 0xa000) {  //ROM起動のとき
   813:         XEiJ.mpuBootDevice = 0x0000;  //STD起動にする
   814:       }
   815:     }
   816: 
   817:     smrOverride ();
   818: 
   819:   }  //smrReset()
   820: 
   821:   //smrOverride ()
   822:   //  SRAMの設定を上書きする
   823:   //  ここから再起動もSRAMに上書きする
   824:   public static void smrOverride () {
   825:     if (MainMemory.mmrRls (0x00ed0000) == 0x82773638 &&  //X68
   826:         MainMemory.mmrRls (0x00ed0004) == 0x30303057) {  //000W  初期化されている。初期化されていないときに上書きしても意味がない
   827: 
   828:       //メモリサイズ
   829:       if (smrModifyMemorySizeOn) {
   830:         int memorySizeAddress = 0x00ed0008;
   831:         int memorySizeOld = MainMemory.mmrRls (memorySizeAddress);
   832:         int memorySizeNew = MainMemory.mmrMemorySizeCurrent;
   833:         if (memorySizeOld != memorySizeNew) {
   834:           MainMemory.mmrWl (memorySizeAddress, memorySizeNew);
   835:           System.out.printf (Multilingual.mlnJapanese ?
   836:                              "SRAM にあるメモリサイズを %dMB から %dMB に変更しました\n" :
   837:                              "Changed the memory size in SRAM from %dMB to %dMB\n",
   838:                              memorySizeOld >> 20,
   839:                              memorySizeNew >> 20);
   840:         }
   841:       }
   842: 
   843:       //ROM起動ハンドル
   844:       int romHandleAddress = 0x00ed000c;
   845:       int romHandleOld = MainMemory.mmrRls (romHandleAddress);
   846:       int romHandleNew = XEiJ.mpuROMBootHandle != -1 ? XEiJ.mpuROMBootHandle : smrROMBootHandle;
   847:       if (romHandleNew != -1 &&
   848:           romHandleOld != romHandleNew) {
   849:         MainMemory.mmrWl (romHandleAddress, romHandleNew);
   850:         System.out.printf (Multilingual.mlnJapanese ?
   851:                            "SRAM にある ROM 起動ハンドルを $%08X から $%08X に変更しました\n" :
   852:                            "Changed the ROM boot handle in SRAM from $%08X to $%08X\n",
   853:                            romHandleOld,
   854:                            romHandleNew);
   855:       }
   856: 
   857:       //RAM起動アドレス
   858:       int ramAddressAddress = 0x00ed0010;
   859:       int ramAddressOld = MainMemory.mmrRls (ramAddressAddress);
   860:       int ramAddressNew = smrRAMBootAddress;
   861:       if (ramAddressNew != -1 &&
   862:           ramAddressOld != ramAddressNew) {
   863:         MainMemory.mmrWl (ramAddressAddress, ramAddressNew);
   864:         System.out.printf (Multilingual.mlnJapanese ?
   865:                            "SRAM にある RAM 起動アドレスを $%08X から $%08X に変更しました\n" :
   866:                            "Changed the RAM boot address in SRAM from $%08X to $%08X\n",
   867:                            ramAddressOld,
   868:                            ramAddressNew);
   869:       }
   870: 
   871:       //起動デバイス
   872:       int deviceAddress = 0x00ed0018;
   873:       int deviceOld = MainMemory.mmrRwz (deviceAddress);
   874:       int deviceNew = XEiJ.mpuBootDevice != -1 ? XEiJ.mpuBootDevice : smrBootDevice;
   875:       if (deviceNew != -1 &&
   876:           deviceOld != deviceNew) {
   877:         MainMemory.mmrWw (deviceAddress, deviceNew);
   878:         System.out.printf (Multilingual.mlnJapanese ?
   879:                            "SRAM にある起動デバイスを %s から %s に変更しました\n" :
   880:                            "Changed the boot device in SRAM from %s to %s\n",
   881:                            smrBootDescription (romHandleOld, ramAddressOld, deviceOld),
   882:                            smrBootDescription (romHandleNew, ramAddressNew, deviceNew));
   883:       }
   884: 
   885:       //リピート開始
   886:       int repeatDelayAddress = 0x00ed003a;
   887:       int repeatDelayOld = MainMemory.mmrRbz (repeatDelayAddress);
   888:       int repeatDelayNew = smrRepeatDelay;
   889:       if (repeatDelayNew != -1 &&
   890:           repeatDelayOld != repeatDelayNew) {
   891:         MainMemory.mmrWb (repeatDelayAddress, repeatDelayNew);
   892:         System.out.printf (Multilingual.mlnJapanese ?
   893:                            "SRAM にあるリピート開始を %dms から %dms に変更しました\n" :
   894:                            "Changed the repeat delay in SRAM from %dms to %dms\n",
   895:                            200 + 100 * (repeatDelayOld & 15),
   896:                            200 + 100 * (repeatDelayNew & 15));
   897:       }
   898: 
   899:       //リピート間隔
   900:       int repeatIntervalAddress = 0x00ed003b;
   901:       int repeatIntervalOld = MainMemory.mmrRbz (repeatIntervalAddress);
   902:       int repeatIntervalNew = smrRepeatInterval;
   903:       if (repeatIntervalNew != -1 &&
   904:           repeatIntervalOld != repeatIntervalNew) {
   905:         MainMemory.mmrWb (repeatIntervalAddress, repeatIntervalNew);
   906:         System.out.printf (Multilingual.mlnJapanese ?
   907:                            "SRAM にあるリピート間隔を %dms から %dms に変更しました\n" :
   908:                            "Changed the repeat interval in SRAM from %dms to %dms\n",
   909:                            30 + 5 * (repeatDelayOld & 15),
   910:                            30 + 5 * (repeatDelayNew & 15));
   911:       }
   912: 
   913:       boolean iplrom16 = (XEiJ.currentAccelerator == XEiJ.ACCELERATOR_HYBRID ||
   914:                           XEiJ.currentAccelerator == XEiJ.ACCELERATOR_060TURBO ||
   915:                           XEiJ.currentAccelerator == XEiJ.ACCELERATOR_060TURBOPRO ||
   916:                           ROM.romIPLROM16On);  //IPLROM 1.6か
   917: 
   918:       //ROMデバッガ起動フラグ
   919:       if (smrRomdbFlag != -1) {  //設定する
   920:         boolean nonexistence = (XEiJ.currentModel.getIPLROM () == 130 && !iplrom16 &&
   921:                                 ROM.romROM30Data == null);  //ROMデバッガがないか。IPLROM 1.3でROM30.DATが指定されていない
   922:         int address = 0x00ed0058;
   923:         int oldData = MainMemory.mmrRbz (address);
   924:         int newData = (nonexistence ? 0 :  //ROMデバッガがないときOFF
   925:                        !iplrom16 && smrRomdbFlag == 1 ? 255 :  //IPLROM 1.6でないときCONをAUXに変更
   926:                        smrRomdbFlag);
   927:         if (oldData != newData) {
   928:           MainMemory.mmrWb (address, newData);
   929:           System.out.printf (Multilingual.mlnJapanese ?
   930:                              "SRAM にある ROM デバッガ起動フラグを %s から %s に変更しました\n" :
   931:                              "ROM debugger startup flag in SRAM changed from %s to %s\n",
   932:                              oldData == 0 ? "OFF" : oldData == 255 ? "AUX" : "CON",
   933:                              newData == 0 ? "OFF" : newData == 255 ? "AUX" : "CON");
   934:         }
   935:       }
   936: 
   937:       //起動時のキャッシュモード
   938:       if (smrCacheMode != -1) {
   939:         int address = 0x00ed0090;
   940:         int oldData = MainMemory.mmrRbz (address);
   941:         int newData = smrCacheMode;
   942:         if (oldData != newData) {
   943:           MainMemory.mmrWb (address, newData);
   944:           System.out.printf (Multilingual.mlnJapanese ?
   945:                              "SRAM にある起動時のキャッシュモードを %s から %s に変更しました\n" :
   946:                              "Cache mode at startup in SRAM changed from %s to %s\n",
   947:                              smrCacheToString (oldData),
   948:                              smrCacheToString (newData));
   949:         }
   950:       }
   951: 
   952:       //起動音
   953:       if (smrStupsndMode != -1) {
   954:         int address = 0x00ed0091;
   955:         int oldData = MainMemory.mmrRbz (address);
   956:         int newData = (!iplrom16 && 2 <= smrStupsndMode ? 1 :  //IPLROM 1.6でないとき2-126を1に変更
   957:                        smrStupsndMode);
   958:         if (oldData != newData) {
   959:           MainMemory.mmrWb (address, newData);
   960:           System.out.printf (Multilingual.mlnJapanese ?
   961:                              "SRAM にある起動音の設定を %s から %s に変更しました\n" :
   962:                              "Startup sound setting in SRAM changed from %s to %s\n",
   963:                              smrStupsndToString (oldData),
   964:                              smrStupsndToString (newData));
   965:         }
   966:       }
   967: 
   968:       //SASIハードディスクの最大数
   969:       int hdMaxAddress = 0x00ed005a;
   970:       int hdMaxOld = MainMemory.mmrRbz (hdMaxAddress);
   971:       int sasiFlag = MainMemory.mmrRbz (0x00ed006f) == 'V' ? MainMemory.mmrRbz (0x00ed0071) : 0;
   972:       int hdMaxNew = SPC.spcSCSIINOn ? 2 * (32 - Integer.numberOfLeadingZeros (sasiFlag)) : HDC.hdcHDMax;
   973:       if (hdMaxOld != hdMaxNew) {
   974:         MainMemory.mmrWb (hdMaxAddress, hdMaxNew);
   975:         System.out.printf (Multilingual.mlnJapanese ?
   976:                            "SRAM にある SASI ハードディスクの最大数を %d から %d に変更しました\n" :
   977:                            "Changed the maximum number of SASI hard disks in SRAM from %d to %d\n",
   978:                            hdMaxOld, hdMaxNew);
   979:       }
   980: 
   981:     }
   982:     //「ここから再起動」をキャンセルする
   983:     //XEiJ.mpuBootDevice = -1;
   984:     //XEiJ.mpuROMBootHandle = -1;
   985:   }
   986: 
   987:   //smrCacheToString (mode)
   988:   //  キャッシュモードを文字列に変換する
   989:   public static String smrCacheToString (int mode) {
   990:     return (mode == 0 ? "off-off" :
   991:             mode == 1 ? "off-on" :
   992:             mode == 2 ? "on-off" :
   993:             mode == 3 ? "on-on" :
   994:             "");
   995:   }  //smrCacheToString
   996: 
   997:   //smrStringToCache (s)
   998:   //  文字列をキャッシュモードに変換する
   999:   public static int smrStringToCache (String s) {
  1000:     s = s.toLowerCase ();
  1001:     return (s.equals ("off-off") ? 0 :
  1002:             s.equals ("off-on") ? 1 :
  1003:             s.equals ("on-off") ? 2 :
  1004:             s.equals ("on-on") ? 3 :
  1005:             -1);
  1006:   }  //smrStringToCache
  1007: 
  1008:   //smrStupsndToString (mode)
  1009:   //  起動音を文字列に変換する
  1010:   public static String smrStupsndToString (int mode) {
  1011:     String s = "";
  1012:     if (mode == 0) {
  1013:       s = "off";
  1014:     } else if (mode == 1) {
  1015:       s = "on";
  1016:     } else if (2 <= mode && mode <= 127) {
  1017:       int i = mode - (mode >> 2);
  1018:       int o = i / 12;
  1019:       int n = i % 12;
  1020:       if (9 <= n) {
  1021:         o++;
  1022:       }
  1023:       s = "o" + o + (n == 0 ? "d#" :
  1024:                      n == 1 ? "e" :
  1025:                      n == 2 ? "f" :
  1026:                      n == 3 ? "f#" :
  1027:                      n == 4 ? "g" :
  1028:                      n == 5 ? "g#" :
  1029:                      n == 6 ? "a" :
  1030:                      n == 7 ? "a#" :
  1031:                      n == 8 ? "b" :
  1032:                      n == 9 ? "c" :
  1033:                      n == 10 ? "c#" :
  1034:                      "d");
  1035:     }
  1036:     return s;
  1037:   }  //smrStupsndToString
  1038: 
  1039:   //smrStringToStupsnd (s)
  1040:   //  文字列を起動音に変換する
  1041:   public static int smrStringToStupsnd (String s) {
  1042:     s = s.toLowerCase ();
  1043:     int mode = -1;
  1044:     if (s.equals ("off")) {
  1045:       mode = 0;
  1046:     } else if (s.equals ("on")) {
  1047:       mode = 1;
  1048:     } else {
  1049:       int l = s.length ();
  1050:       int c0 = l < 1 ? -1 : s.charAt (0);
  1051:       int c1 = l < 2 ? -1 : s.charAt (1);
  1052:       int c2 = l < 3 ? -1 : s.charAt (2);
  1053:       int c3 = l < 4 ? -1 : s.charAt (3);
  1054:       if (c0 == 'o' &&
  1055:           '0' <= c1 && c1 <= '8' &&
  1056:           'a' <= c2 && c2 <= 'g') {
  1057:         int o = c1 - '0';
  1058:         int n = (c2 == 'a' ? 6 :
  1059:                  c2 == 'b' ? 8 :
  1060:                  c2 == 'c' ? -3 :
  1061:                  c2 == 'd' ? -1 :
  1062:                  c2 == 'e' ? 1 :
  1063:                  c2 == 'f' ? 2 :
  1064:                  4);
  1065:         if (c3 == '#' || c3 == '+') {
  1066:           n++;
  1067:         } else if (c3 == '-') {
  1068:           n--;
  1069:         }
  1070:         int i = 12 * o + n;
  1071:         if (2 <= i && i <= 95) {
  1072:           mode = i + i / 3;
  1073:         }
  1074:       }
  1075:     }
  1076:     return mode;
  1077:   }  //smrStringToStupsnd
  1078: 
  1079:   static {
  1080:     if (false) {
  1081:       //起動音の文字列変換の確認
  1082:       for (int mode = 0; mode <= 126; mode++) {  //127は不可
  1083:         if (mode % 4 == 3) {
  1084:           continue;
  1085:         }
  1086:         String s = smrStupsndToString (mode);
  1087:         int i = smrStringToStupsnd (s);
  1088:         System.out.printf ("mode=%d s=%s i=%d\n", mode, s, i);
  1089:       }
  1090:     }
  1091:   }
  1092: 
  1093:   //s = smrBootDescription (code, romHandle, ramAddress)
  1094:   //  device      $00ED0018  起動デバイス
  1095:   //                           $0000  STD  FD→HD→ROM→RAM
  1096:   //                           $8xxx  HD
  1097:   //                           $9xxx  FD
  1098:   //                           $Axxx  ROM  ROM起動ハンドルからROM起動アドレスを取り出して呼び出す
  1099:   //                                       ROM起動ハンドルがバスエラーになるときはSTDで起動する
  1100:   //                           $Bxxx  RAM  RAM起動アドレスを呼び出す。先頭が$60でなければならない
  1101:   //  romHandle   $00ED000C  ROM起動ハンドル
  1102:   //  ramAddress  $00ED0010  RAM起動アドレス
  1103:   public static String smrBootDescription (int romHandle, int ramAddress, int device) {
  1104:     switch (device & 0xf000) {
  1105:     case 0x8000:
  1106:       return "HD" + (device >> 8 & 15);
  1107:     case 0x9000:
  1108:       return "2HD" + (device >> 8 & 3);
  1109:     case 0xa000:
  1110:       return ((romHandle & ~(7 << 2)) == SPC.SPC_HANDLE_IN ? "SCSI" + ((romHandle >> 2) & 7) :   //内蔵SCSI
  1111:               (romHandle & ~(7 << 2)) == SPC.SPC_HANDLE_EX ? "SCSI" + ((romHandle >> 2) & 7) :   //拡張SCSI
  1112:               "ROM$" + XEiJ.fmtHex6 (romHandle));
  1113:     case 0xb000:
  1114:       return "RAM$" + XEiJ.fmtHex6 (ramAddress);
  1115:     default:
  1116:       return "STD";
  1117:     }
  1118:   }
  1119: 
  1120:   //smrClear ()
  1121:   //  SRAMクリア
  1122:   public static void smrClear () {
  1123:     XEiJ.pnlExitFullScreen (true);
  1124:     if (JOptionPane.showConfirmDialog (
  1125:       XEiJ.frmFrame,
  1126:       Multilingual.mlnJapanese ? "SRAM をクリアしますか?" : "Do you want to clear SRAM?",
  1127:       Multilingual.mlnJapanese ? "確認" : "Confirmation",
  1128:       JOptionPane.YES_NO_OPTION,
  1129:       JOptionPane.PLAIN_MESSAGE) == JOptionPane.YES_OPTION) {
  1130:       Arrays.fill (MainMemory.mmrM8, 0x00ed0000, 0x00ed0000 + 65536, (byte) 0x00);
  1131:     }
  1132:   }  //smrClear()
  1133: 
  1134:   //smrLoad ()
  1135:   //  SRAM読み込み
  1136:   public static void smrLoad () {
  1137:     JFileChooser2 fileChooser = new JFileChooser2 ();
  1138:     fileChooser.setFileFilter (new javax.swing.filechooser.FileFilter () {  //java.io.FileFilterと紛らわしい
  1139:       @Override public boolean accept (File file) {
  1140:         String name = file.getName ();
  1141:         String upperName = name.toUpperCase ();
  1142:         return (file.isDirectory () ||
  1143:                 (file.isFile () &&
  1144:                  upperName.startsWith ("SRAM")));
  1145:       }
  1146:       @Override public String getDescription () {
  1147:         return (Multilingual.mlnJapanese ?
  1148:                 "SRAM データファイル (SRAM*.*)" :
  1149:                 "SRAM data files (SRAM*.*)");
  1150:       }
  1151:     });
  1152:     if (fileChooser.showOpenDialog (null) == JFileChooser.APPROVE_OPTION) {
  1153:       File file = fileChooser.getSelectedFile ();
  1154:       String name = file.getPath ();
  1155:       if (!smrLoadData (name)) {  //読み込めなかった
  1156:         XEiJ.pnlExitFullScreen (true);
  1157:         JOptionPane.showMessageDialog (null,
  1158:                                        Multilingual.mlnJapanese ?
  1159:                                        name + " のサイズが違います" :
  1160:                                        name + " has wrong size");
  1161:         return;
  1162:       }
  1163:     }
  1164:   }  //smrLoad()
  1165: 
  1166:   //success = smrLoadData (name)
  1167:   //  SRAMのイメージファイルを読み込む
  1168:   public static boolean smrLoadData (String name) {
  1169:     byte[] array = XEiJ.rscGetFile (name, smrSramSizeRequest);
  1170:     if (array != null) {  //読み込めた
  1171:       System.arraycopy (array, 0, MainMemory.mmrM8, 0x00ed0000, smrSramSizeRequest);  //SRAMにコピーする
  1172:       if (smrSramSizeRequest < 65536) {
  1173:         Arrays.fill (MainMemory.mmrM8, 0x00ed0000 + smrSramSizeRequest, 0x00ed0000 + 65536, (byte) 0x00);  //空き
  1174:       }
  1175:       return true;
  1176:     }
  1177:     return false;
  1178:   }
  1179: 
  1180:   //smrSave ()
  1181:   //  SRAM書き出し
  1182:   public static void smrSave () {
  1183:     JFileChooser2 fileChooser = new JFileChooser2 ();
  1184:     fileChooser.setFileFilter (new javax.swing.filechooser.FileFilter () {  //java.io.FileFilterと紛らわしい
  1185:       @Override public boolean accept (File file) {
  1186:         String name = file.getName ();
  1187:         String upperName = name.toUpperCase ();
  1188:         return (file.isDirectory () ||
  1189:                 (file.isFile () &&
  1190:                  upperName.startsWith ("SRAM")));
  1191:       }
  1192:       @Override public String getDescription () {
  1193:         return (Multilingual.mlnJapanese ?
  1194:                 "SRAM データファイル (SRAM*.*)" :
  1195:                 "SRAM data files (SRAM*.*)");
  1196:       }
  1197:     });
  1198:     if (fileChooser.showSaveDialog (null) == JFileChooser.APPROVE_OPTION) {
  1199:       XEiJ.rscPutFile (fileChooser.getSelectedFile ().getPath (), MainMemory.mmrM8, 0x00ed0000, smrSramSizeRequest);
  1200:     }
  1201:   }  //smrSave()
  1202: 
  1203: }  //class SRAM