XEiJ.java
     1: //========================================================================================
     2: //  XEiJ.java
     3: //    en:Main class
     4: //    ja:メインクラス
     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: package xeij;
    14: 
    15: import java.awt.*;
    16: import java.awt.datatransfer.*;
    17: import java.awt.dnd.*;
    18: import java.awt.event.*;
    19: import java.awt.geom.*;
    20: import java.awt.image.*;
    21: import java.io.*;
    22: import java.net.*;
    23: import java.nio.charset.*;
    24: import java.nio.file.*;
    25: import java.util.*;
    26: import java.util.regex.*;
    27: import java.util.stream.*;
    28: import java.util.zip.*;
    29: import javax.imageio.*;
    30: import javax.imageio.stream.*;
    31: import javax.swing.*;
    32: import javax.swing.event.*;
    33: import javax.swing.text.*;
    34: 
    35: public class XEiJ {
    36: 
    37:   //システムプロパティ
    38:   //  mainクラスの先頭に書く
    39:   //  これでも駄目(間に合わない)ならjavaのオプションに書く
    40:   //    java -Dsun.java2d.d3d=false -Dsun.java2d.xrender=false -jar XEiJ.jar ...
    41:   static {
    42:     System.setProperty ("sun.java2d.d3d", "false");
    43:     System.setProperty ("sun.java2d.xrender", "false");
    44:   }
    45: 
    46:   //名前とバージョン
    47:   public static final String PRG_TITLE = "XEiJ (X68000 Emulator in Java)";  //タイトル
    48:   public static final String PRG_VERSION = "0.26.05.17";  //バージョン
    49:   public static final String PRG_AUTHOR = "Makoto Kamada";  //作者
    50:   public static final String PRG_WEBPAGE = "https://stdkmd.net/xeij/";  //ウェブページ
    51: 
    52:   public static final String PRG_JAVA_VENDOR = "Oracle Corporation";  //動作を確認しているJavaのベンダー
    53:   public static final String PRG_JAVA_VERSION = "26.0.1";  //動作を確認しているJavaのバージョン
    54:   public static final String PRG_OS_ARCH = "amd64";  //動作を確認しているOSのアーキテクチャ
    55:   public static final String PRG_OS_NAME = "Windows 11";  //動作を確認しているOSの名前
    56: 
    57:   //全体の設定
    58:   //  bit0..3のテストにシフトを使う
    59:   //    TEST_BIT_0_SHIFT ? a << 31 != 0 : (a & 1) != 0
    60:   //    TEST_BIT_1_SHIFT ? a << 30 < 0 : (a & 2) != 0
    61:   //    TEST_BIT_2_SHIFT ? a << 29 < 0 : (a & 4) != 0
    62:   //    TEST_BIT_3_SHIFT ? a << 28 < 0 : (a & 8) != 0
    63:   public static final boolean TEST_BIT_0_SHIFT = false;  //true=bit0のテストにシフトを使う
    64:   public static final boolean TEST_BIT_1_SHIFT = false;  //true=bit1のテストにシフトを使う
    65:   public static final boolean TEST_BIT_2_SHIFT = true;  //true=bit2のテストにシフトを使う
    66:   public static final boolean TEST_BIT_3_SHIFT = true;  //true=bit3のテストにシフトを使う
    67:   //  shortの飽和処理にキャストを使う
    68:   //    x = SHORT_SATURATION_CAST ? (short) x == x ? x : x >> 31 ^ 32767 : Math.max (-32768, Math.min (32767, x));
    69:   //    m = SHORT_SATURATION_CAST ? (short) m == m ? m : m >> 31 ^ 32767 : Math.max (-32768, Math.min (32767, m));
    70:   //    l = SHORT_SATURATION_CAST ? (short) l == l ? l : l >> 31 ^ 32767 : Math.max (-32768, Math.min (32767, l));
    71:   //    r = SHORT_SATURATION_CAST ? (short) r == r ? r : r >> 31 ^ 32767 : Math.max (-32768, Math.min (32767, r));
    72:   //  または
    73:   //    if (SHORT_SATURATION_CAST) {
    74:   //      if ((short) x != x) {
    75:   //        x = x >> 31 ^ 32767;
    76:   //      }
    77:   //    } else {
    78:   //      if (x < -32768) {
    79:   //        x = -32768;
    80:   //      } else if (x > 32767) {
    81:   //        x = 32767;
    82:   //      }
    83:   //    }
    84:   public static final boolean SHORT_SATURATION_CAST = false;  //shortの飽和処理にキャストを使う
    85: 
    86:   //バイナリデータの埋め込み
    87:   //  byte[]の場合
    88:   //    Javaはbyteの定数配列をstatic final byte[] XXX={~}で直接記述しにくい
    89:   //      bit7がセットされているデータをいちいち(byte)でキャストしなければならない
    90:   //      初期化コードが巨大化してコンパイラを通らなくなる
    91:   //    Stringに詰め込んで起動時にString.getBytes(Charset)を使ってbyte[]に展開する
    92:   //    ISO-8859-1はすべてのJava実行環境で実装しなければならないことになっているので環境依存にはならない
    93:   //    static final int[] XXX={~}で書いておいてPerlスクリプトで文字列に変換する
    94:   //    final int[]をbyte[]に変更すると動作が遅くなる場合があることに注意する
    95:   //    perl misc/itob.pl xeij/???.java XXX
    96:   public static final Charset ISO_8859_1 = Charset.forName ("ISO-8859-1");
    97:   static {
    98:     if (false) {
    99:       //ISO-8859-1が8bitバイナリデータを素通りさせるかどうかのテスト
   100:       StringBuilder sb = new StringBuilder ();
   101:       for (int i = 0; i < 256; i++) {
   102:         sb.append ((char) i);
   103:       }
   104:       byte[] bb = sb.toString ().getBytes (ISO_8859_1);
   105:       for (int i = 0; i < 256; i++) {
   106:         System.out.printf ("%02x %02x %s\n", i, bb[i] & 255, i == (bb[i] & 255) ? "OK" : "ERROR");
   107:       }
   108:     }
   109:   }
   110:   //  char[]の場合
   111:   //    byte[]の場合と同様にStringに詰め込んで起動時にString.toCharArray()を使ってchar[]に展開する
   112:   //    static final int[] XXX={~}で書いておいてPerlスクリプトで文字列に変換する
   113:   //    final int[]をchar[]に変更すると動作が遅くなる場合があることに注意する
   114:   //    perl misc/itoc.pl xeij/???.java XXX
   115: 
   116: 
   117: 
   118:   //========================================================================================
   119:   //$$PRG プログラムの入り口と出口
   120: 
   121:   //動作環境
   122:   public static String prgJavaVendor;  //動作環境のJavaのベンダー
   123:   public static String prgJavaVersion;  //動作環境のJavaのバージョン
   124:   public static String prgOsArch;  //動作環境のアーキテクチャ
   125:   public static String prgOsName;  //OSの名前
   126:   public static boolean prgIsLinux;  //true=Linux
   127:   public static boolean prgIsMac;  //true=Mac
   128:   public static boolean prgIsWindows;  //true=Windows
   129: 
   130:   public static boolean prgCaseIgnored;  //true=ファイル名の大文字と小文字が区別されない
   131: 
   132:   public static boolean prgVerbose;
   133:   public static boolean prgTiniLog;
   134: 
   135:   public static String[] prgArgs;
   136: 
   137:   //main (args)
   138:   //  開始
   139:   public static void main (String[] args) {
   140: 
   141:     //jSerialCommの不具合対策
   142:     //  jSerialCommはキャッシュされたdllファイルの扱いが雑で問題を引き起こすことがある
   143:     //  XEiJの起動時にキャッシュディレクトリを削除して毎回dllファイルを作り直させる
   144:     if (true) {
   145:       try {
   146:         String def = System.getProperty ("os.name").toLowerCase ().contains ("win") ? "C:\\Temp" : "/tmp";
   147:         Stream.of (new File (System.getProperty ("java.io.tmpdir", def),
   148:                              "jSerialComm").getCanonicalFile ().toPath (),
   149:                    new File (System.getProperty ("user.home", def),
   150:                              ".jSerialComm").getCanonicalFile ().toPath ())
   151:           .filter (Files::exists)
   152:             .forEach (dir -> {
   153:               try {
   154:                 Files.walk (dir)
   155:                   .sorted (Comparator.reverseOrder ())
   156:                     .forEach (path -> {
   157:                       if (Files.exists (path)) {
   158:                         try {
   159:                           Files.delete (path);
   160:                           //System.out.println ("Deleted: " + path);
   161:                         } catch (IOException ioe) {
   162:                           System.err.println ("Failed to delete: " + path + " (" + ioe.getMessage () + ")");
   163:                         }
   164:                       }
   165:                     });
   166:               } catch (IOException ioe) {
   167:                 System.err.println ("Failed to walk: " + dir + " (" + ioe.getMessage () + ")");
   168:               }
   169:             });
   170:       } catch (IOException ioe) {
   171:       }
   172:     }
   173: 
   174:     prgArgs = args;
   175: 
   176:     //起動する
   177:     SwingUtilities.invokeLater (new Runnable () {
   178:       @Override public void run () {
   179:         new XEiJ ();
   180:       }
   181:     });
   182: 
   183:   }  //main(String[])
   184: 
   185:   //XEiJ ()
   186:   //  コンストラクタ
   187:   public XEiJ () {
   188: 
   189:     prgJavaVendor = System.getProperty ("java.vendor");
   190:     prgJavaVersion = System.getProperty ("java.version");
   191:     prgOsArch = System.getProperty ("os.arch");
   192:     prgOsName = System.getProperty ("os.name");
   193:     prgIsLinux = 0 <= prgOsName.indexOf ("Linux");
   194:     prgIsMac = 0 <= prgOsName.indexOf ("Mac");
   195:     prgIsWindows = 0 <= prgOsName.indexOf ("Windows");
   196: 
   197:     System.out.print ("\n" +
   198:                       "-------------------------------------------------\n" +
   199:                       PRG_TITLE + " version " + PRG_VERSION + "\n" +
   200:                       "-------------------------------------------------\n");
   201: 
   202:     //初期化
   203:     //  この段階でコンポーネントを参照してはならない
   204:     //  メニューの初期値に必要な情報があればここで作っておく
   205:     prgCaseIgnored = new File ("A").equals (new File ("a"));  //ファイル名の大文字と小文字が区別されるか
   206:     fmtInit ();  //BCD 10進数変換
   207:     Multilingual.mlnInit ();  //MLN 多言語化  sgsInit()よりも前
   208: 
   209:     System.out.println (Multilingual.mlnJapanese ? "java.vendor は " + prgJavaVendor + " です" :
   210:                         "java.vendor is " + prgJavaVendor);
   211:     System.out.println (Multilingual.mlnJapanese ? "java.version は " + prgJavaVersion + " です" :
   212:                         "java.version is " + prgJavaVersion);
   213:     System.out.println (Multilingual.mlnJapanese ? "os.arch は " + prgOsArch + " です" :
   214:                         "os.arch is " + prgOsArch);
   215:     System.out.println (Multilingual.mlnJapanese ? "os.name は " + prgOsName + " です" :
   216:                         "os.name is " + prgOsName);
   217: 
   218:     rbtInit ();  //RBT ロボット
   219: 
   220:     Settings.sgsInit ();  //SGS 設定  mlnInit()よりも後、他の~Init()よりも前
   221:     LnF.lnfInit ();  //Look&Feel
   222:     Bubble.bblInit ();  //BBL バブル lnfInit()よりも後
   223: 
   224:     CharacterCode.chrInit ();  //CHR 文字コード
   225: 
   226:     TickerQueue.tkqInit ();  //TKQ ティッカーキュー
   227: 
   228:     RS232CTerminal.trmInit ();  //TRM RS-232C設定とターミナル。tkqInitよりも後
   229: 
   230:     if (MercuryUnit.MU4_ON) {
   231:       MercuryUnit.mu4Init ();
   232:     }
   233:     xt3Init ();  //XT3 Xellent30
   234:     mdlInit ();  //MDL 機種。sgsInit()よりも後
   235: 
   236:     if (InstructionBreakPoint.IBP_ON) {
   237:       InstructionBreakPoint.ibpInit ();  //IBP 命令ブレークポイント
   238:     }
   239:     if (DataBreakPoint.DBP_ON) {
   240:       DataBreakPoint.dbpInit ();  //DBP データブレークポイント
   241:     }
   242:     busInit ();  //BUS バスコントローラ  ibpInit()とdbpInit()よりも後
   243:     MainMemory.mmrInit ();  //MMR メインメモリ。romInitよりも前
   244:     ROM.romInit ();  //ROM ROM。mpuInit()よりも前。mmrInitよりも後
   245:     CRTC.crtInit ();  //CRT CRTコントローラ
   246:     VideoController.vcnInit ();  //VCN ビデオコントローラ
   247:     HD63450.dmaInit ();  //DMA DMAコントローラ
   248:     svsInit ();  //SVS スーパーバイザ領域設定
   249:     MC68901.mfpInit ();  //MFP MFP
   250:     RP5C15.rtcInit ();  //RTC RTC
   251:     sysInit ();  //SYS システムポート
   252:     if (OPMLog.OLG_ON) {
   253:       OPMLog.olgInit ();  //OLG OPMログ。opmInitよりも前
   254:     }
   255:     OPM.opmInit ();  //OPM FM音源
   256:     ADPCM.pcmInit ();  //PCM ADPCM音源
   257:     FDC.fdcInit ();  //FDC FDコントローラ
   258:     HDC.hdcInit ();  //HDC SASI HDコントローラ
   259:     if (HostCDROM.HCD_ENABLED) {  //HCD ホストCD-ROM  spcInitよりも前
   260:       HostCDROM.hcdInit ();
   261:     }
   262:     SPC.spcInit ();  //SPC SCSIプロトコルコントローラ  hcdInitよりも後
   263:     Z8530.sccInit ();  //SCC SCC  rbtInit()よりも後
   264:     IOInterrupt.ioiInit ();  //IOI I/O割り込み
   265:     SpriteScreen.sprInit ();  //SPR スプライト画面
   266:     bnkInit ();  //BNK バンクメモリ
   267:     SRAM.smrInit ();  //SMR SRAM
   268: 
   269:     PPI.ppiInit ();  //PPI PPI
   270:     PrinterPort.prnInit ();  //PRN プリンタポート
   271:     Indicator.indInit ();  //IND インジケータ
   272: 
   273:     SlowdownTest.sdtInit ();  //SDT 鈍化テスト
   274:     Keyboard.kbdInit ();  //KBD キーボード  keydlyとkeyrepはSRAMが先なのでsmrInit()よりも後
   275:     CONDevice.conInit ();  //CON CONデバイス制御
   276:     Mouse.musInit ();  //MUS マウス
   277:     pnlInit ();  //PNL パネル
   278:     frmInit ();  //FRM フレーム
   279: 
   280:     dbgInit ();  //DBG デバッガ共通コンポーネント
   281:     RegisterList.drpInit ();  //DRP レジスタ
   282:     DisassembleList.ddpInit ();  //DDP 逆アセンブルリスト
   283:     MemoryDumpList.dmpInit ();  //DMP メモリダンプリスト
   284:     LogicalSpaceMonitor.atwInit ();  //ATW アドレス変換ウインドウ
   285:     PhysicalSpaceMonitor.paaInit ();  //PAA 物理アドレス空間ウインドウ
   286:     DebugConsole.dgtInit ();  //DGT デバッグコンソール
   287:     if (BranchLog.BLG_ON) {
   288:       BranchLog.blgInit ();  //BLG 分岐ログ
   289:     }
   290:     if (ProgramFlowVisualizer.PFV_ON) {
   291:       ProgramFlowVisualizer.pfvInit ();  //PFV プログラムフロービジュアライザ
   292:     }
   293:     if (RasterBreakPoint.RBP_ON) {
   294:       RasterBreakPoint.rbpInit ();  //RBP ラスタブレークポイント
   295:     }
   296:     if (ScreenModeTest.SMT_ON) {
   297:       ScreenModeTest.smtInit ();  //SMT 表示モードテスト
   298:     }
   299:     if (RootPointerList.RTL_ON) {
   300:       RootPointerList.rtlInit ();  //RTL ルートポインタリスト
   301:     }
   302:     if (SpritePatternViewer.SPV_ON) {
   303:       SpritePatternViewer.spvInit ();  //SPV スプライトパターンビュア
   304:     }
   305:     if (PaletteViewer.PLV_ON) {
   306:       PaletteViewer.plvInit ();  //PLV パレットビュア
   307:     }
   308:     if (ATCMonitor.ACM_ON) {
   309:       ATCMonitor.acmInit ();  //ACM アドレス変換キャッシュモニタ
   310:     }
   311: 
   312:     SoundSource.sndInit ();  //SND サウンド
   313:     FEFunction.fpkInit ();  //FPK FEファンクション
   314:     mpuInit ();  //MPU MPU。romInit()よりも後
   315:     MC68060.mmuInit ();  //MMU メモリ管理ユニット
   316:     SoundMonitor.smnInit ();  //SMN 音声モニタ
   317:     HFS.hfsInit ();  //HFS ホストファイルシステムインタフェイス
   318: 
   319:     GIFAnimation.gifInit ();  //GIF GIFアニメーション
   320:     if (FlashingLights.FLR_ON) {
   321:       FlashingLights.flrInit ();  //FLR 点滅光の軽減  pnlInitより後
   322:     }
   323:     TextCopy.txcInit ();  //TXC テキスト画面コピー
   324:     ButtonFunction.bfnInit ();  //BFN ボタン機能割り当て
   325: 
   326:     //コンポーネントを作る
   327:     //  他のコンポーネントを参照するときは順序に注意する
   328:     Settings.sgsMakeMenu ();  //SGS 設定  mnbMakeMenu()よりも前
   329:     mdlMakeMenu ();  //MDL 機種  mnbMakeMenu(),mpuMakeMenu()よりも前
   330:     FDC.fdcMakeMenu ();  //FDC FDコントローラ  mnbMakeMenu()よりも前
   331:     HDC.hdcMakeMenu ();  //HDC SASI HDコントローラ  mdlMakeMenu()よりも後,mnbMakeMenu()よりも前
   332:     SPC.spcMakeMenu ();  //SPC SCSIプロトコルコントローラ  mdlMakeMenu()よりも後,mnbMakeMenu()よりも前
   333:     SRAM.smrMakeMenu ();  //SMR SRAM  mnbMakeMenuより前、mpuMakeMenuより前
   334:     mpuMakeMenu ();  //MPU MPU  mdlMakeMenuより後、smrMakeMenuより後、mnbMakeMenuより前
   335:     clpMake ();  //CLP クリップボード  mnbMakeMenu()よりも前
   336:     pnlMake ();  //PNL パネル  mnbMakeMenu()よりも前
   337:     mnbMakeMenu ();  //MNB メニューバー  pnlMake()よりも後
   338:     frmMake ();  //FRM フレーム
   339:     dbgMakePopup ();  //DBG デバッガ共通コンポーネント
   340: 
   341:     if (FlashingLights.FLR_ON) {
   342:       FlashingLights.flrInform ();  //mnbMakeMenuより後
   343:     }
   344: 
   345:     //デバッグフラグを消し忘れないようにする
   346:     final String flags = (
   347:       "" +
   348:       (EFPBox.CIR_DEBUG_TRACE ? " EFPBox.CIR_DEBUG_TRACE" : "") +
   349:       (FDC.FDC_DEBUG_TRACE ? " FDC.FDC_DEBUG_TRACE" : "") +
   350:       (FEFunction.FPK_DEBUG_TRACE ? " FEFunction.FPK_DEBUG_TRACE" : "") +
   351:       (HD63450.DMA_DEBUG_TRACE != 0 ? " HD63450.DMA_DEBUG_TRACE" : "") +
   352:       (HDC.HDC_DEBUG_TRACE ? " HDC.HDC_DEBUG_TRACE" : "") +
   353:       (HDC.HDC_DEBUG_COMMAND ? " HDC.HDC_DEBUG_COMMAND" : "") +
   354:       (HFS.HFS_DEBUG_TRACE ? " HFS.HFS_DEBUG_TRACE" : "") +
   355:       (HFS.HFS_DEBUG_FILE_INFO ? " HFS.HFS_DEBUG_FILE_INFO" : "") +
   356:       (HFS.HFS_COMMAND_TRACE ? " HFS.HFS_COMMAND_TRACE" : "") +
   357:       (HFS.HFS_BUFFER_TRACE ? " HFS.HFS_BUFFER_TRACE" : "") +
   358:       (IOInterrupt.IOI_DEBUG_TRACE ? " IOInterrupt.IOI_DEBUG_TRACE" : "") +
   359:       (Keyboard.KBD_DEBUG_LED ? " Keyboard.KBD_DEBUG_LED" : "") +
   360:       (MC68060.MMU_DEBUG_COMMAND ? " MC68060.MMU_DEBUG_COMMAND" : "") +
   361:       (MC68060.MMU_DEBUG_TRANSLATION ? " MC68060.MMU_DEBUG_TRANSLATION" : "") +
   362:       (MC68060.MMU_NOT_ALLOCATE_CACHE ? " MC68060.MMU_NOT_ALLOCATE_CACHE" : "") +
   363:       (RP5C15.RTC_DEBUG_TRACE ? " RP5C15.RTC_DEBUG_TRACE" : "") +
   364:       (SPC.SPC_DEBUG_ON ? " SPC.SPC_DEBUG_ON" : "") +
   365:       (Z8530.SCC_DEBUG_ON ? " Z8530.SCC_DEBUG_ON" : "")
   366:       );
   367:     if (!"".equals (flags)) {
   368:       pnlExitFullScreen (true);
   369:       JOptionPane.showMessageDialog (null, "debug flags:" + flags);
   370:     }
   371: 
   372:     //動作を開始する
   373:     //  イベントリスナーを設定する
   374:     //  タイマーを起動する
   375:     tmrStart ();  //TMR タイマー
   376: 
   377:     Keyboard.kbdStart ();  //KBD キーボード
   378:     Mouse.musStart ();  //MUS マウス
   379:     pnlStart ();  //PNL パネル
   380:     frmStart ();  //FRM フレーム
   381:     SoundSource.sndStart ();  //SND サウンド
   382: 
   383:     if (DataBreakPoint.DBP_ON) {
   384:       DataBreakPoint.dbpStart ();  //DBP データブレークポイント
   385:     }
   386:     if (RasterBreakPoint.RBP_ON) {
   387:       RasterBreakPoint.rbpStart ();  //RBP ラスタブレークポイント
   388:     }
   389:     if (ScreenModeTest.SMT_ON) {
   390:       ScreenModeTest.smtStart ();  //SMT 表示モードテスト
   391:     }
   392:     if (OPMLog.OLG_ON) {
   393:       OPMLog.olgStart ();  //OLG OPMログ
   394:     }
   395:     SoundMonitor.smnStart ();  //SMN 音声モニタ
   396:     RS232CTerminal.trmStart ();  //TRM ターミナルウインドウ
   397:     PPI.ppiStart ();  //PPI PPI
   398:     PrinterPort.prnStart ();  //PRN プリンタポート
   399:     if (BranchLog.BLG_ON) {
   400:       BranchLog.blgStart ();  //BLG 分岐ログ
   401:     }
   402:     if (ProgramFlowVisualizer.PFV_ON) {
   403:       ProgramFlowVisualizer.pfvStart ();  //PFV プログラムフロービジュアライザ
   404:     }
   405:     RegisterList.drpStart ();  //DRP レジスタ
   406:     DisassembleList.ddpStart ();  //DDP 逆アセンブルリスト
   407:     MemoryDumpList.dmpStart ();  //DMP メモリダンプリスト
   408:     LogicalSpaceMonitor.atwStart ();  //ATW アドレス変換ウインドウ
   409:     PhysicalSpaceMonitor.paaStart ();  //PAA 物理アドレス空間ウインドウ
   410:     DebugConsole.dgtStart ();  //DGT コンソール
   411:     if (RootPointerList.RTL_ON) {
   412:       RootPointerList.rtlStart ();  //RTL ルートポインタリスト
   413:     }
   414:     if (SpritePatternViewer.SPV_ON) {
   415:       SpritePatternViewer.spvStart ();  //SPV スプライトパターンビュア
   416:     }
   417:     if (PaletteViewer.PLV_ON) {
   418:       PaletteViewer.plvStart ();  //PLV パレットビュア
   419:     }
   420:     if (ATCMonitor.ACM_ON) {
   421:       ATCMonitor.acmStart ();  //ACM アドレス変換キャッシュモニタ
   422:     }
   423:     ButtonFunction.bfnStart ();  //BFN ボタン機能割り当て
   424: 
   425:     if (Settings.sgsSaveiconValue != null) {
   426:       String[] a = Settings.sgsSaveiconValue.split (",");
   427:       if (0 < a.length) {
   428:         saveIcon (a[0], LnF.LNF_ICON_IMAGES);
   429:         if (1 < a.length) {
   430:           saveImage (LnF.LNF_ICON_IMAGE_16, a[1]);
   431:           if (2 < a.length) {
   432:             saveImage (LnF.LNF_ICON_IMAGE_32, a[2]);
   433:             if (3 < a.length) {
   434:               saveImage (LnF.LNF_ICON_IMAGE_48, a[3]);
   435:             }
   436:           }
   437:         }
   438:       }
   439:       prgTini ();
   440:       return;
   441:     }
   442: 
   443:     //コアを起動する
   444:     mpuReset (-1, -1);
   445: 
   446:     pnlBoot2 ();
   447: 
   448:   }  //コンストラクタ
   449: 
   450: 
   451: 
   452:   //prgTini ()
   453:   //  プログラムの後始末
   454:   public static void prgTini () {
   455:     if (prgTiniLog) {
   456:       System.out.println ("prgTini: call mpuStop");
   457:     }
   458:     mpuStop (null);
   459:     try {
   460:       if (OPMLog.OLG_ON) {
   461:         if (prgTiniLog) {
   462:           System.out.println ("prgTini: call orgTini");
   463:         }
   464:         OPMLog.olgTini ();  //OLG OPMログ
   465:       }
   466:       if (prgTiniLog) {
   467:         System.out.println ("prgTini: call bfnTini");
   468:       }
   469:       ButtonFunction.bfnTini ();  //BFN ボタン機能割り当て
   470:       if (prgTiniLog) {
   471:         System.out.println ("prgTini: call txcTini");
   472:       }
   473:       TextCopy.txcTini ();  //TXC テキスト画面コピー
   474:       if (prgTiniLog) {
   475:         System.out.println ("prgTini: call gifTini");
   476:       }
   477:       GIFAnimation.gifTini ();  //GIFアニメーション
   478:       if (FlashingLights.FLR_ON) {
   479:         if (prgTiniLog) {
   480:           System.out.println ("prgTini: call flrTini");
   481:         }
   482:         FlashingLights.flrTini ();  //FLR 点滅光の軽減
   483:       }
   484:       if (prgTiniLog) {
   485:         System.out.println ("prgTini: call sndTini");
   486:       }
   487:       SoundSource.sndTini ();  //SND サウンド
   488:       if (prgTiniLog) {
   489:         System.out.println ("prgTini: call kbdTini");
   490:       }
   491:       Keyboard.kbdTini ();  //KBD キーボード
   492:       if (prgTiniLog) {
   493:         System.out.println ("prgTini: call musTini");
   494:       }
   495:       Mouse.musTini ();  //MUS マウス
   496:       if (prgTiniLog) {
   497:         System.out.println ("prgTini: call conTini");
   498:       }
   499:       CONDevice.conTini ();  //CON CONデバイス制御
   500:       if (prgTiniLog) {
   501:         System.out.println ("prgTini: call ppiTini");
   502:       }
   503:       PPI.ppiTini ();  //PPI PPI
   504:       if (prgTiniLog) {
   505:         System.out.println ("prgTini: call prnTini");
   506:       }
   507:       PrinterPort.prnTini ();  //PRN プリンタポート
   508:       if (prgTiniLog) {
   509:         System.out.println ("prgTini: call fdcTini");
   510:       }
   511:       FDC.fdcTini ();  //FDC FDコントローラ
   512:       if (prgTiniLog) {
   513:         System.out.println ("prgTini: call hdcTini");
   514:       }
   515:       HDC.hdcTini ();  //HDC SASI HDコントローラ
   516:       if (HostCDROM.HCD_ENABLED) {  //HCD ホストCD-ROM
   517:         if (prgTiniLog) {
   518:           System.out.println ("prgTini: call hcdTini");
   519:         }
   520:         HostCDROM.hcdTini ();
   521:       }
   522:       if (prgTiniLog) {
   523:         System.out.println ("prgTini: call spcTini");
   524:       }
   525:       SPC.spcTini ();  //SPC SCSIプロトコルコントローラ
   526:       if (prgTiniLog) {
   527:         System.out.println ("prgTini: call hfsTini");
   528:       }
   529:       HFS.hfsTini ();  //HFS ホストファイルシステムインタフェイス
   530:       if (prgTiniLog) {
   531:         System.out.println ("prgTini: call sccTini");
   532:       }
   533:       Z8530.sccTini ();  //SCC SCC
   534:       if (prgTiniLog) {
   535:         System.out.println ("prgTini: call crtTini");
   536:       }
   537:       CRTC.crtTini ();  //CRT CRTコントローラ
   538:       if (prgTiniLog) {
   539:         System.out.println ("prgTini: call sprTini");
   540:       }
   541:       SpriteScreen.sprTini ();  //SPR スプライト画面
   542:       if (prgTiniLog) {
   543:         System.out.println ("prgTini: call pnlTini");
   544:       }
   545:       pnlTini ();  //PNL パネル
   546:       if (prgTiniLog) {
   547:         System.out.println ("prgTini: call bnkTini");
   548:       }
   549:       bnkTini ();  //BNK バンクメモリ
   550:       if (prgTiniLog) {
   551:         System.out.println ("prgTini: call romTini");
   552:       }
   553:       ROM.romTini ();  //ROM
   554:       if (MercuryUnit.MU4_ON) {
   555:         if (prgTiniLog) {
   556:           System.out.println ("prgTini: call mu4Tini");
   557:         }
   558:         MercuryUnit.mu4Tini ();
   559:       }
   560:       if (prgTiniLog) {
   561:         System.out.println ("prgTini: call xt3Tini");
   562:       }
   563:       xt3Tini ();  //XT3 Xellent30
   564:       if (prgTiniLog) {
   565:         System.out.println ("prgTini: call mdlTini");
   566:       }
   567:       mdlTini ();  //MDL 機種
   568:       if (prgTiniLog) {
   569:         System.out.println ("prgTini: call smrTini");
   570:       }
   571:       SRAM.smrTini ();  //SMR SRAM
   572:       if (prgTiniLog) {
   573:         System.out.println ("prgTini: call busTini");
   574:       }
   575:       busTini ();  //BUS バスコントローラ
   576:       if (SpritePatternViewer.SPV_ON) {
   577:         if (prgTiniLog) {
   578:           System.out.println ("prgTini: call spvTini");
   579:         }
   580:         SpritePatternViewer.spvTini ();  //SPV スプライトパターンビュア
   581:       }
   582:       if (PaletteViewer.PLV_ON) {
   583:         if (prgTiniLog) {
   584:           System.out.println ("prgTini: call plvTini");
   585:         }
   586:         PaletteViewer.plvTini ();  //PLV パレットビュア
   587:       }
   588:       if (prgTiniLog) {
   589:         System.out.println ("prgTini: call trmTini");
   590:       }
   591:       RS232CTerminal.trmTini ();  //TRM RS-232C設定とターミナル
   592:       if (prgTiniLog) {
   593:         System.out.println ("prgTini: call lnfTini");
   594:       }
   595:       LnF.lnfTini ();
   596:       if (prgTiniLog) {
   597:         System.out.println ("prgTini: call tmrTini");
   598:       }
   599:       tmrTini ();  //TMR タイマー
   600:       if (prgTiniLog) {
   601:         System.out.println ("prgTini: call sgsTini");
   602:       }
   603:       Settings.sgsTini ();  //SGS 設定
   604:     } catch (Exception e) {  //終了時に予期しないエラーが発生すると終了できなくなってしまうので、すべてのExceptionをcatchする
   605:       e.printStackTrace ();
   606:     }
   607:     System.exit (0);
   608:   }  //prgTini()
   609: 
   610:   //prgOpenJavaDialog ()
   611:   //  Java実行環境の情報
   612:   public static void prgOpenJavaDialog () {
   613:     pnlExitFullScreen (true);
   614:     JOptionPane.showMessageDialog (
   615:       frmFrame,
   616:       ComponentFactory.createGridPanel (
   617:         3,  //colCount
   618:         6,  //rowCount
   619:         "paddingLeft=6,paddingRight=6",  //gridStyles
   620:         "italic,right;left;left",  //colStyless
   621:         "italic,center;colSpan=3,widen",  //rowStyless
   622:         "",  //cellStyless
   623:         //
   624:         null,  //(0,0)
   625:         Multilingual.mlnJapanese ? "実行中" : "Running",  //(1,0)
   626:         Multilingual.mlnJapanese ? "推奨" : "Recommended",  //(2,0)
   627:         //
   628:         ComponentFactory.createHorizontalSeparator (),  //(0,1)
   629:         //
   630:         Multilingual.mlnJapanese ? "Java のベンダー" : "Java Vendor",  //(0,2)
   631:         prgJavaVendor,  //(1,2)
   632:         PRG_JAVA_VENDOR,  //(2,2)
   633:         //
   634:         Multilingual.mlnJapanese ? "Java のバージョン" : "Java Version",  //(0,3)
   635:         prgJavaVersion,  //(1,3)
   636:         PRG_JAVA_VERSION,  //(2,3)
   637:         //
   638:         Multilingual.mlnJapanese ? "OS のアーキテクチャ" : "OS Architecture",  //(0,4)
   639:         prgOsArch,  //(1,4)
   640:         PRG_OS_ARCH,  //(2,4)
   641:         //
   642:         Multilingual.mlnJapanese ? "OS の名前" : "OS Name",  //(0,5)
   643:         prgOsName,  //(1,5)
   644:         PRG_OS_NAME  //(2,5)
   645:         ),
   646:       Multilingual.mlnJapanese ? "Java 実行環境の情報" : "Java runtime environment information",
   647:       JOptionPane.PLAIN_MESSAGE);
   648:   }  //prgOpenJavaDialog()
   649: 
   650:   //prgOpenAboutDialog ()
   651:   //  バージョン情報
   652:   public static void prgOpenAboutDialog () {
   653:     pnlExitFullScreen (true);
   654:     JOptionPane.showMessageDialog (
   655:       frmFrame,
   656:       ComponentFactory.createGridPanel (
   657:         2, 4, "paddingLeft=6,paddingRight=6", "italic,right;left", "", "",
   658:         Multilingual.mlnJapanese ? "タイトル" : "Title"  ,  //(0,0)
   659:         PRG_TITLE,  //(1,0)
   660:         Multilingual.mlnJapanese ? "バージョン" : "Version",  //(0,1)
   661:         PRG_VERSION,  //(1,1)
   662:         Multilingual.mlnJapanese ? "作者" : "Author" ,  //(0,2)
   663:         PRG_AUTHOR,  //(1,2)
   664:         Multilingual.mlnJapanese ? "ウェブページ" : "Webpage",  //(0,3)
   665:         PRG_WEBPAGE  //(1,3)
   666:         ),
   667:       Multilingual.mlnJapanese ? "バージョン情報" : "Version information",
   668:       JOptionPane.PLAIN_MESSAGE);
   669:   }  //prgOpenAboutDialog()
   670: 
   671:   //prgOpenXEiJLicenseDialog ()
   672:   //  XEiJライセンスダイアログ
   673:   public static void prgOpenXEiJLicenseDialog () {
   674:     pnlExitFullScreen (true);
   675:     JOptionPane.showMessageDialog (
   676:       frmFrame,
   677:       ComponentFactory.createScrollTextPane (rscGetResourceText ("license_XEiJ.txt"), 550, 300),
   678:       Multilingual.mlnJapanese ? "XEiJ 使用許諾条件" : "XEiJ License",
   679:       JOptionPane.PLAIN_MESSAGE);
   680:   }  //prgOpenXEiJLicenseDialog()
   681: 
   682:   //prgOpenSHARPLicenseDialog ()
   683:   //  FSHARPライセンスダイアログ
   684:   public static void prgOpenSHARPLicenseDialog () {
   685:     pnlExitFullScreen (true);
   686:     JOptionPane.showMessageDialog (
   687:       frmFrame,
   688:       ComponentFactory.createScrollTextPane (rscGetResourceText ("license_FSHARP.txt", "Shift_JIS"), 550, 300),
   689:       Multilingual.mlnJapanese ? "無償公開された X68000 の基本ソフトウェア製品の許諾条件" : "License of the basic software products for X68000 that were distributed free of charge",
   690:       JOptionPane.PLAIN_MESSAGE);
   691:   }  //prgOpenSHARPLicenseDialog()
   692: 
   693:   //prgOpenYmfmLicenseDialog ()
   694:   //  ymfmライセンスダイアログ
   695:   public static void prgOpenYmfmLicenseDialog () {
   696:     pnlExitFullScreen (true);
   697:     JOptionPane.showMessageDialog (
   698:       frmFrame,
   699:       ComponentFactory.createScrollTextPane (rscGetResourceText ("license_ymfm.txt"), 550, 300),
   700:       "ymfm License",
   701:       JOptionPane.PLAIN_MESSAGE);
   702:   }  //prgOpenYmfmLicenseDialog()
   703: 
   704:   //prgOpenJSerialCommLicenseDialog ()
   705:   //  jSerialCommライセンスダイアログ
   706:   public static void prgOpenJSerialCommLicenseDialog () {
   707:     pnlExitFullScreen (true);
   708:     JOptionPane.showMessageDialog (
   709:       frmFrame,
   710:       ComponentFactory.createVerticalSplitPane (
   711:         ComponentFactory.createScrollTextPane (rscGetResourceText ("LICENSE-APACHE-2.0"), 550, 300),
   712:         ComponentFactory.createScrollTextPane (rscGetResourceText ("LICENSE-LGPL-3.0"), 550, 300)
   713:         ),
   714:       "jSerialComm License",
   715:       JOptionPane.PLAIN_MESSAGE);
   716:   }  //prgOpenJSerialCommLicenseDialog()
   717: 
   718:   //prgPrintClass (o)
   719:   //  オブジェクトを表示する
   720:   public static void prgPrintClass (Object o) {
   721:     System.out.println (o.toString ());
   722:     //スーパークラスを遡る
   723:     try {
   724:       Stack<Class<?>> s = new Stack<Class<?>> ();
   725:       for (Class<?> c = o.getClass (); c != null; c = c.getSuperclass ()) {
   726:         s.push (c);
   727:       }
   728:       for (int i = 0; !s.empty (); i++) {
   729:         for (int j = 0; j < i; j++) {
   730:           System.out.print ("  ");
   731:         }
   732:         System.out.println (s.pop ().getName ());
   733:       }
   734:     } catch (Exception e) {
   735:     }
   736:   }  //prgPrintClass(Object)
   737: 
   738:   //prgPrintStackTrace ()
   739:   //  スタックトレースを表示する
   740:   //  メソッドがどのような経路で呼び出されたか確認したいときに使う
   741:   public static void prgPrintStackTrace () {
   742:     Exception e = new Exception ();
   743:     e.fillInStackTrace ();
   744:     prgPrintStackTraceOf (e);
   745:   }  //prgPrintStackTrace()
   746:   public static void prgPrintStackTraceOf (Exception e) {
   747:     //e.printStackTrace ();
   748:     System.out.println ("------------------------------------------------");
   749:     System.out.println (e.toString ());
   750:     System.out.println ("\t" + e.getMessage ());
   751:     for (StackTraceElement ste : e.getStackTrace ()) {
   752:       System.out.println ("\tat " + ste.toString ());
   753:     }
   754:     System.out.println ("------------------------------------------------");
   755:   }  //prgPrintStackTraceOf()
   756: 
   757:   //prgStopOnce ()
   758:   //  1回目だけ停止する。2回目以降は何もしない
   759:   //  特定の条件で止めて近くにブレークポイントを仕掛けたいときに使う
   760:   public static boolean prgStopDone = false;
   761:   public static void prgStopOnce () {
   762:     if (!prgStopDone) {
   763:       prgStopDone = true;
   764:       mpuStop (null);
   765:     }
   766:   }  //prgStopOnce()
   767: 
   768: 
   769: 
   770:   //========================================================================================
   771:   //$$TMR タイマ
   772:   //  tmrTimerは1つだけ存在する
   773:   //  1つのタイマにスケジュールされたタスクはオーバーラップしない
   774:   //  固定遅延実行
   775:   //    tmrTimer.schedule (task, delay, interval)
   776:   //    次回の実行開始予定時刻=max(今回の実行終了時刻,今回の実行開始時刻+interval)
   777:   //  固定頻度実行
   778:   //    tmrTimer.scheduleAtFixedRate (task, delay, interval)
   779:   //    次回の実行開始予定時刻=max(今回の実行終了時刻,初回の実行開始時刻+interval*今回までの実行回数)
   780: 
   781:   //時刻の周波数
   782:   //  mpuClockTimeなどのカウンタが1秒間に進む数
   783:   //  10^10のとき
   784:   //    1周期   0.1nanosecond
   785:   //    2^31-1  0.2second
   786:   //    2^53-1  10day
   787:   //    2^63-1  29year
   788:   //  10^11のとき
   789:   //    1周期   10picosecond
   790:   //    2^31-1  21millisecond
   791:   //    2^53-1  1day
   792:   //    2^63-1  2.9year
   793:   //  10^12のとき
   794:   //    1周期   1picosecond
   795:   //    2^31-1  2.1millisecond
   796:   //    2^53-1  2.5hour
   797:   //    2^63-1  3.5month
   798:   public static final long TMR_FREQ = 1000000000000L;  //10^12Hz。1ps
   799: 
   800:   //メインタイマ
   801:   public static final long TMR_DELAY = 10L;  //ms
   802:   public static final long TMR_INTERVAL = 10L;  //ms
   803: 
   804:   //タイマ
   805:   public static java.util.Timer tmrTimer;  //Timerだけだとjavax.swing.Timerと紛らわしい
   806: 
   807:   //tmrStart ()
   808:   //  タイマを開始する
   809:   public static void tmrStart () {
   810:     tmrTimer = new java.util.Timer ();  //Timerだけだとjavax.swing.Timerと紛らわしい
   811:   }  //tmrStart()
   812: 
   813:   //tmrTini ()
   814:   //  タイマの後始末
   815:   public static void tmrTini () {
   816:     if (tmrTimer != null) {
   817:       tmrTimer.cancel ();
   818:     }
   819:   }  //tmrTini()
   820: 
   821: 
   822: 
   823:   //========================================================================================
   824:   //$$PNL パネル
   825:   //
   826:   //  固定倍率のとき
   827:   //    パネルの最小サイズはスクリーンのサイズに固定倍率を掛けて切り上げた値
   828:   //    スクリーンの表示サイズはスクリーンのサイズに固定倍率を掛けて丸めた値
   829:   //  ウインドウに合わせるとき
   830:   //    倍率は
   831:   //      パネルの幅をスクリーンの幅で割った結果
   832:   //      パネルの高さからキーボードの高さを引いてスクリーンの高さで割った結果
   833:   //    のどちらか小さい方
   834:   //
   835:   //  スクリーンの大きさに固定倍率を掛けて丸めた値から倍率を逆算すると固定倍率よりも小さくなってしまう場合がある
   836:   //
   837:   //  全画面表示
   838:   //    キーボードと合わせてパネルにちょうど入り切るようにスクリーンの拡大率と表示位置を計算する
   839:   //  ウインドウに合わせる
   840:   //    可能ならばユーザがパネルの大きさを変更できるようにする
   841:   //    パネルの大きさが最小倍率で入り切らないとき
   842:   //      プログラムがパネルの大きさを変更できるとき
   843:   //        パネルの大きさを最小倍率でちょうど入り切る大きさに変更する
   844:   //      パネルの中央に表示する
   845:   //    パネルの大きさが最小倍率で入り切るとき
   846:   //      パネルの大きさに合わせてスクリーンを拡大縮小する
   847:   //  固定倍率
   848:   //    可能ならばユーザがパネルの大きさを変更できないようにする
   849:   //    プログラムがパネルの大きさを変更できるとき
   850:   //      パネルの大きさを固定倍率でちょうど入り切る大きさに変更する
   851:   //    スクリーンを拡大縮小してキーボードと一緒にパネルの中央に表示する
   852: 
   853: 
   854:   //ビットマップのサイズ
   855:   public static final int PNL_BM_OFFSET_BITS = 10;
   856:   public static final int PNL_BM_WIDTH = 1 << PNL_BM_OFFSET_BITS;
   857:   public static final int PNL_BM_HEIGHT = 1024;
   858: 
   859:   //アスペクト比
   860:   //  パラメータはaspectratio解像度名=画面比名
   861:   //  解像度番号→解像度名
   862:   //    [resolutionNumber]=resolutionName
   863:   public static final String[] PNL_ASPECT_RESOLUTION_NAME = {
   864:     "256x256",   //0  crtmodtest -l0 -m2
   865:     "384x256",   //1  crtmodtest -l0 -m28
   866:     "512x512",   //2  crtmodtest -l0 -m0
   867:     "640x480",   //3  crtmodtest -l1 -m19
   868:     "768x512",   //4  crtmodtest -l0 -m16
   869:     "1024x848",  //5  crtmodtest -l0 -m18
   870:   };
   871:   //  解像度数
   872:   public static final int PNL_ASPECT_RESOLUTION_COUNT = PNL_ASPECT_RESOLUTION_NAME.length;
   873:   //  画面比番号→画面比名
   874:   //    [ratioNumber]=screenAspectRatioName
   875:   public static final String[] PNL_ASPECT_SCREEN_NAME = {
   876:     "1:1",    //0  1.0
   877:     "64:53",  //1  1.207547
   878:     "4:3",    //2  1.333333
   879:     "7:5",    //3  1.4
   880:     "13:9",   //4  1.444444
   881:     "3:2",    //5  1.5
   882:   };
   883:   //  画面比数
   884:   public static final int PNL_ASPECT_RATIO_COUNT = PNL_ASPECT_SCREEN_NAME.length;
   885:   //  解像度番号→デフォルトの画面比番号
   886:   //    [resolutionNumber]=defaultRatioNumber
   887:   //    Settings.SGS_DEFAULT_PARAMETERSと合わせること
   888:   public static final int[] PNL_ASPECT_DEFAULT_RATIO = {
   889:     2,  //0   256x256  4:3
   890:     2,  //1   384x256  4:3
   891:     2,  //2   512x512  4:3
   892:     2,  //3   640x480  4:3
   893:     5,  //4   768x512  3:2
   894:     1,  //5  1024x848  64:53
   895:   };
   896:   //  画面比番号→ピクセル比名(256x256/512x512)
   897:   //    [ratioNumber]=pixelAspectRatioName
   898:   public static final String[] PNL_ASPECT_PIXEL_NAME_02 = {
   899:     "1:1",    //0  1.0
   900:     null,     //1
   901:     "4:3",    //2  1.333333
   902:     "7:5",    //3  1.4
   903:     "13:9",   //4  1.444444
   904:     "3:2",    //5  1.5
   905:   };
   906:   //  画面比番号→ピクセル比名(384x256/768x512)
   907:   //    [ratioNumber]=pixelAspectRatioName
   908:   public static final String[] PNL_ASPECT_PIXEL_NAME_14 = {
   909:     null,       //0
   910:     null,       //1
   911:     "8:9",      //2  0.8888889  4/768:3/512
   912:     "14:15",    //3  0.9333333  5/768:5/512
   913:     "26:27",    //4  0.962963   13/768:9/512
   914:     "1:1",      //5  1.0        3/768:2/512
   915:   };
   916:   //  画面比番号→ピクセル比名(640x480)
   917:   //    [ratioNumber]=pixelAspectRatioName
   918:   public static final String[] PNL_ASPECT_PIXEL_NAME_3 = {
   919:     null,     //0
   920:     null,     //1
   921:     "1:1",    //2  1.0        4/640:3/480
   922:     "21:20",  //3  1.05       7/640:5/480
   923:     "13:12",  //4  1.083333   13/640:9/480
   924:     "9:8",    //5  1.125      3/640:2/480
   925:   };
   926:   //  画面比番号→ピクセル比名(1024x848)
   927:   //    [ratioNumber]=pixelAspectRatioName
   928:   public static final String[] PNL_ASPECT_PIXEL_NAME_5 = {
   929:     null,       //0
   930:     "1:1",      //1  1.0        64/1024:53/848
   931:     "53:48",    //2  1.104167   4/1024:3/848
   932:     "371:320",  //3  1.159375   7/1024:5/848
   933:     "689:576",  //4  1.196181   13/1024:9/848
   934:     "159:128",  //5  1.242188   3/1024:2/848
   935:   };
   936:   //  画面比番号→画面比
   937:   //    [ratioNumber]=screenAspectRatio
   938:   public static final float[] PNL_ASPECT_SCREEN_RATIO = {
   939:     1.0F / 1.0F,    //0  1.0
   940:     64.0F / 53.0F,  //1  1.207547
   941:     4.0F / 3.0F,    //2  1.333333
   942:     7.0F / 5.0F,    //3  1.4
   943:     13.0F / 9.0F,   //4  1.444444
   944:     3.0F / 2.0F,    //5  1.5
   945:   };
   946:   //  画面比番号→ピクセル比(256x256/512x512)
   947:   //    [ratioNumber]=pixelAspectRatio
   948:   public static final float[] PNL_ASPECT_PIXEL_RATIO_02 = {
   949:     1.0F / 1.0F,    //0  1.0
   950:     0.0F,           //1
   951:     4.0F / 3.0F,    //2  1.333333
   952:     7.0F / 5.0F,    //3  1.4
   953:     13.0F / 9.0F,   //4  1.444444
   954:     3.0F / 2.0F,    //5  1.5
   955:   };
   956:   //  画面比番号→ピクセル比(384x256/768x512)
   957:   //    [ratioNumber]=pixelAspectRatio
   958:   public static final float[] PNL_ASPECT_PIXEL_RATIO_14 = {
   959:     0.0F,             //0
   960:     0.0F,             //1
   961:     8.0F / 9.0F,      //2  0.8888889  4/768:3/512
   962:     14.0F / 15.0F,    //3  0.9333333  5/768:5/512
   963:     26.0F / 27.0F,    //4  0.962963   13/768:9/512
   964:     1.0F / 1.0F,      //5  1.0        3/768:2/512
   965:   };
   966:   //  画面比番号→ピクセル比(640x480)
   967:   //    [ratioNumber]=pixelAspectRatio
   968:   public static final float[] PNL_ASPECT_PIXEL_RATIO_3 = {
   969:     0.0F,           //0
   970:     0.0F,           //1
   971:     1.0F / 1.0F,    //2  1.0        4/640:3/480
   972:     21.0F / 20.0F,  //3  1.05       7/640:5/480
   973:     13.0F / 12.0F,  //4  1.083333   13/640:9/480
   974:     9.0F / 8.0F,    //5  1.125      3/640:2/480
   975:   };
   976:   //  画面比番号→ピクセル比(1024x848)
   977:   //    [ratioNumber]=pixelAspectRatio
   978:   public static final float[] PNL_ASPECT_PIXEL_RATIO_5 = {
   979:     0.0F,             //0
   980:     1.0F / 1.0F,      //1  1.0        64/1024:53/848
   981:     53.0F / 48.0F,    //2  1.104167   4/1024:3/848
   982:     371.0F / 320.0F,  //3  1.159375   7/1024:5/848
   983:     689.0F / 576.0F,  //4  1.196181   13/1024:9/848
   984:     159.0F / 128.0F,  //5  1.242188   3/1024:2/848
   985:   };
   986:   //  解像度番号→画面比番号→ピクセル比名
   987:   //    [resolutionNumber][ratioNumber]=pixelAspectName
   988:   public static final String[][] PNL_ASPECT_NAME_MATRIX = {
   989:     PNL_ASPECT_PIXEL_NAME_02,  //0   256x256
   990:     PNL_ASPECT_PIXEL_NAME_14,  //1   384x256
   991:     PNL_ASPECT_PIXEL_NAME_02,  //2   512x512
   992:     PNL_ASPECT_PIXEL_NAME_3,   //3   640x480
   993:     PNL_ASPECT_PIXEL_NAME_14,  //4   768x512
   994:     PNL_ASPECT_PIXEL_NAME_5,   //5  1024x848
   995:   };
   996:   //  解像度番号→画面比番号→ピクセル比
   997:   //    [resolutionNumber][ratioNumber]=pixelAspectRatio
   998:   public static final float[][] PNL_ASPECT_RATIO_MATRIX = {
   999:     PNL_ASPECT_PIXEL_RATIO_02,  //0   256x256
  1000:     PNL_ASPECT_PIXEL_RATIO_14,  //1   384x256
  1001:     PNL_ASPECT_PIXEL_RATIO_02,  //2   512x512
  1002:     PNL_ASPECT_PIXEL_RATIO_3,   //3   640x480
  1003:     PNL_ASPECT_PIXEL_RATIO_14,  //4   768x512
  1004:     PNL_ASPECT_PIXEL_RATIO_5,   //5  1024x848
  1005:   };
  1006:   //  解像度番号→画面比番号
  1007:   //    [resolutionNumber]=ratioNumber
  1008:   public static int[] pnlAspectMap;
  1009:   //  (24k,HRL,VReso,HReso)→(水平方向の拡大率,垂直方向の拡大率)
  1010:   //    [CRTC.crtHRLCurr<<4|CRTC.crtVResoCurr<<2|CRTC.crtHResoCurr]
  1011:   public static float[] pnlAspectTableX;
  1012:   public static float[] pnlAspectTableY;
  1013: 
  1014:   //サイズと位置
  1015:   public static final int PNL_MIN_WIDTH = 64;  //画面の最小幅
  1016:   public static final int PNL_MIN_HEIGHT = 64;  //画面の最小高さ
  1017:   public static int pnlScreenWidth;  //X68000から見た表示領域のサイズ。幅は常に8の倍数
  1018:   public static int pnlScreenHeight;
  1019:   public static float pnlStretchModeX;  //水平方向の拡大率。pnlAspectTableX[key]
  1020:   public static float pnlStretchModeY;  //垂直方向の拡大率。pnlAspectTableY[key]
  1021:   public static int pnlStretchWidth;  //ピクセルの縦横比に合わせて伸縮された表示領域の幅。Math.round((float)pnlScreenWidth*pnlStretchModeX)
  1022:   public static int pnlStretchHeight;  //ピクセルの縦横比に合わせて伸縮された表示領域の高さ。Math.round((float)pnlScreenHeight*pnlStretchModeY)
  1023:   //  回転
  1024:   public static boolean PNL_ROTATION_ON = true;
  1025:   public static int pnlRotationMode;  //反時計回り0=0度,1=90度,2=180度,3=270度
  1026:   public static AffineTransform pnlRotationTransformLeft;  //アフィン変換
  1027:   public static AffineTransform pnlRotationTransformRight;
  1028:   public static double pnlMatrixL00, pnlMatrixL10, pnlMatrixL01, pnlMatrixL11, pnlMatrixL02, pnlMatrixL12;  //変換
  1029:   public static double pnlMatrixR00, pnlMatrixR10, pnlMatrixR01, pnlMatrixR11, pnlMatrixR02, pnlMatrixR12;
  1030:   public static double pnlInverseL00, pnlInverseL10, pnlInverseL01, pnlInverseL11, pnlInverseL02, pnlInverseL12;  //逆変換
  1031:   public static double pnlInverseR00, pnlInverseR10, pnlInverseR01, pnlInverseR11, pnlInverseR02, pnlInverseR12;
  1032:   public static int pnlRotatedWidth;  //pnlStretchWidth,pnlStretchHeightを回転させた幅と高さ
  1033:   public static int pnlRotatedHeight;
  1034:   //  拡大
  1035:   public static int pnlZoomWidth;  //描画サイズ。pnlRotatedWidth,pnlRotatedHeightを同じ比率で拡大
  1036:   public static int pnlZoomHeight;
  1037:   public static int pnlZoomRatioOutX;  //65536*pnlZoomWidth/pnlScreenWidth
  1038:   public static int pnlZoomRatioOutY;  //65536*pnlZoomHeight/pnlScreenHeight
  1039:   public static int pnlZoomRatioInX;  //65536*pnlScreenWidth/pnlZoomWidth
  1040:   public static int pnlZoomRatioInY;  //65536*pnlScreenHeight/pnlZoomHeight
  1041:   public static int pnlWidth;  //パネルのサイズ
  1042:   public static int pnlHeight;
  1043:   public static Dimension pnlSize;  //パネルの推奨サイズ。pnlWidth,pnlHeight
  1044:   public static int pnlScreenX1;  //スクリーンのX座標。1=左開始,2=左終了,3=右開始,4=右終了
  1045:   public static int pnlScreenX2;
  1046:   public static int pnlScreenX3;
  1047:   public static int pnlScreenX4;
  1048:   public static int pnlScreenY1;  //スクリーンのY座標。1=上開始,2=上終了,3=下開始,4=下終了
  1049:   public static int pnlScreenY2;
  1050:   public static int pnlScreenY3;
  1051:   public static int pnlScreenY4;
  1052:   public static int pnlKeyboardX;  //キーボードの表示位置。pnlUpdateArrangement()が設定する
  1053:   public static int pnlKeyboardY;
  1054:   public static int pnlMinimumWidth;  //パネルの最小サイズ
  1055:   public static int pnlMinimumHeight;
  1056:   public static int pnlGlobalX;  //画面上の表示位置
  1057:   public static int pnlGlobalY;
  1058: 
  1059:   //モード
  1060:   public static final boolean PNL_FILL_BACKGROUND = true;  //true=常に背景を塗り潰してから描画する
  1061:   public static boolean pnlFillBackgroundRequest;  //true=次回のpaintで背景を塗り潰す
  1062:   public static boolean pnlIsFullScreenSupported;  //true=全画面表示に移行できる
  1063:   public static boolean pnlPrevKeyboardOn;  //true=全画面表示に移行する前はキーボードを表示していた
  1064:   public static boolean pnlHideKeyboard;  //true=全画面表示のときキーボードを隠す
  1065: 
  1066:   //補間アルゴリズム
  1067:   //  RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR  軽い
  1068:   //  RenderingHints.VALUE_INTERPOLATION_BILINEAR          頑張る
  1069:   //  RenderingHints.VALUE_INTERPOLATION_BICUBIC           重すぎる?
  1070:   public static Object pnlInterpolation;  //補間アルゴリズム
  1071: 
  1072:   //ホストのリフレッシュレートに合わせる
  1073:   public static final double PNL_MIN_RATE = 1.0;
  1074:   public static final double PNL_MAX_RATE = 1000.0;
  1075:   public static final double PNL_DEFAULT_RATE = 59.94;  //デフォルトのリフレッシュレート(Hz)。指定がなく取得もできなかったときの値
  1076:   public static double pnlRefreshRate;  //指定されたリフレッシュレート(Hz)。0.0=指定なし
  1077:   public static double pnlFixedRate;  //指定されたか取得できたかデフォルトを採用して確定したリフレッシュレート(Hz)。0.0=未確定(指定がなくて未取得)
  1078:   public static boolean pnlAdjustVsync;  //true=ホストのリフレッシュレートに合わせる
  1079: 
  1080:   //イメージとビットマップ
  1081:   //
  1082:   //  立体視OFFのとき
  1083:   //    左に描く
  1084:   //    左を表示する
  1085:   //
  1086:   //  立体視ONのとき
  1087:   //    垂直映像開始で
  1088:   //      0=3=左右OPENまたは2=左OPENのとき
  1089:   //        左に描く
  1090:   //      1=右OPENのとき
  1091:   //        右に描く
  1092:   //    drawRasterの後で
  1093:   //      0=3=左右OPENのとき
  1094:   //        左から右へコピー
  1095:   //    左右を表示する
  1096:   //
  1097:   //  シャッターの左右CLOSEは左右OPENとみなす
  1098:   //    TVコントロール信号の送信で$00E8E003に$08や$00が書き込まれて左右CLOSEされてしまう
  1099:   //    左右CLOSEすると何も表示されないので止まってしまったように見える
  1100:   //    接続ケーブル配線図によると~3DRだけで左OPENと右OPENを切り替えており左右CLOSEは存在しない
  1101:   //
  1102:   //  X68000-ファミコン3Dシステム接続ケーブル配線図
  1103:   //            X68000 STEREOSCOPIC端子側
  1104:   //            6pin Mini-DIN オス 半田面
  1105:   //                ┌─┐    ┌─┐
  1106:   //              ┌┘  └──┘  └┐
  1107:   //            ┌┘   GND    GND   └┐
  1108:   //            │      ○6  5○────┐
  1109:   //            │  VCC1              ││
  1110:   //          ┌───○4      3○~3DL││
  1111:   //          ││                    ││
  1112:   //          ││  ~3DR○2  1○      ││
  1113:   //          │└┐    │ VSYNC(3D)┌┘│
  1114:   //          │  └┐  │        ┌┘  │
  1115:   //          │    └─│────┘    │
  1116:   //          │        └──┐        │
  1117:   //    ┌──│───────│────│─┐
  1118:   //    │  ○│○  ○  ○  ○│○  ○  ○  │
  1119:   //    │   8│ 7   6   5   4│ 3   2   1  │
  1120:   //    └┐  │              │          ┌┘
  1121:   //      │  ○  ○  ○  ○  ○  ○  ○  │
  1122:   //      │  15  14  13  12  11  10   9  │
  1123:   //      └───────────────┘
  1124:   //           D-Sub 15pin オス 半田面
  1125:   //           ファミコン3Dシステム側
  1126:   //      出典:電脳倶楽部17号(1989年10月号)
  1127:   //
  1128:   public static final boolean PNL_STEREOSCOPIC_ON = true;
  1129:   //!!! XEiJ.PNL_USE_THREADとCRTC.CRT_ENABLE_INTERMITTENTを同時にtrueにしないこと
  1130:   public static final boolean PNL_USE_THREAD = true;  //true=パネルの表示にスレッドを使う
  1131:   //if PNL_USE_THREAD
  1132:   public static BufferedImage[] pnlScreenImageLeftArray;  //イメージ左
  1133:   public static BufferedImage[] pnlScreenImageRightArray;  //イメージ右
  1134:   //  if PNL_ROTATION_ON
  1135:   public static BufferedImage[] pnlScreenSubImageLeftArray;  //イメージ左の表示範囲のサブイメージ
  1136:   public static BufferedImage[] pnlScreenSubImageRightArray;  //イメージ右の表示範囲のサブイメージ
  1137:   //  endif
  1138:   public static int[][] pnlBMLeftArray;  //ビットマップ左
  1139:   public static int[][] pnlBMRightArray;  //ビットマップ右
  1140:   public static volatile int pnlBMWrite;  //書き込むビットマップ番号。コアスレッドが更新する
  1141:   public static volatile int pnlBMRead;  //読み出すビットマップ番号。描画スレッドが更新する
  1142:   //else
  1143:   public static BufferedImage pnlScreenImageLeft;  //イメージ左
  1144:   public static BufferedImage pnlScreenImageRight;  //イメージ右
  1145:   //  if PNL_ROTATION_ON
  1146:   public static BufferedImage pnlScreenSubImageLeft;  //イメージ左の表示範囲のサブイメージ
  1147:   public static BufferedImage pnlScreenSubImageRight;  //イメージ右の表示範囲のサブイメージ
  1148:   //  endif
  1149:   public static int[] pnlBMLeft;  //ビットマップ左
  1150:   public static int[] pnlBMRight;  //ビットマップ右
  1151:   //endif
  1152:   public static int[] pnlBM;  //描画するビットマップ
  1153:   public static boolean pnlStereoscopicOn;  //true=立体視
  1154:   public static final int PNL_NAKED_EYE_CROSSING = 0;  //裸眼交差法
  1155:   public static final int PNL_NAKED_EYE_PARALLEL = 1;  //裸眼平行法
  1156:   public static final int PNL_SIDE_BY_SIDE       = 2;  //サイドバイサイド
  1157:   public static final int PNL_TOP_AND_BOTTOM     = 3;  //トップアンドボトム
  1158:   public static int pnlStereoscopicMethod;  //0=裸眼交差法,1=裸眼平行法,2=サイドバイサイド,3=トップアンドボトム
  1159:   public static int pnlStereoscopicFactor;  //pnlStereoscopicOn&&(pnlStereoscopicMethod==PNL_NAKED_EYE_CROSSING||pnlStereoscopicMethod==PNL_NAKED_EYE_PARALLEL)?2:1
  1160:   public static int pnlStereoscopicShutter;  //$00E8E003のbit1-0。0=3=左右OPEN,1=右OPEN,2=左OPEN
  1161: 
  1162:   //パネル
  1163:   public static JPanel pnlPanel;  //パネル
  1164:   //if PNL_USE_THREAD
  1165:   public static Thread pnlThread;  //スレッド
  1166:   public static boolean pnlInterrupted;  //pnlThread.isInterrupted()の代わり
  1167:   public static long pnlWakeupTime;  //スレッドを起こす時刻(ミリ)
  1168:   public static long pnlWakeupTimeMNP;  //スレッドを起こす時刻(マイクロナノピコ)
  1169:   public static final boolean PNL_USE_CANVAS = PNL_USE_THREAD && true;  //true=パネルの表示にキャンバスを使う
  1170:   //  if PNL_USE_CANVAS
  1171:   public static boolean pnlUseCanvasRequest;
  1172:   public static boolean pnlUseCanvas;  //true=パネルの表示にキャンバスを使う
  1173:   public static Canvas pnlCanvas;  //キャンバス
  1174:   public static Component pnlCanvasOrPanel;  //PNL_USE_CANVAS&&pnlUseCanvas?pnlCanvas:pnlPanel
  1175:   //  endif
  1176:   //endif
  1177: 
  1178:   //メニュー
  1179:   public static int pnlFixedScale;
  1180:   public static SpinnerNumberModel pnlFixedModel;
  1181:   public static JSpinner pnlFixedSpinner;
  1182: 
  1183:   //pnlInit ()
  1184:   //  パネルのフィールドを初期化する
  1185:   public static void pnlInit () {
  1186:     pnlInit2 ();
  1187: 
  1188:     //設定
  1189: 
  1190:     //  固定倍率
  1191:     pnlFixedScale = Math.max (10, Math.min (1000, Settings.sgsGetInt ("fixedscale")));
  1192: 
  1193:     //  アスペクト比
  1194:     pnlAspectMap = new int[PNL_ASPECT_RESOLUTION_COUNT];
  1195:     for (int resolutionNumber = 0; resolutionNumber < PNL_ASPECT_RESOLUTION_COUNT; resolutionNumber++) {
  1196:       String resolutionName = PNL_ASPECT_RESOLUTION_NAME[resolutionNumber];
  1197:       String screenName = Settings.sgsGetString ("aspectratio" + resolutionName);
  1198:       int ratioNumber = PNL_ASPECT_DEFAULT_RATIO[resolutionNumber];
  1199:       for (int tempRatioNumber = 0; tempRatioNumber < PNL_ASPECT_RATIO_COUNT; tempRatioNumber++) {
  1200:         if (PNL_ASPECT_RATIO_MATRIX[resolutionNumber][tempRatioNumber] == 0.0F) {
  1201:           continue;
  1202:         }
  1203:         if (PNL_ASPECT_SCREEN_NAME[tempRatioNumber].equals (screenName)) {
  1204:           ratioNumber = tempRatioNumber;
  1205:           break;
  1206:         }
  1207:       }
  1208:       pnlAspectMap[resolutionNumber] = ratioNumber;
  1209:     }
  1210:     pnlAspectTableX = new float[64];
  1211:     pnlAspectTableY = new float[64];
  1212:     pnlUpdateAspectTable ();
  1213: 
  1214:     //  補間アルゴリズム
  1215:     switch (Settings.sgsGetString ("interpolation").toLowerCase ()) {
  1216:     case "nearest":  //最近傍補間
  1217:       pnlInterpolation = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
  1218:       break;
  1219:     case "bilinear":  //線形補間
  1220:       pnlInterpolation = RenderingHints.VALUE_INTERPOLATION_BILINEAR;
  1221:       break;
  1222:     case "bicubic":  //三次補間
  1223:       pnlInterpolation = RenderingHints.VALUE_INTERPOLATION_BICUBIC;
  1224:       break;
  1225:     default:
  1226:       pnlInterpolation = RenderingHints.VALUE_INTERPOLATION_BILINEAR;
  1227:     }
  1228: 
  1229:     //  ホストのリフレッシュレートに合わせる
  1230:     pnlRefreshRate = 0.0;
  1231:     {
  1232:       String s = Settings.sgsGetString ("refreshrate");
  1233:       if (!s.equals ("")) {
  1234:         try {
  1235:           double rate = Double.parseDouble (s);
  1236:           if (PNL_MIN_RATE <= rate && rate <= PNL_MAX_RATE) {
  1237:             pnlRefreshRate = rate;
  1238:           }
  1239:         } catch (NumberFormatException nfe) {
  1240:         }
  1241:       }
  1242:     }
  1243:     pnlFixedRate = pnlRefreshRate;
  1244:     pnlAdjustVsync = Settings.sgsGetOnOff ("adjustvsync");
  1245: 
  1246:     pnlPrevKeyboardOn = true;
  1247: 
  1248:     pnlHideKeyboard = Settings.sgsGetOnOff ("hidekeyboard");
  1249: 
  1250:     //イメージとビットマップ
  1251:     if (PNL_USE_THREAD) {
  1252:       pnlScreenImageLeftArray = new BufferedImage[4];
  1253:       pnlScreenImageRightArray = new BufferedImage[4];
  1254:       if (PNL_ROTATION_ON) {
  1255:         pnlScreenSubImageLeftArray = new BufferedImage[4];
  1256:         pnlScreenSubImageRightArray = new BufferedImage[4];
  1257:       }
  1258:       pnlBMLeftArray = new int[4][];
  1259:       pnlBMRightArray = new int[4][];
  1260:       for (int n = 0; n < 4; n++) {
  1261:         pnlScreenImageLeftArray[n] = new BufferedImage (PNL_BM_WIDTH, PNL_BM_HEIGHT, BufferedImage.TYPE_INT_ARGB);
  1262:         pnlScreenImageRightArray[n] = new BufferedImage (PNL_BM_WIDTH, PNL_BM_HEIGHT, BufferedImage.TYPE_INT_ARGB);
  1263:         if (PNL_ROTATION_ON) {
  1264:           pnlScreenSubImageLeftArray[n] = null;
  1265:           pnlScreenSubImageRightArray[n] = null;
  1266:         }
  1267:         pnlBMLeftArray[n] = ((DataBufferInt) pnlScreenImageLeftArray[n].getRaster ().getDataBuffer ()).getData ();
  1268:         pnlBMRightArray[n] = ((DataBufferInt) pnlScreenImageRightArray[n].getRaster ().getDataBuffer ()).getData ();
  1269:       }
  1270:       pnlBMWrite = 0;
  1271:       pnlBM = pnlBMLeftArray[pnlBMWrite & 3];  //左に描く
  1272:       pnlBMRead = 0;
  1273:       pnlThread = null;
  1274:       pnlInterrupted = false;
  1275:       pnlWakeupTime = 0L;
  1276:       pnlWakeupTimeMNP = 0L;
  1277:       if (PNL_USE_CANVAS) {
  1278:         pnlUseCanvasRequest = Settings.sgsGetOnOff ("usecanvas");
  1279:         pnlUseCanvas = pnlUseCanvasRequest;
  1280:         pnlCanvas = null;
  1281:       }
  1282:     } else {
  1283:       pnlScreenImageLeft = new BufferedImage (PNL_BM_WIDTH, PNL_BM_HEIGHT, BufferedImage.TYPE_INT_ARGB);
  1284:       pnlScreenImageRight = new BufferedImage (PNL_BM_WIDTH, PNL_BM_HEIGHT, BufferedImage.TYPE_INT_ARGB);
  1285:       if (PNL_ROTATION_ON) {
  1286:         pnlScreenSubImageLeft = null;
  1287:         pnlScreenSubImageRight = null;
  1288:       }
  1289:       pnlBMLeft = ((DataBufferInt) pnlScreenImageLeft.getRaster ().getDataBuffer ()).getData ();
  1290:       pnlBMRight = ((DataBufferInt) pnlScreenImageRight.getRaster ().getDataBuffer ()).getData ();
  1291:       pnlBM = pnlBMLeft;  //左に描く
  1292:     }
  1293:     pnlStereoscopicOn = Settings.sgsGetOnOff ("stereoscopic");
  1294:     switch (Settings.sgsGetString ("stereoscopicmethod").toLowerCase ()) {
  1295:     case "nakedeyecrossing":
  1296:       pnlStereoscopicMethod = PNL_NAKED_EYE_CROSSING;
  1297:       break;
  1298:     case "nakedeyeparallel":
  1299:       pnlStereoscopicMethod = PNL_NAKED_EYE_PARALLEL;
  1300:       break;
  1301:     case "sidebyside":
  1302:       pnlStereoscopicMethod = PNL_SIDE_BY_SIDE;
  1303:       break;
  1304:     case "topandbottom":
  1305:       pnlStereoscopicMethod = PNL_TOP_AND_BOTTOM;
  1306:       break;
  1307:     default:
  1308:       pnlStereoscopicMethod = PNL_NAKED_EYE_CROSSING;
  1309:     }
  1310:     pnlStereoscopicFactor = pnlStereoscopicOn && (pnlStereoscopicMethod == PNL_NAKED_EYE_CROSSING ||
  1311:                                                   pnlStereoscopicMethod == PNL_NAKED_EYE_PARALLEL) ? 2 : 1;
  1312:     pnlStereoscopicShutter = 0;  //左右OPEN
  1313: 
  1314:     //サイズと位置
  1315:     pnlScreenWidth = 768;
  1316:     pnlScreenHeight = 512;
  1317:     pnlStretchModeX = 1.0F;
  1318:     pnlStretchModeY = 1.0F;
  1319:     pnlStretchWidth = Math.round ((float) pnlScreenWidth * pnlStretchModeX);
  1320:     pnlStretchHeight = Math.round ((float) pnlScreenHeight * pnlStretchModeY);
  1321:     //  回転
  1322:     if (PNL_ROTATION_ON) {
  1323:       pnlRotationMode = Settings.sgsGetInt ("rotation", 0);
  1324:       if (pnlRotationMode < 0 || 3 < pnlRotationMode) {
  1325:         pnlRotationMode = 0;
  1326:       }
  1327:       pnlRotationTransformLeft = new AffineTransform ();
  1328:       pnlRotationTransformRight = new AffineTransform ();
  1329:     }
  1330:     pnlRotatedWidth = pnlStretchWidth;
  1331:     pnlRotatedHeight = pnlStretchHeight;
  1332:     if (PNL_ROTATION_ON && ((pnlRotationMode & 1) != 0)) {  //90度または270度のとき
  1333:       pnlRotatedWidth = pnlStretchHeight;  //幅と高さを入れ替える
  1334:       pnlRotatedHeight = pnlStretchWidth;
  1335:     }
  1336:     //  拡大
  1337:     pnlZoomWidth = pnlRotatedWidth;
  1338:     pnlZoomHeight = pnlRotatedHeight;
  1339:     pnlWidth = Math.max (pnlZoomWidth * pnlStereoscopicFactor, Keyboard.kbdWidth);
  1340:     pnlHeight = pnlZoomHeight + Keyboard.kbdHeight;
  1341:     pnlSize = new Dimension (pnlWidth, pnlHeight);
  1342:     pnlScreenX1 = (pnlWidth - pnlZoomWidth * pnlStereoscopicFactor) >> 1;
  1343:     pnlScreenY1 = 0;
  1344:     pnlArrangementCommon ();
  1345:     pnlMinimumWidth = Math.max (PNL_MIN_WIDTH, Keyboard.kbdWidth);
  1346:     pnlMinimumHeight = PNL_MIN_HEIGHT + Keyboard.kbdHeight;
  1347:     pnlGlobalX = 0;
  1348:     pnlGlobalY = 0;
  1349: 
  1350:     //モード
  1351:     if (!PNL_FILL_BACKGROUND) {
  1352:       pnlFillBackgroundRequest = true;
  1353:     }
  1354: 
  1355:     //メニュー
  1356:     pnlFixedModel = new SpinnerNumberModel (pnlFixedScale, 10, 1000, 1);
  1357:     pnlFixedSpinner = ComponentFactory.createNumberSpinner (pnlFixedModel, 4, new ChangeListener () {
  1358:       @Override public void stateChanged (ChangeEvent ce) {
  1359:         if (pnlMode != PNL_FIXEDSCALE) {  //固定倍率になっていない
  1360:           pnlSetMode (PNL_FIXEDSCALE);  //固定倍率に切り替える
  1361:         } else {  //固定倍率になっている
  1362:           pnlUpdateArrangement ();  //再配置のみ
  1363:         }
  1364:       }
  1365:     });
  1366: 
  1367:     if (PNL_ROUNDED_CORNER_ON) {
  1368:       pnlRoundedCornerModel = new SpinnerNumberModel (pnlRoundedCornerRatio, 0, 50, 1);
  1369:       pnlRoundedCornerSpinner = ComponentFactory.createNumberSpinner (pnlRoundedCornerModel, 2, new ChangeListener () {
  1370:         @Override public void stateChanged (ChangeEvent ce) {
  1371:           pnlRoundedCornerRatio = pnlRoundedCornerModel.getNumber ().intValue ();
  1372:           if (PNL_ROUNDED_CORNER_TEST || pnlMode == PNL_FULLSCREEN) {
  1373:             pnlUpdateArrangement ();
  1374:           }
  1375:         }
  1376:       });
  1377:     }
  1378: 
  1379:   }  //pnlInit()
  1380: 
  1381:   //rate = pnlGetRefreshRate ()
  1382:   //  ホストのリフレッシュレートを取得する
  1383:   public static double pnlGetRefreshRate () {
  1384:     double rate = 0.0;
  1385:     GraphicsConfiguration gc = frmFrame.getGraphicsConfiguration ();
  1386:     if (gc != null) {
  1387:       GraphicsDevice gd = gc.getDevice ();
  1388:       DisplayMode dm = gd.getDisplayMode ();
  1389:       int i = dm.getRefreshRate ();  //リフレッシュレート
  1390:       if (i != DisplayMode.REFRESH_RATE_UNKNOWN) {
  1391:         rate = (i == 23 ? 23.98 :
  1392:                 i == 29 ? 29.97 :
  1393:                 i == 59 ? 59.94 :
  1394:                 i == 119 ? 119.88 :
  1395:                 i == 239 ? 239.76 :
  1396:                 (double) i);
  1397:         if (rate < PNL_MIN_RATE || PNL_MAX_RATE < rate) {  //念の為
  1398:           rate = 0.0;
  1399:         }
  1400:       }
  1401:     }
  1402:     if (rate == 0.0) {
  1403:       rate = PNL_DEFAULT_RATE;
  1404:       System.out.printf (Multilingual.mlnJapanese ?
  1405:                          "ホストのリフレッシュレートを取得できません。デフォルトの %.2f Hz を使います\n" :
  1406:                          "Cannot get host refresh rate. Use default %.2f Hz\n", rate);
  1407:     } else {
  1408:       System.out.printf (Multilingual.mlnJapanese ?
  1409:                          "ホストのリフレッシュレートは %.2f Hz です\n" :
  1410:                          "Host refresh rate is %.2f Hz\n", rate);
  1411:     }
  1412:     return rate;
  1413:   }  //nlGetRefreshRate
  1414: 
  1415:   //  立体視をon/offする
  1416:   public static void pnlSetStereoscopic (boolean on, int method) {
  1417:     if (pnlStereoscopicOn != on || pnlStereoscopicMethod != method) {
  1418:       pnlStereoscopicMethod = method;
  1419:       pnlStereoscopicFactor = on && (pnlStereoscopicMethod == PNL_NAKED_EYE_CROSSING ||
  1420:                                      pnlStereoscopicMethod == PNL_NAKED_EYE_PARALLEL) ? 2 : 1;
  1421:       if (!pnlStereoscopicOn && on) {  //off→on
  1422:         if (PNL_USE_THREAD) {
  1423:           for (int n = 0; n < 4; n++) {
  1424:             System.arraycopy (pnlBMLeftArray[n], 0, pnlBMRightArray[n], 0, 1024 * 1024);  //左から右へコピー
  1425:           }
  1426:         } else {
  1427:           System.arraycopy (pnlBMLeft, 0, pnlBMRight, 0, 1024 * 1024);  //左から右へコピー
  1428:         }
  1429:       } else if (pnlStereoscopicOn && !on) {  //on→off
  1430:         if (PNL_USE_THREAD) {
  1431:           pnlBM = pnlBMLeftArray[pnlBMWrite & 3];  //左に描く
  1432:         } else {
  1433:           pnlBM = pnlBMLeft;  //左に描く
  1434:         }
  1435:       }
  1436:       pnlStereoscopicOn = on;
  1437:       pnlUpdateArrangement ();
  1438:     }
  1439:   }
  1440: 
  1441:   //  後始末
  1442:   public static void pnlTini () {
  1443:     pnlTini2 ();
  1444:     if (PNL_USE_THREAD) {
  1445:       if (pnlThread != null) {
  1446:         pnlInterrupted = true;
  1447:         try {
  1448:           pnlThread.join (100L);
  1449:         } catch (InterruptedException ie) {
  1450:         }
  1451:         pnlThread = null;
  1452:       }
  1453:     }
  1454:     //設定
  1455:     //  固定倍率
  1456:     Settings.sgsPutInt ("fixedscale", pnlFixedScale);
  1457: 
  1458:     //  アスペクト比
  1459:     for (int resolutionNumber = 0; resolutionNumber < PNL_ASPECT_RESOLUTION_COUNT; resolutionNumber++) {
  1460:       String resolutionName = PNL_ASPECT_RESOLUTION_NAME[resolutionNumber];
  1461:       int ratioNumber = pnlAspectMap[resolutionNumber];
  1462:       String screenName = PNL_ASPECT_SCREEN_NAME[ratioNumber];
  1463:       Settings.sgsPutString ("aspectratio" + resolutionName, screenName);
  1464:     }
  1465: 
  1466:     //  補間アルゴリズム
  1467:     Settings.sgsPutString ("interpolation",
  1468:                            pnlInterpolation == RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR ? "nearest" :
  1469:                            pnlInterpolation == RenderingHints.VALUE_INTERPOLATION_BILINEAR ? "bilinear" :
  1470:                            pnlInterpolation == RenderingHints.VALUE_INTERPOLATION_BICUBIC ? "bicubic" :
  1471:                            "bilinear");
  1472:     //  ホストのリフレッシュレートに合わせる
  1473:     if (pnlRefreshRate != PNL_DEFAULT_RATE) {
  1474:       Settings.sgsPutString ("refreshrate",
  1475:                              pnlRefreshRate == 0.0 ? "" : String.valueOf (pnlRefreshRate));
  1476:     }
  1477:     Settings.sgsPutOnOff ("adjustvsync", pnlAdjustVsync);
  1478: 
  1479:     Settings.sgsPutOnOff ("hidekeyboard", pnlHideKeyboard);
  1480: 
  1481:     if (PNL_USE_CANVAS) {
  1482:       Settings.sgsPutOnOff ("usecanvas", pnlUseCanvasRequest);
  1483:     }
  1484: 
  1485:     //  立体視
  1486:     Settings.sgsPutOnOff ("stereoscopic", pnlStereoscopicOn);
  1487:     Settings.sgsPutString ("stereoscopicmethod",
  1488:                            pnlStereoscopicMethod == PNL_NAKED_EYE_CROSSING ? "nakedeyecrossing" :
  1489:                            pnlStereoscopicMethod == PNL_NAKED_EYE_PARALLEL ? "nakedeyeparallel" :
  1490:                            pnlStereoscopicMethod == PNL_SIDE_BY_SIDE ? "sidebyside" :
  1491:                            pnlStereoscopicMethod == PNL_TOP_AND_BOTTOM ? "topandbottom" :
  1492:                            "nakedeyecrossing");
  1493: 
  1494:     //  回転
  1495:     if (PNL_ROTATION_ON) {
  1496:       Settings.sgsPutInt ("rotation", pnlRotationMode);
  1497:     }
  1498: 
  1499:   }  //pnlTini
  1500: 
  1501:   //pnlUpdateAspectTable ()
  1502:   //  ピクセルアスペクト比テーブルを更新する
  1503:   public static void pnlUpdateAspectTable () {
  1504:     float[] ratio = new float[PNL_ASPECT_RESOLUTION_COUNT];  //[resolutionNumber]=pixelAspectRatio
  1505:     for (int resolutionNumber = 0; resolutionNumber < PNL_ASPECT_RESOLUTION_COUNT; resolutionNumber++) {
  1506:       int ratioNumber = pnlAspectMap[resolutionNumber];
  1507:       ratio[resolutionNumber] = PNL_ASPECT_RATIO_MATRIX[resolutionNumber][ratioNumber];
  1508:     }
  1509:     Arrays.fill (pnlAspectTableY, 1.0F);
  1510:     //              HRL V  H
  1511:     pnlAspectTableX[0b0_00_00] = ratio[0] * 2.0F;  //69/6 256x256
  1512:     pnlAspectTableX[0b0_00_01] = ratio[2];         //69/3 512x256
  1513:     pnlAspectTableX[0b0_00_10] = ratio[4];         //69/2 768x256
  1514:     pnlAspectTableX[0b0_00_11] = ratio[3];         //50/2 640x240
  1515:     pnlAspectTableX[0b0_01_00] = ratio[0] * 2.0F;  //69/6 256x512
  1516:     pnlAspectTableX[0b0_01_01] = ratio[2];         //69/3 512x512
  1517:     pnlAspectTableX[0b0_01_10] = ratio[4];         //69/2 768x512
  1518:     pnlAspectTableX[0b0_01_11] = ratio[3];         //50/2 640x480
  1519:     pnlAspectTableX[0b0_10_00] = ratio[0] * 4.0F;  //69/6 256x1024
  1520:     pnlAspectTableX[0b0_10_01] = ratio[2] * 2.0F;  //69/3 512x1024
  1521:     pnlAspectTableX[0b0_10_10] = ratio[4] * 2.0F;  //69/2 768x1024
  1522:     pnlAspectTableX[0b0_10_11] = ratio[3] * 2.0F;  //50/2 640x960
  1523:     pnlAspectTableX[0b0_11_00] = ratio[0] * 4.0F;
  1524:     pnlAspectTableX[0b0_11_01] = ratio[2] * 2.0F;
  1525:     pnlAspectTableX[0b0_11_10] = ratio[4] * 2.0F;
  1526:     pnlAspectTableX[0b0_11_11] = ratio[3] * 2.0F;
  1527:     pnlAspectTableX[0b1_00_00] = ratio[0] * 2.0F;  //69/6 256x256
  1528:     pnlAspectTableX[0b1_00_01] = ratio[1] * 2.0F;  //69/4 384x256
  1529:     pnlAspectTableX[0b1_00_10] = ratio[4];         //69/2 768x256
  1530:     pnlAspectTableX[0b1_00_11] = ratio[3];         //50/2 640x240
  1531:     pnlAspectTableX[0b1_01_00] = ratio[0] * 2.0F;  //69/6 256x512
  1532:     pnlAspectTableX[0b1_01_01] = ratio[1] * 2.0F;  //69/4 384x512
  1533:     pnlAspectTableX[0b1_01_10] = ratio[4];         //69/2 768x512
  1534:     pnlAspectTableX[0b1_01_11] = ratio[3];         //50/2 640x480
  1535:     pnlAspectTableX[0b1_10_00] = ratio[0] * 4.0F;  //69/6 256x1024
  1536:     pnlAspectTableX[0b1_10_01] = ratio[1] * 2.0F;  //69/4 384x1024
  1537:     pnlAspectTableX[0b1_10_10] = ratio[4] * 2.0F;  //69/2 768x1024
  1538:     pnlAspectTableX[0b1_10_11] = ratio[3] * 2.0F;  //50/2 640x960
  1539:     pnlAspectTableX[0b1_11_00] = ratio[0] * 4.0F;
  1540:     pnlAspectTableX[0b1_11_01] = ratio[1] * 2.0F;
  1541:     pnlAspectTableX[0b1_11_10] = ratio[4] * 2.0F;
  1542:     pnlAspectTableX[0b1_11_11] = ratio[3] * 2.0F;
  1543:     //24k
  1544:     for (int i = 0; i < 32; i++) {
  1545:       pnlAspectTableX[32 + i] = pnlAspectTableX[i];
  1546:     }
  1547:     //                   HRL V  H
  1548:     pnlAspectTableX[32 + 0b0_00_10] = ratio[5];         //69/2 1024x212
  1549:     pnlAspectTableY[32 + 0b0_00_10] = 2.0F;
  1550:     pnlAspectTableX[32 + 0b0_01_10] = ratio[5];         //69/2 1024x424
  1551:     pnlAspectTableY[32 + 0b0_01_10] = 2.0F;
  1552:     pnlAspectTableX[32 + 0b0_10_10] = ratio[5];         //69/2 1024x848
  1553:     pnlAspectTableX[32 + 0b0_11_10] = ratio[5];
  1554:     pnlAspectTableX[32 + 0b1_00_01] = ratio[5];         //69/4 512x212
  1555:     pnlAspectTableX[32 + 0b1_01_01] = ratio[5];         //69/4 512x424
  1556:     pnlAspectTableX[32 + 0b1_10_01] = ratio[5] * 2.0F;  //69/4 512x848
  1557:     pnlAspectTableX[32 + 0b1_11_01] = ratio[5] * 2.0F;
  1558:   }  //pnlUpdateAspectTable
  1559: 
  1560:   //pnlMake ()
  1561:   //  パネルを作る
  1562:   public static void pnlMake () {
  1563:     pnlMake2 ();
  1564: 
  1565:     //パネル
  1566:     if (PNL_USE_CANVAS && pnlUseCanvas) {
  1567:       pnlCanvas = new Canvas ();
  1568:       pnlPanel = new JPanel (new BorderLayout (0, 0));
  1569:       pnlPanel.add (pnlCanvas, BorderLayout.CENTER);
  1570:       pnlCanvasOrPanel = pnlCanvas;
  1571:     } else {
  1572:       pnlPanel = new JPanel () {
  1573:         @Override protected void paintComponent (Graphics g) {
  1574:           pnlPaintCommon (g);
  1575:         }
  1576:         @Override protected void paintBorder (Graphics g) {
  1577:         }
  1578:         @Override protected void paintChildren (Graphics g) {
  1579:         }
  1580:       };
  1581:       pnlCanvasOrPanel = pnlPanel;
  1582:     }
  1583:     pnlPanel.setBackground (Color.black);
  1584:     pnlPanel.setOpaque (true);
  1585:     pnlPanel.setPreferredSize (pnlSize);
  1586:     //矢印カーソルを表示する
  1587:     if (Mouse.musCursorAvailable) {
  1588:       pnlPanel.setCursor (Mouse.musCursorArray[1]);  //pnlCanvasOrPanelは不可
  1589:     }
  1590: 
  1591:   }  //pnlMake()
  1592: 
  1593:   //pnlPaintCommon (g)
  1594:   //  描画共通
  1595:   public static void pnlPaintCommon (Graphics g) {
  1596:     Graphics2D g2 = (Graphics2D) g;
  1597:     if (PNL_FILL_BACKGROUND || pnlFillBackgroundRequest) {  //背景を塗り潰す
  1598:       if (!PNL_FILL_BACKGROUND) {
  1599:         pnlFillBackgroundRequest = false;
  1600:       }
  1601:       g2.setRenderingHint (RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
  1602:       g2.setColor (Color.black);
  1603:       g2.fillRect (0, 0, pnlWidth, pnlHeight);
  1604:     }
  1605:     g2.setRenderingHint (RenderingHints.KEY_INTERPOLATION, pnlInterpolation);
  1606:     boolean compositeSet = false;
  1607:     if (FlashingLights.FLR_ON &&
  1608:         FlashingLights.flrScreen) {
  1609:       float brightness = FlashingLights.flrBrightness[pnlBMRead & 3];
  1610:       if (brightness < 1.0F) {
  1611:         g2.setComposite (
  1612:           AlphaComposite.getInstance (AlphaComposite.SRC_OVER, brightness));
  1613:         compositeSet = true;
  1614:       }
  1615:     }
  1616:     if (PNL_USE_THREAD) {
  1617:       int d = pnlBMWrite - pnlBMRead;
  1618:       if (false) {
  1619:         System.out.print (d);
  1620:       }
  1621:       if (d < 1) {  //足りない
  1622:         pnlBMRead += d - 1;  //繰り返す
  1623:       } else if (3 < d) {  //多すぎる
  1624:         pnlBMRead += d - 3;  //読み飛ばす
  1625:       }
  1626:       int n = pnlBMRead++ & 3;
  1627:       if (PNL_STEREOSCOPIC_ON && pnlStereoscopicOn) {  //立体視ON
  1628:         BufferedImage leftImage;
  1629:         BufferedImage rightImage;
  1630:         if (pnlStereoscopicMethod == PNL_NAKED_EYE_CROSSING) {
  1631:           leftImage = pnlScreenImageRightArray[n];
  1632:           rightImage = pnlScreenImageLeftArray[n];
  1633:         } else {
  1634:           //pnlStereoscopicMethod == PNL_NAKED_EYE_PARALLEL
  1635:           //pnlStereoscopicMethod == PNL_SIDE_BY_SIDE
  1636:           //pnlStereoscopicMethod == PNL_TOP_AND_BOTTOM
  1637:           leftImage = pnlScreenImageLeftArray[n];
  1638:           rightImage = pnlScreenImageRightArray[n];
  1639:         }
  1640:         if (PNL_ROTATION_ON && pnlRotationMode != 0) {
  1641:           g2.drawImage (leftImage, pnlRotationTransformLeft, null);
  1642:           g2.drawImage (rightImage, pnlRotationTransformRight, null);
  1643:         } else {
  1644:           g2.drawImage (leftImage,
  1645:                         pnlScreenX1, pnlScreenY1,
  1646:                         pnlScreenX2, pnlScreenY2,
  1647:                         0, 0, pnlScreenWidth, pnlScreenHeight,
  1648:                         null);
  1649:           g2.drawImage (rightImage,
  1650:                         pnlScreenX3, pnlScreenY3,
  1651:                         pnlScreenX4, pnlScreenY4,
  1652:                         0, 0, pnlScreenWidth, pnlScreenHeight,
  1653:                         null);
  1654:         }
  1655:       } else {  //立体視OFF
  1656:         if (PNL_ROTATION_ON && pnlRotationMode != 0) {
  1657:           g2.drawImage (pnlScreenSubImageLeftArray[n], pnlRotationTransformLeft, null);
  1658:         } else {
  1659:           g2.drawImage (pnlScreenImageLeftArray[n],
  1660:                         pnlScreenX1, pnlScreenY1,
  1661:                         pnlScreenX2, pnlScreenY2,
  1662:                         0, 0, pnlScreenWidth, pnlScreenHeight,
  1663:                         null);
  1664:         }
  1665:       }
  1666:     } else {  //!PNL_USE_THREAD
  1667:       if (PNL_STEREOSCOPIC_ON && pnlStereoscopicOn) {  //立体視ON
  1668:         BufferedImage leftImage;
  1669:         BufferedImage rightImage;
  1670:         if (pnlStereoscopicMethod == PNL_NAKED_EYE_CROSSING) {
  1671:           leftImage = pnlScreenImageRight;
  1672:           rightImage = pnlScreenImageLeft;
  1673:         } else {
  1674:           //pnlStereoscopicMethod == PNL_NAKED_EYE_PARALLEL
  1675:           //pnlStereoscopicMethod == PNL_SIDE_BY_SIDE
  1676:           //pnlStereoscopicMethod == PNL_TOP_AND_BOTTOM
  1677:           leftImage = pnlScreenImageLeft;
  1678:           rightImage = pnlScreenImageRight;
  1679:         }
  1680:         if (PNL_ROTATION_ON && pnlRotationMode != 0) {
  1681:           g2.drawImage (leftImage, pnlRotationTransformLeft, null);
  1682:           g2.drawImage (rightImage, pnlRotationTransformRight, null);
  1683:         } else {
  1684:           g2.drawImage (leftImage,
  1685:                         pnlScreenX1, pnlScreenY1,
  1686:                         pnlScreenX2, pnlScreenY2,
  1687:                         0, 0, pnlScreenWidth, pnlScreenHeight,
  1688:                         null);
  1689:           g2.drawImage (rightImage,
  1690:                         pnlScreenX3, pnlScreenY3,
  1691:                         pnlScreenX4, pnlScreenY4,
  1692:                         0, 0, pnlScreenWidth, pnlScreenHeight,
  1693:                         null);
  1694:         }
  1695:       } else {  //立体視OFF
  1696:         if (PNL_ROTATION_ON && pnlRotationMode != 0) {
  1697:           g2.drawImage (pnlScreenImageLeft, pnlRotationTransformLeft, null);
  1698:         } else {
  1699:           g2.drawImage (pnlScreenImageLeft,
  1700:                         pnlScreenX1, pnlScreenY1,
  1701:                         pnlScreenX2, pnlScreenY2,
  1702:                         0, 0, pnlScreenWidth, pnlScreenHeight,
  1703:                         null);
  1704:         }
  1705:       }
  1706:     }
  1707:     if (compositeSet) {
  1708:       g2.setComposite (
  1709:         AlphaComposite.getInstance (
  1710:           AlphaComposite.SRC_OVER,
  1711:           1.0F));
  1712:     }
  1713:     g2.setRenderingHint (RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
  1714:     g2.drawImage (Keyboard.kbdImage, pnlKeyboardX, pnlKeyboardY, null);  //Graphics.drawImage()はimage==nullのとき何もしない
  1715:     //
  1716:     if (TextCopy.txcEncloseEachTime && 0 <= TextCopy.txcRow1) {
  1717:       int x = TextCopy.txcCol1 << 3;
  1718:       int w = (TextCopy.txcCol2 - TextCopy.txcCol1 + 1) << 3;
  1719:       int y = TextCopy.txcRow1 << 4;
  1720:       int h = (TextCopy.txcRow2 - TextCopy.txcRow1 + 1) << 4;
  1721:       x -= CRTC.crtR10TxXCurr;
  1722:       y -= CRTC.crtR11TxYCurr;
  1723:       g2.setColor (Color.red);
  1724:       if (PNL_ROTATION_ON) {
  1725:         AffineTransform savedTransform = g2.getTransform ();
  1726:         g2.transform (pnlRotationTransformLeft);
  1727:         g2.drawRect (x, y, w, h);
  1728:         g2.setTransform (savedTransform);
  1729:       } else {
  1730:         g2.drawRect (pnlScreenX1 + ((x * pnlZoomRatioOutX) >> 16),
  1731:                      pnlScreenY1 + ((y * pnlZoomRatioOutY) >> 16),
  1732:                      ((w * pnlZoomRatioOutX) >> 16) - 1,
  1733:                      ((h * pnlZoomRatioOutY) >> 16) - 1);
  1734:       }
  1735:     }
  1736:     if (Bubble.BBL_ON) {
  1737:       Bubble.bblDraw (g2);
  1738:     }
  1739:   }  //pnlPaintCommon
  1740: 
  1741:   //pnlStart ()
  1742:   //  パネルの動作を開始する
  1743:   //  イベントリスナーを設定する
  1744:   public static void pnlStart () {
  1745:     pnlStart2 ();
  1746: 
  1747:     //コンポーネントリスナー
  1748:     ComponentFactory.addListener (
  1749:       pnlPanel,
  1750:       new ComponentAdapter () {
  1751:         @Override public void componentResized (ComponentEvent ce) {
  1752:           pnlUpdateArrangement ();
  1753:         }
  1754:       });
  1755: 
  1756:     if (PNL_USE_THREAD) {
  1757:       if (PNL_USE_CANVAS && pnlUseCanvas) {
  1758:         pnlCanvas.createBufferStrategy (2);
  1759:         pnlThread = new Thread () {
  1760:           @Override public void run () {
  1761:             do {
  1762:               BufferStrategy bs = pnlCanvas.getBufferStrategy ();
  1763:               if (bs != null) {
  1764:                 Graphics g = bs.getDrawGraphics ();
  1765:                 pnlPaintCommon (g);
  1766:                 g.dispose ();
  1767:                 bs.show ();
  1768:               }
  1769:             } while (!pnlInterrupted && pnlWakeupCommon ());
  1770:           }
  1771:         };
  1772:       } else {
  1773:         pnlThread = new Thread () {
  1774:           @Override public void run () {
  1775:             do {
  1776:               pnlPanel.repaint ();
  1777:             } while (!pnlInterrupted && pnlWakeupCommon ());
  1778:           }
  1779:         };
  1780:       }
  1781:       pnlWakeupTime = System.currentTimeMillis ();
  1782:       pnlWakeupTimeMNP = 0L;
  1783:       pnlThread.start ();
  1784:     }
  1785: 
  1786:   }  //pnlStart()
  1787: 
  1788:   public static boolean pnlWakeupCommon () {
  1789:     long t = System.currentTimeMillis ();
  1790:     if (CRTC.crtTotalLength == 0L) {  //未確定
  1791:       pnlWakeupTime += 40L;
  1792:     } else {
  1793:       pnlWakeupTime += CRTC.crtTotalLength;
  1794:       pnlWakeupTimeMNP += CRTC.crtTotalLengthMNP;
  1795:       if (1000000000L <= pnlWakeupTimeMNP) {
  1796:         pnlWakeupTime++;
  1797:         pnlWakeupTimeMNP -= 1000000000L;
  1798:       }
  1799:     }
  1800:     pnlWakeupTime = Math.max (pnlWakeupTime, t + 4L);
  1801:     try {
  1802:       Thread.sleep (pnlWakeupTime - t);
  1803:     } catch (InterruptedException ie) {
  1804:       return false;
  1805:     }
  1806:     return true;
  1807:   }
  1808: 
  1809:   //pnlExitFullScreen (dialog)
  1810:   //  ダイアログやサブウインドウを開く前に全画面表示を終了する
  1811:   //  macOSのとき全画面表示のままモーダルダイアログを開くと操作できなくなる
  1812:   //  Windowsでも全画面表示のままサブウインドウを開くとサブウインドウが見えないので全画面表示を終了しなければならなくなる
  1813:   public static void pnlExitFullScreen (boolean dialog) {
  1814:     if (prgIsMac || !dialog) {
  1815:       pnlSetFullScreenOn (false);
  1816:     }
  1817:   }
  1818: 
  1819:   //pnlToggleFullScreen ()
  1820:   //  全画面表示の切り替え
  1821:   public static void pnlToggleFullScreen () {
  1822:     if (pnlMode == PNL_FIXEDSCALE || pnlMode == PNL_FITINWINDOW) {
  1823:       pnlSetMode (PNL_FULLSCREEN);
  1824:     } else {
  1825:       pnlSetMode (pnlPrevMode);  //全画面表示だけでなく最大化も終了させる
  1826:     }
  1827:   }  //pnlToggleFullScreen
  1828: 
  1829:   //pnlToggleMaximized ()
  1830:   //  最大化の切り替え
  1831:   public static void pnlToggleMaximized () {
  1832:     if (pnlMode == PNL_FIXEDSCALE || pnlMode == PNL_FITINWINDOW) {
  1833:       pnlSetMode (PNL_MAXIMIZED);
  1834:     } else {
  1835:       pnlSetMode (pnlPrevMode);  //最大化だけでなく全画面表示も終了させる
  1836:     }
  1837:   }  //pnlToggleMaximized
  1838: 
  1839:   //pnlSetFullScreenOn (on)
  1840:   //  全画面表示を設定する
  1841:   public static void pnlSetFullScreenOn (boolean on) {
  1842:     if (on) {
  1843:       pnlSetMode (PNL_FULLSCREEN);
  1844:     } else if (pnlMode == PNL_FULLSCREEN) {
  1845:       pnlSetMode (pnlPrevMode);
  1846:     }
  1847:   }  //pnlSetFullScreenOn
  1848: 
  1849:   //pnlSetFitInWindowOn (on)
  1850:   //  ウインドウに合わせるモードを設定する
  1851:   //  ウインドウに合わせるモードには全画面表示が含まれる
  1852:   public static void pnlSetFitInWindowOn (boolean on) {
  1853:     if (!on) {
  1854:       pnlSetMode (PNL_FIXEDSCALE);
  1855:     } else if (pnlMode == PNL_FIXEDSCALE) {
  1856:       pnlSetMode (PNL_FITINWINDOW);
  1857:     }
  1858:   }  //pnlSetFitInWindowOn
  1859: 
  1860:   //pnlUpdateArrangement ()
  1861:   //  スクリーンとキーボードの配置を再計算する
  1862:   //    リサイズ、最大化、全画面表示などの操作でパネルの大きさが変わったとき
  1863:   //    ウインドウに合わせるかどうかが変わったとき
  1864:   //    ウインドウに合わせないが固定倍率が変わったとき
  1865:   //    キーボードの有無または種類が変わったとき
  1866:   //    X68000の画面モードが変更されてスクリーンの大きさが変わったとき
  1867:   //    立体視のon/offが変わったとき
  1868:   //    アスペクト比が変わったとき
  1869:   public static void pnlUpdateArrangement () {
  1870:     pnlWidth = pnlPanel.getWidth ();
  1871:     pnlHeight = pnlPanel.getHeight ();
  1872:     frmMarginWidth = frmFrame.getWidth () - pnlWidth;
  1873:     frmMarginHeight = frmFrame.getHeight () - pnlHeight;
  1874:     int stretchIndex = CRTC.crtHRLCurr << 4 | CRTC.crtVResoCurr << 2 | CRTC.crtHResoCurr;
  1875:     {
  1876:       int htotal = CRTC.crtR00HFrontEndCurr + 1;
  1877:       int vtotal = CRTC.crtR04VFrontEndCurr + 1;
  1878:       if (0 < htotal && 0 < vtotal) {  //0除算を回避する
  1879:         int k = CRTC.crtHRLCurr << 3 | CRTC.crtHighResoCurr << 2 | CRTC.crtHResoCurr;
  1880:         double osc = (double) CRTC.crtFreqs[CRTC.CRT_OSCS[k]] * CRTC.crtVsyncMultiplier;
  1881:         int ratio = CRTC.CRT_DIVS[k];
  1882:         double hfreq = osc / (ratio * htotal << 3);
  1883:         if (24000.0 <= hfreq && hfreq < 25000.0) {  //24k
  1884:           stretchIndex += 32;
  1885:         }
  1886:       }
  1887:     }
  1888:     pnlStretchModeX = pnlAspectTableX[stretchIndex];
  1889:     pnlStretchModeY = pnlAspectTableY[stretchIndex];
  1890:     pnlScreenWidth = Math.max (PNL_MIN_WIDTH, (CRTC.crtR03HDispEndCurr - CRTC.crtR02HBackEndCurr) << 3);
  1891:     pnlScreenHeight = Math.max (PNL_MIN_HEIGHT, (CRTC.crtR07VDispEndCurr - CRTC.crtR06VBackEndCurr) << (CRTC.crtInterlace || CRTC.crtSlit ? 1 : 0));
  1892:     pnlStretchWidth = Math.round ((float) pnlScreenWidth * pnlStretchModeX);
  1893:     pnlStretchHeight = Math.round ((float) pnlScreenHeight * pnlStretchModeY);
  1894:     if (RasterBreakPoint.RBP_ON) {
  1895:       //ラスタブレークポイントウインドウが開いていたら更新する
  1896:       if ((dbgVisibleMask & DBG_RBP_VISIBLE_MASK) != 0) {
  1897:         RasterBreakPoint.rbpUpdateFrame ();
  1898:       }
  1899:     }
  1900:     //
  1901:     pnlFixedScale = pnlFixedModel.getNumber ().intValue ();  //固定倍率
  1902:     //スクリーンとキーボードの配置を決める
  1903:     pnlRotatedWidth = pnlStretchWidth;
  1904:     pnlRotatedHeight = pnlStretchHeight;
  1905:     if (PNL_ROTATION_ON && ((pnlRotationMode & 1) != 0)) {  //90度または270度のとき
  1906:       pnlRotatedWidth = pnlStretchHeight;  //幅と高さを入れ替える
  1907:       pnlRotatedHeight = pnlStretchWidth;
  1908:     }
  1909:     if (pnlMode == PNL_FIXEDSCALE) {  //固定倍率のとき
  1910:       //配置の計算
  1911:       //perl optdiv.pl 32768 100
  1912:       //  x/100==x*5243>>>19 (0<=x<=43698) [32768*5243==171802624]
  1913:       //pnlZoomWidth = (pnlRotatedWidth * pnlFixedScale + 50) / 100;
  1914:       //pnlZoomHeight = (pnlRotatedHeight * pnlFixedScale + 50) / 100;
  1915:       pnlZoomWidth = (pnlRotatedWidth * pnlFixedScale + 50) * 5243 >>> 19;
  1916:       pnlZoomHeight = (pnlRotatedHeight * pnlFixedScale + 50) * 5243 >>> 19;
  1917:       int width = Math.max (Math.max (PNL_MIN_WIDTH, pnlZoomWidth * pnlStereoscopicFactor), Keyboard.kbdWidth);
  1918:       int height = Math.max (PNL_MIN_HEIGHT, pnlZoomHeight) + Keyboard.kbdHeight;
  1919:       pnlScreenX1 = (width - pnlZoomWidth * pnlStereoscopicFactor) >> 1;
  1920:       pnlScreenY1 = (height - pnlZoomHeight - Keyboard.kbdHeight) >> 1;
  1921:       if (pnlWidth != width || pnlHeight != height) {  //パネルの大きさが合っていないとき
  1922:         pnlWidth = width;
  1923:         pnlHeight = height;
  1924:         pnlMinimumWidth = width;  //固定倍率では使わないがウインドウに合わせるモードに移行したとき最小サイズが変化したことを検知できるようにする
  1925:         pnlMinimumHeight = height;
  1926:         pnlSize.setSize (width, height);
  1927:         pnlPanel.setMinimumSize (pnlSize);
  1928:         pnlPanel.setMaximumSize (pnlSize);
  1929:         pnlPanel.setPreferredSize (pnlSize);
  1930:       }
  1931:       frmMinimumSize.setSize (pnlMinimumWidth + frmMarginWidth, pnlMinimumHeight + frmMarginHeight);
  1932:       frmFrame.setMinimumSize (frmMinimumSize);
  1933:       frmFrame.setMaximumSize (frmMinimumSize);
  1934:       frmFrame.setPreferredSize (frmMinimumSize);
  1935:       frmFrame.setResizable (false);
  1936:       frmFrame.pack ();
  1937:     } else {  //ウインドウに合わせるとき
  1938:       //配置の計算
  1939:       if (PNL_ROUNDED_CORNER_ON) {
  1940:         //画面幅=回転後幅*立体視係数
  1941:         int screenWidth = pnlRotatedWidth * pnlStereoscopicFactor;
  1942:         //画面高さ=回転後高さ
  1943:         int screenHeight = pnlRotatedHeight;
  1944:         //最大幅=パネル幅
  1945:         int maximumWidth = pnlWidth;
  1946:         //最大高さ=パネル高さ-キーボード高さ
  1947:         int maximumHeight = pnlHeight - Keyboard.kbdHeight;
  1948:         //角丸半径=min(パネル幅,パネル高さ)*角丸率
  1949:         //  全画面表示でないか、サイドバイサイドまたはトップアンドボトムのとき0
  1950:         //  短辺の長さが奇数で50%のとき切り上げないこと
  1951:         double cornerRadius = (!(PNL_ROUNDED_CORNER_TEST || pnlMode == PNL_FULLSCREEN) ||
  1952:                                (pnlStereoscopicOn &&
  1953:                                 (pnlStereoscopicMethod == PNL_SIDE_BY_SIDE ||
  1954:                                  pnlStereoscopicMethod == PNL_TOP_AND_BOTTOM)) ? 0 :
  1955:                                Math.min (pnlWidth, pnlHeight) * (double) pnlRoundedCornerRatio / 100.0);
  1956:         //角丸幅=角丸半径*2
  1957:         double cornerWidth = cornerRadius * 2.0;
  1958:         //角丸高さ=角丸半径*(キーボードあり?1:2)
  1959:         double cornerHeight = cornerRadius * (Keyboard.kbdHeight != 0 ? 1.0 : 2.0);
  1960:         //直線幅=最大幅-角丸幅
  1961:         double straightWidth = maximumWidth - cornerWidth;
  1962:         //直線高さ=最大高さ-角丸高さ
  1963:         double straightHeight = maximumHeight - cornerHeight;
  1964:         if (maximumHeight * screenWidth <= straightWidth * screenHeight) {
  1965:           //最大高さ*画面幅<=直線幅*画面高さ
  1966:           //直線幅が十分に大きい。画面が上下の壁に接する
  1967:           //拡大高さ=最大高さ
  1968:           pnlZoomHeight = maximumHeight;
  1969:           //拡大幅=round(拡大高さ*画面幅/画面高さ)
  1970:           pnlZoomWidth = (pnlZoomHeight * screenWidth + (screenHeight >> 1)) / screenHeight;
  1971:           //画面座標
  1972:           if (pnlStereoscopicOn && pnlStereoscopicMethod == PNL_SIDE_BY_SIDE) {
  1973:             //サイドバイサイド。左半分の中央に半分の幅で配置する
  1974:             pnlScreenX1 = ((maximumWidth >> 1) - (pnlZoomWidth >> 1)) >> 1;
  1975:           } else {
  1976:             pnlScreenX1 = (maximumWidth - pnlZoomWidth * pnlStereoscopicFactor) >> 1;
  1977:           }
  1978:           pnlScreenY1 = 0;
  1979:         } else if (maximumWidth * screenHeight <= straightHeight * screenWidth) {
  1980:           //最大幅*画面高さ<=直線高さ*画面幅
  1981:           //直線高さが十分に大きい。画面が左右の壁に接する
  1982:           //拡大幅=最大幅
  1983:           pnlZoomWidth = maximumWidth;
  1984:           //拡大高さ=round(拡大幅*画面高さ/画面幅)
  1985:           pnlZoomHeight = (pnlZoomWidth * screenHeight + (screenWidth >> 1)) / screenWidth;
  1986:           //画面座標
  1987:           pnlScreenX1 = 0;
  1988:           if (pnlStereoscopicOn && pnlStereoscopicMethod == PNL_TOP_AND_BOTTOM) {
  1989:             //トップアンドボトム。上半分の中央に半分の高さで配置する
  1990:             pnlScreenY1 = ((maximumHeight >> 1) - (pnlZoomHeight >> 1)) >> 1;
  1991:           } else {
  1992:             pnlScreenY1 = (maximumHeight - pnlZoomHeight) >> 1;
  1993:           }
  1994:         } else {
  1995:           //縦横比が近い。画面が角丸に接する
  1996:           //  角丸上の点について縦横比が一致する位置を求める
  1997:           //  曲線0<=x,0<=y,x^n+y^n=1上の点A,Bからそれらの間にある点Mを求める
  1998:           //    A+Bの方向にある曲線上の点M
  1999:           //      mx=(ax+bx)/sqrt[n]((ax+bx)^n+(ay+by)^n)
  2000:           //      my=(ay+by)/sqrt[n]((ax+bx)^n+(ay+by)^n)
  2001:           //    n=2の場合
  2002:           //      加法定理と半角の公式を使うと式が簡単になる
  2003:           //      加法定理
  2004:           //        cos(a+b)=cos(a)*cos(b)-sin(a)*sin(b)
  2005:           //        sin(a+b)=sin(a)*cos(b)+cos(a)*sin(b)
  2006:           //      半角の公式
  2007:           //        cos(t/2)^2=(1+cos(t))/2
  2008:           //        sin(t/2)^2=(1-cos(t))/2
  2009:           //      角の2等分(0<=a,b<=pi/2)
  2010:           //        cos((a+b)/2)=sqrt((1+cos(a+b))/2)
  2011:           //        sin((a+b)/2)=sqrt((1-cos(a+b))/2)
  2012:           //      mx=sqrt(1/2+(ax*bx-ay*by)/2)
  2013:           //      my=sqrt(1/2-(ax*bx-ay*by)/2)
  2014:           //    n=3の場合
  2015:           //      mx=(ax+bx)/cbrt(2+3*(ax*bx*(ax+bx)+ay*by*(ay+by)))
  2016:           //      my=(ay+by)/cbrt(2+3*(ax*bx*(ax+bx)+ay*by*(ay+by)))
  2017:           //  曲線のままでは式が複雑になるのでここでは多角形を用いる
  2018:           double ax = 1.0;
  2019:           double ay = 0.0;
  2020:           double bx = 0.0;
  2021:           double by = 1.0;
  2022:           for (int i = 0; i < 4; i++) {  //16分割。64角形
  2023:             double mx;
  2024:             double my;
  2025:             if (false) {  //n=2
  2026:               double t = (ax * bx - ay * by) * 0.5;
  2027:               mx = Math.sqrt (0.5 + t);
  2028:               my = Math.sqrt (0.5 - t);
  2029:             } else {  //n=3
  2030:               double sx = ax + bx;
  2031:               double sy = ay + by;
  2032:               double t = Math.cbrt (2.0 + 3.0 * (ax * bx * sx + ay * by * sy));
  2033:               mx = sx / t;
  2034:               my = sy / t;
  2035:             }
  2036:             //仮幅=直線幅+mx*角丸幅
  2037:             double temporaryWidth = straightWidth + mx * cornerWidth;
  2038:             //仮高さ=直線高さ+my*角丸高さ
  2039:             double temporaryHeight = straightHeight + my * cornerHeight;
  2040:             if (temporaryHeight * screenWidth <= temporaryWidth * screenHeight) {
  2041:               //仮高さ*画面幅<=仮幅*画面高さ
  2042:               //横に長過ぎる。M-Bに狭める
  2043:               ax = mx;
  2044:               ay = my;
  2045:             } else {
  2046:               //縦に長過ぎる。A-Mに狭める
  2047:               bx = mx;
  2048:               by = my;
  2049:             }
  2050:           }
  2051:           //直線AB上の点について縦横比が一致する位置を求める
  2052:           //  仮幅=直線幅+(ax+(bx-ax)*t)*角丸幅
  2053:           //  仮高さ=直線高さ+(ay+(by-ay)*t)*角丸高さ
  2054:           //  仮幅/仮高さ=画面幅/画面高さ
  2055:           //
  2056:           //  仮幅*画面高さ=仮高さ*画面幅
  2057:           //  (直線幅+(ax+(bx-ax)*t)*角丸幅)*画面高さ=(直線高さ+(ay+(by-ay)*t)*角丸高さ)*画面幅
  2058:           //  直線幅*画面高さ+(ax+(bx-ax)*t)*角丸幅*画面高さ=直線高さ*画面幅+(ay+(by-ay)*t)*角丸高さ*画面幅
  2059:           //  直線幅*画面高さ+ax*角丸幅*画面高さ+(bx-ax)*t*角丸幅*画面高さ=直線高さ*画面幅+ay*角丸高さ*画面幅+(by-ay)*t*角丸高さ*画面幅
  2060:           //  (bx-ax)*t*角丸幅*画面高さ-(by-ay)*t*角丸高さ*画面幅=直線高さ*画面幅+ay*角丸高さ*画面幅-直線幅*画面高さ-ax*角丸幅*画面高さ
  2061:           //  ((bx-ax)*角丸幅*画面高さ-(by-ay)*角丸高さ*画面幅)*t=(直線高さ+ay*角丸高さ)*画面幅-(直線幅+ax*角丸幅)*画面高さ
  2062:           //  t=((直線高さ+ay*角丸高さ)*画面幅-(直線幅+ax*角丸幅)*画面高さ)/((bx-ax)*角丸幅*画面高さ-(by-ay)*角丸高さ*画面幅)
  2063:           double t = (((straightHeight + ay * cornerHeight) * screenWidth
  2064:                        - (straightWidth + ax * cornerWidth) * screenHeight)
  2065:                       / ((bx - ax) * cornerWidth * screenHeight
  2066:                          - (by - ay) * cornerHeight * screenWidth));
  2067:           //拡大幅=直線幅+(ax+(bx-ax)*t)*角丸幅
  2068:           pnlZoomWidth = (int) Math.round (straightWidth + (ax + (bx - ax) * t) * cornerWidth);
  2069:           if (false) {
  2070:             //拡大高さ=直線高さ+(ay+(by-ay)*t)*角丸高さ
  2071:             pnlZoomHeight = (int) Math.round (straightHeight + (ay + (by - ay) * t) * cornerHeight);
  2072:           } else {
  2073:             //拡大高さ=round(拡大幅*画面高さ/画面幅)
  2074:             pnlZoomHeight = (pnlZoomWidth * screenHeight + (screenWidth >> 1)) / screenWidth;
  2075:           }
  2076:           //画面座標
  2077:           pnlScreenX1 = (maximumWidth - pnlZoomWidth * pnlStereoscopicFactor) >> 1;
  2078:           pnlScreenY1 = (maximumHeight - pnlZoomHeight) >> 1;
  2079:         }
  2080:       } else {
  2081:         if (pnlWidth * pnlRotatedHeight >= (pnlHeight - Keyboard.kbdHeight) * (pnlRotatedWidth * pnlStereoscopicFactor)) {  //ウインドウに合わせると上下に隙間ができないとき
  2082:           //パネルの下端にキーボード配置して残った部分にスクリーンを目一杯拡大する
  2083:           //    pnlScreenX1                                          pnlScreenX1            pnlScreenX1
  2084:           //    |pnlZoomWidth|    |pnlZoomWidth|  |pnlZoomWidth|    |pnlZoomWidth|        |pnlZoomWidth|
  2085:           //  +-+------------+-+  +------------+  +------------+  +-+------------+-+  +---+------------+---+ --
  2086:           //  | |            | |  |            |  |            |  | |            | |  |   |            |   |
  2087:           //  | |   screen   | |  |   screen   |  |   screen   |  | |   screen   | |  |   |   screen   |   | pnlZoomHeight
  2088:           //  | |            | |  |            |  |            |  | |            | |  |   |            |   |
  2089:           //  | +-+--------+-+ |  +-+--------+-+  +------------+  +-+------------+-+  | +-+------------+-+ | -- pnlKeyboardY
  2090:           //  |   |keyboard|   |  | |keyboard| |  |  keyboard  |  |    keyboard    |  | |    keyboard    | | kbdHeight
  2091:           //  +---+--------+---+  +-+--------+-+  +------------+  +----------------+  +-+----------------+-+ --
  2092:           //      |                 |                             |    kbdWidth    |    |    kbdWidth    |
  2093:           //      pnlKeyboardX      pnlKeyboardX                                        pnlKeyboardX
  2094:           pnlZoomHeight = pnlHeight - Keyboard.kbdHeight;
  2095:           pnlZoomWidth = (pnlZoomHeight * pnlRotatedWidth + (pnlRotatedHeight >> 1)) / pnlRotatedHeight;
  2096:           if (pnlStereoscopicOn && pnlStereoscopicMethod == PNL_SIDE_BY_SIDE) {
  2097:             pnlScreenX1 = ((pnlWidth >> 1) - (pnlZoomWidth >> 1)) >> 1;
  2098:           } else {
  2099:             pnlScreenX1 = (pnlWidth - pnlZoomWidth * pnlStereoscopicFactor) >> 1;
  2100:           }
  2101:           pnlScreenY1 = 0;
  2102:         } else {  //ウインドウに合わせると上下に隙間ができるとき
  2103:           //左右が先につっかえたのだからスクリーンの幅がキーボードの幅よりも狭いということはない
  2104:           //  スクリーンの幅がキーボードの幅よりも狭かったらスクリーンの上と左右の両方に隙間があることになってしまうのでウインドウに合っていない
  2105:           //  |pnlZoomWidth|  |pnlZoomWidth|
  2106:           //  +------------+  +------------+
  2107:           //  |            |  |            |
  2108:           //  +------------+  +------------+ -- pnlScreenY1
  2109:           //  |            |  |            |
  2110:           //  |   screen   |  |   screen   | pnlZoomHeight
  2111:           //  |            |  |            |
  2112:           //  +-+--------+-+  +------------+ -- pnlKeyboardY
  2113:           //  | |keyboard| |  |  keyboard  | kbdHeight
  2114:           //  | +--------+ |  +------------+ --
  2115:           //  |            |  |            |
  2116:           //  +------------+  +------------+
  2117:           //    |kbdWidth|    |  kbdWidth  |
  2118:           //    pnlKeyboardX
  2119:           pnlZoomWidth = pnlWidth / pnlStereoscopicFactor;
  2120:           pnlZoomHeight = (pnlZoomWidth * pnlStereoscopicFactor * pnlRotatedHeight + (pnlRotatedWidth * pnlStereoscopicFactor >> 1)) / (pnlRotatedWidth * pnlStereoscopicFactor);
  2121:           pnlScreenX1 = 0;
  2122:           if (pnlStereoscopicOn && pnlStereoscopicMethod == PNL_TOP_AND_BOTTOM) {
  2123:             pnlScreenY1 = (((pnlHeight - Keyboard.kbdHeight) >> 1) - (pnlZoomHeight >> 1)) >> 1;
  2124:           } else {
  2125:             pnlScreenY1 = (pnlHeight - (pnlZoomHeight + Keyboard.kbdHeight)) >> 1;
  2126:           }
  2127:         }
  2128:       }  //PNL_ROUNDED_CORNER_ON
  2129:       //最小サイズと最大サイズ
  2130:       int minimumWidth = Math.max (PNL_MIN_WIDTH, Keyboard.kbdWidth);
  2131:       int minimumHeight = PNL_MIN_HEIGHT + Keyboard.kbdHeight;
  2132:       if (pnlMinimumWidth != minimumWidth || pnlMinimumHeight != minimumHeight) {  //最小サイズが変化した。ウインドウに合わせるモードに移行したかキーボードの有無または種類が変わった
  2133:         pnlMinimumWidth = minimumWidth;
  2134:         pnlMinimumHeight = minimumHeight;
  2135:       }
  2136:       frmMinimumSize.setSize (pnlMinimumWidth + frmMarginWidth, pnlMinimumHeight + frmMarginHeight);
  2137:       frmFrame.setMinimumSize (frmMinimumSize);
  2138:       frmFrame.setMaximumSize (null);
  2139:       frmFrame.setResizable (true);
  2140:     }
  2141:     //
  2142:     pnlArrangementCommon ();
  2143:     Mouse.musUpdateSpeedRatio ();
  2144:     if (!PNL_FILL_BACKGROUND) {
  2145:       pnlFillBackgroundRequest = true;
  2146:     }
  2147:     if (FlashingLights.FLR_ON &&
  2148:         FlashingLights.flrEnabled) {
  2149:       FlashingLights.flrMakeIndex ();
  2150:     }
  2151:   }  //pnlUpdateArrangement
  2152: 
  2153:   public static void pnlArrangementCommon () {
  2154:     if (PNL_STEREOSCOPIC_ON && pnlStereoscopicOn) {
  2155:       if (pnlStereoscopicMethod == PNL_NAKED_EYE_CROSSING ||
  2156:           pnlStereoscopicMethod == PNL_NAKED_EYE_PARALLEL) {
  2157:         pnlScreenX2 = pnlScreenX1 + pnlZoomWidth;
  2158:         pnlScreenX3 = pnlScreenX2;
  2159:         pnlScreenX4 = pnlScreenX3 + pnlZoomWidth;
  2160:         pnlScreenY2 = pnlScreenY1 + pnlZoomHeight;
  2161:         pnlScreenY3 = pnlScreenY1;
  2162:         pnlScreenY4 = pnlScreenY2;
  2163:       } else if (pnlStereoscopicMethod == PNL_SIDE_BY_SIDE) {
  2164:         pnlScreenX2 = pnlScreenX1 + (pnlZoomWidth >> 1);
  2165:         pnlScreenX3 = pnlScreenX2;
  2166:         pnlScreenX4 = pnlScreenX3 + (pnlZoomWidth >> 1);
  2167:         pnlScreenY2 = pnlScreenY1 + pnlZoomHeight;
  2168:         pnlScreenY3 = pnlScreenY1;
  2169:         pnlScreenY4 = pnlScreenY2;
  2170:       } else {  //pnlStereoscopicMethod == PNL_TOP_AND_BOTTOM
  2171:         pnlScreenX2 = pnlScreenX1 + pnlZoomWidth;
  2172:         pnlScreenX3 = pnlScreenX1;
  2173:         pnlScreenX4 = pnlScreenX2;
  2174:         pnlScreenY2 = pnlScreenY1 + (pnlZoomHeight >> 1);
  2175:         pnlScreenY3 = pnlScreenY2;
  2176:         pnlScreenY4 = pnlScreenY3 + (pnlZoomHeight >> 1);
  2177:       }
  2178:     } else {
  2179:       pnlScreenX2 = pnlScreenX1 + pnlZoomWidth;
  2180:       pnlScreenX3 = pnlScreenX1;
  2181:       pnlScreenX4 = pnlScreenX2;
  2182:       pnlScreenY2 = pnlScreenY1 + pnlZoomHeight;
  2183:       pnlScreenY3 = pnlScreenY1;
  2184:       pnlScreenY4 = pnlScreenY2;
  2185:     }
  2186:     pnlKeyboardX = (pnlWidth - Keyboard.kbdWidth) >> 1;
  2187:     pnlKeyboardY = pnlScreenY4;
  2188:     pnlZoomRatioOutX = ((pnlZoomWidth * pnlStereoscopicFactor) << 16) / pnlScreenWidth;
  2189:     pnlZoomRatioOutY = (pnlZoomHeight << 16) / pnlScreenHeight;
  2190:     pnlZoomRatioInX = (pnlScreenWidth << 16) / (pnlZoomWidth * pnlStereoscopicFactor);
  2191:     pnlZoomRatioInY = (pnlScreenHeight << 16) / pnlZoomHeight;
  2192:     if (PNL_ROTATION_ON) {
  2193:       //サブイメージを作る
  2194:       if (PNL_USE_THREAD) {
  2195:         for (int n = 0; n < 4; n++) {
  2196:           pnlScreenSubImageLeftArray[n] = pnlScreenImageLeftArray[n].getSubimage (0, 0, pnlScreenWidth, pnlScreenHeight);
  2197:           pnlScreenSubImageRightArray[n] = pnlScreenImageRightArray[n].getSubimage (0, 0, pnlScreenWidth, pnlScreenHeight);
  2198:         }
  2199:       } else {
  2200:         pnlScreenSubImageLeft = pnlScreenImageLeft.getSubimage (0, 0, pnlScreenWidth, pnlScreenHeight);
  2201:         pnlScreenSubImageRight = pnlScreenImageRight.getSubimage (0, 0, pnlScreenWidth, pnlScreenHeight);
  2202:       }
  2203:       //アフィン変換を作る
  2204:       //  レクタングル(ax,ay)-(bx,by)を
  2205:       //  反時計回りに0度,90度,180度,270度回転させて
  2206:       //  レクタングル(cx,cy)-(dx,dy)に収める
  2207:       double ax = 0.0;
  2208:       double ay = 0.0;
  2209:       double bx = (double) pnlScreenWidth;
  2210:       double by = (double) pnlScreenHeight;
  2211:       double l00, l10, l01, l11, l02, l12;
  2212:       double r00, r10, r01, r11, r02, r12;
  2213:       if (pnlRotationMode == 0) {  //0度
  2214:         double cx = (double) pnlScreenX1;
  2215:         double cy = (double) pnlScreenY1;
  2216:         double dx = (double) pnlScreenX2;
  2217:         double dy = (double) pnlScreenY2;
  2218:         l00 = (cx - dx) / (ax - bx);
  2219:         l10 = 0.0;
  2220:         l01 = 0.0;
  2221:         l11 = (cy - dy) / (ay - by);
  2222:         l02 = (ax * dx - bx * cx) / (ax - bx);
  2223:         l12 = (ay * dy - by * cy) / (ay - by);
  2224:         cx = (double) pnlScreenX3;
  2225:         cy = (double) pnlScreenY3;
  2226:         dx = (double) pnlScreenX4;
  2227:         dy = (double) pnlScreenY4;
  2228:         r00 = (cx - dx) / (ax - bx);
  2229:         r10 = 0.0;
  2230:         r01 = 0.0;
  2231:         r11 = (cy - dy) / (ay - by);
  2232:         r02 = (ax * dx - bx * cx) / (ax - bx);
  2233:         r12 = (ay * dy - by * cy) / (ay - by);
  2234:       } else if (pnlRotationMode == 1) {  //90度
  2235:         double cx = (double) pnlScreenX1;
  2236:         double cy = (double) pnlScreenY1;
  2237:         double dx = (double) pnlScreenX2;
  2238:         double dy = (double) pnlScreenY2;
  2239:         l00 = 0.0;
  2240:         l10 = (dy - cy) / (ax - bx);
  2241:         l01 = (cx - dx) / (ay - by);
  2242:         l11 = 0.0;
  2243:         l02 = (ay * dx - by * cx) / (ay - by);
  2244:         l12 = (ax * cy - bx * dy) / (ax - bx);
  2245:         cx = (double) pnlScreenX3;
  2246:         cy = (double) pnlScreenY3;
  2247:         dx = (double) pnlScreenX4;
  2248:         dy = (double) pnlScreenY4;
  2249:         r00 = 0.0;
  2250:         r10 = (dy - cy) / (ax - bx);
  2251:         r01 = (cx - dx) / (ay - by);
  2252:         r11 = 0.0;
  2253:         r02 = (ay * dx - by * cx) / (ay - by);
  2254:         r12 = (ax * cy - bx * dy) / (ax - bx);
  2255:       } else if (pnlRotationMode == 2) {  //180度
  2256:         double cx = (double) pnlScreenX1;
  2257:         double cy = (double) pnlScreenY1;
  2258:         double dx = (double) pnlScreenX2;
  2259:         double dy = (double) pnlScreenY2;
  2260:         l00 = (dx - cx) / (ax - bx);
  2261:         l10 = 0.0;
  2262:         l01 = 0.0;
  2263:         l11 = (dy - cy) / (ay - by);
  2264:         l02 = (ax * cx - bx * dx) / (ax - bx);
  2265:         l12 = (ay * cy - by * dy) / (ay - by);
  2266:         cx = (double) pnlScreenX3;
  2267:         cy = (double) pnlScreenY3;
  2268:         dx = (double) pnlScreenX4;
  2269:         dy = (double) pnlScreenY4;
  2270:         r00 = (dx - cx) / (ax - bx);
  2271:         r10 = 0.0;
  2272:         r01 = 0.0;
  2273:         r11 = (dy - cy) / (ay - by);
  2274:         r02 = (ax * cx - bx * dx) / (ax - bx);
  2275:         r12 = (ay * cy - by * dy) / (ay - by);
  2276:       } else {  //270度
  2277:         double cx = (double) pnlScreenX1;
  2278:         double cy = (double) pnlScreenY1;
  2279:         double dx = (double) pnlScreenX2;
  2280:         double dy = (double) pnlScreenY2;
  2281:         l00 = 0.0;
  2282:         l10 = (cy - dy) / (ax - bx);
  2283:         l01 = (dx - cx) / (ay - by);
  2284:         l11 = 0.0;
  2285:         l02 = (ay * cx - by * dx) / (ay - by);
  2286:         l12 = (ax * dy - bx * cy) / (ax - bx);
  2287:         cx = (double) pnlScreenX3;
  2288:         cy = (double) pnlScreenY3;
  2289:         dx = (double) pnlScreenX4;
  2290:         dy = (double) pnlScreenY4;
  2291:         r00 = 0.0;
  2292:         r10 = (cy - dy) / (ax - bx);
  2293:         r01 = (dx - cx) / (ay - by);
  2294:         r11 = 0.0;
  2295:         r02 = (ay * cx - by * dx) / (ay - by);
  2296:         r12 = (ax * dy - bx * cy) / (ax - bx);
  2297:       }
  2298:       pnlRotationTransformLeft.setTransform (l00, l10, l01, l11, l02, l12);
  2299:       pnlRotationTransformRight.setTransform (r00, r10, r01, r11, r02, r12);
  2300:       pnlMatrixL00 = l00;
  2301:       pnlMatrixL10 = l10;
  2302:       pnlMatrixL01 = l01;
  2303:       pnlMatrixL11 = l11;
  2304:       pnlMatrixL02 = l02;
  2305:       pnlMatrixL12 = l12;
  2306:       pnlMatrixR00 = r00;
  2307:       pnlMatrixR10 = r10;
  2308:       pnlMatrixR01 = r01;
  2309:       pnlMatrixR11 = r11;
  2310:       pnlMatrixR02 = r02;
  2311:       pnlMatrixR12 = r12;
  2312:       //逆変換を作る
  2313:       //  d=m00*m11-m01*m10
  2314:       //  [ m00 m01 m02 ](-1)   [  m11/d -m01/d (m01*m12-m02*m11)/d ]
  2315:       //  [ m10 m11 m12 ]     = [ -m10/d  m00/d (m02*m10-m00*m12)/d ]
  2316:       //  [  0   0   1  ]       [    0      0            1          ]
  2317:       //  マウスが(x1,y1)-(x2,y2)にあるときinverseL、(x3,y3)-(x4,y4)にあるときinverseRを使って画面座標を求める
  2318:       double d = l00 * l11 - l01 * l10;
  2319:       pnlInverseL00 = l11 / d;
  2320:       pnlInverseL10 = -l10 / d;
  2321:       pnlInverseL01 = -l01 / d;
  2322:       pnlInverseL11 = l00 / d;
  2323:       pnlInverseL02 = (l01 * l12 - l02 * l11) / d;
  2324:       pnlInverseL12 = (l02 * l10 - l00 * l12) / d;
  2325:       d = r00 * r11 - r01 * r10;
  2326:       pnlInverseR00 = r11 / d;
  2327:       pnlInverseR10 = -r10 / d;
  2328:       pnlInverseR01 = -r01 / d;
  2329:       pnlInverseR11 = r00 / d;
  2330:       pnlInverseR02 = (r01 * r12 - r02 * r11) / d;
  2331:       pnlInverseR12 = (r02 * r10 - r00 * r12) / d;
  2332:     }
  2333:   }  //pnlArrangementCommon
  2334: 
  2335: 
  2336: 
  2337:   //モード
  2338:   public static final int PNL_UNDEFINED   = 0;  //未定義
  2339:   public static final int PNL_FIXEDSCALE  = 1;  //固定倍率
  2340:   public static final int PNL_FITINWINDOW = 2;  //ウインドウに合わせる
  2341:   public static final int PNL_FULLSCREEN  = 3;  //全画面表示
  2342:   public static final int PNL_MAXIMIZED   = 4;  //最大化
  2343:   public static int pnlModeRequest;  //起動時、全画面表示と最大化は遅延して切り替える。最大化はRestorableFrameで復元されている可能性がある
  2344:   public static int pnlMode;  //モード
  2345:   public static int pnlPrevMode;  //全画面表示または最大化に移行する前のモード
  2346: 
  2347:   //メニューアイテム
  2348:   public static JRadioButtonMenuItem mnbFullScreenMenuItem;  //全画面表示
  2349:   public static JRadioButtonMenuItem mnbMaximizedMenuItem;  //最大化
  2350:   public static JRadioButtonMenuItem mnbFitInWindowMenuItem;  //ウインドウに合わせる
  2351:   public static JRadioButtonMenuItem mnbFixedScaleMenuItem;  //固定倍率
  2352: 
  2353:   //角丸調整
  2354:   //  モニタの角が丸く、モニタとX68000の画面の縦横比が近いとき、
  2355:   //  全画面表示にすると画面の角が欠ける問題を回避する
  2356:   //  https://x.com/veryhotcurry/status/2035331642034925809
  2357:   public static boolean PNL_ROUNDED_CORNER_ON = true;
  2358:   public static boolean PNL_ROUNDED_CORNER_TEST = false;  //全画面表示でなくても角丸を適用する
  2359:   public static int pnlRoundedCornerRatio;  //角丸率。0~50。短辺の長さに対するパーセント
  2360:   public static SpinnerNumberModel pnlRoundedCornerModel;
  2361:   public static JSpinner pnlRoundedCornerSpinner;
  2362: 
  2363:   //遅延切り替え
  2364:   public static int PNL_BOOT_DELAY = 500;
  2365:   public static javax.swing.Timer pnlBootTimer;
  2366: 
  2367:   //pnlInit2
  2368:   //  初期化2
  2369:   public static void pnlInit2 () {
  2370:     pnlModeRequest = PNL_UNDEFINED;
  2371:     pnlMode = PNL_FITINWINDOW;
  2372:     pnlPrevMode = PNL_FITINWINDOW;
  2373:     switch (Settings.sgsGetString ("scaling").toLowerCase ()) {
  2374:     case "fullscreen":  //全画面表示
  2375:       pnlModeRequest = PNL_FULLSCREEN;
  2376:       break;
  2377:     case "maximized":  //最大化
  2378:       pnlModeRequest = PNL_MAXIMIZED;
  2379:       break;
  2380:     case "fitinwindow":  //ウインドウに合わせる
  2381:       break;
  2382:     case "fixedscale":  //固定倍率
  2383:       pnlMode = PNL_FIXEDSCALE;
  2384:       break;
  2385:     }
  2386:     if (PNL_ROUNDED_CORNER_ON) {
  2387:       pnlRoundedCornerRatio = Settings.sgsGetInt ("roundedcornerratio", 0, 0, 50);
  2388:     }
  2389:   }  //pnlInit2
  2390: 
  2391:   //pnlTini2
  2392:   //  後始末2
  2393:   public static void pnlTini2 () {
  2394:     Settings.sgsPutString ("scaling",
  2395:                            pnlMode == PNL_FULLSCREEN ? "fullscreen" :
  2396:                            pnlMode == PNL_MAXIMIZED ? "maximized" :
  2397:                            pnlMode == PNL_FITINWINDOW ? "fitinwindow" :
  2398:                            "fixedscale");
  2399:     if (PNL_ROUNDED_CORNER_ON) {
  2400:       Settings.sgsPutInt ("roundedcornerratio", pnlRoundedCornerRatio);
  2401:     }
  2402:   }  //pnlTini2
  2403: 
  2404:   //pnlMake2
  2405:   //  構築2
  2406:   public static void pnlMake2 () {
  2407:     //メニュー
  2408:     ActionListener listener = new ActionListener () {
  2409:       @Override public void actionPerformed (ActionEvent ae) {
  2410:         String command = ae.getActionCommand ();
  2411:         switch (command) {
  2412:         case "Full screen":  //全画面表示
  2413:           pnlSetMode (PNL_FULLSCREEN);
  2414:           break;
  2415:         case "Maximized":  //最大化
  2416:           pnlSetMode (PNL_MAXIMIZED);
  2417:           break;
  2418:         case "Resize the X68000 screen to fit the window":  //Fit in window ウインドウに合わせる
  2419:           pnlSetMode (PNL_FITINWINDOW);
  2420:           break;
  2421:         case "Resize the window to fit the X68000 screen":  //Fixed scale 固定倍率
  2422:           pnlSetMode (PNL_FIXEDSCALE);
  2423:           break;
  2424:         }
  2425:       }
  2426:     };
  2427:     ButtonGroup group = new ButtonGroup ();
  2428:     mnbFullScreenMenuItem = ComponentFactory.setEnabled (
  2429:       Multilingual.mlnText (
  2430:         ComponentFactory.createRadioButtonMenuItem (
  2431:           group,
  2432:           pnlMode == PNL_FULLSCREEN,
  2433:           "Full screen",
  2434:           listener),
  2435:         "ja", "全画面表示"),
  2436:       pnlIsFullScreenSupported);
  2437:     mnbMaximizedMenuItem = Multilingual.mlnText (
  2438:       ComponentFactory.createRadioButtonMenuItem (
  2439:         group,
  2440:         pnlMode == PNL_MAXIMIZED,
  2441:         "Maximized",
  2442:         listener),
  2443:       "ja", "最大化");
  2444:     mnbFitInWindowMenuItem = Multilingual.mlnText (
  2445:       ComponentFactory.createRadioButtonMenuItem (
  2446:         group,
  2447:         pnlMode == PNL_FITINWINDOW,
  2448:         "Resize the X68000 screen to fit the window",  //Fit in window
  2449:         'W',
  2450:         MNB_MODIFIERS,
  2451:         listener),
  2452:       "ja", "X68000の画面をリサイズしてウインドウに合わせる");  //ウインドウに合わせる
  2453:     mnbFixedScaleMenuItem = Multilingual.mlnText (
  2454:       ComponentFactory.createRadioButtonMenuItem (
  2455:         group,
  2456:         pnlMode == PNL_FIXEDSCALE,
  2457:         "Resize the window to fit the X68000 screen",  //Fixed scale
  2458:         'X',
  2459:         MNB_MODIFIERS,
  2460:         listener),
  2461:       "ja", "ウインドウをリサイズしてX68000の画面に合わせる");  //固定倍率
  2462:   }  //pnlMake2
  2463: 
  2464:   //pnlStart2 ()
  2465:   //  開始2
  2466:   public static void pnlStart2 () {
  2467:     //ウインドウステートリスナー
  2468:     frmFrame.addWindowStateListener (new WindowStateListener () {
  2469:       @Override public void windowStateChanged (WindowEvent we) {
  2470:         int state = frmFrame.getExtendedState ();
  2471:         if (pnlMode != PNL_MAXIMIZED &&
  2472:             (state & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH) {  //最大化した
  2473:           pnlSetMode (PNL_MAXIMIZED);
  2474:         } else if (pnlMode == PNL_MAXIMIZED &&
  2475:                    (state & Frame.MAXIMIZED_BOTH) != Frame.MAXIMIZED_BOTH) {  //最大化が終了した
  2476:           pnlSetMode (pnlPrevMode);
  2477:         }
  2478:       }
  2479:     });
  2480:   }  //pnlStart2
  2481: 
  2482:   //pnlBoot2 ()
  2483:   //  起動2
  2484:   public static void pnlBoot2 () {
  2485:     if (pnlModeRequest != PNL_UNDEFINED) {
  2486:       pnlBootTimer = new javax.swing.Timer (PNL_BOOT_DELAY, new ActionListener () {
  2487:         public void actionPerformed (ActionEvent ae) {
  2488:           if (pnlModeRequest == PNL_FULLSCREEN) {
  2489:             mnbFullScreenMenuItem.doClick ();
  2490:           } else if (pnlModeRequest == PNL_MAXIMIZED) {
  2491:             mnbMaximizedMenuItem.doClick ();
  2492:           }
  2493:           pnlBootTimer.stop ();
  2494:           pnlBootTimer = null;
  2495:         }
  2496:       });
  2497:       pnlBootTimer.start ();
  2498:     }
  2499:   }  //pnlBoot2
  2500: 
  2501:   //pnlSetMode (mode)
  2502:   //  モードの変更
  2503:   public static void pnlSetMode (int mode) {
  2504:     do {
  2505:       //変更がなければラジオボタンの確認だけ行う
  2506:       if (pnlMode == mode) {
  2507:         break;
  2508:       }
  2509:       //全画面表示に移行できなければ諦めてラジオボタンを修正する
  2510:       String text = null;
  2511:       if (mode == PNL_FULLSCREEN) {  //変更後が全画面表示
  2512:         if (!pnlIsFullScreenSupported) {  //全画面表示に対応していない
  2513:           JOptionPane.showMessageDialog (
  2514:             frmFrame,
  2515:             Multilingual.mlnJapanese ?
  2516:             "全画面表示に対応していません" :
  2517:             "Full screen is not supported");
  2518:           break;
  2519:         }
  2520:         if (Bubble.BBL_ON) {
  2521:           text = ButtonFunction.bfnFullScreenText ();
  2522:           if (text == null) {  //全画面表示を終了する方法がない
  2523:             JOptionPane.showMessageDialog (
  2524:               frmFrame,
  2525:               Multilingual.mlnJapanese ?
  2526:               "全画面表示を終了するキーまたはボタンがありません" :
  2527:               "No key or button to exit full screen");
  2528:             break;
  2529:           }
  2530:         }
  2531:       }
  2532:       //変更前が全画面表示または最大化のとき
  2533:       if (pnlMode == PNL_FULLSCREEN) {  //変更前が全画面表示
  2534:         pnlMode = pnlPrevMode;
  2535:         if (Bubble.BBL_ON) {
  2536:           Bubble.bblEnd ();
  2537:         }
  2538:         if (frmScreenDevice.getFullScreenWindow () == frmFrame) {  //全画面表示している
  2539:           frmScreenDevice.setFullScreenWindow (null);  //全画面表示を解除する
  2540:           frmFrame.getRootPane().setWindowDecorationStyle (JRootPane.FRAME);  //飾り枠を描く
  2541:         }
  2542:         frmFrame.setJMenuBar (mnbMenuBar);  //メニューバーを表示する
  2543:         if (pnlHideKeyboard) {  //全画面表示のときキーボードを隠す
  2544:           if (pnlPrevKeyboardOn) {  //全画面表示に移行する前はキーボードを表示していた
  2545:             Keyboard.kbdSetOn (true);  //キーボードを表示する
  2546:           }
  2547:         }
  2548:       } else if (pnlMode == PNL_MAXIMIZED) {  //変更前が最大化
  2549:         pnlMode = pnlPrevMode;
  2550:         if ((frmFrame.getExtendedState () & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH) {  //最大化している
  2551:           frmFrame.setExtendedState (Frame.NORMAL);  //最大化を解除する
  2552:         }
  2553:       }
  2554:       //変更後が全画面表示または最大化のとき
  2555:       if (mode == PNL_FULLSCREEN) {  //変更後が全画面表示
  2556:         pnlPrevMode = pnlMode;
  2557:         if (pnlHideKeyboard) {  //全画面表示のときキーボードを隠す
  2558:           pnlPrevKeyboardOn = Keyboard.kbdImage != null;  //全画面表示に移行する前はキーボードを表示していたか
  2559:           if (pnlPrevKeyboardOn) {
  2560:             Keyboard.kbdSetOn (false);  //キーボードを表示しない
  2561:           }
  2562:         }
  2563:         frmFrame.setJMenuBar (null);  //メニューバーを表示しない
  2564:         if (frmScreenDevice.getFullScreenWindow () != frmFrame) {  //全画面表示していない
  2565:           frmFrame.getRootPane().setWindowDecorationStyle (JRootPane.NONE);  //飾り枠を消す
  2566:           frmScreenDevice.setFullScreenWindow (frmFrame);  //全画面表示する
  2567:         }
  2568:         if (Bubble.BBL_ON) {
  2569:           if (text != null) {
  2570:             Bubble.bblStart (text + (Multilingual.mlnJapanese ? "で全画面表示を終了" : " to exit full screen"), 5000L);
  2571:           }
  2572:         }
  2573:       } else if (mode == PNL_MAXIMIZED) {  //変更後が最大化
  2574:         pnlPrevMode = pnlMode;
  2575:         frmFrame.setExtendedState (Frame.MAXIMIZED_BOTH);  //最大化する
  2576:       }
  2577:       pnlMode = mode;
  2578:       //再配置する
  2579:       //  固定倍率のときここでフレームのサイズが変わることがある
  2580:       pnlUpdateArrangement ();
  2581:     } while (false);
  2582:     //ラジオボタンを確認して合っていなければ修正する
  2583:     if (pnlMode == PNL_FIXEDSCALE) {
  2584:       if (!mnbFixedScaleMenuItem.isSelected ()) {
  2585:         mnbFixedScaleMenuItem.setSelected (true);
  2586:       }
  2587:     } else if (pnlMode == PNL_FITINWINDOW) {
  2588:       if (!mnbFitInWindowMenuItem.isSelected ()) {
  2589:         mnbFitInWindowMenuItem.setSelected (true);
  2590:       }
  2591:     } else if (pnlMode == PNL_FULLSCREEN) {
  2592:       if (!mnbFullScreenMenuItem.isSelected ()) {
  2593:         mnbFullScreenMenuItem.setSelected (true);
  2594:       }
  2595:     } else if (pnlMode == PNL_MAXIMIZED) {
  2596:       if (!mnbMaximizedMenuItem.isSelected ()) {
  2597:         mnbMaximizedMenuItem.setSelected (true);
  2598:       }
  2599:     }
  2600:   }  //pnlSetMode
  2601: 
  2602: 
  2603: 
  2604:   //========================================================================================
  2605:   //$$RBT ロボット
  2606: 
  2607:   public static Robot rbtRobot;  //ロボット
  2608: 
  2609:   //rbtInit ()
  2610:   public static void rbtInit () {
  2611: 
  2612:     //ロボット
  2613:     rbtRobot = null;
  2614:     try {
  2615:       rbtRobot = new Robot ();  //プライマリスクリーンのみを対象とする
  2616:     } catch (Exception e) {
  2617:     }
  2618: 
  2619:   }  //rbtInit()
  2620: 
  2621: 
  2622: 
  2623:   //========================================================================================
  2624:   //$$MNB メニューバー
  2625:   //  メニューバーの高さは23px
  2626: 
  2627:   public static final int MNB_MODIFIERS = InputEvent.ALT_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK;  //アクセラレータのモディファイヤ
  2628: 
  2629:   //メニューバー
  2630:   public static JMenuBar mnbMenuBar;  //メニューバー
  2631: 
  2632:   //メニュー
  2633:   public static JMenu mnbFileMenu;  //ファイル
  2634:   public static JMenu mnbDisplayMenu;  //画面
  2635:   public static JMenu mnbSoundMenu;  //音声
  2636:   public static JMenu mnbInputMenu;  //入力
  2637:   public static JMenu mnbConfigMenu;  //設定
  2638:   public static JMenu mnbLanguageMenu;  //言語
  2639: 
  2640:   //メニューアイテム
  2641:   //  チェックボックスなどの変更内容はアクションイベントから取り出せるので個々のメニューアイテムに名前を付ける必要はない
  2642:   //  メニュー以外の方法で変更できるアイテムと一時的に変更できなくなるアイテムに名前をつけておく
  2643:   //  最初から最後まで選択できないメニューアイテムはメニューバーを作る時点で無効化するか、表示しない
  2644:   public static JMenuItem mnbQuitMenuItem;  //終了
  2645:   public static JCheckBoxMenuItem mnbStereoscopicMenuItem;  //立体視
  2646:   public static JCheckBoxMenuItem mnbPlayMenuItem;  //音声出力
  2647:   public static JMenuItem mnbPasteMenuItem;  //貼り付け
  2648:   public static JRadioButtonMenuItem mnbStandardKeyboardMenuItem;  //標準キーボード
  2649:   public static JRadioButtonMenuItem mnbCompactKeyboardMenuItem;  //コンパクトキーボード
  2650:   public static JRadioButtonMenuItem mnbNoKeyboardMenuItem;  //キーボードなし
  2651:   public static JLabel mnbVolumeLabel;  //音量
  2652: 
  2653: 
  2654:   //フォントサイズメニュー
  2655: 
  2656:   //mnbMakeFontSizeMenu ()
  2657:   //  フォントサイズメニューを作る
  2658:   public static JMenu mnbMakeFontSizeMenu () {
  2659:     //  アクションリスナー
  2660:     ActionListener actionListener = new ActionListener () {
  2661:       @Override public void actionPerformed (ActionEvent ae) {
  2662:         String command = ae.getActionCommand ();
  2663:         switch (command) {
  2664:         case "Very small":  //極小
  2665:           LnF.lnfFontSizeRequest = 10;
  2666:           break;
  2667:         case "Small":  //小
  2668:           LnF.lnfFontSizeRequest = 12;
  2669:           break;
  2670:         case "Medium":  //中
  2671:           LnF.lnfFontSizeRequest = 14;
  2672:           break;
  2673:         case "Large":  //大
  2674:           LnF.lnfFontSizeRequest = 16;
  2675:           break;
  2676:         case "Very large":  //極大
  2677:           LnF.lnfFontSizeRequest = 18;
  2678:           break;
  2679:         default:
  2680:           System.out.println ("unknown action command " + command);
  2681:         }
  2682:       }
  2683:     };
  2684:     //  ボタングループ
  2685:     ButtonGroup fontSizeGroup = new ButtonGroup ();
  2686:     //  メニュー
  2687:     return Multilingual.mlnText (
  2688:       ComponentFactory.createMenu (
  2689:         "Font size",
  2690:         Multilingual.mlnText (
  2691:           ComponentFactory.pointSize (
  2692:             ComponentFactory.createRadioButtonMenuItem (fontSizeGroup, LnF.lnfFontSizeRequest == 10, "Very small", actionListener),
  2693:             10),
  2694:           "ja", "極小"),
  2695:         Multilingual.mlnText (
  2696:           ComponentFactory.pointSize (
  2697:             ComponentFactory.createRadioButtonMenuItem (fontSizeGroup, LnF.lnfFontSizeRequest == 12, "Small", actionListener),
  2698:             12),
  2699:           "ja", "小"),
  2700:         Multilingual.mlnText (
  2701:           ComponentFactory.pointSize (
  2702:             ComponentFactory.createRadioButtonMenuItem (fontSizeGroup, LnF.lnfFontSizeRequest == 14, "Medium", actionListener),
  2703:             14),
  2704:           "ja", "中"),
  2705:         Multilingual.mlnText (
  2706:           ComponentFactory.pointSize (
  2707:             ComponentFactory.createRadioButtonMenuItem (fontSizeGroup, LnF.lnfFontSizeRequest == 16, "Large", actionListener),
  2708:             16),
  2709:           "ja", "大"),
  2710:         Multilingual.mlnText (
  2711:           ComponentFactory.pointSize (
  2712:             ComponentFactory.createRadioButtonMenuItem (fontSizeGroup, LnF.lnfFontSizeRequest == 18, "Very large", actionListener),
  2713:             18),
  2714:           "ja", "極大")),
  2715:       "ja", "フォントサイズ");
  2716:   }  //mnbMakeFontSizeMenu
  2717: 
  2718: 
  2719:   //色メニュー
  2720:   public static final DecimalSpinner[] mnbColorSpinners = new DecimalSpinner[9];  //スピナー
  2721:   public static final int[] mnbColorRGB = new int[15];
  2722:   public static JPanel mnbColorPanel;
  2723: 
  2724:   //mnbColorHSBToRGB ()
  2725:   //  LnF.lnfHSBからmnbColorRGBを作る
  2726:   public static void mnbColorHSBToRGB () {
  2727:     for (int i = 0; i <= 14; i++) {
  2728:       int[] t = LnF.LNF_HSB_INTERPOLATION_TABLE[i];
  2729:       float h = (float) (t[0] * LnF.lnfHSB[0] + t[1] * LnF.lnfHSB[1] + t[2] * LnF.lnfHSB[2]) / (49.0F * 360.0F);
  2730:       float s = (float) (t[0] * LnF.lnfHSB[3] + t[1] * LnF.lnfHSB[4] + t[2] * LnF.lnfHSB[5]) / (49.0F * 100.0F);
  2731:       float b = (float) (t[0] * LnF.lnfHSB[6] + t[1] * LnF.lnfHSB[7] + t[2] * LnF.lnfHSB[8]) / (49.0F * 100.0F);
  2732:       mnbColorRGB[i] = Color.HSBtoRGB (h,
  2733:                                        Math.max (0.0F, Math.min (1.0F, s)),
  2734:                                        Math.max (0.0F, Math.min (1.0F, b)));
  2735:     }
  2736:   }  //mnbColorHSBToRGB
  2737: 
  2738:   //mnbMakeColorMenu ()
  2739:   //  色メニューを作る
  2740:   public static JMenu mnbMakeColorMenu () {
  2741:     mnbColorHSBToRGB ();
  2742:     //  パネル
  2743:     mnbColorPanel = ComponentFactory.setColor (
  2744:       ComponentFactory.setFixedSize (
  2745:         new JPanel () {
  2746:           @Override protected void paintComponent (Graphics g) {
  2747:             super.paintComponent (g);
  2748:             for (int i = 0; i <= 14; i++) {
  2749:               g.setColor (new Color (mnbColorRGB[i]));
  2750:               g.fillRect (LnF.lnfFontSize * i, 0, LnF.lnfFontSize, LnF.lnfFontSize * 5);
  2751:             }
  2752:           }
  2753:         },
  2754:         LnF.lnfFontSize * 15, LnF.lnfFontSize * 5),
  2755:       Color.white, Color.black);
  2756:     //  チェンジリスナー
  2757:     ChangeListener changeListener = new ChangeListener () {
  2758:       @Override public void stateChanged (ChangeEvent ce) {
  2759:         DecimalSpinner spinner = (DecimalSpinner) ce.getSource ();
  2760:         LnF.lnfHSB[spinner.getOption ()] = spinner.getIntValue ();
  2761:         mnbColorHSBToRGB ();
  2762:         mnbColorPanel.repaint ();
  2763:       }
  2764:     };
  2765:     //  アクションリスナー
  2766:     ActionListener actionListener = new ActionListener () {
  2767:       @Override public void actionPerformed (ActionEvent ae) {
  2768:         String command = ae.getActionCommand ();
  2769:         switch (command) {
  2770:         case "Reset to default values":  //初期値に戻す
  2771:           for (int i = 0; i < 9; i++) {
  2772:             LnF.lnfHSB[i] = LnF.LNF_DEFAULT_HSB[i];
  2773:             mnbColorSpinners[i].setIntValue (LnF.lnfHSB[i]);
  2774:           }
  2775:           mnbColorHSBToRGB ();
  2776:           mnbColorPanel.repaint ();
  2777:           break;
  2778:         default:
  2779:           System.out.println ("unknown action command " + command);
  2780:         }
  2781:       }
  2782:     };
  2783:     //  スピナー
  2784:     for (int i = 0; i < 9; i++) {
  2785:       mnbColorSpinners[i] = ComponentFactory.createDecimalSpinner (
  2786:         LnF.lnfHSB[i], 0, i < 3 ? 720 : 100, 1, i, changeListener);
  2787:     }
  2788:     //  メニュー
  2789:     return Multilingual.mlnText (
  2790:       ComponentFactory.createMenu (
  2791:         "Color",
  2792:         ComponentFactory.createHorizontalBox (
  2793:           mnbColorSpinners[0],
  2794:           mnbColorSpinners[1],
  2795:           mnbColorSpinners[2],
  2796:           ComponentFactory.createLabel ("H °"),
  2797:           Box.createHorizontalGlue ()
  2798:           ),
  2799:         ComponentFactory.createHorizontalBox (
  2800:           mnbColorSpinners[3],
  2801:           mnbColorSpinners[4],
  2802:           mnbColorSpinners[5],
  2803:           ComponentFactory.createLabel ("S%"),
  2804:           Box.createHorizontalGlue ()
  2805:           ),
  2806:         ComponentFactory.createHorizontalBox (
  2807:           mnbColorSpinners[6],
  2808:           mnbColorSpinners[7],
  2809:           mnbColorSpinners[8],
  2810:           ComponentFactory.createLabel ("B%"),
  2811:           Box.createHorizontalGlue ()
  2812:           ),
  2813:         ComponentFactory.createHorizontalBox (
  2814:           ComponentFactory.setLineBorder (mnbColorPanel),
  2815:           Box.createHorizontalGlue ()
  2816:           ),
  2817:         Multilingual.mlnText (ComponentFactory.createMenuItem ("Reset to default values", actionListener), "ja", "初期値に戻す")
  2818:         ),
  2819:       "ja", "色");
  2820:   }  //mnbMakeColorMenu
  2821: 
  2822: 
  2823:   //言語メニュー
  2824:   //  テキストで書く
  2825:   //    国旗アイコンは対象とするマーケットを選択させるときに使うものであり、表示言語を切り替えるだけのメニューに国旗を用いるのは不適切
  2826:   public static JMenu mnbMakeLanguageMenu () {
  2827:     //  アクションリスナー
  2828:     ActionListener actionListener = new ActionListener () {
  2829:       @Override public void actionPerformed (ActionEvent ae) {
  2830:         String command = ae.getActionCommand ();
  2831:         switch (command) {
  2832:         case "English":
  2833:           Multilingual.mlnChange ("en");
  2834:           break;
  2835:         case "日本語":
  2836:           Multilingual.mlnChange ("ja");
  2837:           break;
  2838:         default:
  2839:           System.out.println ("unknown action command " + command);
  2840:         }
  2841:       }
  2842:     };
  2843:     //  ボタングループ
  2844:     ButtonGroup languageGroup = new ButtonGroup ();
  2845:     //  メニュー
  2846:     return mnbLanguageMenu = Multilingual.mlnText (
  2847:       ComponentFactory.createMenu (
  2848:         "Language", 'L',
  2849:         ComponentFactory.createRadioButtonMenuItem (languageGroup, Multilingual.mlnEnglish, "English", actionListener),
  2850:         ComponentFactory.createRadioButtonMenuItem (languageGroup, Multilingual.mlnJapanese, "日本語", actionListener)
  2851:         ),
  2852:       "ja", "言語");
  2853:   }  //mnbMakeLanguageMenu
  2854: 
  2855: 
  2856:   //mnbMakeMenu ()
  2857:   //  メニューバーを作る
  2858:   //  メニューバーの幅は狭くしたいがメニューの幅が狭すぎると隣のメニューに流れやすくなって操作しにくいのでメニューの数を必要最小限にする
  2859:   public static void mnbMakeMenu () {
  2860: 
  2861:     //アクションリスナー
  2862:     ActionListener listener = new ActionListener () {
  2863:       @Override public void actionPerformed (ActionEvent ae) {
  2864:         Object source = ae.getSource ();
  2865:         String command = ae.getActionCommand ();
  2866:         switch (command) {
  2867: 
  2868:           //ファイルメニュー
  2869:         case "Quit":  //終了
  2870:           prgTini ();
  2871:           break;
  2872: 
  2873:           //画面メニュー
  2874:         case "50%":
  2875:         case "75%":
  2876:         case "100%":
  2877:         case "150%":
  2878:         case "200%":
  2879:           pnlFixedModel.setValue (Integer.valueOf (Integer.parseInt (command.substring (0, command.length () - 1))));  //pnlFixedSpinnerのChangeEventが発動する
  2880:           break;
  2881:         case "Nearest neighbor":  //最近傍補間
  2882:           pnlInterpolation = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
  2883:           break;
  2884:         case "Bilinear":  //線形補間
  2885:           pnlInterpolation = RenderingHints.VALUE_INTERPOLATION_BILINEAR;
  2886:           break;
  2887:         case "Bicubic":  //三次補間
  2888:           pnlInterpolation = RenderingHints.VALUE_INTERPOLATION_BICUBIC;
  2889:           break;
  2890:           //
  2891:         case "Use canvas":  //キャンバスを使う
  2892:           pnlUseCanvasRequest = ((JCheckBoxMenuItem) source).isSelected ();
  2893:           break;
  2894:           //
  2895:         case "Draw all changed pictures":  //変化した画像をすべて描画する
  2896:           if (CRTC.CRT_ENABLE_INTERMITTENT) {
  2897:             CRTC.crtIntermittentInterval = 0;
  2898:           }
  2899:           break;
  2900:         case "Draw a changed picture once every two times":  //変化した画像を 2 回に 1 回描画する
  2901:           if (CRTC.CRT_ENABLE_INTERMITTENT) {
  2902:             CRTC.crtIntermittentInterval = 1;
  2903:           }
  2904:           break;
  2905:         case "Draw a changed picture once every three times":  //変化した画像を 3 回に 1 回描画する
  2906:           if (CRTC.CRT_ENABLE_INTERMITTENT) {
  2907:             CRTC.crtIntermittentInterval = 2;
  2908:           }
  2909:           break;
  2910:         case "Draw a changed picture once every four times":  //変化した画像を 4 回に 1 回描画する
  2911:           if (CRTC.CRT_ENABLE_INTERMITTENT) {
  2912:             CRTC.crtIntermittentInterval = 3;
  2913:           }
  2914:           break;
  2915:         case "Draw a changed picture once every five times":  //変化した画像を 5 回に 1 回描画する
  2916:           if (CRTC.CRT_ENABLE_INTERMITTENT) {
  2917:             CRTC.crtIntermittentInterval = 4;
  2918:           }
  2919:           break;
  2920:           //
  2921:         case "Stereoscopic viewing":  //立体視
  2922:           pnlSetStereoscopic (((JCheckBoxMenuItem) source).isSelected (), pnlStereoscopicMethod);
  2923:           break;
  2924:         case "Naked-eye crossing":  //裸眼交差法
  2925:           pnlSetStereoscopic (pnlStereoscopicOn, PNL_NAKED_EYE_CROSSING);
  2926:           break;
  2927:         case "Naked-eye parallel":  //裸眼平行法
  2928:           pnlSetStereoscopic (pnlStereoscopicOn, PNL_NAKED_EYE_PARALLEL);
  2929:           break;
  2930:         case "Side-by-side":  //サイドバイサイド
  2931:           pnlSetStereoscopic (pnlStereoscopicOn, PNL_SIDE_BY_SIDE);
  2932:           break;
  2933:         case "Top-and-bottom":  //トップアンドボトム
  2934:           pnlSetStereoscopic (pnlStereoscopicOn, PNL_TOP_AND_BOTTOM);
  2935:           break;
  2936:           //
  2937:         case "Sprite pattern viewer":  //スプライトパターンビュア
  2938:           if (SpritePatternViewer.SPV_ON) {
  2939:             SpritePatternViewer.spvOpen ();
  2940:           }
  2941:           break;
  2942:         case "Palette viewer":  //パレットビュア
  2943:           if (PaletteViewer.PLV_ON) {
  2944:             PaletteViewer.plvOpen ();
  2945:           }
  2946:           break;
  2947:         case "Screen mode test":  //表示モードテスト
  2948:           if (ScreenModeTest.SMT_ON) {
  2949:             ScreenModeTest.smtOpen ();
  2950:           }
  2951:           break;
  2952: 
  2953:           //音声メニュー
  2954:         case "Play":  //音声出力
  2955:           SoundSource.sndSetPlayOn (((JCheckBoxMenuItem) source).isSelected ());
  2956:           break;
  2957:         case "OPM output":  //OPM出力
  2958:           OPM.opmSetOutputOn (((JCheckBoxMenuItem) source).isSelected ());
  2959:           break;
  2960:         case "OPM log":  //OPM ログ
  2961:           OPMLog.olgOpen ();
  2962:           break;
  2963:           //
  2964:         case "PCM output":  //PCM出力
  2965:           ADPCM.pcmSetOutputOn (((JCheckBoxMenuItem) source).isSelected ());
  2966:           break;
  2967:         case "Sound thinning":  //音声 間引き
  2968:           SoundSource.sndRateConverter = SoundSource.SND_CHANNELS == 1 ? SoundSource.SNDRateConverter.THINNING_MONO : SoundSource.SNDRateConverter.THINNING_STEREO;
  2969:           break;
  2970:         case "Sound linear interpolation":  //音声 線形補間
  2971:           SoundSource.sndRateConverter = SoundSource.SND_CHANNELS == 1 ? SoundSource.SNDRateConverter.LINEAR_MONO : SoundSource.SNDRateConverter.LINEAR_STEREO;
  2972:           break;
  2973:         case "Sound piecewise-constant area interpolation":  //音声 区分定数面積補間
  2974:           SoundSource.sndRateConverter = SoundSource.SNDRateConverter.CONSTANT_AREA_STEREO_48000;
  2975:           break;
  2976:         case "Sound linear area interpolation":  //音声 線形面積補間
  2977:           SoundSource.sndRateConverter = SoundSource.SNDRateConverter.LINEAR_AREA_STEREO_48000;
  2978:           break;
  2979:         case "Sound monitor":  //音声モニタ
  2980:           SoundMonitor.smnOpen ();
  2981:           break;
  2982:         case "PCM piecewise-constant interpolation":  //PCM 区分定数補間
  2983:           ADPCM.pcmSetInterpolationAlgorithm (ADPCM.PCM_INTERPOLATION_CONSTANT);
  2984:           break;
  2985:         case "PCM linear interpolation":  //PCM 線形補間
  2986:           ADPCM.pcmSetInterpolationAlgorithm (ADPCM.PCM_INTERPOLATION_LINEAR);
  2987:           break;
  2988:         case "PCM hermite interpolation":  //PCM エルミート補間
  2989:           ADPCM.pcmSetInterpolationAlgorithm (ADPCM.PCM_INTERPOLATION_HERMITE);
  2990:           break;
  2991:         case "PCM 8MHz/4MHz":
  2992:           ADPCM.pcmOSCFreqRequest = 0;
  2993:           break;
  2994:         case "PCM 8MHz/16MHz":
  2995:           ADPCM.pcmOSCFreqRequest = 1;
  2996:           break;
  2997:         case "Mercury-Unit V4 (MK-MU1)":
  2998:           MercuryUnit.mu4OnRequest = ((JCheckBoxMenuItem) source).isSelected ();
  2999:           break;
  3000:         case "MU4 output":
  3001:           MercuryUnit.mu4OutputEnable = ((JCheckBoxMenuItem) source).isSelected ();
  3002:           break;
  3003: 
  3004:           //入力メニュー
  3005:         case "Paste":  //貼り付け
  3006:           CONDevice.conDoPaste ();
  3007:           break;
  3008:         case "No keyboard":  //キーボードなし
  3009:           Keyboard.kbdSetOn (false);
  3010:           pnlUpdateArrangement ();
  3011:           break;
  3012:         case "Standard keyboard":  //標準キーボード
  3013:           Keyboard.kbdSetType (Keyboard.KBD_STANDARD_TYPE);
  3014:           Keyboard.kbdSetOn (true);
  3015:           pnlUpdateArrangement ();
  3016:           break;
  3017:         case "Compact keyboard":  //コンパクトキーボード
  3018:           Keyboard.kbdSetType (Keyboard.KBD_COMPACT_TYPE);
  3019:           Keyboard.kbdSetOn (true);
  3020:           pnlUpdateArrangement ();
  3021:           break;
  3022:         case "Hide keyboard in full screen":  //全画面表示のときキーボードを隠す
  3023:           pnlHideKeyboard = ((JCheckBoxMenuItem) source).isSelected ();
  3024:           if (pnlMode == PNL_FULLSCREEN) {
  3025:             pnlUpdateArrangement ();
  3026:           }
  3027:           break;
  3028:         case "Key assignments":  //キー割り当て
  3029:           Keyboard.kbdOpen ();
  3030:           break;
  3031:         case "Joystick port settings":  //ジョイスティックポート設定
  3032:           PPI.ppiOpen ();
  3033:           break;
  3034: 
  3035:           //設定メニュー
  3036:         case "RS-232C and terminal":  //RS-232C とターミナル
  3037:           RS232CTerminal.trmOpen ();
  3038:           break;
  3039:           //  デバッグ
  3040:         case "Console":  //コンソール
  3041:           DebugConsole.dgtOpen ();
  3042:           break;
  3043:         case "Register list":  //レジスタ
  3044:           RegisterList.drpOpen ();
  3045:           break;
  3046:         case "Disassemble list":  //逆アセンブルリスト
  3047:           DisassembleList.ddpOpen (-1, -1, true);
  3048:           break;
  3049:         case "Memory dump list":  //メモリダンプリスト
  3050:           MemoryDumpList.dmpOpen (-1, -1, true);
  3051:           break;
  3052:         case "Logical space monitor":  //論理空間モニタ
  3053:           LogicalSpaceMonitor.atwOpen ();
  3054:           break;
  3055:         case "Physical space monitor":  //物理空間モニタ
  3056:           PhysicalSpaceMonitor.paaOpen ();
  3057:           break;
  3058:         case "Address translation caches monitor":  //アドレス変換キャッシュモニタ
  3059:           if (ATCMonitor.ACM_ON) {
  3060:             ATCMonitor.acmOpen ();
  3061:           }
  3062:           break;
  3063:         case "Branch log":  //分岐ログ
  3064:           if (BranchLog.BLG_ON) {
  3065:             BranchLog.blgOpen (BranchLog.BLG_SELECT_NONE);
  3066:           }
  3067:           break;
  3068:         case "Program flow visualizer":  //プログラムフロービジュアライザ
  3069:           if (ProgramFlowVisualizer.PFV_ON) {
  3070:             ProgramFlowVisualizer.pfvOpen ();
  3071:           }
  3072:           break;
  3073:         case "Raster break point":  //ラスタブレークポイント
  3074:           if (RasterBreakPoint.RBP_ON) {
  3075:             RasterBreakPoint.rbpOpen ();
  3076:           }
  3077:           break;
  3078:         case "Data break point":  //データブレークポイント
  3079:           if (DataBreakPoint.DBP_ON) {
  3080:             DataBreakPoint.dbpOpen ();
  3081:           }
  3082:           break;
  3083:         case "Root pointer list":  //ルートポインタリスト
  3084:           if (RootPointerList.RTL_ON) {
  3085:             RootPointerList.rtlOpen ();
  3086:           }
  3087:           break;
  3088:           //  起動デバイス
  3089:           //  RTC
  3090:         case "Adjust clock to host":  //時計をホストに合わせる
  3091:           RP5C15.rtcSetByHost ();
  3092:           break;
  3093:           //  SRAM
  3094:           //  設定ファイル
  3095:           //
  3096:         case "Printer":  //プリンタ
  3097:           PrinterPort.prnOpen ();
  3098:           break;
  3099:           //
  3100:         case "Print key and mouse button events":  //キーとマウスのボタンのイベントを表示
  3101:           Mouse.musOutputButtonStatus = ((JCheckBoxMenuItem) source).isSelected ();
  3102:           break;
  3103:           //
  3104:         case "Java runtime environment information":
  3105:           prgOpenJavaDialog ();
  3106:           break;
  3107:         case "Version information":
  3108:           prgOpenAboutDialog ();
  3109:           break;
  3110:         case "XEiJ License":
  3111:           prgOpenXEiJLicenseDialog ();
  3112:           break;
  3113:         case "FSHARP License":
  3114:           prgOpenSHARPLicenseDialog ();
  3115:           break;
  3116:         case "ymfm License":
  3117:           prgOpenYmfmLicenseDialog ();
  3118:           break;
  3119:         case "jSerialComm License":
  3120:           prgOpenJSerialCommLicenseDialog ();
  3121:           break;
  3122: 
  3123:         default:
  3124:           System.out.println ("unknown action command " + command);
  3125: 
  3126:         }
  3127:       }
  3128:     };
  3129: 
  3130:     //  メインメモリ
  3131:     ActionListener mainMemoryListener = new ActionListener () {
  3132:       @Override public void actionPerformed (ActionEvent ae) {
  3133:         Object source = ae.getSource ();
  3134:         String command = ae.getActionCommand ();
  3135:         switch (command) {
  3136:         case "1MB":
  3137:           MainMemory.mmrMemorySizeRequest = 0x00100000;
  3138:           break;
  3139:         case "2MB":
  3140:           MainMemory.mmrMemorySizeRequest = 0x00200000;
  3141:           break;
  3142:         case "4MB":
  3143:           MainMemory.mmrMemorySizeRequest = 0x00400000;
  3144:           break;
  3145:         case "6MB":
  3146:           MainMemory.mmrMemorySizeRequest = 0x00600000;
  3147:           break;
  3148:         case "8MB":
  3149:           MainMemory.mmrMemorySizeRequest = 0x00800000;
  3150:           break;
  3151:         case "10MB":
  3152:           MainMemory.mmrMemorySizeRequest = 0x00a00000;
  3153:           break;
  3154:         case "12MB":
  3155:           MainMemory.mmrMemorySizeRequest = 0x00c00000;
  3156:           break;
  3157:         case "Save contents on exit":  //終了時に内容を保存する
  3158:           MainMemory.mmrMemorySaveOn = ((JCheckBoxMenuItem) source).isSelected ();
  3159:           break;
  3160:         }
  3161:       }
  3162:     };
  3163:     ButtonGroup mainMemoryGroup = new ButtonGroup ();
  3164:     JMenu mainMemoryMenu = Multilingual.mlnText (
  3165:       ComponentFactory.createMenu (
  3166:         "Main memory",
  3167:         Multilingual.mlnText (
  3168:           ComponentFactory.createRadioButtonMenuItem (mainMemoryGroup, MainMemory.mmrMemorySizeRequest == 0x00100000, "1MB", mainMemoryListener),
  3169:           "ja", "1MB"),
  3170:         Multilingual.mlnText (
  3171:           ComponentFactory.createRadioButtonMenuItem (mainMemoryGroup, MainMemory.mmrMemorySizeRequest == 0x00200000, "2MB", mainMemoryListener),
  3172:           "ja", "2MB"),
  3173:         Multilingual.mlnText (
  3174:           ComponentFactory.createRadioButtonMenuItem (mainMemoryGroup, MainMemory.mmrMemorySizeRequest == 0x00400000, "4MB", mainMemoryListener),
  3175:           "ja", "4MB"),
  3176:         Multilingual.mlnText (
  3177:           ComponentFactory.createRadioButtonMenuItem (mainMemoryGroup, MainMemory.mmrMemorySizeRequest == 0x00600000, "6MB", mainMemoryListener),
  3178:           "ja", "6MB"),
  3179:         Multilingual.mlnText (
  3180:           ComponentFactory.createRadioButtonMenuItem (mainMemoryGroup, MainMemory.mmrMemorySizeRequest == 0x00800000, "8MB", mainMemoryListener),
  3181:           "ja", "8MB"),
  3182:         Multilingual.mlnText (
  3183:           ComponentFactory.createRadioButtonMenuItem (mainMemoryGroup, MainMemory.mmrMemorySizeRequest == 0x00a00000, "10MB", mainMemoryListener),
  3184:           "ja", "10MB"),
  3185:         Multilingual.mlnText (
  3186:           ComponentFactory.createRadioButtonMenuItem (mainMemoryGroup, MainMemory.mmrMemorySizeRequest == 0x00c00000, "12MB", mainMemoryListener),
  3187:           "ja", "12MB"),
  3188:         ComponentFactory.createHorizontalSeparator (),
  3189:         Multilingual.mlnText (
  3190:           ComponentFactory.createCheckBoxMenuItem (MainMemory.mmrMemorySaveOn, "Save contents on exit", mainMemoryListener),
  3191:           "ja", "終了時に内容を保存する"),
  3192:         SRAM.smrModifyMemorySizeMenuItem
  3193:         ),
  3194:       "ja", "メインメモリ");
  3195: 
  3196:     //  X68030/Xellent30 のハイメモリ
  3197:     ActionListener highMemoryListener = new ActionListener () {
  3198:       @Override public void actionPerformed (ActionEvent ae) {
  3199:         Object source = ae.getSource ();
  3200:         String command = ae.getActionCommand ();
  3201:         switch (command) {
  3202:         case "None":  //なし
  3203:           busHighMemorySize = 0 << 20;
  3204:           break;
  3205:         case "16MB":
  3206:           busHighMemorySize = 16 << 20;
  3207:           break;
  3208:         case "Save contents on exit":  //終了時に内容を保存する
  3209:           busHighMemorySaveOn = ((JCheckBoxMenuItem) source).isSelected ();
  3210:           break;
  3211:         }
  3212:       }
  3213:     };
  3214:     ButtonGroup highMemoryGroup = new ButtonGroup ();
  3215:     JMenu highMemoryMenu = Multilingual.mlnText (
  3216:       ComponentFactory.createMenu (
  3217:         "High memory on X68030/Xellent30",
  3218:         Multilingual.mlnText (
  3219:           ComponentFactory.createRadioButtonMenuItem (highMemoryGroup, busHighMemorySize == 0 << 20, "None", highMemoryListener),
  3220:           "ja", "なし"),
  3221:         Multilingual.mlnText (
  3222:           ComponentFactory.createRadioButtonMenuItem (highMemoryGroup, busHighMemorySize == 16 << 20, "16MB", highMemoryListener),
  3223:           "ja", "16MB"),
  3224:         ComponentFactory.createHorizontalSeparator (),
  3225:         Multilingual.mlnText (
  3226:           ComponentFactory.createCheckBoxMenuItem (busHighMemorySaveOn, "Save contents on exit", highMemoryListener),
  3227:           "ja", "終了時に内容を保存する")
  3228:         ),
  3229:       "ja", "X68030/Xellent30 のハイメモリ");
  3230: 
  3231:     //  060turbo のハイメモリ
  3232:     ActionListener localMemoryListener = new ActionListener () {
  3233:       @Override public void actionPerformed (ActionEvent ae) {
  3234:         Object source = ae.getSource ();
  3235:         String command = ae.getActionCommand ();
  3236:         switch (command) {
  3237:         case "None":  //なし
  3238:           busLocalMemorySize = 0 << 20;
  3239:           break;
  3240:         case "16MB":
  3241:           busLocalMemorySize = 16 << 20;
  3242:           break;
  3243:         case "32MB":
  3244:           busLocalMemorySize = 32 << 20;
  3245:           break;
  3246:         case "64MB":
  3247:           busLocalMemorySize = 64 << 20;
  3248:           break;
  3249:         case "128MB":
  3250:           busLocalMemorySize = 128 << 20;
  3251:           break;
  3252:         case "256MB":
  3253:           busLocalMemorySize = 256 << 20;
  3254:           break;
  3255:         case "384MB":
  3256:           busLocalMemorySize = 384 << 20;
  3257:           break;
  3258:         case "512MB":
  3259:           busLocalMemorySize = 512 << 20;
  3260:           break;
  3261:         case "768MB":
  3262:           busLocalMemorySize = 768 << 20;
  3263:           break;
  3264:         case "Save contents on exit":  //終了時に内容を保存する
  3265:           busLocalMemorySaveOn = ((JCheckBoxMenuItem) source).isSelected ();
  3266:           break;
  3267:         case "Available on X68000":  //X68000 でも有効
  3268:           busHimem68000 = ((JCheckBoxMenuItem) source).isSelected ();
  3269:           break;
  3270:         case "Available on X68030/Xellent30":  //X68030/Xellent30 でも有効
  3271:           busHighMemory060turboOn = ((JCheckBoxMenuItem) source).isSelected ();
  3272:           break;
  3273:         }
  3274:       }
  3275:     };
  3276:     ButtonGroup localMenoryGroup = new ButtonGroup ();
  3277:     JMenu localMemoryMenu = Multilingual.mlnText (
  3278:       ComponentFactory.createMenu (
  3279:         "High memory on 060turbo",
  3280:         Multilingual.mlnText (
  3281:           ComponentFactory.createRadioButtonMenuItem (localMenoryGroup, busLocalMemorySize == 0 << 20, "None", localMemoryListener),
  3282:           "ja", "なし"),
  3283:         ComponentFactory.createRadioButtonMenuItem (localMenoryGroup, busLocalMemorySize == 16 << 20, "16MB", localMemoryListener),
  3284:         ComponentFactory.createRadioButtonMenuItem (localMenoryGroup, busLocalMemorySize == 32 << 20, "32MB", localMemoryListener),
  3285:         ComponentFactory.createRadioButtonMenuItem (localMenoryGroup, busLocalMemorySize == 64 << 20, "64MB", localMemoryListener),
  3286:         ComponentFactory.createRadioButtonMenuItem (localMenoryGroup, busLocalMemorySize == 128 << 20, "128MB", localMemoryListener),
  3287:         ComponentFactory.createRadioButtonMenuItem (localMenoryGroup, busLocalMemorySize == 256 << 20, "256MB", localMemoryListener),
  3288:         ComponentFactory.createRadioButtonMenuItem (localMenoryGroup, busLocalMemorySize == 384 << 20, "384MB", localMemoryListener),
  3289:         ComponentFactory.createRadioButtonMenuItem (localMenoryGroup, busLocalMemorySize == 512 << 20, "512MB", localMemoryListener),
  3290:         ComponentFactory.createRadioButtonMenuItem (localMenoryGroup, busLocalMemorySize == 768 << 20, "768MB", localMemoryListener),
  3291:         ComponentFactory.createHorizontalSeparator (),
  3292:         Multilingual.mlnText (
  3293:           ComponentFactory.createCheckBoxMenuItem (busLocalMemorySaveOn, "Save contents on exit", localMemoryListener),
  3294:           "ja", "終了時に内容を保存する"),
  3295:         ComponentFactory.createHorizontalSeparator (),
  3296:         Multilingual.mlnText (
  3297:           ComponentFactory.createCheckBoxMenuItem (busHimem68000, "Available on X68000", localMemoryListener),
  3298:           "ja", "X68000 でも有効"),
  3299:         Multilingual.mlnText (
  3300:           ComponentFactory.createCheckBoxMenuItem (busHighMemory060turboOn, "Available on X68030/Xellent30", localMemoryListener),
  3301:           "ja", "X68030/Xellent30 でも有効")
  3302:         ),
  3303:       "ja", "060turbo のハイメモリ");
  3304: 
  3305:     //Xellent30
  3306:     ActionListener xellent30Listener = new ActionListener () {
  3307:       @Override public void actionPerformed (ActionEvent ae) {
  3308:         Object source = ae.getSource ();
  3309:         String command = ae.getActionCommand ();
  3310:         switch (command) {
  3311:         case "$00EC0000-$00EC3FFF":
  3312:           xt3DIPSW = 0;
  3313:           break;
  3314:         case "$00EC4000-$00EC7FFF":
  3315:           xt3DIPSW = 1;
  3316:           break;
  3317:         case "$00EC8000-$00ECBFFF":
  3318:           xt3DIPSW = 2;
  3319:           break;
  3320:         case "$00ECC000-$00ECFFFF":
  3321:           xt3DIPSW = 3;
  3322:           break;
  3323:         case "256KB":
  3324:           xt3MemorySizeRequest = 1 << 18;
  3325:           break;
  3326:         case "1MB":
  3327:           xt3MemorySizeRequest = 1 << 20;
  3328:           break;
  3329:         case "Save contents on exit":  //終了時に内容を保存する
  3330:           xt3MemorySave = ((JCheckBoxMenuItem) source).isSelected ();
  3331:           break;
  3332:         }
  3333:       }
  3334:     };
  3335:     ButtonGroup xellent30PortGroup = new ButtonGroup ();
  3336:     ButtonGroup xellent30SizeGroup = new ButtonGroup ();
  3337:     JMenu xellent30Menu = ComponentFactory.createMenu (
  3338:       "Xellent30",
  3339:       ComponentFactory.createRadioButtonMenuItem (
  3340:         xellent30PortGroup,
  3341:         xt3DIPSW == 0,
  3342:         "$00EC0000-$00EC3FFF",
  3343:         xellent30Listener),
  3344:       ComponentFactory.createRadioButtonMenuItem (
  3345:         xellent30PortGroup,
  3346:         xt3DIPSW == 1,
  3347:         "$00EC4000-$00EC7FFF",
  3348:         xellent30Listener),
  3349:       ComponentFactory.createRadioButtonMenuItem (
  3350:         xellent30PortGroup,
  3351:         xt3DIPSW == 2,
  3352:         "$00EC8000-$00ECBFFF",
  3353:         xellent30Listener),
  3354:       ComponentFactory.createRadioButtonMenuItem (
  3355:         xellent30PortGroup,
  3356:         xt3DIPSW == 3,
  3357:         "$00ECC000-$00ECFFFF",
  3358:         xellent30Listener),
  3359:       ComponentFactory.createHorizontalSeparator (),
  3360:       ComponentFactory.createRadioButtonMenuItem (
  3361:         xellent30SizeGroup,
  3362:         xt3MemorySizeRequest == 1 << 18,
  3363:         "256KB",
  3364:         xellent30Listener),
  3365:       ComponentFactory.createRadioButtonMenuItem (
  3366:         xellent30SizeGroup,
  3367:         xt3MemorySizeRequest == 1 << 20,
  3368:         "1MB",
  3369:         xellent30Listener),
  3370:       ComponentFactory.createHorizontalSeparator (),
  3371:       Multilingual.mlnText (
  3372:         ComponentFactory.createCheckBoxMenuItem (xt3MemorySave, "Save contents on exit", xellent30Listener),
  3373:         "ja", "終了時に内容を保存する")
  3374:       );
  3375: 
  3376:     //回転
  3377:     JMenu rotationMenu = null;
  3378:     if (PNL_ROTATION_ON) {
  3379:       ActionListener rotationListener = new ActionListener () {
  3380:         @Override public void actionPerformed (ActionEvent ae) {
  3381:           String command = ae.getActionCommand ();
  3382:           switch (command) {
  3383:           case "No rotation (landscape)":  //回転なし (横画面)
  3384:             pnlRotationMode = 0;
  3385:             pnlUpdateArrangement ();
  3386:             break;
  3387:           case "90-degree rotation (portrait)":  //90 度回転 (縦画面)
  3388:             pnlRotationMode = 1;
  3389:             pnlUpdateArrangement ();
  3390:             break;
  3391:           case "180-degree rotation":  //180 度回転
  3392:             pnlRotationMode = 2;
  3393:             pnlUpdateArrangement ();
  3394:             break;
  3395:           case "270-degree rotation":  //270 度回転
  3396:             pnlRotationMode = 3;
  3397:             pnlUpdateArrangement ();
  3398:             break;
  3399:           default:
  3400:             System.out.println ("unknown action command " + command);
  3401:           }
  3402:         }
  3403:       };
  3404:       ButtonGroup rotationGroup = new ButtonGroup ();
  3405:       rotationMenu = Multilingual.mlnText (
  3406:         ComponentFactory.createMenu (
  3407:           "Rotation",
  3408:           Multilingual.mlnText (
  3409:             ComponentFactory.createRadioButtonMenuItem (rotationGroup, pnlRotationMode == 0, "No rotation (landscape)", rotationListener),
  3410:             "ja", "回転なし (横画面)"),
  3411:           Multilingual.mlnText (
  3412:             ComponentFactory.createRadioButtonMenuItem (rotationGroup, pnlRotationMode == 1, "90-degree rotation (portrait)", rotationListener),
  3413:             "ja", "90 度回転 (縦画面)"),
  3414:           Multilingual.mlnText (
  3415:             ComponentFactory.createRadioButtonMenuItem (rotationGroup, pnlRotationMode == 2, "180-degree rotation", rotationListener),
  3416:             "ja", "180 度回転"),
  3417:           Multilingual.mlnText (
  3418:             ComponentFactory.createRadioButtonMenuItem (rotationGroup, pnlRotationMode == 3, "270-degree rotation", rotationListener),
  3419:             "ja", "270 度回転")
  3420:           ),
  3421:         "ja", "回転");
  3422:     }
  3423: 
  3424:     //アスペクト比
  3425:     ActionListener aspectListener = new ActionListener () {
  3426:       @Override public void actionPerformed (ActionEvent ae) {
  3427:         String command = ae.getActionCommand ();
  3428:         int i = command.indexOf (',');
  3429:         int resolutionNumber = Integer.parseInt (command.substring (0, i));
  3430:         int ratioNumber = Integer.parseInt (command.substring (i + 1));
  3431:         pnlAspectMap[resolutionNumber] = ratioNumber;
  3432:         pnlUpdateAspectTable ();
  3433:         pnlUpdateArrangement ();
  3434:       }  //actionPerformed
  3435:     };  //new ActionListener
  3436:     JMenu aspectMenu = ComponentFactory.createMenu ("Aspect ratio");
  3437:     for (int resolutionNumber = 0; resolutionNumber < PNL_ASPECT_RESOLUTION_COUNT; resolutionNumber++) {
  3438:       JMenu menu = ComponentFactory.createMenu (PNL_ASPECT_RESOLUTION_NAME[resolutionNumber]);
  3439:       ButtonGroup group = new ButtonGroup ();
  3440:       for (int ratioNumber = 0; ratioNumber < PNL_ASPECT_RATIO_COUNT; ratioNumber++) {
  3441:         if (PNL_ASPECT_RATIO_MATRIX[resolutionNumber][ratioNumber] == 0.0F) {
  3442:           continue;
  3443:         }
  3444:         menu.add (
  3445:           ComponentFactory.setText (
  3446:             ComponentFactory.createRadioButtonMenuItem (
  3447:               group,  //buttonGroup
  3448:               pnlAspectMap[resolutionNumber] == ratioNumber,  //selected
  3449:               resolutionNumber + "," + ratioNumber,  //actionCommand
  3450:               aspectListener  //actionListener
  3451:               ),
  3452:             (PNL_ASPECT_RATIO_MATRIX[resolutionNumber] == PNL_ASPECT_PIXEL_RATIO_02 ?
  3453:              String.format ("%s (%.3f)",
  3454:                             PNL_ASPECT_SCREEN_NAME[ratioNumber],
  3455:                             PNL_ASPECT_SCREEN_RATIO[ratioNumber]) :
  3456:              String.format ("%s (%.3f) @ %s (%.3f)",
  3457:                             PNL_ASPECT_SCREEN_NAME[ratioNumber],
  3458:                             PNL_ASPECT_SCREEN_RATIO[ratioNumber],
  3459:                             PNL_ASPECT_NAME_MATRIX[resolutionNumber][ratioNumber],
  3460:                             PNL_ASPECT_RATIO_MATRIX[resolutionNumber][ratioNumber]))  //text
  3461:             )  //setText
  3462:           );  //add
  3463:       }  //for ratioNumber
  3464:       aspectMenu.add (menu);
  3465:     }  //for resolutionNumber
  3466:     aspectMenu = Multilingual.mlnText (aspectMenu, "ja", "アスペクト比");
  3467: 
  3468:     //走査線エフェクト
  3469:     ActionListener scanlineListener = new ActionListener () {
  3470:       @Override public void actionPerformed (ActionEvent ae) {
  3471:         //Object source = ae.getSource ();
  3472:         String command = ae.getActionCommand ();
  3473:         switch (command) {
  3474:         case "Off":  //なし
  3475:           CRTC.crtScanlineEffect = CRTC.ScanlineEffect.OFF;
  3476:           CRTC.crtAllStamp += 2;
  3477:           break;
  3478:         case "Weak":  //弱
  3479:           CRTC.crtScanlineEffect = CRTC.ScanlineEffect.WEAK;
  3480:           CRTC.crtAllStamp += 2;
  3481:           break;
  3482:         case "Medium":  //中
  3483:           CRTC.crtScanlineEffect = CRTC.ScanlineEffect.MEDIUM;
  3484:           CRTC.crtAllStamp += 2;
  3485:           break;
  3486:         case "Strong":  //強
  3487:           CRTC.crtScanlineEffect = CRTC.ScanlineEffect.STRONG;
  3488:           CRTC.crtAllStamp += 2;
  3489:           break;
  3490:         case "Black":  //黒
  3491:           CRTC.crtScanlineEffect = CRTC.ScanlineEffect.BLACK;
  3492:           CRTC.crtAllStamp += 2;
  3493:           break;
  3494:         }
  3495:       }
  3496:     };
  3497:     ButtonGroup scanlineGroup = new ButtonGroup ();
  3498:     JMenu scanlineMenu =
  3499:       Multilingual.mlnText (
  3500:         ComponentFactory.createMenu (
  3501:           "Scanline effect",
  3502:           Multilingual.mlnText (
  3503:             ComponentFactory.createRadioButtonMenuItem (scanlineGroup, CRTC.crtScanlineEffect == CRTC.ScanlineEffect.OFF, "Off", scanlineListener),
  3504:             "ja", "なし"),
  3505:           Multilingual.mlnText (
  3506:             ComponentFactory.createRadioButtonMenuItem (scanlineGroup, CRTC.crtScanlineEffect == CRTC.ScanlineEffect.WEAK, "Weak", scanlineListener),
  3507:             "ja", "弱"),
  3508:           Multilingual.mlnText (
  3509:             ComponentFactory.createRadioButtonMenuItem (scanlineGroup, CRTC.crtScanlineEffect == CRTC.ScanlineEffect.MEDIUM, "Medium", scanlineListener),
  3510:             "ja", "中"),
  3511:           Multilingual.mlnText (
  3512:             ComponentFactory.createRadioButtonMenuItem (scanlineGroup, CRTC.crtScanlineEffect == CRTC.ScanlineEffect.STRONG, "Strong", scanlineListener),
  3513:             "ja", "強"),
  3514:           Multilingual.mlnText (
  3515:             ComponentFactory.createRadioButtonMenuItem (scanlineGroup, CRTC.crtScanlineEffect == CRTC.ScanlineEffect.BLACK, "Black", scanlineListener),
  3516:             "ja", "黒")
  3517:           ),
  3518:         "ja", "走査線エフェクト");
  3519: 
  3520:     //リフレッシュレート
  3521:     JTextField refreshRateTextField = ComponentFactory.createNumberField (pnlRefreshRate == 0.0 ? "" : String.valueOf (pnlRefreshRate), 8);
  3522:     refreshRateTextField.addActionListener (
  3523:       new ActionListener () {
  3524:         @Override public void actionPerformed (ActionEvent ae) {
  3525:           JTextField textField = (JTextField) ae.getSource ();
  3526:           pnlRefreshRate = 0.0;
  3527:           String s = textField.getText ();
  3528:           if (!s.equals ("")) {
  3529:             double rate = 0.0;
  3530:             try {
  3531:               rate = Double.parseDouble (s);
  3532:             } catch (NumberFormatException nfe) {
  3533:             }
  3534:             if (PNL_MIN_RATE <= rate && rate <= PNL_MAX_RATE) {
  3535:               pnlRefreshRate = rate;
  3536:             } else {
  3537:               textField.setText ("");  //""でないがパースできないかできても範囲外のとき""に戻す
  3538:             }
  3539:           }
  3540:           pnlFixedRate = pnlRefreshRate;  //指定がないか無効のとき0.0
  3541:           if (pnlAdjustVsync && pnlFixedRate == 0.0) {
  3542:             pnlFixedRate = pnlGetRefreshRate ();  //なければデフォルトになるので0.0ではなくなる
  3543:           }
  3544:           CRTC.crtUpdateLength ();
  3545:         }
  3546:       });
  3547: 
  3548:     ButtonGroup unitGroup = new ButtonGroup ();
  3549:     ButtonGroup frameGroup = new ButtonGroup ();
  3550:     ButtonGroup hintGroup = new ButtonGroup ();
  3551:     ButtonGroup vgaGroup = new ButtonGroup ();
  3552:     ButtonGroup intermittentGroup = new ButtonGroup ();
  3553:     ButtonGroup sterescopicGroup = new ButtonGroup ();
  3554:     ButtonGroup soundInterpolationGroup = new ButtonGroup ();
  3555:     ButtonGroup adpcmInterpolationGroup = new ButtonGroup ();
  3556:     ButtonGroup adpcmOSCFreqGroup = new ButtonGroup ();
  3557:     ButtonGroup keyboardGroup = new ButtonGroup ();
  3558:     ButtonGroup spritesGroup = new ButtonGroup ();
  3559: 
  3560:     //改造
  3561:     DecimalSpinner[] freqSpinner = new DecimalSpinner[3];
  3562:     ChangeListener freqListener = new ChangeListener () {
  3563:       @Override public void stateChanged (ChangeEvent ce) {
  3564:         DecimalSpinner spinner = (DecimalSpinner) ce.getSource ();
  3565:         int i = spinner.getOption ();
  3566:         CRTC.crtFreqsRequest[i] = spinner.getIntValue ();
  3567:       }
  3568:     };
  3569:     for (int i = 0; i < 3; i++) {
  3570:       freqSpinner[i] = ComponentFactory.createDecimalSpinner (
  3571:         CRTC.crtFreqsRequest[i], CRTC.CRT_MIN_FREQ, CRTC.CRT_MAX_FREQ, 1000000, i, freqListener
  3572:         );
  3573:     }
  3574:     DecimalSpinner sprrasSpinner = ComponentFactory.createDecimalSpinner (
  3575:       SpriteScreen.sprSpritesPerRaster, 0, /*2040*/1016, 1, 0,
  3576:       new ChangeListener () {
  3577:         @Override public void stateChanged (ChangeEvent ce) {
  3578:           SpriteScreen.sprSpritesPerRaster = ((DecimalSpinner) ce.getSource ()).getIntValue ();
  3579:         }
  3580:       });
  3581:     ActionListener modificationListener = new ActionListener () {
  3582:       @Override public void actionPerformed (ActionEvent ae) {
  3583:         Object source = ae.getSource ();
  3584:         String command = ae.getActionCommand ();
  3585:         switch (command) {
  3586:           //ドットクロック
  3587:         case "Adjust to host refresh rate":  //ホストのリフレッシュレートに合わせる
  3588:           pnlAdjustVsync = ((JCheckBoxMenuItem) source).isSelected ();
  3589:           if (pnlAdjustVsync && pnlFixedRate == 0.0) {  //必要だが指定がなくて未取得
  3590:             pnlFixedRate = pnlGetRefreshRate ();
  3591:           }
  3592:           CRTC.crtUpdateLength ();
  3593:           break;
  3594:         case "* Reset to default values":  // * 初期値に戻す
  3595:           for (int i = 0; i < 3; i++) {
  3596:             if (CRTC.crtFreqsRequest[i] != CRTC.CRT_DEFAULT_FREQS[i]) {
  3597:               CRTC.crtFreqsRequest[i] = CRTC.CRT_DEFAULT_FREQS[i];
  3598:               freqSpinner[i].setIntValue (CRTC.crtFreqsRequest[i]);
  3599:             }
  3600:           }
  3601:           break;
  3602:         case "1024-dot non-interlaced":  //1024 ドットノンインターレース
  3603:           CRTC.crtEleventhBitRequest = ((JCheckBoxMenuItem) source).isSelected ();
  3604:           break;
  3605:         case "Can write 0 to bit 0 of CRTC R00":  //CRTC R00 のビット 0 に 0 を書き込める
  3606:           CRTC.crtR00Bit0Zero = ((JCheckBoxMenuItem) source).isSelected ();
  3607:           break;
  3608:           //グラフィック画面
  3609:         case "Extended graphic screen":  //拡張グラフィック画面
  3610:           CRTC.crtExtendedGraphicRequest = ((JCheckBoxMenuItem) source).isSelected ();
  3611:           break;
  3612:           //テキスト画面
  3613:         case "Spherical scrolling of text screen":  //テキスト画面の球面スクロール
  3614:           CRTC.crtSetSphericalScrolling (((JCheckBoxMenuItem) source).isSelected ());
  3615:           break;
  3616:           //スプライト画面
  3617:         case "128 sprites":  //128 枚のスプライト
  3618:           SpriteScreen.sprNumberOfSpritesRequest = 128;
  3619:           break;
  3620:         case "256 sprites":  //256 枚のスプライト
  3621:           SpriteScreen.sprNumberOfSpritesRequest = 256;
  3622:           break;
  3623:         case "504 sprites":  //504 枚のスプライト
  3624:           SpriteScreen.sprNumberOfSpritesRequest = 512;
  3625:           break;
  3626:         case "1016 sprites":  //1016 枚のスプライト
  3627:           SpriteScreen.sprNumberOfSpritesRequest = 1024;
  3628:           break;
  3629:           //case "2040 sprites":  //2040 枚のスプライト
  3630:           //  SpriteScreen.sprNumberOfSpritesRequest = 2048;
  3631:           //  break;
  3632:         case "Full pattern memory":  //フルパターンメモリ
  3633:           SpriteScreen.sprFPMRequest = ((JCheckBoxMenuItem) source).isSelected ();
  3634:           break;
  3635:         case "4096 patterns":  //4096 個のパターン
  3636:           SpriteScreen.sprBankOnRequest = ((JCheckBoxMenuItem) source).isSelected ();
  3637:           break;
  3638:         case "Sprites displayed in 768x512":  //768x512 でスプライトを表示
  3639:           SpriteScreen.spr768x512Request = ((JCheckBoxMenuItem) source).isSelected ();
  3640:           break;
  3641:         case "BG1 displayed in 512x512":  //512x512 で BG1 を表示
  3642:           SpriteScreen.spr512bg1Request = ((JCheckBoxMenuItem) source).isSelected ();
  3643:           break;
  3644:         case "Row and column scroll":  //行スクロールと列スクロール
  3645:           if (SpriteScreen.SPR_RC_SCROLL_ON) {
  3646:             SpriteScreen.sprRcScrollRequest = ((JCheckBoxMenuItem) source).isSelected ();
  3647:           }
  3648:           break;
  3649:         case "** Reset to default values":  // ** 初期値に戻す
  3650:           if (SpriteScreen.sprSpritesPerRaster != 32) {
  3651:             SpriteScreen.sprSpritesPerRaster = 32;
  3652:             sprrasSpinner.setIntValue (SpriteScreen.sprSpritesPerRaster);
  3653:           }
  3654:           break;
  3655:         }
  3656:       }
  3657:     };
  3658:     JMenu modificationMenu =
  3659:       Multilingual.mlnText (
  3660:         ComponentFactory.createMenu (
  3661:           "Modification",
  3662:           Multilingual.mlnText (
  3663:             ComponentFactory.createMenu (
  3664:               "Dot clock",
  3665:               Multilingual.mlnText (
  3666:                 ComponentFactory.createCheckBoxMenuItem (pnlAdjustVsync, "Adjust to host refresh rate", modificationListener),
  3667:                 "ja", "ホストのリフレッシュレートに合わせる"),
  3668:               ComponentFactory.createHorizontalBox (
  3669:                 Box.createHorizontalStrut (20),
  3670:                 refreshRateTextField,
  3671:                 ComponentFactory.createLabel (" Hz"),
  3672:                 Box.createHorizontalGlue ()
  3673:                 ),
  3674:               ComponentFactory.createHorizontalSeparator (),
  3675:               ComponentFactory.createHorizontalBox (
  3676:                 Box.createHorizontalStrut (20),
  3677:                 Multilingual.mlnText (ComponentFactory.createLabel ("Dot clock oscillattor"), "ja", "ドットクロックオシレータ"),
  3678:                 Box.createHorizontalGlue ()
  3679:                 ),
  3680:               ComponentFactory.createHorizontalBox (
  3681:                 Box.createHorizontalStrut (20),
  3682:                 freqSpinner[0],
  3683:                 ComponentFactory.createLabel (" Hz *"),
  3684:                 Box.createHorizontalGlue ()
  3685:                 ),
  3686:               ComponentFactory.createHorizontalBox (
  3687:                 Box.createHorizontalStrut (20),
  3688:                 freqSpinner[1],
  3689:                 ComponentFactory.createLabel (" Hz *"),
  3690:                 Box.createHorizontalGlue ()
  3691:                 ),
  3692:               ComponentFactory.createHorizontalBox (
  3693:                 Box.createHorizontalStrut (20),
  3694:                 freqSpinner[2],
  3695:                 ComponentFactory.createLabel (" Hz *"),
  3696:                 Box.createHorizontalGlue ()
  3697:                 ),
  3698:               Multilingual.mlnText (
  3699:                 ComponentFactory.createMenuItem ("* Reset to default values", modificationListener),
  3700:                 "ja", "* 初期値に戻す"),
  3701:               ComponentFactory.createHorizontalSeparator (),
  3702:               Multilingual.mlnText (
  3703:                 ComponentFactory.createCheckBoxMenuItem (CRTC.crtEleventhBitRequest, "1024-dot non-interlaced", modificationListener),
  3704:                 "ja", "1024 ドットノンインターレース"),
  3705:               Multilingual.mlnText (
  3706:                 ComponentFactory.createCheckBoxMenuItem (CRTC.crtR00Bit0Zero, "Can write 0 to bit 0 of CRTC R00", modificationListener),
  3707:                 "ja", "CRTC R00 のビット 0 に 0 を書き込める")
  3708:               ),  //CRTC
  3709:             "ja", "ドットクロック"),
  3710:           Multilingual.mlnText (
  3711:             ComponentFactory.createMenu (
  3712:               "Graphic screen",
  3713:               !CRTC.CRT_EXTENDED_GRAPHIC ? null : Multilingual.mlnText (
  3714:                 ComponentFactory.createCheckBoxMenuItem (CRTC.crtExtendedGraphicRequest, "Extended graphic screen", modificationListener),
  3715:                 "ja", "拡張グラフィック画面")
  3716:               ),  //Graphic screen
  3717:             "ja", "グラフィック画面"),
  3718:           Multilingual.mlnText (
  3719:             ComponentFactory.createMenu (
  3720:               "Text screen",
  3721:               Multilingual.mlnText (
  3722:                 ComponentFactory.createCheckBoxMenuItem (CRTC.crtSphericalScrolling, "Spherical scrolling of text screen", modificationListener),
  3723:                 "ja", "テキスト画面の球面スクロール")
  3724:               ),  //Text screen
  3725:             "ja", "テキスト画面"),
  3726:           Multilingual.mlnText (
  3727:             ComponentFactory.createMenu (
  3728:               "Sprite screen",
  3729:               Multilingual.mlnText (
  3730:                 ComponentFactory.createRadioButtonMenuItem (
  3731:                   spritesGroup, SpriteScreen.sprNumberOfSpritesRequest == 128, "128 sprites", modificationListener),
  3732:                 "ja", "128 枚のスプライト"),
  3733:               Multilingual.mlnText (
  3734:                 ComponentFactory.createRadioButtonMenuItem (
  3735:                   spritesGroup, SpriteScreen.sprNumberOfSpritesRequest == 256, "256 sprites", modificationListener),
  3736:                 "ja", "256 枚のスプライト"),
  3737:               Multilingual.mlnText (
  3738:                 ComponentFactory.createRadioButtonMenuItem (
  3739:                   spritesGroup, SpriteScreen.sprNumberOfSpritesRequest == 512, "504 sprites", modificationListener),
  3740:                 "ja", "504 枚のスプライト"),
  3741:               Multilingual.mlnText (
  3742:                 ComponentFactory.createRadioButtonMenuItem (
  3743:                   spritesGroup, SpriteScreen.sprNumberOfSpritesRequest == 1024, "1016 sprites", modificationListener),
  3744:                 "ja", "1016 枚のスプライト"),
  3745:               //Multilingual.mlnText (
  3746:               //  ComponentFactory.createRadioButtonMenuItem (
  3747:               //    spritesGroup, SpriteScreen.sprNumberOfSpritesRequest == 2048, "2040 sprites", modificationListener),
  3748:               //  "ja", "2040 枚のスプライト"),
  3749:               ComponentFactory.createHorizontalSeparator (),
  3750:               Multilingual.mlnText (
  3751:                 ComponentFactory.createCheckBoxMenuItem (SpriteScreen.sprFPMRequest, "Full pattern memory", modificationListener),
  3752:                 "ja", "フルパターンメモリ"),
  3753:               ComponentFactory.createHorizontalSeparator (),
  3754:               Multilingual.mlnText (
  3755:                 ComponentFactory.createCheckBoxMenuItem (SpriteScreen.sprBankOnRequest, "4096 patterns", modificationListener),
  3756:                 "ja", "4096 個のパターン"),
  3757:               Multilingual.mlnText (
  3758:                 ComponentFactory.createCheckBoxMenuItem (SpriteScreen.spr768x512Request, "Sprites displayed in 768x512", modificationListener),
  3759:                 "ja", "768x512 でスプライトを表示"),
  3760:               Multilingual.mlnText (
  3761:                 ComponentFactory.createCheckBoxMenuItem (SpriteScreen.spr512bg1Request, "BG1 displayed in 512x512", modificationListener),
  3762:                 "ja", "512x512 で BG1 を表示"),
  3763:               !SpriteScreen.SPR_RC_SCROLL_ON ? null : Multilingual.mlnText (
  3764:                 ComponentFactory.createCheckBoxMenuItem (SpriteScreen.sprRcScrollRequest, "Row and column scroll", modificationListener),
  3765:                 "ja", "行スクロールと列スクロール"),
  3766:               ComponentFactory.createHorizontalSeparator (),
  3767:               ComponentFactory.createHorizontalBox (
  3768:                 Box.createHorizontalStrut (20),
  3769:                 Multilingual.mlnText (ComponentFactory.createLabel ("Number of sprites per raster"), "ja", "ラスタあたりのスプライトの枚数"),
  3770:                 Box.createHorizontalGlue ()
  3771:                 ),
  3772:               ComponentFactory.createHorizontalBox (
  3773:                 Box.createHorizontalStrut (20),
  3774:                 sprrasSpinner,
  3775:                 ComponentFactory.createLabel (" **"),
  3776:                 Box.createHorizontalGlue ()
  3777:                 ),
  3778:               Multilingual.mlnText (
  3779:                 ComponentFactory.createMenuItem ("** Reset to default values", modificationListener),
  3780:               "ja", "** 初期値に戻す")
  3781:               ),  //Sprite screen
  3782:             "ja", "スプライト画面")
  3783:           ),  //Modification
  3784:         "ja", "改造");
  3785: 
  3786:     //メニューバー
  3787:     mnbMenuBar = ComponentFactory.createMenuBar (
  3788: 
  3789:       //ファイルメニュー
  3790:       mnbFileMenu = Multilingual.mlnText (
  3791:         ComponentFactory.createMenu (
  3792:           "File", 'F',
  3793:           //FDDメニュー
  3794:           FDC.fdcMenu,
  3795:           //SASI HDDメニュー
  3796:           HDC.hdcMenu,
  3797:           //内蔵 SCSI HDDメニュー
  3798:           SPC.spcMenu,
  3799:           //HFSメニュー
  3800:           HFS.hfsMenu,
  3801:           ComponentFactory.createHorizontalSeparator (),
  3802:           mnbQuitMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Quit", 'Q', MNB_MODIFIERS, listener), "ja", "終了")
  3803:           ),
  3804:         "ja", "ファイル"),
  3805: 
  3806:       //MPUメニュー
  3807:       mpuMenu,
  3808: 
  3809:       //画面メニュー
  3810:       mnbDisplayMenu = Multilingual.mlnText (
  3811:         ComponentFactory.createMenu (
  3812:           "Display", 'D',
  3813:           mnbFullScreenMenuItem,
  3814:           !PNL_ROUNDED_CORNER_ON ? null : ComponentFactory.createHorizontalBox (
  3815:             Box.createHorizontalStrut (20),
  3816:             Multilingual.mlnText (
  3817:               ComponentFactory.createLabel ("Rounded corner ratio "),
  3818:               "ja", "角丸率 "),
  3819:             pnlRoundedCornerSpinner,
  3820:             ComponentFactory.createLabel ("%"),
  3821:             Box.createHorizontalGlue ()
  3822:             ),
  3823:           mnbMaximizedMenuItem,
  3824:           mnbFitInWindowMenuItem,
  3825:           mnbFixedScaleMenuItem,
  3826:           ComponentFactory.createHorizontalBox (
  3827:             Box.createHorizontalStrut (20),
  3828:             pnlFixedSpinner,
  3829:             Multilingual.mlnText (
  3830:               ComponentFactory.createLabel ("% Scale factor"),
  3831:               "ja", "% 倍率"),
  3832:             Box.createHorizontalGlue ()
  3833:             ),
  3834:           ComponentFactory.createMenuItem ("50%", listener),
  3835:           ComponentFactory.createMenuItem ("75%", listener),
  3836:           ComponentFactory.createMenuItem ("100%", listener),
  3837:           ComponentFactory.createMenuItem ("150%", listener),
  3838:           ComponentFactory.createMenuItem ("200%", listener),
  3839:           ComponentFactory.createHorizontalSeparator (),
  3840:           //回転
  3841:           rotationMenu,
  3842:           //アスペクト比
  3843:           aspectMenu,
  3844:           //補間アルゴリズム
  3845:           Multilingual.mlnText (
  3846:             ComponentFactory.createMenu (
  3847:               "Interpolation algorithm",
  3848:               Multilingual.mlnText (
  3849:                 ComponentFactory.createRadioButtonMenuItem (
  3850:                   hintGroup, pnlInterpolation == RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR,
  3851:                   "Nearest neighbor", listener),
  3852:                 "ja", "最近傍補間"),
  3853:               Multilingual.mlnText (
  3854:                 ComponentFactory.createRadioButtonMenuItem (
  3855:                   hintGroup, pnlInterpolation == RenderingHints.VALUE_INTERPOLATION_BILINEAR,
  3856:                   "Bilinear", listener),
  3857:                 "ja", "線形補間"),
  3858:               Multilingual.mlnText (
  3859:                 ComponentFactory.createRadioButtonMenuItem (
  3860:                   hintGroup, pnlInterpolation == RenderingHints.VALUE_INTERPOLATION_BICUBIC,
  3861:                   "Bicubic", listener),
  3862:                 "ja", "三次補間")
  3863:               ),
  3864:             "ja", "補間アルゴリズム"),
  3865:           //走査線エフェクト
  3866:           scanlineMenu,
  3867:           !PNL_USE_CANVAS ? null : Multilingual.mlnText (
  3868:             ComponentFactory.createCheckBoxMenuItem (pnlUseCanvasRequest, "Use canvas", listener),
  3869:             "ja", "キャンバスを使う"),
  3870:           //間欠描画
  3871:           !CRTC.CRT_ENABLE_INTERMITTENT ? null : Multilingual.mlnText (
  3872:             ComponentFactory.createMenu (
  3873:               "Intermittent drawing",
  3874:               Multilingual.mlnText (
  3875:                 ComponentFactory.createRadioButtonMenuItem (
  3876:                   intermittentGroup, CRTC.crtIntermittentInterval == 0, "Draw all changed pictures", listener),
  3877:                 "ja", "変化した画像をすべて描画する"),
  3878:               Multilingual.mlnText (
  3879:                 ComponentFactory.createRadioButtonMenuItem (
  3880:                   intermittentGroup, CRTC.crtIntermittentInterval == 1, "Draw a changed picture once every two times", listener),
  3881:                 "ja", "変化した画像を 2 回に 1 回描画する"),
  3882:               Multilingual.mlnText (
  3883:                 ComponentFactory.createRadioButtonMenuItem (
  3884:                   intermittentGroup, CRTC.crtIntermittentInterval == 2, "Draw a changed picture once every three times", listener),
  3885:                 "ja", "変化した画像を 3 回に 1 回描画する"),
  3886:               Multilingual.mlnText (
  3887:                 ComponentFactory.createRadioButtonMenuItem (
  3888:                   intermittentGroup, CRTC.crtIntermittentInterval == 3, "Draw a changed picture once every four times", listener),
  3889:                 "ja", "変化した画像を 4 回に 1 回描画する"),
  3890:               Multilingual.mlnText (
  3891:                 ComponentFactory.createRadioButtonMenuItem (
  3892:                   intermittentGroup, CRTC.crtIntermittentInterval == 4, "Draw a changed picture once every five times", listener),
  3893:                 "ja", "変化した画像を 5 回に 1 回描画する")
  3894:               ),
  3895:             "ja", "間欠描画"),
  3896:           //立体視
  3897:           !PNL_STEREOSCOPIC_ON ? null : ComponentFactory.createHorizontalSeparator (),
  3898:           mnbStereoscopicMenuItem = !PNL_STEREOSCOPIC_ON ? null : Multilingual.mlnText (
  3899:             ComponentFactory.createCheckBoxMenuItem (pnlStereoscopicOn, "Stereoscopic viewing", 'T', listener),
  3900:             "ja", "立体視"),
  3901:           !PNL_STEREOSCOPIC_ON ? null : Multilingual.mlnText (
  3902:             ComponentFactory.createMenu (
  3903:               "Stereoscopic settings",
  3904:               !PNL_STEREOSCOPIC_ON ? null : Multilingual.mlnText (
  3905:                 ComponentFactory.createRadioButtonMenuItem (sterescopicGroup,
  3906:                                                             pnlStereoscopicMethod == PNL_NAKED_EYE_CROSSING,
  3907:                                                             "Naked-eye crossing", listener),
  3908:                 "ja", "裸眼交差法"),
  3909:               !PNL_STEREOSCOPIC_ON ? null : Multilingual.mlnText (
  3910:                 ComponentFactory.createRadioButtonMenuItem (sterescopicGroup,
  3911:                                                             pnlStereoscopicMethod == PNL_NAKED_EYE_PARALLEL,
  3912:                                                             "Naked-eye parallel", listener),
  3913:                 "ja", "裸眼平行法"),
  3914:               !PNL_STEREOSCOPIC_ON ? null : Multilingual.mlnText (
  3915:                 ComponentFactory.createRadioButtonMenuItem (sterescopicGroup,
  3916:                                                             pnlStereoscopicMethod == PNL_SIDE_BY_SIDE,
  3917:                                                             "Side-by-side", listener),
  3918:                 "ja", "サイドバイサイド"),
  3919:               !PNL_STEREOSCOPIC_ON ? null : Multilingual.mlnText (
  3920:                 ComponentFactory.createRadioButtonMenuItem (sterescopicGroup,
  3921:                                                             pnlStereoscopicMethod == PNL_TOP_AND_BOTTOM,
  3922:                                                             "Top-and-bottom", listener),
  3923:                 "ja", "トップアンドボトム")
  3924:               ),
  3925:             "ja", "立体視設定"),
  3926:           //GIFアニメーション
  3927:           ComponentFactory.createHorizontalSeparator (),
  3928:           GIFAnimation.gifStartRecordingMenuItem,
  3929:           GIFAnimation.gifSettingsMenu,
  3930:           //改造
  3931:           ComponentFactory.createHorizontalSeparator (),
  3932:           modificationMenu,
  3933:           //
  3934:           SpritePatternViewer.SPV_ON ? Multilingual.mlnText (ComponentFactory.createMenuItem ("Sprite pattern viewer", listener), "ja", "スプライトパターンビュア") : null,
  3935:           PaletteViewer.PLV_ON ? Multilingual.mlnText (ComponentFactory.createMenuItem ("Palette viewer", listener), "ja", "パレットビュア") : null,
  3936:           ScreenModeTest.SMT_ON ? Multilingual.mlnText (ComponentFactory.createMenuItem ("Screen mode test", listener), "ja", "表示モードテスト") : null
  3937:           ),
  3938:         "ja", "画面"),
  3939: 
  3940:       //音声メニュー
  3941:       mnbSoundMenu = ComponentFactory.setEnabled (
  3942:         Multilingual.mlnText (
  3943:           ComponentFactory.createMenu (
  3944:             "Sound", 'S',
  3945:             mnbPlayMenuItem = ComponentFactory.setEnabled (
  3946:               Multilingual.mlnText (ComponentFactory.createCheckBoxMenuItem (SoundSource.sndPlayOn, "Play", 'P', MNB_MODIFIERS, listener), "ja", "音声出力"),
  3947:               SoundSource.sndLine != null),
  3948:             //ボリュームのラベル
  3949:             //  JLabelのalignmentでセンタリングしようとするとチェックボックスのサイズの分だけ右に寄ってしまう
  3950:             //  Boxで囲み、左右にglueを置くことでセンタリングする
  3951:             ComponentFactory.createHorizontalBox (
  3952:               Box.createHorizontalGlue (),
  3953:               Multilingual.mlnText (ComponentFactory.createLabel ("Volume "), "ja", "音量 "),
  3954:               mnbVolumeLabel = ComponentFactory.createLabel (String.valueOf (SoundSource.sndVolume)),
  3955:               Box.createHorizontalGlue ()
  3956:               ),
  3957:             //ボリュームスライダ
  3958:             //  デフォルトのサイズだと間延びした感じになるので幅を狭くする
  3959:             ComponentFactory.setPreferredSize (
  3960:               ComponentFactory.createHorizontalSlider (
  3961:                 0,
  3962:                 SoundSource.SND_VOLUME_MAX,
  3963:                 SoundSource.sndVolume,
  3964:                 SoundSource.SND_VOLUME_STEP,
  3965:                 1,
  3966:                 new ChangeListener () {
  3967:                   @Override public void stateChanged (ChangeEvent ce) {
  3968:                     SoundSource.sndSetVolume (((JSlider) ce.getSource ()).getValue ());
  3969:                   }
  3970:                 }),
  3971:               LnF.lnfFontSize * 18, LnF.lnfFontSize * 2 + 28),
  3972:             Multilingual.mlnText (
  3973:               ComponentFactory.createMenu (
  3974:                 "Sound interpolation",
  3975:                 Multilingual.mlnText (
  3976:                   ComponentFactory.createRadioButtonMenuItem (
  3977:                     soundInterpolationGroup, SoundSource.sndRateConverter == SoundSource.SNDRateConverter.THINNING_STEREO,
  3978:                     "Sound thinning", listener),
  3979:                   "ja", "音声 間引き"),
  3980:                 Multilingual.mlnText (
  3981:                   ComponentFactory.createRadioButtonMenuItem (
  3982:                     soundInterpolationGroup, SoundSource.sndRateConverter == SoundSource.SNDRateConverter.LINEAR_STEREO,
  3983:                     "Sound linear interpolation", listener),
  3984:                   "ja", "音声 線形補間"),
  3985:                 ComponentFactory.setEnabled (
  3986:                   Multilingual.mlnText (
  3987:                     ComponentFactory.createRadioButtonMenuItem (
  3988:                       soundInterpolationGroup, SoundSource.sndRateConverter == SoundSource.SNDRateConverter.CONSTANT_AREA_STEREO_48000,
  3989:                       "Sound piecewise-constant area interpolation", listener),
  3990:                     "ja", "音声 区分定数面積補間"),
  3991:                   SoundSource.SND_CHANNELS == 2 && SoundSource.SND_SAMPLE_FREQ == 48000),
  3992:                 ComponentFactory.setEnabled (
  3993:                   Multilingual.mlnText (
  3994:                     ComponentFactory.createRadioButtonMenuItem (
  3995:                       soundInterpolationGroup, SoundSource.sndRateConverter == SoundSource.SNDRateConverter.LINEAR_AREA_STEREO_48000,
  3996:                       "Sound linear area interpolation", listener),
  3997:                     "ja", "音声 線形面積補間"),
  3998:                   SoundSource.SND_CHANNELS == 2 && SoundSource.SND_SAMPLE_FREQ == 48000)
  3999:                 ),
  4000:               "ja", "音声補間"),
  4001:             Multilingual.mlnText (ComponentFactory.createMenuItem ("Sound monitor", listener), "ja", "音声モニタ"),
  4002:             //
  4003:             ComponentFactory.createHorizontalSeparator (),
  4004:             //
  4005:             ComponentFactory.setEnabled (
  4006:               Multilingual.mlnText (ComponentFactory.createCheckBoxMenuItem (OPM.opmOutputMask != 0, "OPM output", listener), "ja", "OPM 出力"),
  4007:               SoundSource.sndLine != null),
  4008:             !OPMLog.OLG_ON ? null : Multilingual.mlnText (ComponentFactory.createMenuItem ("OPM log", listener), "ja", "OPM ログ"),
  4009:             //
  4010:             ComponentFactory.createHorizontalSeparator (),
  4011:             //
  4012:             ComponentFactory.setEnabled (
  4013:               Multilingual.mlnText (ComponentFactory.createCheckBoxMenuItem (ADPCM.pcmOutputOn, "PCM output", listener), "ja", "PCM 出力"),
  4014:               SoundSource.sndLine != null),
  4015:             Multilingual.mlnText (
  4016:               ComponentFactory.createMenu (
  4017:                 "PCM interpolation",
  4018:                 Multilingual.mlnText (
  4019:                   ComponentFactory.createRadioButtonMenuItem (
  4020:                     adpcmInterpolationGroup, ADPCM.pcmInterpolationAlgorithm == ADPCM.PCM_INTERPOLATION_CONSTANT,
  4021:                     "PCM piecewise-constant interpolation", listener),
  4022:                   "ja", "PCM 区分定数補間"),
  4023:                 Multilingual.mlnText (
  4024:                   ComponentFactory.createRadioButtonMenuItem (
  4025:                     adpcmInterpolationGroup, ADPCM.pcmInterpolationAlgorithm == ADPCM.PCM_INTERPOLATION_LINEAR,
  4026:                     "PCM linear interpolation", listener),
  4027:                   "ja", "PCM 線形補間"),
  4028:                 Multilingual.mlnText (
  4029:                   ComponentFactory.createRadioButtonMenuItem (
  4030:                     adpcmInterpolationGroup, ADPCM.pcmInterpolationAlgorithm == ADPCM.PCM_INTERPOLATION_HERMITE,
  4031:                     "PCM hermite interpolation", listener),
  4032:                   "ja", "PCM エルミート補間")
  4033:                 ),
  4034:               "ja", "PCM 補間"),
  4035:             Multilingual.mlnText (
  4036:               ComponentFactory.createMenu (
  4037:                 "PCM source oscillator frequency",
  4038:                 ComponentFactory.createRadioButtonMenuItem (adpcmOSCFreqGroup, ADPCM.pcmOSCFreqRequest == 0, "PCM 8MHz/4MHz", listener),
  4039:                 ComponentFactory.createRadioButtonMenuItem (adpcmOSCFreqGroup, ADPCM.pcmOSCFreqRequest == 1, "PCM 8MHz/16MHz", listener)
  4040:                 ),
  4041:               "ja", "PCM 原発振周波数"),
  4042:             //
  4043:             !MercuryUnit.MU4_ON ? null :
  4044:             ComponentFactory.createHorizontalSeparator (),
  4045:             !MercuryUnit.MU4_ON ? null :
  4046:             ComponentFactory.createCheckBoxMenuItem (
  4047:               MercuryUnit.mu4OnRequest,
  4048:               "Mercury-Unit V4 (MK-MU1)",
  4049:               listener),
  4050:             !MercuryUnit.MU4_ON ? null :
  4051:             Multilingual.mlnText (
  4052:               ComponentFactory.createCheckBoxMenuItem (
  4053:                 MercuryUnit.mu4OutputEnable,
  4054:                 "MU4 output",
  4055:                 listener),
  4056:               "ja", "MU4 出力"),
  4057:             ComponentFactory.createHorizontalSeparator (),
  4058:             SRAM.smrStupsndMenu
  4059:             ),
  4060:           "ja", "音声"),
  4061:         SoundSource.sndLine != null),
  4062: 
  4063:       //入力メニュー
  4064:       mnbInputMenu = Multilingual.mlnText (
  4065:         ComponentFactory.createMenu (
  4066:           "Input", 'I',
  4067:           mnbPasteMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Paste", 'V', MNB_MODIFIERS, listener), "ja", "貼り付け"),
  4068:           CONDevice.conSettingsMenu,
  4069:           TextCopy.txcMakeMenuItem (),
  4070:           TextCopy.txcMakeSettingMenu (),
  4071:           ComponentFactory.createHorizontalSeparator (),
  4072:           mnbNoKeyboardMenuItem = Multilingual.mlnText (
  4073:             ComponentFactory.createRadioButtonMenuItem (keyboardGroup, !Keyboard.kbdOn, "No keyboard", 'K', MNB_MODIFIERS, listener),
  4074:             "ja", "キーボードなし"),
  4075:           mnbStandardKeyboardMenuItem = Multilingual.mlnText (
  4076:             ComponentFactory.createRadioButtonMenuItem (keyboardGroup, Keyboard.kbdOn && Keyboard.kbdType == Keyboard.KBD_STANDARD_TYPE, "Standard keyboard", listener),
  4077:             "ja", "標準キーボード"),
  4078:           mnbCompactKeyboardMenuItem = Multilingual.mlnText (
  4079:             ComponentFactory.createRadioButtonMenuItem (keyboardGroup, Keyboard.kbdOn && Keyboard.kbdType == Keyboard.KBD_COMPACT_TYPE, "Compact keyboard", listener),
  4080:             "ja", "コンパクトキーボード"),
  4081:           Multilingual.mlnText (
  4082:             ComponentFactory.createCheckBoxMenuItem (pnlHideKeyboard, "Hide keyboard in full screen", listener),
  4083:           "ja", "全画面表示のときキーボードを隠す"),
  4084:           Multilingual.mlnText (ComponentFactory.createMenuItem ("Key assignments", listener), "ja", "キー割り当て"),
  4085:           ButtonFunction.bfnMakeMenuItem (),
  4086:           SRAM.smrRepeatDelayMenu,
  4087:           SRAM.smrRepeatIntervalMenu,
  4088:           !Keyboard.KBD_ZKEY_ON ? null : Keyboard.kbdZKeyMenu,
  4089:           ComponentFactory.createHorizontalSeparator (),
  4090:           Mouse.musSeamlessMouseCheckBox,
  4091:           Mouse.musFollowScrollCheckBox,
  4092:           Mouse.musCtrlRightCheckBox,
  4093:           Mouse.musEdgeAccelerationCheckBox,
  4094:           Mouse.musMouseCursorSpeedBox,
  4095:           Mouse.musSpeedSlider,
  4096:           Mouse.musHostsPixelUnitsCheckBox,
  4097:           ComponentFactory.createHorizontalSeparator (),
  4098:           Multilingual.mlnText (ComponentFactory.createMenuItem ("Joystick port settings", listener), "ja", "ジョイスティックポート設定")
  4099:           ),
  4100:         "ja", "入力"),
  4101: 
  4102:       //設定メニュー
  4103:       mnbConfigMenu = Multilingual.mlnText (
  4104:         ComponentFactory.createMenu (
  4105:           "Config", 'G',
  4106:           Multilingual.mlnText (ComponentFactory.createMenuItem ("RS-232C and terminal", listener), "ja", "RS-232C とターミナル"),
  4107:           Multilingual.mlnText (
  4108:             ComponentFactory.createMenu (
  4109:               "Debug",
  4110:               Multilingual.mlnText (ComponentFactory.createMenuItem ("Console", listener), "ja", "コンソール"),
  4111:               Multilingual.mlnText (ComponentFactory.createMenuItem ("Register list", listener), "ja", "レジスタリスト"),
  4112:               Multilingual.mlnText (ComponentFactory.createMenuItem ("Disassemble list", listener), "ja", "逆アセンブルリスト"),
  4113:               Multilingual.mlnText (ComponentFactory.createMenuItem ("Memory dump list", listener), "ja", "メモリダンプリスト"),
  4114:               Multilingual.mlnText (ComponentFactory.createMenuItem ("Logical space monitor", listener), "ja", "論理空間モニタ"),
  4115:               Multilingual.mlnText (ComponentFactory.createMenuItem ("Physical space monitor", listener), "ja", "物理空間モニタ"),
  4116:               ATCMonitor.ACM_ON ? Multilingual.mlnText (ComponentFactory.createMenuItem ("Address translation caches monitor", listener), "ja", "アドレス変換キャッシュモニタ") : null,
  4117:               BranchLog.BLG_ON ? Multilingual.mlnText (ComponentFactory.createMenuItem ("Branch log", listener), "ja", "分岐ログ") : null,
  4118:               ProgramFlowVisualizer.PFV_ON ? Multilingual.mlnText (ComponentFactory.createMenuItem ("Program flow visualizer", listener), "ja", "プログラムフロービジュアライザ") : null,
  4119:               RasterBreakPoint.RBP_ON ? Multilingual.mlnText (ComponentFactory.createMenuItem ("Raster break point", listener), "ja", "ラスタブレークポイント") : null,
  4120:               DataBreakPoint.DBP_ON ? Multilingual.mlnText (ComponentFactory.createMenuItem ("Data break point", listener), "ja", "データブレークポイント") : null,
  4121:               RootPointerList.RTL_ON ? Multilingual.mlnText (ComponentFactory.createMenuItem ("Root pointer list", listener), "ja", "ルートポインタリスト") : null,
  4122:               ComponentFactory.createHorizontalSeparator (),
  4123:               SRAM.smrRomdbMenu
  4124:               ),
  4125:             "ja", "デバッグ"),
  4126:           SRAM.smrBootMenu,
  4127:           mainMemoryMenu,
  4128:           highMemoryMenu,
  4129:           localMemoryMenu,
  4130:           xellent30Menu,
  4131:           ComponentFactory.createHorizontalSeparator (),
  4132:           ComponentFactory.createMenu (
  4133:             "RTC",
  4134:             Multilingual.mlnText (
  4135:               ComponentFactory.createMenuItem ("Adjust clock to host", listener),
  4136:               "ja", "時計をホストに合わせる")
  4137:             ),
  4138:           Z8530.sccMakeMenu (),
  4139:           SRAM.smrMenu,
  4140:           Settings.sgsMenu,
  4141:           ComponentFactory.createHorizontalSeparator (),
  4142:           Multilingual.mlnText (ComponentFactory.createMenuItem ("Printer", listener), "ja", "プリンタ"),
  4143:           ROM.romMenu,
  4144:           Multilingual.mlnText (
  4145:             ComponentFactory.createMenu (
  4146:               "Miscellaneous",
  4147:               SlowdownTest.sdtCheckBoxMenuItem,
  4148:               SlowdownTest.sdtBox,
  4149:               Multilingual.mlnText (
  4150:                 ComponentFactory.createCheckBoxMenuItem (Mouse.musOutputButtonStatus, "Print key and mouse button events", listener),
  4151:                 "ja", "キーとマウスのボタンのイベントを表示")
  4152:               ),
  4153:             "ja", "その他"),
  4154:           ComponentFactory.createHorizontalSeparator (),
  4155:           Multilingual.mlnText (
  4156:             ComponentFactory.createMenu (
  4157:               "Accessibility",
  4158:               //点滅光の軽減
  4159:               !FlashingLights.FLR_ON ? null :
  4160:               FlashingLights.flrMakeMenu (),
  4161:               !FlashingLights.FLR_ON ? null :
  4162:               ComponentFactory.createHorizontalSeparator (),
  4163:               //フォントサイズ
  4164:               mnbMakeFontSizeMenu (),
  4165:               //色
  4166:               mnbMakeColorMenu ()
  4167:               ),
  4168:             "ja", "アクセシビリティ"),
  4169:           ComponentFactory.createHorizontalSeparator (),
  4170:           Multilingual.mlnText (
  4171:             ComponentFactory.createMenuItem ("Java runtime environment information", listener),
  4172:             "ja", "Java 実行環境の情報"),
  4173:           Multilingual.mlnText (
  4174:             ComponentFactory.createMenuItem ("Version information", listener),
  4175:             "ja", "バージョン情報"),
  4176:           Multilingual.mlnText (
  4177:             ComponentFactory.createMenu (
  4178:               "License",
  4179:               Multilingual.mlnText (ComponentFactory.createMenuItem ("XEiJ License", listener), "ja", "XEiJ 使用許諾条件"),
  4180:               Multilingual.mlnText (ComponentFactory.createMenuItem ("FSHARP License", listener), "ja", "FSHARP 許諾条件"),
  4181:               Multilingual.mlnText (ComponentFactory.createMenuItem ("ymfm License", listener), "ja", "ymfm License"),
  4182:               Multilingual.mlnText (ComponentFactory.createMenuItem ("jSerialComm License", listener), "ja", "jSerialComm License")
  4183:               ),
  4184:             "ja", "使用許諾条件")
  4185:           ),
  4186:         "ja", "設定"),
  4187: 
  4188:       mnbMakeLanguageMenu (),  //言語メニュー
  4189: 
  4190:       //インジケータ
  4191:       Box.createHorizontalGlue (),  //インジケータをセンタリングする
  4192:       ComponentFactory.createVerticalBox (
  4193:         Box.createVerticalGlue (),
  4194:         Indicator.indBox,
  4195:         Box.createVerticalGlue ()
  4196:         ),
  4197:       Box.createHorizontalGlue ()
  4198: 
  4199:       );
  4200:   }  //mnbMakeMenu()
  4201: 
  4202: 
  4203: 
  4204:   //========================================================================================
  4205:   //$$FRM フレーム
  4206: 
  4207:   //モード
  4208:   public static boolean frmIsActive;  //true=フォーカスがある
  4209: 
  4210:   //フレーム
  4211:   public static JFrame frmFrame;  //フレーム
  4212:   public static int frmMarginWidth;  //パネルからフレームまでのマージン
  4213:   public static int frmMarginHeight;
  4214:   public static Dimension frmMinimumSize;  //pnlMinimumWidth+frmMarginWidth,pnlMinimumHeight+frmMarginHeight フレームの最小サイズ
  4215: 
  4216:   //スクリーンデバイス
  4217:   public static GraphicsDevice frmScreenDevice;  //スクリーンデバイス
  4218: 
  4219:   //ドラッグアンドドロップ
  4220:   public static DropTarget frmDropTarget;
  4221: 
  4222:   //frmInit ()
  4223:   //  フレームを初期化する
  4224:   public static void frmInit () {
  4225:     frmIsActive = false;
  4226:     frmScreenDevice = GraphicsEnvironment.getLocalGraphicsEnvironment ().getDefaultScreenDevice ();  //スクリーンデバイス
  4227:     pnlIsFullScreenSupported = frmScreenDevice.isFullScreenSupported ();  //全画面表示に移行できるかどうか
  4228:   }  //frmInit()
  4229: 
  4230:   //frmMake ()
  4231:   //  フレームを作る
  4232:   public static void frmMake () {
  4233: 
  4234:     //フレーム
  4235:     frmFrame = ComponentFactory.createRestorableFrame (
  4236:       Settings.SGS_FRM_FRAME_KEY,
  4237:       PRG_TITLE + " version " + PRG_VERSION,
  4238:       mnbMenuBar,
  4239:       pnlPanel);
  4240:     frmUpdateTitle ();
  4241:     frmFrame.setIconImage (LnF.LNF_ICON_IMAGE_48);  //タスクバーのアイコンを変更する
  4242:     frmFrame.setDefaultCloseOperation (WindowConstants.DISPOSE_ON_CLOSE);
  4243:     //frmFrame.setResizable (false);  //リサイズ不可
  4244: 
  4245:     //パネルからフレームまでのマージンを確認する
  4246:     //!!! 最大化された状態で起動したときこの時点でfrmFrameとpnlPanelのサイズが合っていないためfrmMinimumSizeが不適切な値になる
  4247:     frmMarginWidth = frmFrame.getWidth () - pnlPanel.getWidth ();
  4248:     frmMarginHeight = frmFrame.getHeight () - pnlPanel.getHeight ();
  4249:     frmMinimumSize = new Dimension (pnlMinimumWidth + frmMarginWidth, pnlMinimumHeight + frmMarginHeight);
  4250:     frmFrame.setMinimumSize (frmMinimumSize);
  4251: 
  4252:     //ドラッグアンドドロップ
  4253:     //  FDイメージが放り込まれたらそこから再起動する
  4254:     frmDropTarget = new DropTarget (pnlPanel, DnDConstants.ACTION_COPY, new DropTargetAdapter () {
  4255:       @Override public void dragOver (DropTargetDragEvent dtde) {
  4256:         if (dtde.isDataFlavorSupported (DataFlavor.javaFileListFlavor)) {
  4257:           dtde.acceptDrag (DnDConstants.ACTION_COPY);
  4258:           return;
  4259:         }
  4260:         dtde.rejectDrag ();
  4261:       }
  4262:       @Override public void drop (DropTargetDropEvent dtde) {
  4263:         try {
  4264:           if (dtde.isDataFlavorSupported (DataFlavor.javaFileListFlavor)) {
  4265:             dtde.acceptDrop (DnDConstants.ACTION_COPY);
  4266:             boolean reset = false;  //true=ここから再起動,false=開く
  4267:             int fdu0 = -1;
  4268:             int fdu = 0;
  4269:             int hdu0 = -1;
  4270:             int hdu = 0;
  4271:             int scu0 = -1;
  4272:             int scu = 0;
  4273:             int hfu0 = -1;
  4274:             int hfu = 0;
  4275:             for (Object o : (java.util.List) dtde.getTransferable ().getTransferData (DataFlavor.javaFileListFlavor)) {
  4276:               if (o instanceof File) {
  4277:                 File file = (File) o;
  4278:                 if (file.isFile ()) {  //ファイルのとき。HFS以外のフィルタがディレクトリを受け入れてしまうのでディレクトリを除外する
  4279:                   if (FDC.fdcFileFilter.accept (file)) {  //FDのイメージファイルのとき
  4280:                     if (fdu < FDC.FDC_MAX_UNITS &&
  4281:                         FDC.fdcUnitArray[fdu].insert (file.getPath (), false)) {  //挿入できた
  4282:                       if (fdu0 < 0) {
  4283:                         fdu0 = fdu;
  4284:                       }
  4285:                       fdu++;
  4286:                       continue;
  4287:                     }
  4288:                   }
  4289:                   if (HDC.hdcFileFilter.accept (file)) {  //SASIハードディスクのイメージファイルのとき
  4290:                     if (hdu < 16 &&
  4291:                         HDC.hdcUnitArray[hdu].insert (file.getPath (), false)) {  //挿入できた
  4292:                       if (hdu0 < 0) {
  4293:                         hdu0 = hdu;
  4294:                       }
  4295:                       hdu++;
  4296:                       continue;
  4297:                     }
  4298:                   }
  4299:                   if (SPC.spcFileFilter.accept (file)) {  //SCSIハードディスク/CD-ROMのイメージファイルのとき
  4300:                     if (scu < 16 &&
  4301:                         SPC.spcUnitArray[scu].insert (file.getPath (), false)) {  //挿入できた
  4302:                       if (scu0 < 0) {
  4303:                         scu0 = scu;
  4304:                       }
  4305:                       scu++;
  4306:                       continue;
  4307:                     }
  4308:                   }
  4309:                 }
  4310:                 if (HFS.hfsFileFilter.accept (file)) {  //ディレクトリまたはHUMAN.SYSのとき
  4311:                   if (hfu < HFS.HFS_MAX_UNITS &&
  4312:                       HFS.hfsUnitArray[hfu].insert (file.getPath (), false)) {  //挿入できた
  4313:                     if (hfu0 < 0) {
  4314:                       hfu0 = hfu;
  4315:                     }
  4316:                     hfu++;
  4317:                     continue;
  4318:                   }
  4319:                 }
  4320:               }
  4321:               reset = false;  //挿入できないファイルがあったときはリセットをキャンセルする
  4322:             }
  4323:             dtde.dropComplete (true);
  4324:             if (reset) {
  4325:               if (fdu0 >= 0) {
  4326:                 mpuReset (0x9070 | fdu0 << 8, -1);
  4327:               } else if (hdu0 >= 0) {
  4328:                 mpuReset (0x8000 | hdu0 << 8, -1);
  4329:               } else if (scu0 >= 0) {
  4330:                 mpuReset (0xa000, SPC.SPC_HANDLE_EX + (scu0 << 2));  //拡張SCSIがなければ内蔵SCSIに読み替えられる
  4331:               } else if (hfu0 >= 0) {
  4332:                 HFS.hfsBootUnit = hfu0;
  4333:                 mpuReset (0xa000, HFS.HFS_BOOT_HANDLE);
  4334:               }
  4335:             }
  4336:             return;
  4337:           }
  4338:         } catch (UnsupportedFlavorException ufe) {
  4339:           //ufe.printStackTrace ();
  4340:         } catch (IOException ioe) {
  4341:           //ioe.printStackTrace ();
  4342:         }
  4343:         dtde.rejectDrop();
  4344:       }
  4345:     });
  4346: 
  4347:   }  //frmMake()
  4348: 
  4349:   //frmUpdateTitle ()
  4350:   //  フレームのタイトルを更新する
  4351:   public static void frmUpdateTitle () {
  4352:     frmFrame.setTitle ((currentAccelerator == ACCELERATOR_HYBRID ? "X68000 Hybrid" :
  4353:                         currentModel.getName () +
  4354:                         (currentAccelerator == ACCELERATOR_XELLENT30 ? " with Xellent30" :
  4355:                          currentAccelerator == ACCELERATOR_060TURBO ? " with 060turbo" :
  4356:                          currentAccelerator == ACCELERATOR_060TURBOPRO ? " with 060turboPRO" : "")) +
  4357:                        " - " + PRG_TITLE + " version " + PRG_VERSION);
  4358:   }
  4359: 
  4360:   //frmStart ()
  4361:   //  フレームのイベントリスナーを設定して動作を開始する
  4362:   public static void frmStart () {
  4363: 
  4364:     //ウインドウリスナー
  4365:     //  ウインドウを開いたとき  activated,opened
  4366:     //  フォーカスを失ったとき  deactivated
  4367:     //  フォーカスを取得したとき  activated
  4368:     //  ウインドウをアイコン化したとき  iconified,[deactivated]
  4369:     //  ウインドウを元のサイズに戻したとき  deiconified,activated
  4370:     //  ウインドウを閉じたとき  closing,[deactivated],closed
  4371:     ComponentFactory.addListener (
  4372:       frmFrame,
  4373:       new WindowAdapter () {
  4374:         @Override public void windowActivated (WindowEvent we) {
  4375:           frmIsActive = true;
  4376:         }
  4377:         @Override public void windowClosing (WindowEvent we) {
  4378:           prgTini ();
  4379:         }
  4380:         @Override public void windowDeactivated (WindowEvent we) {
  4381:           frmIsActive = false;
  4382:           //Mouse.musSetSeamlessOn (true);  //フォーカスを失ったときはシームレスに切り替える
  4383:         }
  4384:         @Override public void windowOpened (WindowEvent we) {
  4385:           if (pnlAdjustVsync && pnlFixedRate == 0.0) {  //必要だが指定がなくて未取得
  4386:             pnlFixedRate = pnlGetRefreshRate ();
  4387:           }
  4388:         }
  4389:       });
  4390: 
  4391:     //コンポーネントリスナー
  4392:     //  エクスクルーシブマウスモードのときに使うパネルの座標を得る
  4393:     //  全画面表示のON/OFFを行ったときcomponentMovedが呼ばれないことがあるのでcomponentResizedでもパネルの座標を得る
  4394:     ComponentFactory.addListener (
  4395:       frmFrame,
  4396:       new ComponentAdapter () {
  4397:         @Override public void componentMoved (ComponentEvent ce) {
  4398:           Point p = pnlPanel.getLocationOnScreen ();
  4399:           pnlGlobalX = p.x;
  4400:           pnlGlobalY = p.y;
  4401:         }
  4402:         @Override public void componentResized (ComponentEvent ce) {
  4403:           Point p = pnlPanel.getLocationOnScreen ();
  4404:           pnlGlobalX = p.x;
  4405:           pnlGlobalY = p.y;
  4406:         }
  4407:       });
  4408: 
  4409:   }  //frmStart()
  4410: 
  4411: 
  4412: 
  4413:   //========================================================================================
  4414:   //$$CLP クリップボード
  4415: 
  4416:   public static BufferedImage clpClipboardImage;  //コピーされるイメージ
  4417:   public static String clpClipboardString;  //コピーされる文字列
  4418:   public static Clipboard clpClipboard;  //クリップボード
  4419:   public static Transferable clpImageContents;  //イメージをコピーするときに渡すデータ
  4420:   public static Transferable clpStringContents;  //文字列をコピーするときに渡すデータ
  4421:   public static ClipboardOwner clpClipboardOwner;  //クリップボードオーナー。コピーするときにデータに付ける情報
  4422:   public static boolean clpIsClipboardOwner;  //true=クリップボードに入っているデータは自分がコピーした
  4423: 
  4424:   //clpMake ()
  4425:   //  クリップボードを作る
  4426:   //  mnbMake()より前に呼び出すこと
  4427:   public static void clpMake () {
  4428:     Toolkit toolkit = Toolkit.getDefaultToolkit ();
  4429:     clpClipboard = null;
  4430:     try {
  4431:       clpClipboard = toolkit.getSystemClipboard ();  //クリップボード
  4432:     } catch (Exception e) {
  4433:       return;
  4434:     }
  4435:     clpClipboardImage = null;  //コピーされるイメージ
  4436:     clpClipboardString = null;  //コピーされる文字列
  4437:     clpImageContents = new Transferable () {
  4438:       public Object getTransferData (DataFlavor flavor) throws UnsupportedFlavorException {
  4439:         if (flavor == DataFlavor.imageFlavor) {
  4440:           return clpClipboardImage;
  4441:         } else {
  4442:           throw new UnsupportedFlavorException (flavor);
  4443:         }
  4444:       }
  4445:       public DataFlavor[] getTransferDataFlavors () {
  4446:         return new DataFlavor[] { DataFlavor.imageFlavor };
  4447:       }
  4448:       public boolean isDataFlavorSupported (DataFlavor flavor) {
  4449:         return flavor == DataFlavor.imageFlavor;
  4450:       }
  4451:     };
  4452:     clpStringContents = new Transferable () {
  4453:       public Object getTransferData (DataFlavor flavor) throws UnsupportedFlavorException {
  4454:         if (flavor == DataFlavor.stringFlavor) {
  4455:           return clpClipboardString;
  4456:         } else {
  4457:           throw new UnsupportedFlavorException (flavor);
  4458:         }
  4459:       }
  4460:       public DataFlavor[] getTransferDataFlavors () {
  4461:         return new DataFlavor[] { DataFlavor.stringFlavor };
  4462:       }
  4463:       public boolean isDataFlavorSupported (DataFlavor flavor) {
  4464:         return flavor == DataFlavor.stringFlavor;
  4465:       }
  4466:     };
  4467:     clpIsClipboardOwner = false;  //自分はまだコピーしていない
  4468:     //クリップボードオーナー
  4469:     //  lostOwnership   クリップボードの所有者でなくなったとき
  4470:     clpClipboardOwner = new ClipboardOwner () {
  4471:       @Override public void lostOwnership (Clipboard clipboard, Transferable contents) {
  4472:         clpIsClipboardOwner = false;
  4473:       }
  4474:     };
  4475:     //フレーバーリスナー
  4476:     //  flavorsChanged  クリップボードのDataFlavorが変化したとき
  4477:     clpClipboard.addFlavorListener (new FlavorListener () {
  4478:       @Override public void flavorsChanged (FlavorEvent fe) {
  4479:         boolean available = false;
  4480:         try {
  4481:           available = clpClipboard.isDataFlavorAvailable (DataFlavor.stringFlavor);
  4482:         } catch (IllegalStateException ise) {
  4483:         }
  4484:         if (mnbPasteMenuItem != null) {
  4485:           mnbPasteMenuItem.setEnabled (available);  //文字列ならば貼り付けできる
  4486:         }
  4487:       }
  4488:     });
  4489:     if (!clpClipboard.isDataFlavorAvailable (DataFlavor.stringFlavor)) {  //文字列がコピーされていない
  4490:       if (mnbPasteMenuItem != null) {
  4491:         mnbPasteMenuItem.setEnabled (false);  //貼り付け選択不可
  4492:       }
  4493:     }
  4494:   }  //clpMake
  4495: 
  4496:   //clpCopy (s)
  4497:   //  クリップボードに文字列をコピーする
  4498:   public static void clpCopy (String s) {
  4499:     if (clpClipboard != null && s != null) {
  4500:       clpClipboardString = s;
  4501:       try {
  4502:         clpClipboard.setContents (clpStringContents, clpClipboardOwner);
  4503:         clpIsClipboardOwner = true;  //自分がコピーした
  4504:       } catch (Exception e) {
  4505:         return;
  4506:       }
  4507:     }
  4508:   }  //clpCopy
  4509: 
  4510: 
  4511: 
  4512:   //========================================================================================
  4513:   //$$XT3 Xellent30
  4514:   //
  4515:   //  DIPSW
  4516:   //        1    2     ポートのアドレス
  4517:   //    0  OFF  OFF  $00EC0000~$00EC3FFF
  4518:   //    1  OFF  ON   $00EC4000~$00EC7FFF
  4519:   //    2  ON   OFF  $00EC8000~$00ECBFFF
  4520:   //    3  ON   ON   $00ECC000~$00ECFFFF
  4521:   //
  4522:   //  ポート
  4523:   //    FEDCBA9876543210
  4524:   //                 |||
  4525:   //                 ||bit0:メモリの位置。0=$00Bxxxxx,1=$00Fxxxxx
  4526:   //                 |bit1:メモリの有無。0=なし,1=あり
  4527:   //                 bit2:MPU。0=MC68000,1=MC68030
  4528:   //    +$3FFFまで同じワードが繰り返される
  4529:   //
  4530: 
  4531:   //DIPSW
  4532:   public static int xt3DIPSWRequest;  //DIPSW。0~3
  4533:   public static int xt3DIPSW;
  4534:   public static int xt3PortAddress;  //ポートのアドレス。0x00ec0000+(xt3DIPSW<<14)
  4535: 
  4536:   //メモリ
  4537:   public static int xt3MemorySizeRequest;  //メモリのサイズ。1<<18(256KB)または1<<20(1MB)
  4538:   public static int xt3MemorySize;
  4539:   public static boolean xt3MemoryEnabled;  //メモリの有無。false=なし,true=あり
  4540:   public static int xt3MemoryPosition;  //メモリの位置。xt3MemoryArray[0]のアドレス。11<<20または15<<20
  4541:   public static int xt3MemoryStart;  //メモリの開始アドレス。xt3MemoryPosition+(1<<20)-xt3MemorySize
  4542:   public static final byte[] xt3MemoryArray = new byte[1 << 20];  //メモリの内容の配列。常に1MB
  4543:   public static boolean xt3MemorySave;  //メモリの保存フラグ。true=保存する。常に1MBを保存・復元する
  4544: 
  4545:   //MPU
  4546:   public static int xt3SavedPC;  //MC68000のPC
  4547:   public static final int[] xt3SavedRn = new int[16];  //MC68000のRn
  4548: 
  4549:   //初期化
  4550:   public static void xt3Init () {
  4551: 
  4552:     //DIPSW
  4553:     xt3DIPSWRequest = Math.max (0, Math.min (3, Settings.sgsGetInt ("xt3dipsw")));  //メニューで変更できる
  4554:     xt3DIPSW = xt3DIPSWRequest;  //リセットで更新する
  4555: 
  4556:     //ポートのアドレス
  4557:     xt3PortAddress = 0x00ec0000 + (xt3DIPSW << 14);  //リセットで更新する
  4558: 
  4559:     //メモリのサイズ
  4560:     int memoryKB = Settings.sgsGetInt ("xt3memorykb");
  4561:     if (!(memoryKB == 1 << 8 || memoryKB == 1 << 10)) {
  4562:       memoryKB = 1 << 8;
  4563:     }
  4564:     xt3MemorySizeRequest = memoryKB << 10;  //メニューで変更できる
  4565:     xt3MemorySize = xt3MemorySizeRequest;  //リセットで更新する
  4566: 
  4567:     //メモリの有無
  4568:     xt3MemoryEnabled = false;  //リセットで更新する。ポートで変更できる
  4569: 
  4570:     //メモリの位置
  4571:     xt3MemoryPosition = 11 << 20;  //リセットで更新する。ポートで変更できる
  4572: 
  4573:     //メモリの開始アドレス
  4574:     xt3MemoryStart = xt3MemoryPosition + (1 << 20) - xt3MemorySize;  //リセットで更新する。ポートで変更できる
  4575: 
  4576:     //メモリの内容の配列
  4577:     //xt3MemoryArray = new byte[1 << 20];
  4578:     byte[] memoryArray = Settings.sgsGetData ("xt3memorydata");  //リセットでは更新しない。動作中に変化する
  4579:     Arrays.fill (xt3MemoryArray,  //array
  4580:                  (byte) 0);  //data
  4581:     if (memoryArray.length != 0) {  //復元するデータがある
  4582:       System.arraycopy (memoryArray, 0,  //from
  4583:                         xt3MemoryArray, 0,  //to
  4584:                         Math.min (memoryArray.length, xt3MemoryArray.length));  //length
  4585:       if (memoryArray.length < xt3MemoryArray.length) {
  4586:         Arrays.fill (xt3MemoryArray,  //array
  4587:                      memoryArray.length,  //from
  4588:                      xt3MemoryArray.length,  //to
  4589:                      (byte) 0);  //data
  4590:       }
  4591:     }
  4592: 
  4593:     //メモリの保存フラグ
  4594:     xt3MemorySave = Settings.sgsGetOnOff ("xt3memorysave");  //メニューで変更できる
  4595: 
  4596:     //MPU
  4597:     xt3SavedPC = 0;  //リセットで更新する
  4598:     //xt3SavedRn = new int[16];
  4599:     Arrays.fill (xt3SavedRn, 0);  //リセットで更新する
  4600: 
  4601:     xt3Reset ();
  4602:   }
  4603: 
  4604:   //後始末
  4605:   public static void xt3Tini () {
  4606: 
  4607:     //DIPSW
  4608:     Settings.sgsPutInt ("xt3dipsw", xt3DIPSW);  //メニューで変更できる
  4609: 
  4610:     //メモリのサイズ
  4611:     Settings.sgsPutInt ("xt3memorykb", xt3MemorySizeRequest >> 10);  //メニューで変更できる
  4612: 
  4613:     //メモリの内容の配列
  4614:     boolean zero = true;
  4615:     if (xt3MemorySave) {
  4616:       for (int i = 0; i < 1 << 20; i++) {
  4617:         if (xt3MemoryArray[i] != 0) {
  4618:           zero = false;
  4619:           break;
  4620:         }
  4621:       }
  4622:     }
  4623:     if (zero) {
  4624:       Settings.sgsCurrentMap.put ("xt3memorydata", "");
  4625:     } else {
  4626:       if (false) {
  4627:         Settings.sgsCurrentMap.put ("xt3memorydata",
  4628:                                     ByteArray.byaEncodeBase64 (ByteArray.byaEncodeGzip (xt3MemoryArray, 0, 1 << 20)));  //動作中に変化する
  4629:       } else {
  4630:         Settings.sgsPutData ("xt3memorydata",
  4631:                              Arrays.copyOf (xt3MemoryArray, 1 << 20));
  4632:       }
  4633:     }
  4634:     //メモリの保存フラグ
  4635:     Settings.sgsPutOnOff ("xt3memorysave", xt3MemorySave);  //メニューで変更できる
  4636: 
  4637:   }
  4638: 
  4639:   //リセット
  4640:   public static void xt3Reset () {
  4641: 
  4642:     //ポートのアドレス
  4643:     xt3PortAddress = 0x00ec0000 + (xt3DIPSW << 14);  //リセットで更新する
  4644: 
  4645:     //メモリのサイズ
  4646:     xt3MemorySize = xt3MemorySizeRequest;  //リセットで更新する
  4647: 
  4648:     //メモリの有無
  4649:     xt3MemoryEnabled = false;  //リセットで更新する。ポートで変更できる
  4650: 
  4651:     //メモリの位置
  4652:     xt3MemoryPosition = 11 << 20;  //リセットで更新する。ポートで変更できる
  4653: 
  4654:     //メモリの開始アドレス
  4655:     xt3MemoryStart = xt3MemoryPosition + (1 << 20) - xt3MemorySize;  //リセットで更新する。ポートで変更できる
  4656: 
  4657:     //MPU
  4658:     xt3SavedPC = 0;  //リセットで更新する
  4659:     Arrays.fill (xt3SavedRn, 0);  //リセットで更新する
  4660: 
  4661:   }
  4662: 
  4663:   //リードワード
  4664:   public static int xt3PortRead () {
  4665:     return (currentIsSecond ? 4 : 0) | (xt3MemoryEnabled ? 2 : 0) | (xt3MemoryPosition == 11 << 20 ? 0 : 1);
  4666:   }
  4667: 
  4668:   //ライトワード
  4669:   public static void xt3PortWrite (int d) {
  4670:     boolean nextIsSecond = (d & 4) != 0;
  4671:     boolean memoryEnabled = (d & 2) != 0;
  4672:     int memoryPosition = (d & 1) == 0 ? 11 << 20 : 15 << 20;
  4673: 
  4674:     if (xt3MemoryEnabled != memoryEnabled ||
  4675:         xt3MemoryPosition != memoryPosition) {  //メモリの有無または位置が変更された
  4676:       if (xt3MemoryEnabled) {  //元の位置から取り除く
  4677:         if (xt3MemoryPosition == 11 << 20) {  //$00Bxxxxx
  4678:           if (MainMemory.mmrMemorySizeCurrent < 12 << 20) {  //メインメモリが12MBない
  4679:             busSuper (MemoryMappedDevice.MMD_NUL, (12 << 20) - xt3MemorySize, 12 << 20);  //空きに戻す
  4680:           } else {  //メインメモリが12MBある
  4681:             busUser (MemoryMappedDevice.MMD_MMR, (12 << 20) - xt3MemorySize, 12 << 20);  //メインメモリに戻す
  4682:           }
  4683:         } else {  //$00Fxxxxx
  4684:           busSuper (MemoryMappedDevice.MMD_ROM, (16 << 20) - xt3MemorySize, 16 << 20);  //ROMに戻す
  4685:         }
  4686:       }
  4687:       xt3MemoryEnabled = memoryEnabled;  //メモリの有無
  4688:       xt3MemoryPosition = memoryPosition;  //メモリの位置
  4689:       if (xt3MemoryEnabled) {  //新しい位置に配置する
  4690:         if (xt3MemoryPosition == 11 << 20) {  //$00Bxxxxx
  4691:           busUser (MemoryMappedDevice.MMD_XTM, (12 << 20) - xt3MemorySize, 12 << 20);  //メモリを配置する
  4692:         } else {  //$00Fxxxxx
  4693:           busUser (MemoryMappedDevice.MMD_XTM, (16 << 20) - xt3MemorySize, 16 << 20);  //メモリを配置する
  4694:         }
  4695:       }
  4696:     }
  4697: 
  4698:     if (currentIsSecond != nextIsSecond) {  //MPUが変わる
  4699: 
  4700:       if (nextIsSecond) {  //MC68000→MC68EC030
  4701: 
  4702:         //HALTしたときのPCとRnを保存する
  4703:         xt3SavedPC = regPC;
  4704:         System.arraycopy (regRn, 0, xt3SavedRn, 0, 16);
  4705: 
  4706:         //MC68000を停止する
  4707:         if (mpuTask != null) {
  4708:           mpuClockLimit = 0L;
  4709:           System.out.println (Multilingual.mlnJapanese ?
  4710:                               Model.MPU_NAMES[currentFirstMPU] + " を停止します" :
  4711:                               Model.MPU_NAMES[currentFirstMPU] + " stops");
  4712:           mpuTask.cancel ();
  4713:           mpuTask = null;
  4714:         }
  4715: 
  4716:         //MC68EC030を起動する
  4717:         tmrTimer.schedule (new TimerTask () {
  4718:           @Override public void run () {
  4719: 
  4720:             //MPU
  4721:             currentIsSecond = true;
  4722:             currentMPU = currentSecondMPU;
  4723:             mpuSetCurrentClock (specifiedSecondClock);
  4724: 
  4725:             if (MC68EC030.M30_DIV_ZERO_V_FLAG) {
  4726:               MC68EC030.m30DivZeroVFlag = false;
  4727:             }
  4728: 
  4729:             RegisterList.drpSetMPU ();
  4730:             mpuSFC = mpuDFC = mpuCACR = mpuBUSCR = mpuUSP = mpuVBR = mpuCAAR = mpuMSP = mpuISP = 0;
  4731:             mpuPCR = 0x04300500 | MPU_060_REV << 8;
  4732:             MC68060.mmuReset ();  //TCR,ITT0,ITT1,DTT0,DTT1,URP,SRP。060→000/030のときアドレス変換をOFFにする必要がある
  4733:             //MC68EC030
  4734:             mpuIgnoreAddressError = true;
  4735:             fpuBox = fpuMotherboardCoprocessor;
  4736:             fpuBox.epbReset ();
  4737:             fpuFPn = fpuBox.epbFPn;
  4738:             mpuCacheOn = (mpuCACR & 0x00000101) != 0;
  4739:             mpuSetWait ();
  4740:             //
  4741:             regSRT1 = regSRT0 = 0;
  4742:             regSRS = REG_SR_S;
  4743:             regSRM = 0;
  4744:             regSRI = REG_SR_I;
  4745:             regCCR = 0;
  4746:             Arrays.fill (regRn, 0);
  4747:             //PCとSSPをRAMから読み出す
  4748:             regRn[15] = MainMemory.mmrRls (0x00000000);
  4749:             regPC = MainMemory.mmrRls (0x00000004);
  4750:             //割り込み
  4751:             mpuIMR = 0;
  4752:             mpuIRR = 0;
  4753:             if (MC68901.MFP_DELAYED_INTERRUPT) {
  4754:               mpuDIRR = 0;
  4755:             }
  4756:             mpuISR = 0;
  4757:             //動作開始
  4758:             mpuStart ();
  4759:           }
  4760:         }, TMR_DELAY);
  4761: 
  4762:       } else {  //MC68EC030→MC68000
  4763: 
  4764:         //MC68EC030を停止する
  4765:         if (mpuTask != null) {
  4766:           mpuClockLimit = 0L;
  4767:           System.out.println (Multilingual.mlnJapanese ? "MC68EC030 を停止します" : "MC68EC030 stops");
  4768:           mpuTask.cancel ();
  4769:           mpuTask = null;
  4770:         }
  4771: 
  4772:         //MC68000を起動する
  4773:         tmrTimer.schedule (new TimerTask () {
  4774:           @Override public void run () {
  4775: 
  4776:             //MPU
  4777:             currentIsSecond = false;
  4778:             currentMPU = currentFirstMPU;
  4779:             mpuSetCurrentClock (specifiedFirstClock);
  4780: 
  4781:             RegisterList.drpSetMPU ();
  4782:             mpuSFC = mpuDFC = mpuCACR = mpuBUSCR = mpuUSP = mpuVBR = mpuCAAR = mpuMSP = mpuISP = 0;
  4783:             mpuPCR = 0x04300500 | MPU_060_REV << 8;
  4784:             MC68060.mmuReset ();  //TCR,ITT0,ITT1,DTT0,DTT1,URP,SRP。060→000/030のときアドレス変換をOFFにする必要がある
  4785:             //MC68000
  4786:             mpuIgnoreAddressError = false;
  4787:             mpuCacheOn = false;
  4788:             mpuSetWait ();
  4789:             //
  4790:             regSRT1 = regSRT0 = 0;
  4791:             regSRS = REG_SR_S;
  4792:             regSRM = 0;
  4793:             regSRI = REG_SR_I;
  4794:             regCCR = 0;
  4795:             //HALTしたときのPCとRnを復元する
  4796:             regPC = xt3SavedPC;
  4797:             System.arraycopy (xt3SavedRn, 0, regRn, 0, 16);
  4798:             //割り込み
  4799:             mpuIMR = 0;
  4800:             mpuIRR = 0;
  4801:             if (MC68901.MFP_DELAYED_INTERRUPT) {
  4802:               mpuDIRR = 0;
  4803:             }
  4804:             mpuISR = 0;
  4805:             //動作開始
  4806:             mpuStart ();
  4807:           }
  4808:         }, TMR_DELAY);
  4809: 
  4810:       }
  4811:     }
  4812:   }
  4813: 
  4814: 
  4815: 
  4816:   //========================================================================================
  4817:   //$$MDL 機種
  4818: 
  4819:   public static JMenu mdlMenu;  //メニュー
  4820: 
  4821:   public static JRadioButtonMenuItem mdlShodaiMenuItem;
  4822:   public static JRadioButtonMenuItem mdlACEMenuItem;
  4823:   public static JRadioButtonMenuItem mdlEXPERTMenuItem;
  4824:   public static JRadioButtonMenuItem mdlPROMenuItem;
  4825:   public static JRadioButtonMenuItem mdlSUPERMenuItem;
  4826:   public static JRadioButtonMenuItem mdlXVIMenuItem;
  4827:   public static JRadioButtonMenuItem mdlXellent30MenuItem;
  4828:   public static JRadioButtonMenuItem mdlCompactMenuItem;
  4829:   public static JRadioButtonMenuItem mdlHybridMenuItem;
  4830:   public static JRadioButtonMenuItem mdl060turboPROMenuItem;
  4831:   public static JRadioButtonMenuItem mdlX68030MenuItem;
  4832:   public static JRadioButtonMenuItem mdl030CompactMenuItem;
  4833:   public static JRadioButtonMenuItem mdl060turboMenuItem;
  4834:   public static JCheckBoxMenuItem mdlMC68010MenuItem;
  4835: 
  4836:   public static JMenu coproFPUMenu;
  4837: 
  4838:   //アクセラレータ
  4839:   public static final int ACCELERATOR_HYBRID      = 1;  //Compact+33.3MHz+IPLROM 1.6
  4840:   public static final int ACCELERATOR_XELLENT30   = 2;  //XVI+secondMPU
  4841:   public static final int ACCELERATOR_060TURBO    = 3;  //X68030+MC68060
  4842:   public static final int ACCELERATOR_060TURBOPRO = 4;  //PRO+MC68060
  4843:   public static final double MHZ_HYBRID_VALUE = 100.0 / 3.0;  //Hybridの動作周波数。33.3MHz
  4844:   public static final String MHZ_HYBRID_STRING = "33.3";
  4845:   public static final double MHZ_060TURBO_VALUE = 50.0;  //060turbo/060turboPROの動作周波数
  4846:   public static final String MHZ_060TURBO_STRING = "50";
  4847: 
  4848:   //指定された値
  4849:   //  機種とアクセラレータ
  4850:   public static Model specifiedModel;  //指定された機種
  4851:   public static int specifiedAccelerator;  //指定されたアクセラレータ
  4852:   public static boolean mpu010;  //false=68000を使う,true=68010を使う
  4853:   //  MPU
  4854:   public static boolean specifiedIsSecond;  //指定されたMPUは2番目か
  4855:   public static int specifiedFirstMPU;  //指定された1番目のMPU。Model.MPU_MC68000~Model.MPU_MC68060
  4856:   public static int specifiedSecondMPU;  //指定された2番目のMPU。Model.MPU_MC68000~Model.MPU_MC68060
  4857:   public static int specifiedMPU;  //指定されたMPU。specifiedIsSecond?specifiedSecondMPU:specifiedFirstMPU
  4858:   //  クロック(MHz)
  4859:   public static double specifiedFirstClock;  //指定された1番目のクロック(MHz)
  4860:   public static double specifiedSecondClock;  //指定された2番目のクロック(MHz)
  4861:   public static double specifiedClock;  //指定されたクロック(MHz)。specifiedIsSecond?specifiedSecondClock:specifiedFirstClock
  4862:   //  コプロセッサとオンチップFPU
  4863:   public static int specifiedCopro0;  //マザーボードコプロセッサ。0=なし,1=MC68881,2=MC68882,7=フルスペック,+8=三倍精度
  4864:   public static int specifiedCopro1;  //拡張コプロセッサ#1。0=なし,1=MC68881,2=MC68882,7=フルスペック,+8=三倍精度
  4865:   public static int specifiedCopro2;  //拡張コプロセッサ#2。0=なし,1=MC68881,2=MC68882,7=フルスペック,+8=三倍精度
  4866:   public static int specifiedOnchipFPU;  //オンチップFPU。0=なし,6=MC68060,7=フルスペック,+8=三倍精度
  4867: 
  4868:   //現在の値
  4869:   //  機種とアクセラレータ
  4870:   public static Model currentModel;  //現在の機種
  4871:   public static int currentAccelerator;  //現在のアクセラレータ
  4872:   //  MPU
  4873:   public static boolean currentIsSecond;  //現在のMPUは2番目か
  4874:   public static int currentFirstMPU;  //現在の1番目のMPU。Model.MPU_MC68000~Model.MPU_MC68060
  4875:   public static int currentSecondMPU;  //現在の2番目のMPU。Model.MPU_MC68000~Model.MPU_MC68060
  4876:   public static int currentMPU;  //現在のMPU。currentIsSecond?currentSecondMPU:currentFirstMPU
  4877:   //  クロック(MHz)は指定された値を用いる
  4878:   //  コプロセッサとオンチップFPU
  4879:   public static int currentCopro0;  //マザーボードコプロセッサ。0=なし,1=MC68881,2=MC68882,7=フルスペック,+8=三倍精度
  4880:   public static int currentCopro1;  //拡張コプロセッサ#1。0=なし,1=MC68881,2=MC68882,7=フルスペック,+8=三倍精度
  4881:   public static int currentCopro2;  //拡張コプロセッサ#2。0=なし,1=MC68881,2=MC68882,7=フルスペック,+8=三倍精度
  4882:   public static int currentOnchipFPU;  //オンチップFPU。0=なし,6=MC68060,7=フルスペック,+8=三倍精度
  4883: 
  4884:   //mdlInit ()
  4885:   //  機種の指定を読み取る
  4886:   public static void mdlInit () {
  4887: 
  4888:     //機種とアクセラレータ
  4889:     specifiedModel = Model.COMPACT;
  4890:     specifiedAccelerator = ACCELERATOR_HYBRID;
  4891:     mpu010 = Settings.sgsGetOnOff ("mpu010");
  4892:     {
  4893:       String paramModel = Settings.sgsGetString ("model");
  4894:       switch (paramModel.toLowerCase ()) {
  4895:       case "":
  4896:       case "none":
  4897:       case "hybrid":
  4898:         specifiedModel = Model.COMPACT;
  4899:         specifiedAccelerator = ACCELERATOR_HYBRID;
  4900:         break;
  4901:       case "xellent30":
  4902:         specifiedModel = Model.XVI;
  4903:         specifiedAccelerator = ACCELERATOR_XELLENT30;
  4904:         break;
  4905:       case "060turbo":
  4906:         specifiedModel = Model.X68030;
  4907:         specifiedAccelerator = ACCELERATOR_060TURBO;
  4908:         break;
  4909:       case "060turbopro":
  4910:         specifiedModel = Model.PRO;
  4911:         specifiedAccelerator = ACCELERATOR_060TURBOPRO;
  4912:         break;
  4913:       default:
  4914:         Model model = Model.fromTypeOrSynonym (paramModel);
  4915:         if (model != null) {
  4916:           specifiedModel = model;
  4917:           specifiedAccelerator = 0;
  4918:         } else {
  4919:           System.out.println (Multilingual.mlnJapanese ?
  4920:                               paramModel + " は不明な機種です" :
  4921:                               paramModel + " is unknown model");
  4922:           specifiedModel = Model.COMPACT;
  4923:           specifiedAccelerator = ACCELERATOR_HYBRID;
  4924:         }
  4925:       }
  4926:     }
  4927:     //MPU
  4928:     specifiedIsSecond = false;
  4929:     specifiedFirstMPU = specifiedModel.getMPU ();
  4930:     specifiedSecondMPU = Model.MPU_MC68EC030;
  4931:     {
  4932:       String[] paramMPUs = Settings.sgsGetString ("mpu").split (",");
  4933:       for (int i = 0; i < 2; i++) {
  4934:         int mpu = 0;
  4935:         String paramMPU = i < paramMPUs.length ? paramMPUs[i] : "";
  4936:         switch (paramMPU) {
  4937:         case "":
  4938:         case "none":
  4939:         case "-1":
  4940:           mpu = (i == 0 ?
  4941:                  (specifiedAccelerator == ACCELERATOR_060TURBO ||
  4942:                   specifiedAccelerator == ACCELERATOR_060TURBOPRO ? Model.MPU_MC68060 :
  4943:                   specifiedModel.getMPU ()) :
  4944:                  Model.MPU_MC68EC030);
  4945:           break;
  4946:         case "0":
  4947:         case "68000":
  4948:         case "mc68000":
  4949:           mpu = Model.MPU_MC68000;
  4950:           break;
  4951:         case "1":
  4952:         case "68010":
  4953:         case "mc68010":
  4954:           mpu = Model.MPU_MC68010;
  4955:           break;
  4956:           //case "2":
  4957:           //case "68020":
  4958:           //case "mc68020":
  4959:           //  specifiedFirstMPU = Model.MPU_MC68020;
  4960:           //  break;
  4961:         case "3":
  4962:         case "68ec030":
  4963:         case "mc68ec030":
  4964:           mpu = Model.MPU_MC68EC030;
  4965:           break;
  4966:           //case "68030":
  4967:           //case "mc68030":
  4968:           //  mpu = Model.MPU_MC68030;
  4969:           //  break;
  4970:           //case "68lc040":
  4971:           //case "mc68lc040":
  4972:           //  mpu = Model.MPU_MC68LC040;
  4973:           //  break;
  4974:           //case "4":
  4975:           //case "68040":
  4976:           //case "mc68040":
  4977:           //  mpu = Model.MPU_MC68040;
  4978:           //  break;
  4979:           //case "68lc060":
  4980:           //case "mc68lc060":
  4981:           //  mpu = Model.MPU_MC68LC060;
  4982:           //  break;
  4983:         case "6":
  4984:         case "68060":
  4985:         case "mc68060":
  4986:           mpu = Model.MPU_MC68060;
  4987:           break;
  4988:         default:
  4989:           Model model = Model.fromTypeOrSynonym (paramMPU);
  4990:           if (model != null) {
  4991:             mpu = model.getMPU ();
  4992:           } else {
  4993:             System.out.println (Multilingual.mlnJapanese ?
  4994:                                 paramMPU + " は不明な MPU です" :
  4995:                                 paramMPU + " is unknown MPU");
  4996:             mpu = specifiedModel.getMPU ();
  4997:           }
  4998:         }  //switch
  4999:         if (i == 0) {
  5000:           specifiedFirstMPU = mpu;
  5001:         } else {
  5002:           specifiedSecondMPU = mpu;
  5003:         }
  5004:       }  //for i
  5005:     }
  5006:     specifiedMPU = specifiedIsSecond ? specifiedSecondMPU : specifiedFirstMPU;
  5007:     //クロック(MHz)
  5008:     specifiedFirstClock = specifiedModel.getClock ();
  5009:     specifiedSecondClock = specifiedFirstClock * 2.0;
  5010:     {
  5011:       String[] paramClocks = Settings.sgsGetString ("clock").split (",");
  5012:       for (int i = 0; i < 2; i++) {
  5013:         double clock = 0.0;
  5014:         String paramClock = i < paramClocks.length ? paramClocks[i] : "";
  5015:         switch (paramClock.toLowerCase ()) {
  5016:         case "":
  5017:         case "none":
  5018:         case "-1":
  5019:           clock = (i == 0 ?
  5020:                    (specifiedAccelerator == ACCELERATOR_HYBRID ? MHZ_HYBRID_VALUE :  //33.3MHz
  5021:                     specifiedAccelerator == ACCELERATOR_060TURBO ||
  5022:                     specifiedAccelerator == ACCELERATOR_060TURBOPRO ? MHZ_060TURBO_VALUE :
  5023:                     specifiedModel.getClock ()) :
  5024:                    specifiedFirstClock * 2.0);
  5025:           break;
  5026:         case "hybrid":
  5027:           clock = MHZ_HYBRID_VALUE;  //33.3MHz
  5028:           break;
  5029:         case "060turbo":
  5030:         case "060turbopro":
  5031:           clock = MHZ_060TURBO_VALUE;
  5032:           break;
  5033:         case "16.7":
  5034:         case "xellent30":
  5035:           clock = 50.0 / 3.0;  //16.7MHz
  5036:           break;
  5037:         case "33.3":
  5038:           clock = 100.0 / 3.0;  //33.3MHz
  5039:           break;
  5040:         case "66.7":
  5041:           clock = 200.0 / 3.0;  //66.7MHz
  5042:           break;
  5043:         default:
  5044:           if (paramClock.matches ("^(?:" +
  5045:                                   "[-+]?" +  //符号
  5046:                                   "(?:[0-9]+(?:\\.[0-9]*)?|\\.[0-9]+)" +  //仮数部
  5047:                                   "(?:[Ee][-+]?[0-9]+)?" +  //指数部
  5048:                                   ")$")) {
  5049:             double d = Double.parseDouble (paramClock);
  5050:             if (1.0 <= d && d <= 1000.0) {
  5051:               clock = d;
  5052:             }
  5053:           } else {
  5054:             System.out.println (Multilingual.mlnJapanese ?
  5055:                                 paramClock + " は不明な動作周波数です" :
  5056:                                 paramClock + " is unknown clock frequency");
  5057:             clock = specifiedModel.getClock ();
  5058:           }
  5059:         }  //switch
  5060:         if (i == 0) {
  5061:           specifiedFirstClock = clock;
  5062:         } else {
  5063:           specifiedSecondClock = clock;
  5064:         }
  5065:       }  //for i
  5066:     }
  5067:     specifiedClock = specifiedIsSecond ? specifiedSecondClock : specifiedFirstClock;
  5068:     //コプロセッサとオンチップFPU
  5069:     specifiedCopro0 = 15 & Settings.sgsGetInt ("copro0", 2);
  5070:     if (!((7 & specifiedCopro0) == 0 ||
  5071:           (7 & specifiedCopro0) == 1 ||
  5072:           (7 & specifiedCopro0) == 2 ||
  5073:           (7 & specifiedCopro0) == 7)) {
  5074:       specifiedCopro0 = (8 & specifiedCopro0) | 2;
  5075:     }
  5076:     specifiedCopro1 = 15 & Settings.sgsGetInt ("copro1", 2);
  5077:     if (!((7 & specifiedCopro1) == 0 ||
  5078:           (7 & specifiedCopro1) == 1 ||
  5079:           (7 & specifiedCopro1) == 2 ||
  5080:           (7 & specifiedCopro1) == 7)) {
  5081:       specifiedCopro1 = (8 & specifiedCopro1) | 2;
  5082:     }
  5083:     specifiedCopro2 = 15 & Settings.sgsGetInt ("copro2", 2);
  5084:     if (!((7 & specifiedCopro2) == 0 ||
  5085:           (7 & specifiedCopro2) == 1 ||
  5086:           (7 & specifiedCopro2) == 2 ||
  5087:           (7 & specifiedCopro2) == 7)) {
  5088:       specifiedCopro2 = (8 & specifiedCopro2) | 2;
  5089:     }
  5090:     specifiedOnchipFPU = 15 & Settings.sgsGetInt ("onchipfpu", 7);
  5091:     if (!((7 & specifiedOnchipFPU) == 0 ||
  5092:           (7 & specifiedOnchipFPU) == 6 ||
  5093:           (7 & specifiedOnchipFPU) == 7)) {
  5094:       specifiedOnchipFPU = (8 & specifiedOnchipFPU) | 7;
  5095:     }
  5096:     //現在の値にコピーしておく
  5097:     //  機種とアクセラレータ
  5098:     currentModel = specifiedModel;
  5099:     currentAccelerator = specifiedAccelerator;
  5100:     //  MPU
  5101:     currentIsSecond = specifiedIsSecond;
  5102:     currentFirstMPU = specifiedFirstMPU;
  5103:     currentSecondMPU = specifiedSecondMPU;
  5104:     currentMPU = specifiedMPU;
  5105:     //  クロック(MHz)
  5106:     //  コプロセッサとオンチップFPU
  5107:     currentCopro0 = specifiedCopro0;
  5108:     currentCopro1 = specifiedCopro1;
  5109:     currentCopro2 = specifiedCopro2;
  5110:     currentOnchipFPU = specifiedOnchipFPU;
  5111: 
  5112:     //任意の負荷率
  5113:     mpuUtilOn = Settings.sgsGetOnOff ("util");  //任意の負荷率
  5114:     mpuUtilRatio = fmtParseInt (Settings.sgsGetString ("ratio"), 0, 1, 100, 100);  //任意の負荷率
  5115:     //任意の周波数
  5116:     mpuArbFreqMHz = fmtParseInt (Settings.sgsGetString ("mhz"), 0, 1, 1000, 100);
  5117:     if (mpuUtilOn) {
  5118:       mpuArbFreqOn = false;
  5119:     } else {
  5120:       mpuArbFreqOn = !(specifiedClock == 10.0 ||
  5121:                        specifiedClock == 50.0 / 3.0 ||  //16.7MHz
  5122:                        specifiedClock == 25.0 ||
  5123:                        specifiedClock == 100.0 / 3.0 ||  //33.3MHz
  5124:                        specifiedClock == 50.0 ||
  5125:                        specifiedClock == 200.0 / 3.0 ||  //66.7MHz
  5126:                        specifiedClock == 75.0 ||
  5127:                        specifiedClock == 100.0);
  5128:       if (mpuArbFreqOn) {
  5129:         mpuArbFreqMHz = (int) specifiedClock;
  5130:       }
  5131:     }
  5132: 
  5133:     //ウェイトサイクル
  5134:     mpuROMWaitCycles = 0;
  5135:     mpuRAMWaitCycles = 0;
  5136:     mpuCacheOn = false;
  5137:     //mpuNoWaitTime = new WaitTime ();
  5138:     mpuNoWaitTime.ram = 0;
  5139:     mpuNoWaitTime.gvram = 0;
  5140:     mpuNoWaitTime.tvram = 0;
  5141:     mpuNoWaitTime.crtc = 0;
  5142:     mpuNoWaitTime.palet = 0;
  5143:     mpuNoWaitTime.vicon = 0;
  5144:     mpuNoWaitTime.dmac = 0;
  5145:     mpuNoWaitTime.mfp = 0;
  5146:     mpuNoWaitTime.rtc = 0;
  5147:     mpuNoWaitTime.prnport = 0;
  5148:     mpuNoWaitTime.sysport = 0;
  5149:     mpuNoWaitTime.opm = 0;
  5150:     mpuNoWaitTime.adpcm = 0;
  5151:     mpuNoWaitTime.fdc = 0;
  5152:     mpuNoWaitTime.fdd = 0;
  5153:     mpuNoWaitTime.hdc = 0;
  5154:     mpuNoWaitTime.scc = 0;
  5155:     mpuNoWaitTime.ppi = 0;
  5156:     mpuNoWaitTime.ioi = 0;
  5157:     mpuNoWaitTime.sprc = 0;
  5158:     mpuNoWaitTime.sram = 0;
  5159:     mpuNoWaitTime.rom = 0;
  5160:     mpuNoWaitTime.ramlong = mpuNoWaitTime.ram << 1;
  5161:     mpuNoWaitTime.romlong = mpuNoWaitTime.rom << 1;
  5162:     //dmaNoWaitTime = new WaitTime ();
  5163:     dmaNoWaitTime.ram = 0;
  5164:     dmaNoWaitTime.gvram = 0;
  5165:     dmaNoWaitTime.tvram = 0;
  5166:     dmaNoWaitTime.crtc = 0;
  5167:     dmaNoWaitTime.palet = 0;
  5168:     dmaNoWaitTime.vicon = 0;
  5169:     dmaNoWaitTime.dmac = 0;
  5170:     dmaNoWaitTime.mfp = 0;
  5171:     dmaNoWaitTime.rtc = 0;
  5172:     dmaNoWaitTime.prnport = 0;
  5173:     dmaNoWaitTime.sysport = 0;
  5174:     dmaNoWaitTime.opm = 0;
  5175:     dmaNoWaitTime.adpcm = 0;
  5176:     dmaNoWaitTime.fdc = 0;
  5177:     dmaNoWaitTime.fdd = 0;
  5178:     dmaNoWaitTime.hdc = 0;
  5179:     dmaNoWaitTime.scc = 0;
  5180:     dmaNoWaitTime.ppi = 0;
  5181:     dmaNoWaitTime.ioi = 0;
  5182:     dmaNoWaitTime.sprc = 0;
  5183:     dmaNoWaitTime.sram = 0;
  5184:     dmaNoWaitTime.rom = 0;
  5185:     dmaNoWaitTime.ramlong = dmaNoWaitTime.ram << 1;
  5186:     dmaNoWaitTime.romlong = dmaNoWaitTime.rom << 1;
  5187:     //mpuWaitTime = new WaitTime ();
  5188:     //dmaWaitTime = new WaitTime ();
  5189:     busWaitCyclesRequest = Settings.sgsGetOnOff ("waitcycles");
  5190:     busWaitCycles = busWaitCyclesRequest;
  5191:     busWaitTime = busWaitCycles ? mpuWaitTime : mpuNoWaitTime;
  5192: 
  5193:   }  //mdlInit()
  5194: 
  5195:   public static void mdlTini () {
  5196:     //機種とアクセラレータ
  5197:     Settings.sgsPutString ("model",
  5198:                            specifiedAccelerator == ACCELERATOR_HYBRID ? "Hybrid" :
  5199:                            specifiedAccelerator == ACCELERATOR_XELLENT30 ? "Xellent30" :
  5200:                            specifiedAccelerator == ACCELERATOR_060TURBO ? "060turbo" :
  5201:                            specifiedAccelerator == ACCELERATOR_060TURBOPRO ? "060turboPRO" :
  5202:                            specifiedModel.getSynonym () != null ? specifiedModel.getSynonym () :
  5203:                            specifiedModel.getType ());
  5204:     Settings.sgsPutOnOff ("mpu010", mpu010);
  5205:     //MPU
  5206:     //  機種のデフォルトと同じときは省略する
  5207:     int defaultFirstMPU = (specifiedAccelerator == ACCELERATOR_060TURBO ||
  5208:                            specifiedAccelerator == ACCELERATOR_060TURBOPRO ? Model.MPU_MC68060 :
  5209:                            specifiedModel.getMPU ());
  5210:     int defaultSecondMPU = Model.MPU_MC68EC030;
  5211:     Settings.sgsPutString ("mpu",
  5212:                            (specifiedFirstMPU == defaultFirstMPU ? "" :
  5213:                             Model.mpuNameOf (specifiedFirstMPU)) +
  5214:                            (specifiedSecondMPU == defaultSecondMPU ? "" :
  5215:                             "," + Model.mpuNameOf (specifiedSecondMPU)));
  5216:     //クロック
  5217:     //  機種のデフォルトと同じときは省略する
  5218:     //  16.7MHzと33.3MHzは機種名で書くと正確に保存できる
  5219:     //  現在のクロックを保存する
  5220:     double defaultFirstClock = (specifiedAccelerator == ACCELERATOR_HYBRID ? MHZ_HYBRID_VALUE :  //33.3MHz
  5221:                                 specifiedAccelerator == ACCELERATOR_060TURBO ||
  5222:                                 specifiedAccelerator == ACCELERATOR_060TURBOPRO ? MHZ_060TURBO_VALUE :
  5223:                                 specifiedModel.getClock ());
  5224:     double defaultSecondClock = defaultFirstClock * 2.0;
  5225:     Settings.sgsPutString ("clock",
  5226:                            (specifiedFirstClock == defaultFirstClock ? "" :
  5227:                             specifiedFirstClock == 50.0 / 3.0 ? "16.7" :  //16.7MHz
  5228:                             specifiedFirstClock == 100.0 / 3.0 ? "33.3" :  //33.3MHz
  5229:                             specifiedFirstClock == 200.0 / 3.0 ? "66.7" :  //66.7MHz
  5230:                             String.valueOf ((int) specifiedFirstClock)) +
  5231:                            (specifiedSecondClock == defaultSecondClock ? "" :
  5232:                             "," + (specifiedSecondClock == 50.0 / 3.0 ? "16.7" :  //16.7MHz
  5233:                                    specifiedSecondClock == 100.0 / 3.0 ? "33.3" :  //33.3MHz
  5234:                                    specifiedSecondClock == 200.0 / 3.0 ? "66.7" :  //66.7MHz
  5235:                                    String.valueOf ((int) specifiedSecondClock))));
  5236:     //コプロセッサとオンチップFPU
  5237:     Settings.sgsPutInt ("copro0", specifiedCopro0);
  5238:     Settings.sgsPutInt ("copro1", specifiedCopro1);
  5239:     Settings.sgsPutInt ("copro2", specifiedCopro2);
  5240:     Settings.sgsPutInt ("onchipfpu", specifiedOnchipFPU);
  5241:     //任意の負荷率
  5242:     Settings.sgsPutOnOff ("util",
  5243:                           mpuUtilOn);
  5244:     Settings.sgsPutString ("ratio",
  5245:                            String.valueOf (mpuUtilRatio));
  5246:     //任意の周波数
  5247:     Settings.sgsPutString ("mhz",
  5248:                            String.valueOf (mpuArbFreqMHz));
  5249:     //ウェイトサイクル
  5250:     Settings.sgsPutOnOff ("waitcycles", busWaitCyclesRequest);
  5251:   }
  5252: 
  5253:   public static void mdlMakeMenu () {
  5254: 
  5255:     //アクションリスナー
  5256:     ActionListener listener = new ActionListener () {
  5257:       @Override public void actionPerformed (ActionEvent ae) {
  5258:         Object source = ae.getSource ();
  5259:         switch (ae.getActionCommand ()) {
  5260:         case "X68000 (10MHz)":
  5261:           mdlRequestModel (Model.SHODAI, 0);
  5262:           mpuReset (-1, -1);
  5263:           break;
  5264:         case "X68000 ACE (10MHz)":
  5265:           mdlRequestModel (Model.ACE, 0);
  5266:           mpuReset (-1, -1);
  5267:           break;
  5268:         case "X68000 EXPERT (10MHz)":
  5269:           mdlRequestModel (Model.EXPERT, 0);
  5270:           mpuReset (-1, -1);
  5271:           break;
  5272:         case "X68000 PRO (10MHz)":
  5273:           mdlRequestModel (Model.PRO, 0);
  5274:           mpuReset (-1, -1);
  5275:           break;
  5276:         case "X68000 SUPER (10MHz)":
  5277:           mdlRequestModel (Model.SUPER, 0);
  5278:           mpuReset (-1, -1);
  5279:           break;
  5280:         case "X68000 XVI (16.7MHz)":
  5281:           mdlRequestModel (Model.XVI, 0);
  5282:           mpuReset (-1, -1);
  5283:           break;
  5284:         case "X68000 Compact (16.7MHz)":
  5285:           mdlRequestModel (Model.COMPACT, 0);
  5286:           mpuReset (-1, -1);
  5287:           break;
  5288:           //
  5289:         case "X68030 (25MHz)":
  5290:           mdlRequestModel (Model.X68030, 0);
  5291:           mpuReset (-1, -1);
  5292:           break;
  5293:         case "X68030 Compact (25MHz)":
  5294:           mdlRequestModel (Model.X68030COMPACT, 0);
  5295:           mpuReset (-1, -1);
  5296:           break;
  5297:           //
  5298:         case "X68000 Hybrid (" + MHZ_HYBRID_STRING + "MHz)":
  5299:           mdlRequestModel (Model.COMPACT, ACCELERATOR_HYBRID);
  5300:           mpuReset (-1, -1);
  5301:           break;
  5302:         case "Xellent30 (33.3MHz)":
  5303:           mdlRequestModel (Model.XVI, ACCELERATOR_XELLENT30);
  5304:           mpuReset (-1, -1);
  5305:           break;
  5306:         case "060turbo (" + MHZ_060TURBO_STRING + "MHz)":
  5307:           mdlRequestModel (Model.X68030, ACCELERATOR_060TURBO);
  5308:           mpuReset (-1, -1);
  5309:           break;
  5310:         case "060turboPRO (" + MHZ_060TURBO_STRING + "MHz)":
  5311:           mdlRequestModel (Model.PRO, ACCELERATOR_060TURBOPRO);
  5312:           mpuReset (-1, -1);
  5313:           break;
  5314:           //
  5315:         case "MC68010":
  5316:           mpu010 = ((JCheckBoxMenuItem) source).isSelected ();
  5317:           break;
  5318: 
  5319:         }
  5320:       }
  5321:     };
  5322: 
  5323:     //メニュー
  5324:     ButtonGroup modelGroup = new ButtonGroup ();
  5325:     mdlMenu = Multilingual.mlnText (
  5326:       ComponentFactory.createMenu (
  5327:         "Change the model and reset",
  5328:         mdlShodaiMenuItem = ComponentFactory.createRadioButtonMenuItem (
  5329:           modelGroup,
  5330:           specifiedModel == Model.SHODAI,
  5331:           "X68000 (10MHz)",
  5332:           listener),
  5333:         mdlACEMenuItem = ComponentFactory.createRadioButtonMenuItem (
  5334:           modelGroup,
  5335:           specifiedModel == Model.ACE,
  5336:           "X68000 ACE (10MHz)",
  5337:           listener),
  5338:         mdlEXPERTMenuItem = ComponentFactory.createRadioButtonMenuItem (
  5339:           modelGroup,
  5340:           specifiedModel == Model.EXPERT,
  5341:           "X68000 EXPERT (10MHz)",
  5342:           listener),
  5343:         mdlPROMenuItem = ComponentFactory.createRadioButtonMenuItem (
  5344:           modelGroup,
  5345:           specifiedModel == Model.PRO && specifiedAccelerator == 0,
  5346:           "X68000 PRO (10MHz)",
  5347:           listener),
  5348:         mdlSUPERMenuItem = ComponentFactory.createRadioButtonMenuItem (
  5349:           modelGroup,
  5350:           specifiedModel == Model.SUPER,
  5351:           "X68000 SUPER (10MHz)",
  5352:           listener),
  5353:         mdlXVIMenuItem = ComponentFactory.createRadioButtonMenuItem (
  5354:           modelGroup,
  5355:           specifiedModel == Model.XVI && specifiedAccelerator == 0,
  5356:           "X68000 XVI (16.7MHz)",
  5357:           listener),
  5358:         mdlCompactMenuItem = ComponentFactory.createRadioButtonMenuItem (
  5359:           modelGroup,
  5360:           specifiedModel == Model.COMPACT && specifiedAccelerator == 0,
  5361:           "X68000 Compact (16.7MHz)",
  5362:           listener),
  5363:         //
  5364:         ComponentFactory.createHorizontalSeparator (),
  5365:         //
  5366:         mdlX68030MenuItem = ComponentFactory.createRadioButtonMenuItem (
  5367:           modelGroup,
  5368:           specifiedModel == Model.X68030 && specifiedAccelerator == 0,
  5369:           "X68030 (25MHz)",
  5370:           listener),
  5371:         mdl030CompactMenuItem = ComponentFactory.createRadioButtonMenuItem (
  5372:           modelGroup,
  5373:           specifiedModel == Model.X68030COMPACT,
  5374:           "X68030 Compact (25MHz)",
  5375:           listener),
  5376:         //
  5377:         ComponentFactory.createHorizontalSeparator (),
  5378:         //
  5379:         mdlHybridMenuItem = ComponentFactory.createRadioButtonMenuItem (
  5380:           modelGroup,
  5381:           specifiedModel == Model.COMPACT && specifiedAccelerator == ACCELERATOR_HYBRID,
  5382:           "X68000 Hybrid (" + MHZ_HYBRID_STRING + "MHz)",
  5383:           listener),
  5384:         mdlXellent30MenuItem = ComponentFactory.createRadioButtonMenuItem (
  5385:           modelGroup,
  5386:           specifiedModel == Model.XVI && specifiedAccelerator == ACCELERATOR_XELLENT30,
  5387:           "Xellent30 (33.3MHz)",
  5388:           listener),
  5389:         mdl060turboMenuItem = ComponentFactory.createRadioButtonMenuItem (
  5390:           modelGroup,
  5391:           specifiedModel == Model.X68030 && specifiedAccelerator == ACCELERATOR_060TURBO,
  5392:           "060turbo (" + MHZ_060TURBO_STRING + "MHz)",
  5393:           listener),
  5394:         mdl060turboPROMenuItem = ComponentFactory.createRadioButtonMenuItem (
  5395:           modelGroup,
  5396:           specifiedModel == Model.PRO && specifiedAccelerator == ACCELERATOR_060TURBOPRO,
  5397:           "060turboPRO (" + MHZ_060TURBO_STRING + "MHz)",
  5398:           listener),
  5399:         //
  5400:         ComponentFactory.createHorizontalSeparator (),
  5401:         //
  5402:         mdlMC68010MenuItem = ComponentFactory.createCheckBoxMenuItem (
  5403:           mpu010,
  5404:           "MC68010",
  5405:           listener)
  5406:         ),
  5407:       "ja", "機種を変更してリセット");
  5408: 
  5409:     //コプロセッサとオンチップFPU
  5410:     ActionListener copro0Listener = new ActionListener () {
  5411:       @Override public void actionPerformed (ActionEvent ae) {
  5412:         String command = ae.getActionCommand ();
  5413:         switch (command) {
  5414:         case "Not installed":
  5415:           specifiedCopro0 = (8 & specifiedCopro0) | 0;
  5416:           break;
  5417:         case "MC68881":
  5418:           specifiedCopro0 = (8 & specifiedCopro0) | 1;
  5419:           break;
  5420:         case "MC68882":
  5421:           specifiedCopro0 = (8 & specifiedCopro0) | 2;
  5422:           break;
  5423:         case "Full specification":
  5424:           specifiedCopro0 = (8 & specifiedCopro0) | 7;
  5425:           break;
  5426:         case "Extended precision (19 digits)":
  5427:           specifiedCopro0 = 0 | (7 & specifiedCopro0);
  5428:           break;
  5429:         case "Triple precision (24 digits)":
  5430:           specifiedCopro0 = 8 | (7 & specifiedCopro0);
  5431:           break;
  5432:         default:
  5433:           System.out.println ("unknown action command " + command);
  5434:         }
  5435:       }
  5436:     };
  5437:     //
  5438:     ActionListener copro1Listener = new ActionListener () {
  5439:       @Override public void actionPerformed (ActionEvent ae) {
  5440:         String command = ae.getActionCommand ();
  5441:         switch (command) {
  5442:         case "Not installed":
  5443:           specifiedCopro1 = (8 & specifiedCopro1) | 0;
  5444:           break;
  5445:         case "MC68881":
  5446:           specifiedCopro1 = (8 & specifiedCopro1) | 1;
  5447:           break;
  5448:         case "MC68882":
  5449:           specifiedCopro1 = (8 & specifiedCopro1) | 2;
  5450:           break;
  5451:         case "Full specification":
  5452:           specifiedCopro1 = (8 & specifiedCopro1) | 7;
  5453:           break;
  5454:         case "Extended precision (19 digits)":
  5455:           specifiedCopro1 = 0 | (7 & specifiedCopro1);
  5456:           break;
  5457:         case "Triple precision (24 digits)":
  5458:           specifiedCopro1 = 8 | (7 & specifiedCopro1);
  5459:           break;
  5460:         default:
  5461:           System.out.println ("unknown action command " + command);
  5462:         }
  5463:       }
  5464:     };
  5465:     //
  5466:     ActionListener copro2Listener = new ActionListener () {
  5467:       @Override public void actionPerformed (ActionEvent ae) {
  5468:         String command = ae.getActionCommand ();
  5469:         switch (command) {
  5470:         case "Not installed":
  5471:           specifiedCopro2 = (8 & specifiedCopro2) | 0;
  5472:           break;
  5473:         case "MC68881":
  5474:           specifiedCopro2 = (8 & specifiedCopro2) | 1;
  5475:           break;
  5476:         case "MC68882":
  5477:           specifiedCopro2 = (8 & specifiedCopro2) | 2;
  5478:           break;
  5479:         case "Full specification":
  5480:           specifiedCopro2 = (8 & specifiedCopro2) | 7;
  5481:           break;
  5482:         case "Extended precision (19 digits)":
  5483:           specifiedCopro2 = 0 | (7 & specifiedCopro2);
  5484:           break;
  5485:         case "Triple precision (24 digits)":
  5486:           specifiedCopro2 = 8 | (7 & specifiedCopro2);
  5487:           break;
  5488:         default:
  5489:           System.out.println ("unknown action command " + command);
  5490:         }
  5491:       }
  5492:     };
  5493:     //
  5494:     ActionListener onchipFPUListener = new ActionListener () {
  5495:       @Override public void actionPerformed (ActionEvent ae) {
  5496:         String command = ae.getActionCommand ();
  5497:         switch (command) {
  5498:         case "Not installed":
  5499:           specifiedOnchipFPU = (8 & specifiedOnchipFPU) | 0;
  5500:           break;
  5501:         case "MC68060":
  5502:           specifiedOnchipFPU = (8 & specifiedOnchipFPU) | 6;
  5503:           break;
  5504:         case "Full specification":
  5505:           specifiedOnchipFPU = (8 & specifiedOnchipFPU) | 7;
  5506:           break;
  5507:         case "Extended precision (19 digits)":
  5508:           specifiedOnchipFPU = 0 | (7 & specifiedOnchipFPU);
  5509:           break;
  5510:         case "Triple precision (24 digits)":
  5511:           specifiedOnchipFPU = 8 | (7 & specifiedOnchipFPU);
  5512:           break;
  5513:         default:
  5514:           System.out.println ("unknown action command " + command);
  5515:         }
  5516:       }
  5517:     };
  5518:     //
  5519:     ButtonGroup copro00Group = new ButtonGroup ();
  5520:     ButtonGroup copro01Group = new ButtonGroup ();
  5521:     ButtonGroup copro10Group = new ButtonGroup ();
  5522:     ButtonGroup copro11Group = new ButtonGroup ();
  5523:     ButtonGroup copro20Group = new ButtonGroup ();
  5524:     ButtonGroup copro21Group = new ButtonGroup ();
  5525:     ButtonGroup onchipFPU0Group = new ButtonGroup ();
  5526:     ButtonGroup onchipFPU1Group = new ButtonGroup ();
  5527:     //
  5528:     coproFPUMenu = Multilingual.mlnText (
  5529:       ComponentFactory.createMenu (
  5530:         "Coprocessor and on-chip FPU",
  5531:         //
  5532:         Multilingual.mlnText (
  5533:           ComponentFactory.createMenu (
  5534:             "Motherboard coprocessor",
  5535:             Multilingual.mlnText (
  5536:               ComponentFactory.createRadioButtonMenuItem (copro00Group, (7 & specifiedCopro0) == 0, "Not installed", copro0Listener),
  5537:               "ja", "なし"),
  5538:             ComponentFactory.createRadioButtonMenuItem (copro00Group, (7 & specifiedCopro0) == 1, "MC68881", copro0Listener),
  5539:             ComponentFactory.createRadioButtonMenuItem (copro00Group, (7 & specifiedCopro0) == 2, "MC68882", copro0Listener),
  5540:             Multilingual.mlnText (
  5541:               ComponentFactory.createRadioButtonMenuItem (copro00Group, (7 & specifiedCopro0) == 7, "Full specification", copro0Listener),
  5542:               "ja", "フルスペック"),
  5543:             ComponentFactory.createHorizontalSeparator (),
  5544:             Multilingual.mlnText (
  5545:               ComponentFactory.createRadioButtonMenuItem (copro01Group, (8 & specifiedCopro0) == 0, "Extended precision (19 digits)", copro0Listener),
  5546:               "ja", "拡張精度 (19 桁)"),
  5547:             Multilingual.mlnText (
  5548:               ComponentFactory.createRadioButtonMenuItem (copro01Group, (8 & specifiedCopro0) != 0, "Triple precision (24 digits)", copro0Listener),
  5549:               "ja", "三倍精度 (24 桁)")),
  5550:           "ja", "マザーボードコプロセッサ"),
  5551:         //
  5552:         Multilingual.mlnText (
  5553:           ComponentFactory.createMenu (
  5554:             "Extension coprocessor #1",
  5555:             Multilingual.mlnText (
  5556:               ComponentFactory.createRadioButtonMenuItem (copro10Group, (7 & specifiedCopro1) == 0, "Not installed", copro1Listener),
  5557:               "ja", "なし"),
  5558:             ComponentFactory.createRadioButtonMenuItem (copro10Group, (7 & specifiedCopro1) == 1, "MC68881", copro1Listener),
  5559:             ComponentFactory.createRadioButtonMenuItem (copro10Group, (7 & specifiedCopro1) == 2, "MC68882", copro1Listener),
  5560:             Multilingual.mlnText (
  5561:               ComponentFactory.createRadioButtonMenuItem (copro10Group, (7 & specifiedCopro1) == 7, "Full specification", copro1Listener),
  5562:               "ja", "フルスペック"),
  5563:             ComponentFactory.createHorizontalSeparator (),
  5564:             Multilingual.mlnText (
  5565:               ComponentFactory.createRadioButtonMenuItem (copro11Group, (8 & specifiedCopro1) == 0, "Extended precision (19 digits)", copro1Listener),
  5566:               "ja", "拡張精度 (19 桁)"),
  5567:             Multilingual.mlnText (
  5568:               ComponentFactory.createRadioButtonMenuItem (copro11Group, (8 & specifiedCopro1) != 0, "Triple precision (24 digits)", copro1Listener),
  5569:               "ja", "三倍精度 (24 桁)")),
  5570:           "ja", "拡張コプロセッサ #1"),
  5571:         //
  5572:         Multilingual.mlnText (
  5573:           ComponentFactory.createMenu (
  5574:             "Extension coprocessor #2",
  5575:             Multilingual.mlnText (
  5576:               ComponentFactory.createRadioButtonMenuItem (copro20Group, (7 & specifiedCopro2) == 0, "Not installed", copro2Listener),
  5577:               "ja", "なし"),
  5578:             ComponentFactory.createRadioButtonMenuItem (copro20Group, (7 & specifiedCopro2) == 1, "MC68881", copro2Listener),
  5579:             ComponentFactory.createRadioButtonMenuItem (copro20Group, (7 & specifiedCopro2) == 2, "MC68882", copro2Listener),
  5580:             Multilingual.mlnText (
  5581:               ComponentFactory.createRadioButtonMenuItem (copro20Group, (7 & specifiedCopro2) == 7, "Full specification", copro2Listener),
  5582:               "ja", "フルスペック"),
  5583:             ComponentFactory.createHorizontalSeparator (),
  5584:             Multilingual.mlnText (
  5585:               ComponentFactory.createRadioButtonMenuItem (copro21Group, (8 & specifiedCopro2) == 0, "Extended precision (19 digits)", copro2Listener),
  5586:               "ja", "拡張精度 (19 桁)"),
  5587:             Multilingual.mlnText (
  5588:               ComponentFactory.createRadioButtonMenuItem (copro21Group, (8 & specifiedCopro2) != 0, "Triple precision (24 digits)", copro2Listener),
  5589:               "ja", "三倍精度 (24 桁)")),
  5590:           "ja", "拡張コプロセッサ #2"),
  5591:         //
  5592:         Multilingual.mlnText (
  5593:           ComponentFactory.createMenu (
  5594:             "On-chip FPU",
  5595:             Multilingual.mlnText (
  5596:               ComponentFactory.createRadioButtonMenuItem (onchipFPU0Group, (7 & specifiedOnchipFPU) == 0, "Not installed", onchipFPUListener),
  5597:               "ja", "なし"),
  5598:             ComponentFactory.createRadioButtonMenuItem (onchipFPU0Group, (7 & specifiedOnchipFPU) == 6, "MC68060", onchipFPUListener),
  5599:             Multilingual.mlnText (
  5600:               ComponentFactory.createRadioButtonMenuItem (onchipFPU0Group, (7 & specifiedOnchipFPU) == 7, "Full specification", onchipFPUListener),
  5601:               "ja", "フルスペック"),
  5602:             ComponentFactory.createHorizontalSeparator (),
  5603:             Multilingual.mlnText (
  5604:               ComponentFactory.createRadioButtonMenuItem (onchipFPU1Group, (8 & specifiedOnchipFPU) == 0, "Extended precision (19 digits)", onchipFPUListener),
  5605:               "ja", "拡張精度 (19 桁)"),
  5606:             Multilingual.mlnText (
  5607:               ComponentFactory.createRadioButtonMenuItem (onchipFPU1Group, (8 & specifiedOnchipFPU) != 0, "Triple precision (24 digits)", onchipFPUListener),
  5608:               "ja", "三倍精度 (24 桁)")),
  5609:           "ja", "オンチップ FPU")),
  5610:       "ja", "コプロセッサとオンチップ FPU");
  5611: 
  5612:   }  //mdlMakeMenu
  5613: 
  5614:   public static void mdlRequestModel (Model model, int accelerator) {
  5615:     specifiedModel = model;
  5616:     specifiedAccelerator = accelerator;
  5617:     //MPU
  5618:     specifiedIsSecond = false;
  5619:     specifiedFirstMPU = specifiedModel.getMPU ();
  5620:     specifiedSecondMPU = Model.MPU_MC68EC030;
  5621:     specifiedMPU = specifiedIsSecond ? specifiedSecondMPU : specifiedFirstMPU;
  5622:     specifiedFirstClock = specifiedModel.getClock ();
  5623:     specifiedSecondClock = specifiedFirstClock * 2.0;
  5624:     specifiedClock = specifiedIsSecond ? specifiedSecondClock : specifiedFirstClock;
  5625:     //アクセラレータ
  5626:     switch (accelerator) {
  5627:     case ACCELERATOR_HYBRID:
  5628:       specifiedFirstClock = MHZ_HYBRID_VALUE;  //33.3MHz
  5629:       specifiedClock = specifiedIsSecond ? specifiedSecondClock : specifiedFirstClock;
  5630:       break;
  5631:     case ACCELERATOR_XELLENT30:
  5632:       break;
  5633:     case ACCELERATOR_060TURBO:
  5634:     case ACCELERATOR_060TURBOPRO:
  5635:       specifiedFirstMPU = Model.MPU_MC68060;
  5636:       specifiedFirstClock = MHZ_060TURBO_VALUE;
  5637:       specifiedClock = specifiedIsSecond ? specifiedSecondClock : specifiedFirstClock;
  5638:     }
  5639:     //任意の負荷率と任意の周波数を無効化
  5640:     mpuUtilOn = false;
  5641:     mpuArbFreqOn = false;
  5642:     mpuSetCurrentClock (specifiedClock);
  5643:     //機種を変更してリセットのラジオボタンをセット
  5644:     if (accelerator == ACCELERATOR_HYBRID) {
  5645:       mdlHybridMenuItem.setSelected (true);
  5646:     } else if (accelerator == ACCELERATOR_XELLENT30) {
  5647:       mdlXellent30MenuItem.setSelected (true);
  5648:     } else if (accelerator == ACCELERATOR_060TURBO) {
  5649:       mdl060turboMenuItem.setSelected (true);
  5650:     } else if (accelerator == ACCELERATOR_060TURBOPRO) {
  5651:       mdl060turboPROMenuItem.setSelected (true);
  5652:     } else if (specifiedModel == Model.SHODAI) {
  5653:       mdlShodaiMenuItem.setSelected (true);
  5654:     } else if (specifiedModel == Model.ACE) {
  5655:       mdlACEMenuItem.setSelected (true);
  5656:     } else if (specifiedModel == Model.EXPERT) {
  5657:       mdlEXPERTMenuItem.setSelected (true);
  5658:     } else if (specifiedModel == Model.PRO) {
  5659:       mdlPROMenuItem.setSelected (true);
  5660:     } else if (specifiedModel == Model.SUPER) {
  5661:       mdlSUPERMenuItem.setSelected (true);
  5662:     } else if (specifiedModel == Model.XVI) {
  5663:       mdlXVIMenuItem.setSelected (true);
  5664:     } else if (specifiedModel == Model.COMPACT) {
  5665:       mdlCompactMenuItem.setSelected (true);
  5666:     } else if (specifiedModel == Model.X68030) {
  5667:       mdlX68030MenuItem.setSelected (true);
  5668:     } else if (specifiedModel == Model.X68030COMPACT) {
  5669:       mdl030CompactMenuItem.setSelected (true);
  5670:     }
  5671:     //FPU
  5672:     //SCSI
  5673:     HDC.hdcSASIMenuItem.setSelected (!currentModel.isSCSI ());  //Built-in SASI
  5674:     SPC.spcSCSIINMenuItem.setSelected (currentModel.isSCSI ());  //Built-in SCSI
  5675:   }
  5676: 
  5677: 
  5678: 
  5679:   //========================================================================================
  5680:   //$$MPU MPU
  5681: 
  5682:   //コンパイルスイッチ
  5683:   public static final boolean MPU_INLINE_EXCEPTION = true;  //true=例外処理をインライン展開する。速くなる
  5684:   public static final boolean MPU_COMPOUND_POSTINCREMENT = false;  //true=(pc)+をbusRbs((pc+=2)-1),busRws((pc+=2)-2),busRls((pc+=4)-4)のように書く。見た目はスマートだが最適化しにくくなる?
  5685: 
  5686:   public static final boolean MPU_SWITCH_MISC_OPCODE = false;  //true=RTSなどのswitchのキーはオペコード全体,false=下位6bit
  5687:   public static final boolean MPU_SWITCH_BCC_CONDITION = false;  //true=オペコードのswitchでBccをccで分類する
  5688:   public static final boolean MPU_SWITCH_BCC_OFFSET = false;  //true=オペコードのswitchでBRA/BSR/Bccを8bitオフセットの上位2bitで分類する
  5689:   public static final boolean MPU_SWITCH_SCC_CONDITION = true;  //true=オペコードのswitchでScc/DBRA/DBcc/TRAPccをccで分類する
  5690: 
  5691:   public static final boolean MPU_OMIT_EXTRA_READ = false;  //true=余分なリードを省略する。MC68000のBRA.S/BSR.S/Bcc.S/CLR/SF
  5692:   public static final boolean MPU_OMIT_OFFSET_READ = false;  //true=条件分岐命令で分岐しないときオフセットのリードを省略する
  5693: 
  5694:   //TMR_FREQ単位のタイマカウンタで到達し得ない時刻を表す定数
  5695:   //  TMR_FREQ=10^12のとき到達するのに3.5ヶ月かかる
  5696:   //  3.5ヶ月間動かしっぱなしにすると破綻する
  5697:   public static final long FAR_FUTURE = 0x7fffffffffffffffL;
  5698: 
  5699:   //ステータスレジスタ
  5700:   //  トレース
  5701:   //     srT1    srT0
  5702:   //    0x0000  0x0000  トレースなし
  5703:   //    0x0000  0x4000  フローの変化をトレース
  5704:   //    0x8000  0x0000  すべての命令をトレース
  5705:   //    0x8000  0x4000  未定義
  5706:   public static final int REG_SR_T1  = 0b10000000_00000000;
  5707:   public static final int REG_SR_T0  = 0b01000000_00000000;  //(020/030/040)
  5708:   //  モード
  5709:   //      srS     srM
  5710:   //    0x0000  0x0000  ユーザモード(USPを使用)
  5711:   //    0x0000  0x1000  ユーザモード(USPを使用)
  5712:   //    0x2000  0x0000  スーパーバイザ割り込みモード(ISPを使用)
  5713:   //    0x2000  0x1000  スーパーバイザマスタモード(MSPを使用)
  5714:   public static final int REG_SR_S   = 0b00100000_00000000;
  5715:   public static final int REG_SR_M   = 0b00010000_00000000;  //(020/030/040/060)
  5716:   //  割り込み
  5717:   public static final int REG_SR_I   = 0b00000111_00000000;
  5718: 
  5719:   //コンディションコードレジスタ
  5720:   public static final int REG_CCR_X  = 0b00000000_00010000;
  5721:   public static final int REG_CCR_N  = 0b00000000_00001000;
  5722:   public static final int REG_CCR_Z  = 0b00000000_00000100;
  5723:   public static final int REG_CCR_V  = 0b00000000_00000010;
  5724:   public static final int REG_CCR_C  = 0b00000000_00000001;
  5725:   public static final int REG_CCR_MASK = REG_CCR_X | REG_CCR_N | REG_CCR_Z | REG_CCR_V | REG_CCR_C;  //CCRの有効なビット
  5726: 
  5727:   public static char[] REG_CCRXMAP = "00000000000000001111111111111111".toCharArray ();
  5728:   public static char[] REG_CCRNMAP = "00000000111111110000000011111111".toCharArray ();
  5729:   public static char[] REG_CCRZMAP = "00001111000011110000111100001111".toCharArray ();
  5730:   public static char[] REG_CCRVMAP = "00110011001100110011001100110011".toCharArray ();
  5731:   public static char[] REG_CCRCMAP = "01010101010101010101010101010101".toCharArray ();
  5732: 
  5733:   //割り込みレベル
  5734:   //  順序の変更やレベルの追加はコードの変更が必要
  5735:   public static final int MPU_IOI_INTERRUPT_LEVEL = 1;
  5736:   public static final int MPU_EB2_INTERRUPT_LEVEL = 2;
  5737:   public static final int MPU_DMA_INTERRUPT_LEVEL = 3;
  5738:   public static final int MPU_SCC_INTERRUPT_LEVEL = 5;
  5739:   public static final int MPU_MFP_INTERRUPT_LEVEL = 6;
  5740:   public static final int MPU_SYS_INTERRUPT_LEVEL = 7;
  5741:   public static final int MPU_IOI_INTERRUPT_MASK = 0x80 >> MPU_IOI_INTERRUPT_LEVEL;  //0x40
  5742:   public static final int MPU_EB2_INTERRUPT_MASK = 0x80 >> MPU_EB2_INTERRUPT_LEVEL;  //0x20
  5743:   public static final int MPU_DMA_INTERRUPT_MASK = 0x80 >> MPU_DMA_INTERRUPT_LEVEL;  //0x10
  5744:   public static final int MPU_SCC_INTERRUPT_MASK = 0x80 >> MPU_SCC_INTERRUPT_LEVEL;  //0x04
  5745:   public static final int MPU_MFP_INTERRUPT_MASK = 0x80 >> MPU_MFP_INTERRUPT_LEVEL;  //0x02
  5746:   public static final int MPU_SYS_INTERRUPT_MASK = 0x80 >> MPU_SYS_INTERRUPT_LEVEL;  //0x01
  5747: 
  5748:   public static final boolean MPU_INTERRUPT_SWITCH = true;  //true=最上位の割り込みをswitchで判別する
  5749: 
  5750:   //コンディションコード
  5751:   public static final boolean T = true;
  5752:   public static final boolean F = false;
  5753:   //  cccc==CCCC_cc                               cccc  cc
  5754:   public static final int CCCC_T  = 0b0000;  //0000  T       1                always true
  5755:   public static final int CCCC_F  = 0b0001;  //0001  F       0                always false
  5756:   public static final int CCCC_HI = 0b0010;  //0010  HI      ~C&~Z            high
  5757:   public static final int CCCC_LS = 0b0011;  //0011  LS      C|Z              low or same
  5758:   public static final int CCCC_CC = 0b0100;  //0100  CC(HS)  ~C               carry clear (high or same)
  5759:   public static final int CCCC_CS = 0b0101;  //0101  CS(LO)  C                carry set (low)
  5760:   public static final int CCCC_NE = 0b0110;  //0110  NE      ~Z               not equal
  5761:   public static final int CCCC_EQ = 0b0111;  //0111  EQ      Z                equal
  5762:   public static final int CCCC_VC = 0b1000;  //1000  VC      ~V               overflow clear
  5763:   public static final int CCCC_VS = 0b1001;  //1001  VS      V                overflow set
  5764:   public static final int CCCC_PL = 0b1010;  //1010  PL      ~N               plus
  5765:   public static final int CCCC_MI = 0b1011;  //1011  MI      N                minus
  5766:   public static final int CCCC_GE = 0b1100;  //1100  GE      N&V|~N&~V        greater or equal
  5767:   public static final int CCCC_LT = 0b1101;  //1101  LT      N&~V|~N&V        less than
  5768:   public static final int CCCC_GT = 0b1110;  //1110  GT      N&V&~Z|~N&~V&~Z  greater than
  5769:   public static final int CCCC_LE = 0b1111;  //1111  LE      Z|N&~V|~N&V      less or equal
  5770:   //F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //X
  5771:   //F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,T,F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,T,  //N
  5772:   //F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //Z
  5773:   //F,F,T,T,F,F,T,T,F,F,T,T,F,F,T,T,F,F,T,T,F,F,T,T,F,F,T,T,F,F,T,T,  //V
  5774:   //F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //C
  5775:   //  BCCMAP[CCCC_cc<<5|ccr]==trueならば条件成立
  5776:   public static final boolean[] BCCMAP = {
  5777:     T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //T       NF
  5778:     F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //F       NT
  5779:     T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //HI      NLS
  5780:     F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //LS      NHI
  5781:     T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,  //CC(HS)  NCS(NLO)
  5782:     F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //CS(LO)  NCC(NHS)
  5783:     T,T,T,T,F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,F,F,F,F,  //NE(NZ)  NEQ(NZE)
  5784:     F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //EQ(ZE)  NNE(NNZ)
  5785:     T,T,F,F,T,T,F,F,T,T,F,F,T,T,F,F,T,T,F,F,T,T,F,F,T,T,F,F,T,T,F,F,  //VC      NVS
  5786:     F,F,T,T,F,F,T,T,F,F,T,T,F,F,T,T,F,F,T,T,F,F,T,T,F,F,T,T,F,F,T,T,  //VS      NVC
  5787:     T,T,T,T,T,T,T,T,F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,T,F,F,F,F,F,F,F,F,  //PL      NMI
  5788:     F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,T,F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,T,  //MI      NPL
  5789:     T,T,F,F,T,T,F,F,F,F,T,T,F,F,T,T,T,T,F,F,T,T,F,F,F,F,T,T,F,F,T,T,  //GE      NLT
  5790:     F,F,T,T,F,F,T,T,T,T,F,F,T,T,F,F,F,F,T,T,F,F,T,T,T,T,F,F,T,T,F,F,  //LT      NGE
  5791:     T,T,F,F,F,F,F,F,F,F,T,T,F,F,F,F,T,T,F,F,F,F,F,F,F,F,T,T,F,F,F,F,  //GT      NLE
  5792:     F,F,T,T,T,T,T,T,T,T,F,F,T,T,T,T,F,F,T,T,T,T,T,T,T,T,F,F,T,T,T,T,  //LE      NGT
  5793:   };
  5794: 
  5795:   //  MPU_CCCMAP[cccc<<5|ccr]==(BCCMAP[cccc<<5|ccr]?'1':'0')
  5796:   public static final char[] MPU_CCCMAP = (
  5797:     "11111111111111111111111111111111" +
  5798:     "00000000000000000000000000000000" +
  5799:     "10100000101000001010000010100000" +
  5800:     "01011111010111110101111101011111" +
  5801:     "10101010101010101010101010101010" +
  5802:     "01010101010101010101010101010101" +
  5803:     "11110000111100001111000011110000" +
  5804:     "00001111000011110000111100001111" +
  5805:     "11001100110011001100110011001100" +
  5806:     "00110011001100110011001100110011" +
  5807:     "11111111000000001111111100000000" +
  5808:     "00000000111111110000000011111111" +
  5809:     "11001100001100111100110000110011" +
  5810:     "00110011110011000011001111001100" +
  5811:     "11000000001100001100000000110000" +
  5812:     "00111111110011110011111111001111").toCharArray ();
  5813: 
  5814:   //  (MPU_CC_cc<<ccr<0)==trueならば条件成立
  5815:   //  (MPU_CC_cc<<ccr<0)==BCCMAP[CCCC_cc<<5|ccr]
  5816:   public static final int MPU_CC_T  = 0b11111111111111111111111111111111;  //T
  5817:   public static final int MPU_CC_F  = 0b00000000000000000000000000000000;  //F
  5818:   public static final int MPU_CC_HI = 0b10100000101000001010000010100000;  //HI
  5819:   public static final int MPU_CC_LS = 0b01011111010111110101111101011111;  //LS
  5820:   public static final int MPU_CC_HS = 0b10101010101010101010101010101010;  //HS
  5821:   public static final int MPU_CC_LO = 0b01010101010101010101010101010101;  //LO
  5822:   public static final int MPU_CC_NE = 0b11110000111100001111000011110000;  //NE
  5823:   public static final int MPU_CC_EQ = 0b00001111000011110000111100001111;  //EQ
  5824:   public static final int MPU_CC_VC = 0b11001100110011001100110011001100;  //VC
  5825:   public static final int MPU_CC_VS = 0b00110011001100110011001100110011;  //VS
  5826:   public static final int MPU_CC_PL = 0b11111111000000001111111100000000;  //PL
  5827:   public static final int MPU_CC_MI = 0b00000000111111110000000011111111;  //MI
  5828:   public static final int MPU_CC_GE = 0b11001100001100111100110000110011;  //GE
  5829:   public static final int MPU_CC_LT = 0b00110011110011000011001111001100;  //LT
  5830:   public static final int MPU_CC_GT = 0b11000000001100001100000000110000;  //GT
  5831:   public static final int MPU_CC_LE = 0b00111111110011110011111111001111;  //LE
  5832: 
  5833:   //TST.Bのテーブル
  5834:   //  z=255&(~);ccr=ccr&CCR_X|MPU_TSTB_TABLE[z]をz=~;ccr=ccr&CCR_X|MPU_TSTB_TABLE[255&z]にすると速くなることがある
  5835:   //  インデックスが明示的にマスクされていると最適化しやすいのだろう
  5836: /*
  5837:   public static final byte[] MPU_TSTB_TABLE = new byte[256];
  5838:   static {
  5839:     for (int z = 0; z < 256; z++) {
  5840:       MPU_TSTB_TABLE[z] = (byte) (z >> 7 << 3 | z - 1 >> 6 & CCR_Z);
  5841:     }
  5842:   }  //static
  5843: */
  5844: /*
  5845:   public static final byte[] MPU_TSTB_TABLE = {
  5846:     REG_CCR_Z, 0,         0,         0,         0,         0,         0,         0,
  5847:     0,         0,         0,         0,         0,         0,         0,         0,
  5848:     0,         0,         0,         0,         0,         0,         0,         0,
  5849:     0,         0,         0,         0,         0,         0,         0,         0,
  5850:     0,         0,         0,         0,         0,         0,         0,         0,
  5851:     0,         0,         0,         0,         0,         0,         0,         0,
  5852:     0,         0,         0,         0,         0,         0,         0,         0,
  5853:     0,         0,         0,         0,         0,         0,         0,         0,
  5854:     0,         0,         0,         0,         0,         0,         0,         0,
  5855:     0,         0,         0,         0,         0,         0,         0,         0,
  5856:     0,         0,         0,         0,         0,         0,         0,         0,
  5857:     0,         0,         0,         0,         0,         0,         0,         0,
  5858:     0,         0,         0,         0,         0,         0,         0,         0,
  5859:     0,         0,         0,         0,         0,         0,         0,         0,
  5860:     0,         0,         0,         0,         0,         0,         0,         0,
  5861:     0,         0,         0,         0,         0,         0,         0,         0,
  5862:     REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N,
  5863:     REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N,
  5864:     REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N,
  5865:     REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N,
  5866:     REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N,
  5867:     REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N,
  5868:     REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N,
  5869:     REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N,
  5870:     REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N,
  5871:     REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N,
  5872:     REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N,
  5873:     REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N,
  5874:     REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N,
  5875:     REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N,
  5876:     REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N,
  5877:     REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N, REG_CCR_N,
  5878:   };
  5879: */
  5880:   //  perl misc/itob.pl xeij/XEiJ.java MPU_TSTB_TABLE
  5881:   public static final byte[] MPU_TSTB_TABLE = "\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b".getBytes (XEiJ.ISO_8859_1);
  5882: 
  5883:   //BITREVのテーブル
  5884:   //  初期化コードが大きくなりすぎるので最初から展開しておくにはクラスを分ける必要がある
  5885:   public static final int[] MPU_BITREV_TABLE_0 = new int[2048];
  5886:   public static final int[] MPU_BITREV_TABLE_1 = new int[2048];
  5887:   public static final int[] MPU_BITREV_TABLE_2 = new int[2048];
  5888:   static {
  5889:     for (int i = 0; i < 2048; i++) {
  5890:       MPU_BITREV_TABLE_2[i] = (MPU_BITREV_TABLE_1[i] = (MPU_BITREV_TABLE_0[i] = Integer.reverse (i)) >>> 11) >>> 11;
  5891:     }
  5892:   }
  5893: 
  5894:   //アドレッシングモード
  5895:   //                                                              data  memory  control  alterable
  5896:   public static final int EA_DR = 0b000_000;  //D  Dr             x                      x
  5897:   public static final int EA_AR = 0b001_000;  //A  Ar                                    x
  5898:   public static final int EA_MM = 0b010_000;  //M  (Ar)           x     x       x        x
  5899:   public static final int EA_MP = 0b011_000;  //+  (Ar)+          x     x                x
  5900:   public static final int EA_MN = 0b100_000;  //-  -(Ar)          x     x                x
  5901:   public static final int EA_MW = 0b101_000;  //W  (d16,Ar)       x     x       x        x
  5902:   public static final int EA_MX = 0b110_000;  //X  (d8,Ar,Rn.wl)  x     x       x        x
  5903:   public static final int EA_ZW = 0b111_000;  //Z  (xxx).W        x     x       x        x
  5904:   public static final int EA_ZL = 0b111_001;  //Z  (xxx).L        x     x       x        x
  5905:   public static final int EA_PW = 0b111_010;  //P  (d16,PC)       x     x       x
  5906:   public static final int EA_PX = 0b111_011;  //P  (d8,PC,Rn.wl)  x     x       x
  5907:   public static final int EA_IM = 0b111_100;  //I  #<data>        x
  5908:   public static final int MMM_DR = EA_DR >> 3;
  5909:   public static final int MMM_AR = EA_AR >> 3;
  5910:   public static final int MMM_MM = EA_MM >> 3;
  5911:   public static final int MMM_MP = EA_MP >> 3;
  5912:   public static final int MMM_MN = EA_MN >> 3;
  5913:   public static final int MMM_MW = EA_MW >> 3;
  5914:   public static final int MMM_MX = EA_MX >> 3;
  5915:   public static final long EAM_DR = 0xff00000000000000L >>> EA_DR;
  5916:   public static final long EAM_AR = 0xff00000000000000L >>> EA_AR;
  5917:   public static final long EAM_MM = 0xff00000000000000L >>> EA_MM;
  5918:   public static final long EAM_MP = 0xff00000000000000L >>> EA_MP;
  5919:   public static final long EAM_MN = 0xff00000000000000L >>> EA_MN;
  5920:   public static final long EAM_MW = 0xff00000000000000L >>> EA_MW;
  5921:   public static final long EAM_MX = 0xff00000000000000L >>> EA_MX;
  5922:   public static final long EAM_ZW = 0x8000000000000000L >>> EA_ZW;
  5923:   public static final long EAM_ZL = 0x8000000000000000L >>> EA_ZL;
  5924:   public static final long EAM_PW = 0x8000000000000000L >>> EA_PW;
  5925:   public static final long EAM_PX = 0x8000000000000000L >>> EA_PX;
  5926:   public static final long EAM_IM = 0x8000000000000000L >>> EA_IM;
  5927:   public static final long EAM_ALL = EAM_DR|EAM_AR|EAM_MM|EAM_MP|EAM_MN|EAM_MW|EAM_MX|EAM_ZW|EAM_ZL|EAM_PW|EAM_PX|EAM_IM;  //|DAM+-WXZPI|すべて
  5928:   public static final long EAM_ALT = EAM_DR|EAM_AR|EAM_MM|EAM_MP|EAM_MN|EAM_MW|EAM_MX|EAM_ZW|EAM_ZL                     ;  //|DAM+-WXZ  |可変
  5929:   public static final long EAM_DAT = EAM_DR       |EAM_MM|EAM_MP|EAM_MN|EAM_MW|EAM_MX|EAM_ZW|EAM_ZL|EAM_PW|EAM_PX|EAM_IM;  //|D M+-WXZPI|データ
  5930:   public static final long EAM_DME = EAM_DR       |EAM_MM|EAM_MP|EAM_MN|EAM_MW|EAM_MX|EAM_ZW|EAM_ZL|EAM_PW|EAM_PX       ;  //|D M+-WXZP |データレジスタ直接またはメモリ
  5931:   public static final long EAM_DLT = EAM_DR       |EAM_MM|EAM_MP|EAM_MN|EAM_MW|EAM_MX|EAM_ZW|EAM_ZL                     ;  //|D M+-WXZ  |データ可変
  5932:   public static final long EAM_DCN = EAM_DR       |EAM_MM              |EAM_MW|EAM_MX|EAM_ZW|EAM_ZL|EAM_PW|EAM_PX       ;  //|D M  WXZP |データレジスタ直接または制御
  5933:   public static final long EAM_DCL = EAM_DR       |EAM_MM              |EAM_MW|EAM_MX|EAM_ZW|EAM_ZL                     ;  //|D M  WXZ  |データレジスタ直接または制御可変
  5934:   public static final long EAM_ANY =               EAM_MM|EAM_MP|EAM_MN|EAM_MW|EAM_MX|EAM_ZW|EAM_ZL|EAM_PW|EAM_PX|EAM_IM;  //|  M+-WXZPI|レジスタ以外
  5935:   public static final long EAM_MEM =               EAM_MM|EAM_MP|EAM_MN|EAM_MW|EAM_MX|EAM_ZW|EAM_ZL|EAM_PW|EAM_PX       ;  //|  M+-WXZP |メモリ
  5936:   public static final long EAM_MLT =               EAM_MM|EAM_MP|EAM_MN|EAM_MW|EAM_MX|EAM_ZW|EAM_ZL                     ;  //|  M+-WXZ  |メモリ可変
  5937:   public static final long EAM_RDL =               EAM_MM|EAM_MP       |EAM_MW|EAM_MX|EAM_ZW|EAM_ZL|EAM_PW|EAM_PX       ;  //|  M+ WXZP |リードリスト
  5938:   public static final long EAM_WTL =               EAM_MM       |EAM_MN|EAM_MW|EAM_MX|EAM_ZW|EAM_ZL                     ;  //|  M -WXZ  |ライトリスト
  5939:   public static final long EAM_CNT =               EAM_MM              |EAM_MW|EAM_MX|EAM_ZW|EAM_ZL|EAM_PW|EAM_PX       ;  //|  M  WXZP |制御
  5940:   public static final long EAM_CLT =               EAM_MM              |EAM_MW|EAM_MX|EAM_ZW|EAM_ZL                     ;  //|  M  WXZ  |制御可変
  5941: 
  5942:   //汎用レジスタ
  5943:   //  r[15]は現在のスタックポインタ
  5944:   //                              ユーザモード      スーパーバイザモード
  5945:   //                                            マスタモード  割り込みモード
  5946:   //     ユーザスタックポインタ     regRn[15]       mpuUSP         mpuUSP
  5947:   //     マスタスタックポインタ      mpuMSP       regRn[15]        mpuMSP
  5948:   //    割り込みスタックポインタ     mpuISP        mpuISP        regRn[15]
  5949:   //  モードによってmpuUSP,mpuMSP,mpuISPのいずれかをregRn[15]にコピーして使う
  5950:   //  他のモードに切り替えるときはregRn[15]をコピー元のmpuUSP,mpuMSP,mpuISPのいずれかに書き戻してから切り替える
  5951:   //  例えばユーザモードから割り込みモードへ移行するときはregRn[15]→mpuUSP,mpuISP→regRn[15]とする
  5952:   public static final int[] regRn = new int[16 + 1];  //汎用レジスタ。regRn[16]はテンポラリ。レジスタの更新を回避するとき条件分岐する代わりにregRn[16]に書き込む
  5953: 
  5954:   //プログラムカウンタ
  5955:   public static int regPC;  //プログラムカウンタ
  5956:   public static int regPC0;  //実行中の命令の先頭アドレス
  5957: 
  5958:   //オペコードレジスタ
  5959:   public static int regOC;  //オペコード。16bit、0拡張
  5960: 
  5961:   //ステータスレジスタ
  5962:   public static int regSRT1;  //ステータスレジスタのT1。0=トレースなし,REG_SR_T1=すべての命令をトレース
  5963:   public static int regSRT0;  //ステータスレジスタのT0(020/030/040)。0=トレースなし,REG_SR_T0=フローの変化をトレース
  5964:   public static int mpuTraceFlag;  //トレースフラグ。命令実行前にregSRT1をコピーし、分岐命令を実行するときregSRT0をorする。例外が発生したとき0にする。命令実行後に0でなければトレース例外を発動する
  5965:   public static int regSRS;  //ステータスレジスタのS。0=ユーザモード,REG_SR_S=スーパーバイザモード
  5966:   public static int regSRM;  //ステータスレジスタのM(020/030/040/060)。0=割り込みモード,REG_SR_M=マスタモード。割り込みを開始するときクリアされる
  5967:   public static int regSRI;  //ステータスレジスタのI2,I1,I0
  5968: 
  5969:   //コンディションコードレジスタ
  5970:   public static int regCCR;  //コンディションコードレジスタ。000XNZVC。0のビットは0に固定
  5971: 
  5972:   //mpuIMR
  5973:   //  インタラプトマスクレジスタ
  5974:   //  ビットの並び順は01234567
  5975:   //  現在の割り込みマスクレベルよりも高いビットをセットしたマスク
  5976:   //    割り込みマスクレベルがnのときレベル1..nの割り込みが禁止されてレベルn+1..7の割り込みが許可される
  5977:   //    ただし、割り込みマスクレベルが7のときはレベル7割り込みの処理中でなければレベル7割り込みが許可される
  5978:   //  mpuIMR&mpuIRRで最下位の1のビットの割り込みを受け付ける
  5979:   //  irpSetSRでmpuIMR&mpuISRで1のビットの割り込みを終了する
  5980:   //  mpuIMR=0x7f>>(srI>>8)|~mpuISR&1
  5981:   //      srI     mpuIMR    受け付ける割り込みのレベルと順序
  5982:   //    0x0700  0b00000000  なし  レベル7割り込みの処理中のとき
  5983:   //            0b00000001  7     レベル7割り込みの処理中ではないとき
  5984:   //    0x0600  0b00000001  7
  5985:   //    0x0500  0b00000011  7 6
  5986:   //    0x0400  0b00000111  7 6 5
  5987:   //    0x0300  0b00001111  7 6 5 4
  5988:   //    0x0200  0b00011111  7 6 5 4 3
  5989:   //    0x0100  0b00111111  7 6 5 4 3 2
  5990:   //    0x0000  0b01111111  7 6 5 4 3 2 1
  5991:   public static int mpuIMR;
  5992: 
  5993:   //mpuIRR
  5994:   //  インタラプトリクエストレジスタ
  5995:   //  ビットの並び順は01234567
  5996:   //  デバイスが割り込みを要求するときレベルに対応するビットをセットする
  5997:   //  コアが割り込みを受け付けるときレベルに対応するビットをクリアしてデバイスのacknowledge()を呼び出す
  5998:   public static int mpuIRR;
  5999:   public static int mpuDIRR;  //遅延割り込み要求
  6000: 
  6001:   //mpuISR
  6002:   //  インタラプトインサービスレジスタ
  6003:   //  ビットの並び順は01234567
  6004:   //  コアが割り込み処理を開始するときレベルに対応するビットをセットする
  6005:   //  割り込みマスクレベルが下がったとき新しいレベルよりも高いレベルの割り込み処理が終了したものとみなし、
  6006:   //  レベルに対応するビットをクリアしてデバイスのdone()を呼び出す
  6007:   //  done()が呼び出された時点でまだ処理されていない割り込みが残っているデバイスは再度割り込みを要求する
  6008:   public static int mpuISR;
  6009: 
  6010:   //制御レジスタ
  6011:   public static int mpuSFC;    //000  -12346  SFC
  6012:   public static int mpuDFC;    //001  -12346  DFC
  6013:   public static int mpuCACR;   //002  --2346  CACR
  6014:   //protected static int mpuTC;     //003  ----46  TC                        030MMUのTC
  6015:   //protected static int mpuITT0;   //004  ----46  ITT0   IACR0 @ MC68EC040  030MMUのTT0
  6016:   //protected static int mpuITT1;   //005  ----46  ITT1   IACR1 @ MC68EC040  030MMUのTT1
  6017:   //protected static int mpuDTT0;   //006  ----46  DTT0   DACR0 @ MC68EC040
  6018:   //protected static int mpuDTT1;   //007  ----46  DTT1   DACR1 @ MC68EC040
  6019:   public static int mpuBUSCR;  //008  -----6  BUSCR
  6020:   public static int mpuUSP;    //800  -12346  USP    隠れたユーザスタックポインタ。ユーザモードのときはr[15]を参照すること
  6021:   public static int mpuVBR;    //801  -12346  VBR    ベクタベースレジスタ
  6022:   public static int mpuCAAR;   //802  --23--  CAAR
  6023:   public static int mpuMSP;    //803  --234-  MSP    隠れたマスタスタックポインタ。マスタモードのときはr[15]を参照すること
  6024:   public static int mpuISP;    //804  --234-  ISP    隠れた割り込みスタックポインタ。割り込みモードのときはr[15]を参照すること
  6025:   //protected static int mpuMMUSR;  //805  ----4-  MMUSR                     030MMUのMMUSR
  6026:   //protected static int mpuURP;    //806  ----46  URP                       030MMUのCRPの下位32bit
  6027:   //protected static int mpuSRP;    //807  ----46  SRP                       030MMUのSRPの下位32bit
  6028:   public static int mpuPCR;    //808  -----6  PCR
  6029:   //protected static int mpuHCRP;   //                                       030MMUのCRPの上位32bit
  6030:   //protected static int mpuHSRP;   //                                       030MMUのSRPの上位32bit
  6031: 
  6032:   public static final int MPU_060_REV = 7;  //MC68060のリビジョンナンバー。1=F43G,5=G65V,6=E41J
  6033: 
  6034:   //クロック
  6035:   //  時刻は開始からの経過時間
  6036:   public static long mpuClockTime;  //時刻(TMR_FREQ単位)
  6037:   public static long mpuClockLimit;  //タスクの終了時刻
  6038:   public static double mpuClockMHz;  //動作周波数の設定値(MHz)
  6039:   public static double mpuCurrentMHz;  //動作周波数の現在値(MHz)
  6040:   public static int mpuCycleCount;  //命令のサイクル数。実行アドレス計算のサイクル数を含む
  6041:   public static long mpuCycleUnit;  //周波数の表示に使用する1サイクルあたりの時間(TMR_FREQ単位)
  6042:   public static long mpuModifiedUnit;  //mpuCycleCountの1サイクルあたりの時間(TMR_FREQ単位)。MC68030のときmpuCycleUnit*3/5
  6043:   public static long dmaCycleUnit;  //DMAの1サイクルの時間(TMR_FREQ単位)
  6044: 
  6045:   //タイマ
  6046:   //  mpuTaskはコアをスケジュールしなおすときに毎回作り直す
  6047:   public static TimerTask mpuTask;  //null=停止中。null以外=動作中
  6048: 
  6049:   //その他
  6050:   public static int mpuBootDevice;  //起動デバイス。-1=指定なし
  6051:   public static int mpuROMBootHandle;  //ROM起動ハンドル。-1=指定なし
  6052:   public static int mpuSavedBootDevice;  //保存されている起動デバイス。-1=保存されていない
  6053:   public static int mpuSavedROMBootHandle;  //保存されているROM起動ハンドル。-1=保存されていない
  6054: 
  6055:   //コア
  6056:   public static boolean mpuIgnoreAddressError;  //true=アドレスエラーを無視する
  6057: 
  6058:   //ウェイトサイクル
  6059:   public static int mpuROMWaitCycles;  //MPUからROMにアクセスしたときのウェイトのサイクル数。X68000は1。X68030は$00E8E009の上位4bit+2
  6060:   public static int mpuRAMWaitCycles;  //MPUからRAMにアクセスしたときのウェイトのサイクル数。X68000は0。X68030は$00E8E009の下位4bit+2ただし0は0
  6061:   public static boolean mpuCacheOn;  //true=キャッシュON。MPUからRAMとROMにアクセスしたときのウェイトを0にすることで擬似的にキャッシュが効いているように見せる
  6062:   public static final class WaitTime {
  6063:     public long ram;
  6064:     public long gvram;
  6065:     public long tvram;
  6066:     public long crtc;
  6067:     public long palet;
  6068:     public long vicon;
  6069:     public long dmac;
  6070:     public long mfp;
  6071:     public long rtc;
  6072:     public long prnport;
  6073:     public long sysport;
  6074:     public long opm;
  6075:     public long adpcm;
  6076:     public long fdc;
  6077:     public long fdd;
  6078:     public long hdc;
  6079:     public long scc;
  6080:     public long ppi;
  6081:     public long ioi;
  6082:     public long sprc;
  6083:     public long sram;
  6084:     public long rom;
  6085:     public long ramlong;
  6086:     public long romlong;
  6087:     public boolean isDma;
  6088:     public WaitTime (boolean isDma) {
  6089:       this.isDma = isDma;
  6090:     }
  6091:   }
  6092:   public static final WaitTime mpuNoWaitTime = new WaitTime (false);  //MPUウェイトなし
  6093:   public static final WaitTime dmaNoWaitTime = new WaitTime (true);  //DMACウェイトなし
  6094:   public static final WaitTime mpuWaitTime = new WaitTime (false);  //現在のMPUのウェイト
  6095:   public static final WaitTime dmaWaitTime = new WaitTime (true);  //現在のDMACのウェイト
  6096:   public static boolean busWaitCyclesRequest;
  6097:   public static boolean busWaitCycles;  //true=ウェイトサイクルなし。mpuNoWaitTime/dmaNoWaitTimeを使う,false=ウェイトあり。mpuWaitTime/dmaWaitTimeを使う
  6098:   public static WaitTime busWaitTime;  //busWaitCycles?mpuWaitTime:mpuNoWaitTimeまたはbusWaitCycles?dmaWaitTime:dmaNoWaitTime
  6099: 
  6100:   //任意の周波数の指定
  6101:   public static boolean mpuArbFreqOn;  //true=任意の周波数の指定がある。mpuArbFreqOn&&mpuUtilOnは不可
  6102:   public static int mpuArbFreqMHz;  //任意の周波数の指定(MHz)。1~1000
  6103:   public static SpinnerNumberModel mpuArbFreqModel;
  6104:   public static JSpinner mpuArbFreqSpinner;
  6105:   public static JRadioButtonMenuItem mpuArbFreqRadioButtonMenuItem;
  6106: 
  6107:   //任意の負荷率の指定
  6108:   public static boolean mpuUtilOn;  //true=任意の負荷率の指定がある。mpuArbFreqOn&&mpuUtilOnは不可
  6109:   public static int mpuUtilRatio;  //任意の負荷率の指定(%)。1~100
  6110:   public static SpinnerNumberModel mpuUtilModel;
  6111:   public static JSpinner mpuUtilSpinner;
  6112:   public static JRadioButtonMenuItem mpuUtilRadioButtonMenuItem;
  6113: 
  6114:   //周波数と負荷率の調整
  6115:   public static final int MPU_ADJUSTMENT_INTERVAL = 100;  //間隔。TMR_INTERVAL*MPU_ADJUSTMENT_INTERVAL毎に表示する
  6116:   public static int mpuAdjustmentCounter;
  6117:   public static long mpuTotalNano;  //コアのスレッドの動作時間(ns)。本来の動作時間の1/10ならば負荷率10%
  6118:   public static long mpuLastNano;  //前回の時刻(ns)
  6119:   public static double mpuCoreNano1;
  6120:   public static double mpuCoreNano2;
  6121: 
  6122:   //メニュー
  6123:   public static JMenu mpuMenu;
  6124:   public static JMenuItem mpuResetMenuItem;
  6125:   public static JMenuItem mpuOpt1ResetMenuItem;
  6126:   public static JRadioButtonMenuItem mpuClock10MenuItem;
  6127:   public static JRadioButtonMenuItem mpuClock16MenuItem;
  6128:   public static JRadioButtonMenuItem mpuClock25MenuItem;
  6129:   public static JRadioButtonMenuItem mpuClock33MenuItem;
  6130:   public static JRadioButtonMenuItem mpuClock50MenuItem;
  6131:   public static JRadioButtonMenuItem mpuClock66MenuItem;
  6132:   public static JRadioButtonMenuItem mpuClock75MenuItem;
  6133:   public static JRadioButtonMenuItem mpuClock100MenuItem;
  6134: 
  6135:   //デバッグ
  6136:   public static ActionListener mpuDebugActionListener;  //デバッグアクションリスナー
  6137:   public static ArrayList<AbstractButton> mpuButtonsRunning;  //MPUが動作中のときだけ有効なボタン
  6138:   public static ArrayList<AbstractButton> mpuButtonsStopped;  //MPUが停止中のときだけ有効なボタン
  6139:   public static ArrayList<JCheckBox> mpuOriIllegalCheckBoxList;  //ORI.B #$00,D0を不当命令とみなすチェックボックスのリスト
  6140:   public static ArrayList<JCheckBox> mpuStopOnErrorCheckBoxList;  //エラーで停止するチェックボックスのリスト
  6141:   public static ArrayList<JCheckBox> mpuStopAtStartCheckBoxList;  //実行開始位置で停止するチェックボックスのリスト
  6142: 
  6143:   public static int mpuAdvanceCount;  //トレース実行のカウンタ。0以外=トレース実行中
  6144:   public static int mpuStepCount;  //ステップ実行のカウンタ。1以上=ステップ実行中。-1=ステップアンティルリターン実行中
  6145:   public static boolean mpuContinue;  //自然に終了したときは変化しない。インスタント命令ブレークポイントで停止したときはtrue、それ以外で停止したときはfalse
  6146:   public static int mpuUntilReturnSRS;  //ステップアンティルリターン開始時のregSRS
  6147:   public static int mpuUntilReturnRP;  //ステップアンティルリターン開始時のmmuSRPまたはmmuURP
  6148:   public static int mpuUntilReturnPC0;  //ステップアンティルリターン開始時のregPC0
  6149:   public static int mpuUntilReturnSP;  //ステップアンティルリターン開始時のregRn[15]
  6150: 
  6151:   //SX-Window ver3.1のバグ対策
  6152:   //
  6153:   //  無償公開されたSXWIN311.XDFから起動したときリソースファイルから読み込まれるコードに問題がある
  6154:   //  マウスカーソルが指しているメニューの項目の番号を返すサブルーチンでd1レジスタの上位ワードが不定のままdivu.w #$0010,d1を実行している
  6155:   //  このサブルーチンの引数ではないd1レジスタの上位ワードを0にしてから呼び出さないとメニューを選択できない
  6156:   //  実機で露見しないのは直前に呼び出されるサブルーチンが使っているmovem.w <ea>,<list>命令がd1レジスタの上位ワードをほぼ0にしているため
  6157:   //  XEiJで露見したのはこの命令の処理が間違っていてd1レジスタが符号拡張されず上位ワードが0になっていなかったため
  6158:   //
  6159:   //  問題のサブルーチン
  6160:   //    00BFCC74  48E77000              movem.l d1-d3,-(sp)                 H輛.
  6161:   //    00BFCC78  2600                  move.l  d0,d3                       &.
  6162:   //    00BFCC7A  2F00                  move.l  d0,-(sp)                    /.
  6163:   //    00BFCC7C  486DFF80              pea.l   $FF80(a5)                   Hm..
  6164:   //    00BFCC80  A156                  SXCALL  __GMPtInRect                。V
  6165:   //    00BFCC82  508F                  addq.l  #$08,sp                     P夙
  6166:   //    00BFCC84  6738                  beq.s   $00BFCCBE                   g8
  6167:   //    00BFCC86  2003                  move.l  d3,d0                        .
  6168:   //    00BFCC88  3200                  move.w  d0,d1                       2.
  6169:   //    00BFCC8A  4840                  swap.w  d0                          H@
  6170:   //    00BFCC8C  906DFF80              sub.w   $FF80(a5),d0                仁..
  6171:   //    00BFCC90  6B2C                  bmi.s   $00BFCCBE                   k,
  6172:   //    00BFCC92  B06DFF92              cmp.w   $FF92(a5),d0                ーm.地
  6173:   //    00BFCC96  6E26                  bgt.s   $00BFCCBE                   n&
  6174:   //    00BFCC98  926DFF82              sub.w   $FF82(a5),d1                知.L
  6175:   //    00BFCC9C  6B20                  bmi.s   $00BFCCBE                   k 
  6176:   //    00BFCC9E  342DFF9C              move.w  $FF9C(a5),d2                4-.愼
  6177:   //    00BFCCA2  C4FC0010              mulu.w  #$0010,d2                   ト...
  6178:   //    00BFCCA6  B242                  cmp.w   d2,d1                       イB
  6179:   //    00BFCCA8  6E14                  bgt.s   $00BFCCBE                   n.
  6180:   //    00BFCCAA  82FC0010              divu.w  #$0010,d1                   ※..    ←d1レジスタの上位ワードが不定のままdivu.wを実行している
  6181:   //    00BFCCAE  3001                  move.w  d1,d0                       0.
  6182:   //    00BFCCB0  4841                  swap.w  d1                          HA
  6183:   //    00BFCCB2  4A41                  tst.w   d1                          JA
  6184:   //    00BFCCB4  6702                  beq.s   $00BFCCB8                   g.
  6185:   //    00BFCCB6  5240                  addq.w  #$01,d0                     R@
  6186:   //    00BFCCB8  4CDF000E              movem.l (sp)+,d1-d3                 L゚..
  6187:   //    00BFCCBC  4E75                  rts                                 Nu
  6188:   //    00BFCCBE  7000                  moveq.l #$00,d0                     p.
  6189:   //    00BFCCC0  60F6                  bra.s   $00BFCCB8                   `.
  6190:   //
  6191:   //  問題のサブルーチンの呼び出し元
  6192:   //    00BFC9D6  4E56FFF0              link.w  a6,#$FFF0                   NV..
  6193:   //    00BFC9DA  6100FEF4              bsr.w   $00BFC8D0                   a...    ←直前に呼び出されるサブルーチン
  6194:   //    00BFC9DE  202C000A              move.l  $000A(a4),d0                 ,..
  6195:   //    00BFC9E2  61000290              bsr.w   $00BFCC74                   a...    ←問題のサブルーチン
  6196:   //    00BFC9E6  3200                  move.w  d0,d1                       2.
  6197:   //    00BFC9E8  3600                  move.w  d0,d3                       6.
  6198:   //    (以下略)
  6199:   //
  6200:   //  直前に呼び出されるサブルーチン
  6201:   //    00BFC8D0  426DFFA2              clr.w   $FFA2(a5)                   Bm.「
  6202:   //    00BFC8D4  206C0006              movea.l $0006(a4),a0                 l..
  6203:   //    00BFC8D8  4C90000F              movem.w (a0),d0-d3                  L...
  6204:   //    00BFC8DC  5240                  addq.w  #$01,d0                     R@
  6205:   //    00BFC8DE  5241                  addq.w  #$01,d1                     RA
  6206:   //    00BFC8E0  5342                  subq.w  #$01,d2                     SB
  6207:   //    00BFC8E2  5343                  subq.w  #$01,d3                     SC
  6208:   //    00BFC8E4  48AD000FFF80          movem.w d0-d3,$FF80(a5)             0/0
  6209:   //    00BFC8EA  206C0002              movea.l $0002(a4),a0                 l..
  6210:   //    00BFC8EE  2050                  movea.l (a0),a0                      P
  6211:   //    00BFC8F0  30280012              move.w  $0012(a0),d0                0(..
  6212:   //    00BFC8F4  5240                  addq.w  #$01,d0                     R@
  6213:   //    00BFC8F6  3B40FF90              move.w  d0,$FF90(a5)                ;@.食
  6214:   //    00BFC8FA  486DFFA4              pea.l   $FFA4(a5)                   Hm.、
  6215:   //    00BFC8FE  A432                  SXCALL  __SXGetDispRect             、2
  6216:   //    00BFC900  588F                  addq.l  #$04,sp                     X臭
  6217:   //    00BFC902  4CAD000FFFA4          movem.w $FFA4(a5),d0-d3             Lュ...、  ←ここでd1レジスタの上位ワードがほぼ0になる
  6218:   //    00BFC908  9641                  sub.w   d1,d3                       泡
  6219:   //    00BFC90A  48C3                  ext.l   d3                          Hテ      ←このサブルーチンはext.lで符号拡張してからdivu.wを使っているが、符号拡張しておいて符号なし除算というのもおかしい。movem.wでd3も符号拡張されているのでこのext.lは不要で、0<=d1.w<=d3.wでないときもext.lは役に立たない
  6220:   //    00BFC90C  86FC0010              divu.w  #$0010,d3                   ※..
  6221:   //    (以下略)
  6222:   //
  6223:   public static final boolean MPU_SXMENU = false;  //true=対策を施す。movem.w <ea>,<list>を修正して実害がなくなったので外しておく
  6224: 
  6225:   //mpuInit ()
  6226:   //  MPUを初期化する
  6227:   public static void mpuInit () {
  6228:     //コア
  6229:     mpuIgnoreAddressError = false;
  6230:     //レジスタ
  6231:     //r = new int[16];
  6232:     //FPU
  6233:     fpuInit ();  //FPU FPU
  6234:     //クロック
  6235:     mpuClockTime = 0L;
  6236:     mpuClockLimit = 0L;
  6237:     mpuCycleCount = 0;
  6238:     //タイマ
  6239:     mpuTask = null;
  6240:     //例外処理
  6241:     M68kException.m6eSignal = new M68kException ();
  6242:     M68kException.m6eNumber = 0;
  6243:     M68kException.m6eAddress = 0;
  6244:     M68kException.m6eDirection = MPU_WR_WRITE;
  6245:     M68kException.m6eSize = MPU_SS_BYTE;
  6246:     //その他
  6247:     mpuBootDevice = -1;
  6248:     mpuROMBootHandle = -1;
  6249:     mpuSavedBootDevice = -1;
  6250:     mpuSavedROMBootHandle = -1;
  6251:     //任意の周波数の指定
  6252:     //mpuArbFreqOn = !(clockMHz == 10.0 ||
  6253:     //                 clockMHz == 50.0 / 3.0 ||  //16.7MHz
  6254:     //                 clockMHz == 25.0 ||
  6255:     //                 clockMHz == 100.0 / 3.0 ||  //33.3MHz
  6256:     //                 clockMHz == 50.0 ||
  6257:     //                 clockMHz == 200.0 / 3.0 ||  //66.7MHz
  6258:     //                 clockMHz == 75.0 ||
  6259:     //                 clockMHz == 100.0);
  6260:     //mpuArbFreqMHz = mpuArbFreqOn ? (int) clockMHz : 100;
  6261:     //任意の負荷率の指定
  6262:     //mpuUtilOn = false;
  6263:     //mpuUtilRatio = 100;
  6264: 
  6265:     //カウンタ
  6266:     mpuAdjustmentCounter = MPU_ADJUSTMENT_INTERVAL;
  6267:     mpuTotalNano = 0L;
  6268:     mpuLastNano = System.nanoTime ();
  6269:     mpuCoreNano1 = mpuCoreNano2 = 0.5 * 1e+6 * (double) (TMR_INTERVAL * MPU_ADJUSTMENT_INTERVAL);  //負荷率50%
  6270: 
  6271:     mpuButtonsRunning = new ArrayList<AbstractButton> ();
  6272:     mpuButtonsStopped = new ArrayList<AbstractButton> ();
  6273: 
  6274:     mpuOriIllegalCheckBoxList = new ArrayList<JCheckBox> ();
  6275:     mpuStopOnErrorCheckBoxList = new ArrayList<JCheckBox> ();
  6276:     mpuStopAtStartCheckBoxList = new ArrayList<JCheckBox> ();
  6277: 
  6278:     mpuAdvanceCount = 0;
  6279:     mpuStepCount = 0;
  6280:     mpuContinue = false;
  6281:     mpuUntilReturnSRS = 0;
  6282:     mpuUntilReturnRP = 0;
  6283:     mpuUntilReturnPC0 = 0;
  6284:     mpuUntilReturnSP = 0;
  6285: 
  6286:     //デバッグアクションリスナー
  6287:     mpuDebugActionListener = new ActionListener () {
  6288:       @Override public void actionPerformed (ActionEvent ae) {
  6289:         Object source = ae.getSource ();
  6290:         switch (ae.getActionCommand ()) {
  6291:         case "Stop":  //停止
  6292:           if (RootPointerList.RTL_ON) {
  6293:             if (RootPointerList.rtlCurrentSupervisorTaskIsStoppable ||
  6294:                 RootPointerList.rtlCurrentUserTaskIsStoppable) {
  6295:               mpuStop (null);  //"Stop Button"
  6296:             }
  6297:           } else {
  6298:             mpuStop (null);  //"Stop Button"
  6299:           }
  6300:           break;
  6301:         case "Trace":  //トレース
  6302:           mpuAdvance (1);
  6303:           break;
  6304:         case "Trace 10 times":  //トレース 10 回
  6305:           mpuAdvance (10);
  6306:           break;
  6307:         case "Trace 100 times":  //トレース 100 回
  6308:           mpuAdvance (100);
  6309:           break;
  6310:         case "Step":  //ステップ
  6311:           mpuStep (1);
  6312:           break;
  6313:         case "Step 10 times":  //ステップ 10 回
  6314:           mpuStep (10);
  6315:           break;
  6316:         case "Step 100 times":  //ステップ 100 回
  6317:           mpuStep (100);
  6318:           break;
  6319:         case "Step until return":  //ステップアンティルリターン
  6320:           mpuStepUntilReturn ();
  6321:           break;
  6322:         case "Run":  //実行
  6323:           mpuStart ();
  6324:           break;
  6325:           //
  6326:         case "Consider ORI.B #$00,D0 as an illegal instruction" :
  6327:           if (DBG_ORI_BYTE_ZERO_D0) {
  6328:             dbgOriByteZeroD0 = ((JCheckBox) source).isSelected ();
  6329:             for (JCheckBox checkBox : mpuOriIllegalCheckBoxList) {
  6330:               if (checkBox.isSelected () != dbgOriByteZeroD0) {
  6331:                 checkBox.setSelected (dbgOriByteZeroD0);
  6332:               }
  6333:             }
  6334:           }
  6335:           break;
  6336:         case "Stop on error":
  6337:           dbgStopOnError = ((JCheckBox) source).isSelected ();
  6338:           for (JCheckBox checkBox : mpuStopOnErrorCheckBoxList) {
  6339:             if (checkBox.isSelected () != dbgStopOnError) {
  6340:               checkBox.setSelected (dbgStopOnError);
  6341:             }
  6342:           }
  6343:           break;
  6344:         case "Stop at execution start position":
  6345:           dbgStopAtStart = ((JCheckBox) source).isSelected ();
  6346:           for (JCheckBox checkBox : mpuStopAtStartCheckBoxList) {
  6347:             if (checkBox.isSelected () != dbgStopAtStart) {
  6348:               checkBox.setSelected (dbgStopAtStart);
  6349:             }
  6350:           }
  6351:           break;
  6352:         }
  6353:       }  //actionPerformed(ActionEvent)
  6354:     };  //mpuDebugActionListener
  6355: 
  6356:   }  //mpuInit()
  6357: 
  6358:   //mpuMakeOriIllegalCheckBox ()
  6359:   //  ORI.B #$00,D0を不当命令とみなすチェックボックスを作る
  6360:   public static JCheckBox mpuMakeOriIllegalCheckBox () {
  6361:     JCheckBox checkBox = Multilingual.mlnToolTipText (
  6362:       ComponentFactory.createIconCheckBox (
  6363:         DBG_ORI_BYTE_ZERO_D0 ? dbgOriByteZeroD0 : null,
  6364:         LnF.LNF_ORI_BYTE_ZERO_D0_IMAGE,
  6365:         LnF.LNF_ORI_BYTE_ZERO_D0_SELECTED_IMAGE,
  6366:         "Consider ORI.B #$00,D0 as an illegal instruction", mpuDebugActionListener),
  6367:       "ja", "ORI.B #$00,D0 を不当命令とみなす");
  6368:     mpuOriIllegalCheckBoxList.add (checkBox);
  6369:     return checkBox;
  6370:   }  //mpuMakeOriIllegalCheckBox
  6371: 
  6372:   //mpuMakeStopOnErrorCheckBox ()
  6373:   //  エラーで停止するチェックボックスを作る
  6374:   public static JCheckBox mpuMakeStopOnErrorCheckBox () {
  6375:     JCheckBox checkBox = Multilingual.mlnToolTipText (
  6376:       ComponentFactory.createIconCheckBox (
  6377:         dbgStopOnError,
  6378:         LnF.LNF_STOP_ON_ERROR_IMAGE,
  6379:         LnF.LNF_STOP_ON_ERROR_SELECTED_IMAGE,
  6380:         "Stop on error", mpuDebugActionListener),
  6381:       "ja", "エラーで停止する");
  6382:     mpuStopOnErrorCheckBoxList.add (checkBox);
  6383:     return checkBox;
  6384:   }  //mpuMakeStopOnErrorCheckBox
  6385: 
  6386:   //mpuMakeStopAtStartCheckBox ()
  6387:   //  実行開始位置で停止するチェックボックスを作る
  6388:   public static JCheckBox mpuMakeStopAtStartCheckBox () {
  6389:     JCheckBox checkBox = Multilingual.mlnToolTipText (
  6390:       ComponentFactory.createIconCheckBox (
  6391:         dbgStopAtStart,
  6392:         LnF.LNF_STOP_AT_START_IMAGE,
  6393:         LnF.LNF_STOP_AT_START_SELECTED_IMAGE,
  6394:         "Stop at execution start position", mpuDebugActionListener),
  6395:       "ja", "実行開始位置で停止する");
  6396:     mpuStopAtStartCheckBoxList.add (checkBox);
  6397:     return checkBox;
  6398:   }  //mpuMakeStopAtStartCheckBox
  6399: 
  6400:   //mpuMakeMenu ()
  6401:   //  mdlMakeMenuより後
  6402:   //  smrMakeMenuより後
  6403:   //  mnbMakeMenuより前
  6404:   public static void mpuMakeMenu () {
  6405:     //メニュー
  6406:     ButtonGroup unitGroup = new ButtonGroup ();
  6407:     ActionListener listener = new ActionListener () {
  6408:       @Override public void actionPerformed (ActionEvent ae) {
  6409:         Object source = ae.getSource ();
  6410:         switch (ae.getActionCommand ()) {
  6411:         case "Reset":  //リセット
  6412:           mpuReset (-1, -1);
  6413:           break;
  6414:         case "Hold down OPT.1 and reset":  //OPT.1 を押しながらリセット
  6415:           mpuReset (0, -1);
  6416:           break;
  6417:         case "Interrupt":  //インタラプト
  6418:           sysInterrupt ();  //インタラプトスイッチが押された
  6419:           break;
  6420:         case "10MHz":
  6421:           mpuArbFreqOn = false;
  6422:           mpuUtilOn = false;
  6423:           mpuSetCurrentClock (10.0);
  6424:           break;
  6425:         case "16.7MHz":
  6426:           mpuArbFreqOn = false;
  6427:           mpuUtilOn = false;
  6428:           mpuSetCurrentClock (50.0 / 3.0);  //16.7MHz
  6429:           break;
  6430:         case "25MHz":
  6431:           mpuArbFreqOn = false;
  6432:           mpuUtilOn = false;
  6433:           mpuSetCurrentClock (25.0);
  6434:           break;
  6435:         case "33.3MHz":
  6436:           mpuArbFreqOn = false;
  6437:           mpuUtilOn = false;
  6438:           mpuSetCurrentClock (100.0 / 3.0);  //33.3MHz
  6439:           break;
  6440:         case "50MHz":
  6441:           mpuArbFreqOn = false;
  6442:           mpuUtilOn = false;
  6443:           mpuSetCurrentClock (50.0);
  6444:           break;
  6445:         case "66.7MHz":
  6446:           mpuArbFreqOn = false;
  6447:           mpuUtilOn = false;
  6448:           mpuSetCurrentClock (200.0 / 3.0);  //66.7MHz
  6449:           break;
  6450:         case "75MHz":
  6451:           mpuArbFreqOn = false;
  6452:           mpuUtilOn = false;
  6453:           mpuSetCurrentClock (75.0);
  6454:           break;
  6455:         case "100MHz":
  6456:           mpuArbFreqOn = false;
  6457:           mpuUtilOn = false;
  6458:           mpuSetCurrentClock (100.0);
  6459:           break;
  6460:         case "Arbitrary frequency":  //任意の周波数
  6461:           mpuArbFreqOn = true;
  6462:           mpuUtilOn = false;
  6463:           mpuSetCurrentClock ((double) mpuArbFreqMHz);
  6464:           break;
  6465:         case "Arbitrary load factor":  //任意の負荷率
  6466:           mpuArbFreqOn = false;
  6467:           mpuUtilOn = true;
  6468:           break;
  6469:         case "FE function instruction":  //FE ファンクション命令
  6470:           FEFunction.fpkOn = ((JCheckBoxMenuItem) source).isSelected ();
  6471:           break;
  6472:         case "Reject FLOATn.X":  //FLOATn.X を組み込まない
  6473:           FEFunction.fpkRejectFloatOn = ((JCheckBoxMenuItem) source).isSelected ();
  6474:           break;
  6475:         case "Cut FC2 pin":  //FC2 ピンをカットする
  6476:           busRequestCutFC2Pin = ((JCheckBoxMenuItem) source).isSelected ();
  6477:           break;
  6478:         case "Wait cycles":  //ウェイトサイクル
  6479:           busWaitCyclesRequest = ((JCheckBoxMenuItem) source).isSelected ();
  6480:           break;
  6481:         case "Use IPLROM 1.6":  //IPLROM 1.6 を使う
  6482:           ROM.romIPLROM16On = ((JCheckBoxMenuItem) source).isSelected ();
  6483:           break;
  6484:         case "Increase IPLROM to 256KB":  //IPLROM を 256KB に増やす
  6485:           ROM.romIPLROM256KOn = ((JCheckBoxMenuItem) source).isSelected ();
  6486:           break;
  6487: 
  6488:         case "Run / Stop":  //実行/停止
  6489:           if (((JCheckBox) source).isSelected ()) {  //Run
  6490:             mpuStart ();
  6491:           } else {  //Stop
  6492:             if (RootPointerList.RTL_ON) {
  6493:               if (RootPointerList.rtlCurrentSupervisorTaskIsStoppable ||
  6494:                   RootPointerList.rtlCurrentUserTaskIsStoppable) {
  6495:                 mpuStop (null);  //"Stop Button"
  6496:               }
  6497:             } else {
  6498:               mpuStop (null);  //"Stop Button"
  6499:             }
  6500:           }
  6501:           pnlPanel.requestFocusInWindow ();  //パネルにフォーカスを戻す。戻さないとキー入力が入らない
  6502:           break;
  6503:         }
  6504:       }
  6505:     };
  6506:     mpuMenu = ComponentFactory.createMenu (
  6507:       "MPU", 'M',
  6508:       mpuResetMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Reset", 'R', MNB_MODIFIERS, listener), "ja", "リセット"),
  6509:       mpuOpt1ResetMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Hold down OPT.1 and reset", 'O', MNB_MODIFIERS, listener), "ja", "OPT.1 を押しながらリセット"),
  6510:       Multilingual.mlnText (ComponentFactory.createMenuItem ("Interrupt", listener), "ja", "インタラプト"),
  6511:       ComponentFactory.createHorizontalSeparator (),
  6512:       mdlMenu,
  6513:       ComponentFactory.createHorizontalSeparator (),
  6514:       mpuClock10MenuItem = ComponentFactory.createRadioButtonMenuItem (
  6515:         unitGroup,
  6516:         !mpuArbFreqOn && !mpuUtilOn && specifiedClock == 10.0,
  6517:         "10MHz",
  6518:         listener),
  6519:       mpuClock16MenuItem = ComponentFactory.createRadioButtonMenuItem (
  6520:         unitGroup,
  6521:         !mpuArbFreqOn && !mpuUtilOn && specifiedClock == 50.0 / 3.0,
  6522:         "16.7MHz",
  6523:         listener),
  6524:       mpuClock25MenuItem = ComponentFactory.createRadioButtonMenuItem (
  6525:         unitGroup,
  6526:         !mpuArbFreqOn && !mpuUtilOn && specifiedClock == 25.0,
  6527:         "25MHz",
  6528:         listener),
  6529:       mpuClock33MenuItem = ComponentFactory.createRadioButtonMenuItem (
  6530:         unitGroup,
  6531:         !mpuArbFreqOn && !mpuUtilOn && specifiedClock == 100.0 / 3.0,
  6532:         "33.3MHz",
  6533:         listener),
  6534:       mpuClock50MenuItem = ComponentFactory.createRadioButtonMenuItem (
  6535:         unitGroup,
  6536:         !mpuArbFreqOn && !mpuUtilOn && specifiedClock == 50.0,
  6537:         "50MHz",
  6538:         listener),
  6539:       mpuClock66MenuItem = ComponentFactory.createRadioButtonMenuItem (
  6540:         unitGroup,
  6541:         !mpuArbFreqOn && !mpuUtilOn && specifiedClock == 200.0 / 3.0,
  6542:         "66.7MHz",
  6543:         listener),
  6544:       mpuClock75MenuItem = ComponentFactory.createRadioButtonMenuItem (
  6545:         unitGroup,
  6546:         !mpuArbFreqOn && !mpuUtilOn && specifiedClock == 75.0,
  6547:         "75MHz",
  6548:         listener),
  6549:       mpuClock100MenuItem = ComponentFactory.createRadioButtonMenuItem (
  6550:         unitGroup,
  6551:         !mpuArbFreqOn && !mpuUtilOn && specifiedClock == 100.0,
  6552:         "100MHz",
  6553:         listener),
  6554:       mpuArbFreqRadioButtonMenuItem = Multilingual.mlnText (
  6555:         ComponentFactory.createRadioButtonMenuItem (
  6556:           unitGroup,
  6557:           mpuArbFreqOn,
  6558:           "Arbitrary frequency",
  6559:           listener),
  6560:         "ja", "任意の周波数"),
  6561:       ComponentFactory.createHorizontalBox (
  6562:         Box.createHorizontalStrut (20),
  6563:         mpuArbFreqSpinner = ComponentFactory.createNumberSpinner (
  6564:           mpuArbFreqModel = new SpinnerNumberModel (mpuArbFreqMHz, 1, 1000, 1),
  6565:           4,
  6566:           new ChangeListener () {
  6567:             @Override public void stateChanged (ChangeEvent ce) {
  6568:               //mpuArbFreqRadioButtonMenuItem.setSelected (true);
  6569:               mpuArbFreqMHz = mpuArbFreqModel.getNumber ().intValue ();
  6570:               if (mpuArbFreqOn) {
  6571:                 mpuSetCurrentClock ((double) mpuArbFreqMHz);
  6572:               }
  6573:             }
  6574:           }
  6575:           ),
  6576:         ComponentFactory.createLabel ("MHz"),
  6577:         Box.createHorizontalGlue ()
  6578:         ),
  6579:       mpuUtilRadioButtonMenuItem = Multilingual.mlnText (
  6580:         ComponentFactory.createRadioButtonMenuItem (
  6581:           unitGroup,
  6582:           mpuUtilOn,
  6583:           "Arbitrary load factor",
  6584:           listener),
  6585:         "ja", "任意の負荷率"),
  6586:       ComponentFactory.createHorizontalBox (
  6587:         Box.createHorizontalStrut (20),
  6588:         mpuUtilSpinner = ComponentFactory.createNumberSpinner (
  6589:           mpuUtilModel = new SpinnerNumberModel (mpuUtilRatio, 1, 100, 1),
  6590:           4,
  6591:           new ChangeListener () {
  6592:             @Override public void stateChanged (ChangeEvent ce) {
  6593:               //mpuUtilRadioButtonMenuItem.setSelected (true);
  6594:               mpuUtilRatio = mpuUtilModel.getNumber ().intValue ();
  6595:             }
  6596:           }
  6597:           ),
  6598:         ComponentFactory.createLabel ("%"),
  6599:         Box.createHorizontalGlue ()
  6600:         ),
  6601:       //
  6602:       ComponentFactory.createHorizontalSeparator (),
  6603:       coproFPUMenu,
  6604:       Multilingual.mlnText (ComponentFactory.createCheckBoxMenuItem (FEFunction.fpkOn, "FE function instruction", listener), "ja", "FE ファンクション命令"),
  6605:       Multilingual.mlnText (ComponentFactory.createCheckBoxMenuItem (FEFunction.fpkRejectFloatOn, "Reject FLOATn.X", listener), "ja", "FLOATn.X を組み込まない"),
  6606:       //
  6607:       ComponentFactory.createHorizontalSeparator (),
  6608:       Multilingual.mlnText (ComponentFactory.createCheckBoxMenuItem (busRequestCutFC2Pin, "Cut FC2 pin", listener), "ja", "FC2 ピンをカットする"),
  6609:       Multilingual.mlnText (ComponentFactory.createCheckBoxMenuItem (busWaitCyclesRequest, "Wait cycles", listener), "ja", "ウェイトサイクル"),
  6610:       ComponentFactory.createHorizontalSeparator (),
  6611:       Multilingual.mlnText (ComponentFactory.createCheckBoxMenuItem (ROM.romIPLROM16On, "Use IPLROM 1.6", listener), "ja", "IPLROM 1.6 を使う"),
  6612:       Multilingual.mlnText (ComponentFactory.createCheckBoxMenuItem (ROM.romIPLROM256KOn, "Increase IPLROM to 256KB", listener), "ja", "IPLROM を 256KB に増やす"),
  6613:       //
  6614:       ComponentFactory.createHorizontalSeparator (),
  6615:       SRAM.smrCacheMenu
  6616:       );
  6617:   }  //mpuMakeMenu()
  6618: 
  6619:   //  クロック(MHz)を設定する
  6620:   public static void mpuSetCurrentClock (double clock) {
  6621:     specifiedClock = clock;
  6622:     if (currentIsSecond) {
  6623:       specifiedSecondClock = clock;
  6624:     } else {
  6625:       specifiedFirstClock = clock;
  6626:     }
  6627:     if (!mpuArbFreqOn && !mpuUtilOn) {
  6628:       if (specifiedClock == 10.0) {
  6629:         mpuClock10MenuItem.setSelected (true);
  6630:       } else if (specifiedClock == 50.0 / 3.0) {  //16.7MHz
  6631:         mpuClock16MenuItem.setSelected (true);
  6632:       } else if (specifiedClock == 25.0) {
  6633:         mpuClock25MenuItem.setSelected (true);
  6634:       } else if (specifiedClock == 100.0 / 3.0) {  //33.3MHz
  6635:         mpuClock33MenuItem.setSelected (true);
  6636:       } else if (specifiedClock == 50.0) {
  6637:         mpuClock50MenuItem.setSelected (true);
  6638:       } else if (specifiedClock == 200.0 / 3.0) {  //66.7MHz
  6639:         mpuClock66MenuItem.setSelected (true);
  6640:       } else if (specifiedClock == 75.0) {
  6641:         mpuClock75MenuItem.setSelected (true);
  6642:       } else if (specifiedClock == 100.0) {
  6643:         mpuClock100MenuItem.setSelected (true);
  6644:       }
  6645:     }
  6646:     mpuClockMHz = specifiedClock;
  6647:     mpuSetClockMHz (mpuClockMHz);  //currentMPUが変更されたときは再計算が必要なのでクロックが変わっていなくても省略できない
  6648:   }
  6649: 
  6650:   //mpuSetClockMHz (mhz)
  6651:   //  mpuCurrentMHz,mpuCycleUnit,mpuModifiedUnitを設定する
  6652:   //  TMR_FREQ=10^12のとき
  6653:   //               mpuModifiedUnitと1サイクルの時間
  6654:   //  mpuClockMHz     000/060         030
  6655:   //    10.0MHz    100000(100ns)  60000(60ns)
  6656:   //    16.7MHz     60000 (60ns)  36000(36ns)
  6657:   //    25.0MHz     40000 (40ns)  24000(24ns)
  6658:   //    33.3MHz     30000 (30ns)  18000(18ns)
  6659:   //    50.0MHz     20000 (20ns)  12000(12ns)
  6660:   public static void mpuSetClockMHz (double mhz) {
  6661:     mhz = Math.max (1.0, Math.min (1000.0, mhz));
  6662:     double lastMHz = mpuCurrentMHz;
  6663:     mpuCurrentMHz = mhz;
  6664:     mpuCycleUnit = (long) (((double) TMR_FREQ / 1000000.0) / mhz + 0.5);
  6665:     //  DBRA命令で比較するとMC68030は3/5、MC68040は2/5、MC68060は1/5くらい?
  6666:     mpuModifiedUnit = (currentMPU == Model.MPU_MC68EC030 ||
  6667:                        currentMPU == Model.MPU_MC68030 ?
  6668:                        (long) (((double) TMR_FREQ * 3.0 / (5.0 * 1000000.0)) / mhz + 0.5) :
  6669:                        currentMPU == Model.MPU_MC68LC040 ||
  6670:                        currentMPU == Model.MPU_MC68040 ?
  6671:                        (long) (((double) TMR_FREQ * 2.0 / (5.0 * 1000000.0)) / mhz + 0.5) :
  6672:                        mpuCycleUnit);
  6673:     if (lastMHz != mhz) {
  6674:       mpuSetWait ();
  6675:     }
  6676:   }  //mpuSetClockMHz(double)
  6677: 
  6678:   //mpuSetWait ()
  6679:   //  ウェイトを設定する
  6680:   //    currentMPU
  6681:   //    mpuCycleUnit
  6682:   //    mpuCacheOn
  6683:   //    mpuROMWaitCycles
  6684:   //    mpuRAMWaitCycles
  6685:   //    dmaCycleUnit
  6686:   //  から
  6687:   //    mpuWaitTime
  6688:   //    dmaWaitTime
  6689:   //  のすべての項目と
  6690:   //    mpuNoWaitTime
  6691:   //  のsramとromを作る
  6692:   //!!! 機種や個体による違いは考慮されていない。DMACのウェイトの機種による違いはDMAC側で調整している
  6693:   //!!! 状態やアクセス方法による違いは考慮されていない
  6694:   //!!! MPUで分類しておりXellent30は考慮されていない
  6695:   //!!! X68030のramとromはロングワード境界を跨がなければ1回でアクセスできるが考慮されていない
  6696:   //!!! 060turboはI/Oポートの書き込みウェイトの間に多数の命令を実行できるが考慮されていない
  6697:   //  参考
  6698:   //                         Execution time of instructions testing I/O ports
  6699:   //    +---------------+-------------------+----------------------------------------------------+
  6700:   //    |               |                   |                execution time (us)                 |
  6701:   //    |   I/O port    |    instruction    |           X68000 10MHz            | X68030 060turbo|
  6702:   //    |               |                   | Shodai  ACE  ACE 2nd  PRO    XVI  | 25MHz   50MHz  |
  6703:   //    +---------------+-------------------+-----------------------------------+----------------+
  6704:   //    | main memory   | tst.w $00000000.l | 1.642  1.642  1.643  1.663  1.650 | 0.2400  0.0399 |
  6705:   //    | GVRAM         | tst.w $00C00000.l | 1.752  1.750  1.750  1.770  1.734 | 0.4951  0.4700 |
  6706:   //    | TVRAM         | tst.w $00E00000.l | 1.829  1.849  1.850  1.840  1.848 | 0.5049  0.4800 |
  6707:   //    | CRTC R00      | tst.w $00E80000.l | 1.740  1.724  1.726  1.770  1.733 | 0.4800  0.4599 |
  6708:   //    | CRTC action   | tst.w $00E80480.l | 1.741  1.725  1.725  1.771  1.733 | 0.4800  0.4600 |
  6709:   //    | VCN gpalet    | tst.w $00E82000.l | 1.875  1.909  1.910  1.912  1.919 | 0.6778  0.6962 |
  6710:   //    | VCN mode      | tst.w $00E82400.l | 1.641  1.640  1.642  1.770  1.733 | 0.4800  0.4601 |
  6711:   //    | DMAC ch0 CSR  | tst.b $00E84000.l | 3.124  3.114  3.115  3.127  3.124 | 1.599   1.501  |
  6712:   //    | MFP GPIP      | tst.b $00E88001.l | 2.088  2.031  2.031  2.082  2.080 | 1.013   0.9801 |
  6713:   //    | RTC onesec    | tst.b $00E8A001.l | 1.776  1.850  1.851  1.773  1.836 | 1.359   1.580  |
  6714:   //    | PRN data      | tst.b $00E8C001.l | 1.742  1.725  1.725  1.771  1.734 | 0.4001  0.3800 |
  6715:   //    | SYS contrast  | tst.b $00E8E001.l | 1.741  1.725  1.726  1.771  1.734 | 0.4000  0.3800 |
  6716:   //    | OPM status    | tst.b $00E90003.l | 1.776  1.852  1.850  1.772  1.835 | 0.8268  0.7801 |
  6717:   //    | PCM status    | tst.b $00E92001.l | 1.776  1.850  1.850  1.771  1.836 | 0.8268  0.7800 |
  6718:   //    | FDC status    | tst.b $00E94001.l | 1.776  1.852  1.850  1.771  1.836 | 0.8266  0.7800 |
  6719:   //    | FDD status    | tst.b $00E94005.l | 1.777  1.850  1.850  1.770  1.836 | 0.8268  0.7801 |
  6720:   //    | HDC status    | tst.b $00E96003.l | 1.776  1.852  1.850  1.770  1.836 | 0.8267  0.7801 |
  6721:   //    | SCC chB RR0   | tst.b $00E98001.l | 2.231  2.234  2.236  2.248  2.244 | 1.760   1.980  |
  6722:   //    | PPI portA     | tst.b $00E9A001.l | 1.777  1.851  1.852  1.771  1.835 | 0.8268  0.7800 |
  6723:   //    | IOI status    | tst.b $00E9C001.l | 1.776  1.851  1.851  1.770  1.835 | 0.8267  0.7800 |
  6724:   //    | SPRC bg0 scrX | tst.w $00EB0800.l | 1.740  1.725  1.726  1.769  1.734 | 0.4800  0.4600 |
  6725:   //    | SRAM          | tst.w $00ED0000.l | 1.741  1.725  1.725  1.772  1.733 | 0.3199  0.3001 |
  6726:   //    | CGROM         | tst.w $00F00000.l | 1.741  1.725  1.725  1.771  1.733 | 0.2399  0.0400 |
  6727:   //    | IPLROM        | tst.w $00FF0000.l | 1.742  1.726  1.725  1.770  1.734 | 0.2400  0.0400 |
  6728:   //    +---------------+-------------------+-----------------------------------+----------------+
  6729:   //    thanks to uchopon, tnb and ita
  6730:   //
  6731:   //                    X68000   X68030 060turbo
  6732:   //                     10MHz    25MHz    50MHz
  6733:   //    main memory      0.123    0.000    0.000
  6734:   //    GVRAM            1.145    6.377   21.500
  6735:   //    TVRAM            2.046    6.623   22.000
  6736:   //    CRTC R00         1.050    6.000   20.995
  6737:   //    CRTC action      1.055    6.000   21.000
  6738:   //    VCN gpalet       2.668   10.945   32.810
  6739:   //    VCN mode         0.592    6.000   21.005
  6740:   //    DMAC ch0 CSR    14.853   33.975   73.050
  6741:   //    MFP GPIP         4.332   19.325   47.005
  6742:   //    RTC onesec       1.718   27.975   77.000
  6743:   //    PRN data         1.060    4.002   17.000
  6744:   //    SYS contrast     1.058    4.000   17.000
  6745:   //    OPM status       1.715   14.670   37.005
  6746:   //    PCM status       1.712   14.670   37.000
  6747:   //    FDC status       1.715   14.665   37.000
  6748:   //    FDD status       1.712   14.670   37.005
  6749:   //    HDC status       1.712   14.668   37.005
  6750:   //    SCC chB RR0      6.025   38.000   97.000
  6751:   //    PPI portA        1.716   14.670   37.000
  6752:   //    IOI status       1.710   14.668   37.000
  6753:   //    SPRC bg0 scrX    1.051    6.000   21.000
  6754:   //    SRAM             1.057    1.998   13.005
  6755:   //    CGROM            1.055   -0.002    0.000
  6756:   //    IPLROM           1.058    0.000    0.000
  6757:   //
  6758:   public static void mpuSetWait () {
  6759:     //MPU
  6760:     if (currentMPU <= Model.MPU_MC68010) {  //68000/68010
  6761:       mpuWaitTime.ram = mpuCycleUnit >> 3;  //DRAMリフレッシュウェイトを1/8サイクル/ワードとする
  6762:       mpuWaitTime.vicon = (long) (mpuCycleUnit * 0.6);
  6763:       mpuWaitTime.crtc =
  6764:         mpuWaitTime.prnport =
  6765:           mpuWaitTime.sysport =
  6766:             mpuWaitTime.sprc =
  6767:               mpuWaitTime.sram =
  6768:                 mpuWaitTime.rom = mpuCycleUnit;
  6769:       mpuWaitTime.gvram = (long) (mpuCycleUnit * 1.1);
  6770:       mpuWaitTime.rtc =
  6771:         mpuWaitTime.opm =
  6772:           mpuWaitTime.adpcm =
  6773:             mpuWaitTime.fdc =
  6774:               mpuWaitTime.fdd =
  6775:                 mpuWaitTime.hdc =
  6776:                   mpuWaitTime.ppi =
  6777:                     mpuWaitTime.ioi = (long) (mpuCycleUnit * 1.7);
  6778:       mpuWaitTime.tvram = mpuCycleUnit * 2;
  6779:       mpuWaitTime.palet = (long) (mpuCycleUnit * 2.6);
  6780:       mpuWaitTime.mfp = (long) (mpuCycleUnit * 4.3);
  6781:       mpuWaitTime.scc = mpuCycleUnit * 6;
  6782:       mpuWaitTime.dmac = mpuCycleUnit * 15;
  6783:       mpuWaitTime.ramlong = mpuWaitTime.ram << 1;
  6784:       mpuWaitTime.romlong = mpuWaitTime.rom << 1;
  6785:     } else if (currentMPU <= Model.MPU_MC68030) {  //68020/68030
  6786:       mpuWaitTime.ram = mpuCacheOn ? 0 : mpuCycleUnit * mpuRAMWaitCycles + (mpuCycleUnit >> 3);
  6787:       mpuWaitTime.rom = mpuCacheOn ? 0 : mpuCycleUnit * mpuROMWaitCycles;
  6788:       mpuWaitTime.sram = mpuCycleUnit * 2;
  6789:       mpuWaitTime.prnport =
  6790:         mpuWaitTime.sysport = mpuCycleUnit * 4;
  6791:       mpuWaitTime.gvram =
  6792:         mpuWaitTime.crtc =
  6793:           mpuWaitTime.vicon =
  6794:             mpuWaitTime.sprc = mpuCycleUnit * 6;
  6795:       mpuWaitTime.tvram = mpuCycleUnit * 7;
  6796:       mpuWaitTime.palet = mpuCycleUnit * 11;
  6797:       mpuWaitTime.opm =
  6798:         mpuWaitTime.adpcm =
  6799:           mpuWaitTime.fdc =
  6800:             mpuWaitTime.fdd =
  6801:               mpuWaitTime.hdc =
  6802:                 mpuWaitTime.ppi =
  6803:                   mpuWaitTime.ioi = mpuCycleUnit * 15;
  6804:       mpuWaitTime.mfp = mpuCycleUnit * 19;
  6805:       mpuWaitTime.rtc = mpuCycleUnit * 28;
  6806:       mpuWaitTime.dmac = mpuCycleUnit * 34;
  6807:       mpuWaitTime.scc = mpuCycleUnit * 38;
  6808:       mpuWaitTime.ramlong = mpuWaitTime.ram;
  6809:       mpuWaitTime.romlong = mpuWaitTime.rom;
  6810:     } else {  //68040/68060
  6811:       mpuWaitTime.ram = mpuCacheOn ? 0 : mpuCycleUnit * mpuRAMWaitCycles + (mpuCycleUnit >> 3);
  6812:       mpuWaitTime.rom = mpuCacheOn ? 0 : mpuCycleUnit * mpuROMWaitCycles;
  6813:       mpuWaitTime.sram = mpuCycleUnit * 13;
  6814:       mpuWaitTime.prnport =
  6815:         mpuWaitTime.sysport = mpuCycleUnit * 17;
  6816:       mpuWaitTime.gvram =
  6817:         mpuWaitTime.crtc =
  6818:           mpuWaitTime.vicon =
  6819:             mpuWaitTime.sprc = mpuCycleUnit * 21;
  6820:       mpuWaitTime.tvram = mpuCycleUnit * 22;
  6821:       mpuWaitTime.palet = mpuCycleUnit * 33;
  6822:       mpuWaitTime.opm =
  6823:         mpuWaitTime.adpcm =
  6824:           mpuWaitTime.fdc =
  6825:             mpuWaitTime.fdd =
  6826:               mpuWaitTime.hdc =
  6827:                 mpuWaitTime.ppi =
  6828:                   mpuWaitTime.ioi = mpuCycleUnit * 37;
  6829:       mpuWaitTime.mfp = mpuCycleUnit * 47;
  6830:       mpuWaitTime.dmac = mpuCycleUnit * 73;
  6831:       mpuWaitTime.rtc = mpuCycleUnit * 77;
  6832:       mpuWaitTime.scc = mpuCycleUnit * 97;
  6833:       mpuWaitTime.ramlong = mpuWaitTime.ram;
  6834:       mpuWaitTime.romlong = mpuWaitTime.rom;
  6835:     }
  6836:     if (true) {
  6837:       //SRAMとROMはウェイトサイクルなしでも0にしない。クロック計測用
  6838:       mpuNoWaitTime.sram = mpuWaitTime.sram;
  6839:       mpuNoWaitTime.rom = mpuWaitTime.rom;
  6840:       mpuNoWaitTime.romlong = mpuWaitTime.romlong;
  6841:     }
  6842:     //DMAC
  6843:     dmaWaitTime.ram = dmaCycleUnit >> 3;  //DRAMリフレッシュウェイトを1/8サイクル/ワードとする
  6844:     dmaWaitTime.sram = 0;
  6845:     dmaWaitTime.rom = 0;
  6846:     dmaWaitTime.gvram =
  6847:       dmaWaitTime.crtc =
  6848:         dmaWaitTime.vicon =
  6849:           dmaWaitTime.prnport =
  6850:             dmaWaitTime.sysport =
  6851:               dmaWaitTime.sprc = dmaCycleUnit;
  6852:     dmaWaitTime.tvram =
  6853:       dmaWaitTime.rtc =
  6854:         dmaWaitTime.opm =
  6855:           dmaWaitTime.adpcm =
  6856:             dmaWaitTime.fdc =
  6857:               dmaWaitTime.fdd =
  6858:                 dmaWaitTime.hdc =
  6859:                   dmaWaitTime.ppi =
  6860:                     dmaWaitTime.ioi = dmaCycleUnit * 2;
  6861:     dmaWaitTime.palet = dmaCycleUnit * 3;
  6862:     dmaWaitTime.mfp = dmaCycleUnit * 4;
  6863:     dmaWaitTime.scc = dmaCycleUnit * 6;
  6864:     dmaWaitTime.dmac = dmaCycleUnit * 15;
  6865:     dmaWaitTime.ramlong = dmaWaitTime.ram << 1;
  6866:     dmaWaitTime.romlong = dmaWaitTime.rom << 1;
  6867:     if (MC68060.CAT_ON) {
  6868:       if (Model.MPU_MC68LC060 <= currentMPU) {  //68LC060,68060
  6869:         MC68060.catMainLongTime = mpuCycleUnit * 13;
  6870:         MC68060.catMainLineTime = mpuCycleUnit * 45;
  6871:         MC68060.catHighLongTime = mpuCycleUnit * 9;
  6872:         MC68060.catHighLineTime = mpuCycleUnit * 15;
  6873:       }
  6874:     }
  6875:   }  //mpuSetWait
  6876: 
  6877:   //mpuReset (device, romHandle)
  6878:   //  MPUをリセットしてからコアのタスクを起動する
  6879:   //  コアのタスクが動いているときはそれを中断する
  6880:   //  動いていたタスクが完全に止まってから再起動する
  6881:   public static void mpuReset (int device, int romHandle) {
  6882: 
  6883:     mpuBootDevice = device;
  6884:     mpuROMBootHandle = romHandle;
  6885: 
  6886:     //mpuBootDevice
  6887:     //  -1=リセット,0=OPT.1キーを押しながらリセット、その他=ここから再起動
  6888:     //  リセットのとき
  6889:     //    保存されている起動デバイスがあるとき
  6890:     //      起動デバイスを保存されている起動デバイスに変更する
  6891:     //      保存されている起動デバイスを消す
  6892:     //  リセット以外のとき
  6893:     //    保存されている起動デバイスがないとき
  6894:     //      起動デバイスを保存する
  6895:     //  メニューで起動デバイスが既定以外に設定されたとき
  6896:     //    保存されている起動デバイスを消す
  6897:     if (mpuBootDevice == -1) {  //リセットのとき
  6898:       if (mpuSavedBootDevice != -1) {  //保存されている起動デバイスがあるとき
  6899:         mpuBootDevice = mpuSavedBootDevice;  //起動デバイスを保存されている起動デバイスに変更する
  6900:         mpuROMBootHandle = mpuSavedROMBootHandle;
  6901:         mpuSavedBootDevice = -1;  //保存されている起動デバイスを消す
  6902:         mpuSavedROMBootHandle = -1;
  6903:       }
  6904:     } else {  //リセット以外のとき
  6905:       if (mpuSavedBootDevice == -1) {  //保存されている起動デバイスがないとき
  6906:         mpuSavedBootDevice = MainMemory.mmrRwz (0x00ed0018);  //起動デバイスを保存する
  6907:         mpuSavedROMBootHandle = MainMemory.mmrRls (0x00ed000c);
  6908:       }
  6909:     }
  6910: 
  6911:     //68000と68010のどちらを使うか選択する
  6912:     if (mpu010) {  //68010を使う
  6913:       if (specifiedFirstMPU == Model.MPU_MC68000) {  //68000のとき
  6914:         specifiedFirstMPU = Model.MPU_MC68010;  //68010に変更する
  6915:       }
  6916:       if (specifiedSecondMPU == Model.MPU_MC68000) {  //68000のとき
  6917:         specifiedSecondMPU = Model.MPU_MC68010;  //68010に変更する
  6918:       }
  6919:     } else {  //68000を使う
  6920:       if (specifiedFirstMPU == Model.MPU_MC68010) {  //68010のとき
  6921:         specifiedFirstMPU = Model.MPU_MC68000;  //68000に変更する
  6922:       }
  6923:       if (specifiedSecondMPU == Model.MPU_MC68010) {  //68010のとき
  6924:         specifiedSecondMPU = Model.MPU_MC68000;  //68000に変更する
  6925:       }
  6926:     }
  6927: 
  6928:     //1番目のMPUを選択する
  6929:     specifiedIsSecond = false;
  6930:     specifiedMPU = specifiedIsSecond ? specifiedSecondMPU : specifiedFirstMPU;
  6931:     specifiedClock = specifiedIsSecond ? specifiedSecondClock : specifiedFirstClock;
  6932: 
  6933:     if (MC68EC030.M30_DIV_ZERO_V_FLAG) {
  6934:       MC68EC030.m30DivZeroVFlag = false;
  6935:     }
  6936: 
  6937:     if (mpuTask != null) {
  6938:       mpuClockLimit = 0L;
  6939:       System.out.println (Multilingual.mlnJapanese ?
  6940:                           "MPU を停止します" :
  6941:                           "MPU stops");
  6942:       mpuTask.cancel ();
  6943:       mpuTask = null;
  6944:     }
  6945: 
  6946:     tmrTimer.schedule (new TimerTask () {
  6947:       @Override public void run () {
  6948: 
  6949:         //リセット後の値を現在の値にする
  6950:         //  機種とアクセラレータ
  6951:         currentModel = specifiedModel;
  6952:         currentAccelerator = specifiedAccelerator;
  6953:         frmUpdateTitle ();
  6954:         //  MPU
  6955:         currentIsSecond = specifiedIsSecond;
  6956:         currentFirstMPU = specifiedFirstMPU;
  6957:         currentSecondMPU = specifiedSecondMPU;
  6958:         currentMPU = specifiedMPU;
  6959:         //  クロック(MHz)
  6960:         mpuSetCurrentClock (specifiedClock);
  6961:         //  コプロセッサとオンチップFPU
  6962:         currentCopro0 = specifiedCopro0;
  6963:         currentCopro1 = specifiedCopro1;
  6964:         currentCopro2 = specifiedCopro2;
  6965:         currentOnchipFPU = specifiedOnchipFPU;
  6966: 
  6967:         //メモリマップを再構築する
  6968:         if (currentMPU < Model.MPU_MC68020) {
  6969:           if (busHimem68000) {
  6970:             busRequestExMemoryStart = 0x10000000;
  6971:             busRequestExMemorySize = busLocalMemorySize;
  6972:             busRequestExMemoryArray = busLocalMemoryArray;
  6973:           } else {
  6974:             busRequestExMemoryStart = 0x10000000;
  6975:             busRequestExMemorySize = 0 << 20;
  6976:             busRequestExMemoryArray = BUS_DUMMY_MEMORY_ARRAY;
  6977:           }
  6978:         } else if (currentMPU < Model.MPU_MC68LC040) {
  6979:           if (busHighMemory060turboOn) {
  6980:             busRequestExMemoryStart = 0x10000000;
  6981:             busRequestExMemorySize = busLocalMemorySize;
  6982:             busRequestExMemoryArray = busLocalMemoryArray;
  6983:           } else {
  6984:             busRequestExMemoryStart = 0x01000000;
  6985:             busRequestExMemorySize = busHighMemorySize;
  6986:             busRequestExMemoryArray = busHighMemoryArray;
  6987:           }
  6988:         } else {
  6989:           busRequestExMemoryStart = 0x10000000;
  6990:           busRequestExMemorySize = busLocalMemorySize;
  6991:           busRequestExMemoryArray = busLocalMemoryArray;
  6992:         }
  6993:         busUpdateMemoryMap ();
  6994: 
  6995:         //ROMを構築する
  6996:         ROM.romReset ();
  6997: 
  6998:         RegisterList.drpSetMPU ();
  6999: 
  7000:         mpuSFC = mpuDFC = mpuCACR = mpuBUSCR = mpuUSP = mpuVBR = mpuCAAR = mpuMSP = mpuISP = 0;
  7001:         mpuPCR = 0x04300500 | MPU_060_REV << 8;
  7002:         MC68060.mmuReset ();  //TCR,ITT0,ITT1,DTT0,DTT1,URP,SRP。060→000/030のときアドレス変換をOFFにする必要がある
  7003: 
  7004:         //マザーボードコプロセッサ
  7005:         if (Model.MPU_MC68020 <= currentMPU) {
  7006:           if ((7 & currentCopro0) == 1) {
  7007:             fpuMotherboardCoprocessor.epbSetMC68881 ();
  7008:           } else if ((7 & currentCopro0) == 2) {
  7009:             fpuMotherboardCoprocessor.epbSetMC68882 ();
  7010:           } else {  //7
  7011:             fpuMotherboardCoprocessor.epbSetFullSpec ();
  7012:           }
  7013:           if ((8 & currentCopro0) == 0) {
  7014:             fpuMotherboardCoprocessor.epbSetExtended ();
  7015:           } else {  //8
  7016:             fpuMotherboardCoprocessor.epbSetTriple ();
  7017:           }
  7018:         }
  7019:         //拡張コプロセッサ#1
  7020:         if ((7 & currentCopro1) == 1) {
  7021:           fpuCoproboard1.epbSetMC68881 ();
  7022:         } else if ((7 & currentCopro1) == 2) {
  7023:           fpuCoproboard1.epbSetMC68882 ();
  7024:         } else {  //7
  7025:           fpuCoproboard1.epbSetFullSpec ();
  7026:         }
  7027:         if ((8 & currentCopro1) == 0) {
  7028:           fpuCoproboard1.epbSetExtended ();
  7029:         } else {  //8
  7030:           fpuCoproboard1.epbSetTriple ();
  7031:         }
  7032:         //拡張コプロセッサ#2
  7033:         if ((7 & currentCopro2) == 1) {
  7034:           fpuCoproboard2.epbSetMC68881 ();
  7035:         } else if ((7 & currentCopro2) == 2) {
  7036:           fpuCoproboard2.epbSetMC68882 ();
  7037:         } else {  //7
  7038:           fpuCoproboard2.epbSetFullSpec ();
  7039:         }
  7040:         if ((8 & currentCopro2) == 0) {
  7041:           fpuCoproboard2.epbSetExtended ();
  7042:         } else {  //8
  7043:           fpuCoproboard2.epbSetTriple ();
  7044:         }
  7045:         //オンチップFPU
  7046:         if (Model.MPU_MC68040 <= currentMPU) {
  7047:           if ((7 & currentOnchipFPU) == 6) {
  7048:             fpuOnChipFPU.epbSetMC68060 ();
  7049:           } else {  //7
  7050:             fpuOnChipFPU.epbSetFullSpec ();
  7051:           }
  7052:           if ((8 & currentOnchipFPU) == 0) {
  7053:             fpuOnChipFPU.epbSetExtended ();
  7054:           } else {
  7055:             fpuOnChipFPU.epbSetTriple ();
  7056:           }
  7057:         }
  7058: 
  7059:         if (!currentModel.isX68030 ()) {  //X68000
  7060:           dmaCycleUnit = TMR_FREQ / 10000000L;  //DMACは10MHz
  7061:           HD63450.dmaBurstInterval = dmaCycleUnit << 4 + (HD63450.dmaBT >> 2);
  7062:           HD63450.dmaBurstSpan = HD63450.dmaBurstInterval >> 1 + (HD63450.dmaBR & 3);
  7063:           mpuROMWaitCycles = 1;
  7064:           mpuRAMWaitCycles = 0;
  7065:         } else {  //X68030
  7066:           dmaCycleUnit = TMR_FREQ / 12500000L;  //DMACは12.5MHz
  7067:           HD63450.dmaBurstInterval = dmaCycleUnit << 4 + (HD63450.dmaBT >> 2);
  7068:           HD63450.dmaBurstSpan = HD63450.dmaBurstInterval >> 1 + (HD63450.dmaBR & 3);
  7069:           mpuROMWaitCycles = 0;
  7070:           mpuRAMWaitCycles = 0;
  7071:         }
  7072: 
  7073:         busWaitCycles = busWaitCyclesRequest;
  7074:         busWaitTime = busWaitCycles ? mpuWaitTime : mpuNoWaitTime;
  7075: 
  7076:         HD63450.dmaReadCycles = (currentModel.isPRO () ? 6 :  //PROは6
  7077:                                  currentModel.isCompact () ? 4 :  //Compactは4
  7078:                                  5);  //その他は5
  7079:         HD63450.dmaWriteCycles = (currentModel.isPRO () ? 6 :  //PROは6
  7080:                                   5);  //その他は5
  7081: 
  7082:         if (currentMPU < Model.MPU_MC68020) {  //68000/68010
  7083: 
  7084:           mpuIgnoreAddressError = false;
  7085:           //mpuSFC = mpuDFC = mpuVBR = mpuISP = 0;
  7086:           mpuCacheOn = false;
  7087: 
  7088:         } else if (currentMPU < Model.MPU_MC68040) {  //68030
  7089: 
  7090:           mpuIgnoreAddressError = true;
  7091:           fpuBox = fpuMotherboardCoprocessor;
  7092:           fpuBox.epbReset ();
  7093:           fpuFPn = fpuBox.epbFPn;
  7094:           //mpuCACR = mpuUSP = mpuVBR = mpuCAAR = mpuMSP = mpuISP = 0;
  7095:           mpuCacheOn = (mpuCACR & 0x00000101) != 0;
  7096: 
  7097:         } else {  //68040/68060
  7098: 
  7099:           mpuIgnoreAddressError = true;
  7100:           fpuBox = fpuOnChipFPU;
  7101:           fpuBox.epbReset ();
  7102:           fpuFPn = fpuBox.epbFPn;
  7103:           //mpuSFC = mpuDFC = mpuCACR = mpuBUSCR = mpuUSP = mpuVBR = mpuURP = mpuSRP = 0;
  7104:           mpuPCR = 0x04300500 | MPU_060_REV << 8;
  7105:           mpuCacheOn = (mpuCACR & 0x80008000) != 0;
  7106:           if (MC68060.CAT_ON) {
  7107:             if (Model.MPU_MC68LC060 <= currentMPU) {  //68LC060,68060
  7108:               MC68060.catReset ();
  7109:             }
  7110:           }
  7111: 
  7112:         }
  7113: 
  7114:         mpuSetWait ();
  7115: 
  7116:         //! SSPとPCをROMのアドレスから直接読み出している
  7117:         regSRT1 = regSRT0 = 0;
  7118:         regSRS = REG_SR_S;
  7119:         regSRM = 0;
  7120:         regSRI = REG_SR_I;
  7121:         regCCR = 0;
  7122:         Arrays.fill (regRn, 0);
  7123:         //r[14] = 0x00001000;  //ROMDB2.32のバグ対策。コードにパッチをあてることにしたので不要
  7124:         regRn[15] = MainMemory.mmrRls (0x00ff0000);
  7125:         regPC = MainMemory.mmrRls (0x00ff0004);
  7126:         //メインメモリ
  7127:         MainMemory.mmrReset ();
  7128:         //バスコントローラ
  7129:         busReset ();
  7130:         if (InstructionBreakPoint.IBP_ON) {
  7131:           InstructionBreakPoint.ibpOp1MemoryMap = InstructionBreakPoint.ibpOp1SuperMap;
  7132:           InstructionBreakPoint.ibpReset ();
  7133:         }
  7134:         if (BranchLog.BLG_ON) {
  7135:           BranchLog.blgReset ();
  7136:         }
  7137:         //割り込み
  7138:         mpuIMR = 0;
  7139:         mpuIRR = 0;
  7140:         if (MC68901.MFP_DELAYED_INTERRUPT) {
  7141:           mpuDIRR = 0;
  7142:         }
  7143:         mpuISR = 0;
  7144:         //これでリセット命令が実行されるまでメインメモリとROM以外のデバイスは動かないはず
  7145:         //動作開始
  7146:         mpuStart ();
  7147:       }
  7148:     }, TMR_DELAY);
  7149: 
  7150:   }  //mpuReset(int,int)
  7151: 
  7152:   //mpuStopAndStart ()
  7153:   //  停止と再開
  7154:   public static void mpuStopAndStart () {
  7155:     if (mpuTask == null) {  //Run
  7156:       mpuStart ();
  7157:     } else {  //Stop
  7158:       if (RootPointerList.RTL_ON) {
  7159:         if (RootPointerList.rtlCurrentSupervisorTaskIsStoppable ||
  7160:             RootPointerList.rtlCurrentUserTaskIsStoppable) {
  7161:           mpuStop (null);
  7162:         }
  7163:       } else {
  7164:         mpuStop (null);
  7165:       }
  7166:     }
  7167:   }  //mpuStopAndStart
  7168: 
  7169:   //mpuStart ()
  7170:   //  コアのタスクを起動する
  7171:   //  コアのタスクが動いているときはそれを中断する
  7172:   //  動いていたタスクが完全に止まってから再起動する
  7173:   public static void mpuStart () {
  7174:     if (mpuTask != null) {
  7175:       mpuClockLimit = 0L;
  7176:       System.out.println (Multilingual.mlnJapanese ?
  7177:                           "MPU を停止します" :
  7178:                           "MPU stops");
  7179:       mpuTask.cancel ();
  7180:       mpuTask = null;
  7181:     }
  7182:     //停止中だけ有効なボタンを無効にする
  7183:     for (AbstractButton button : mpuButtonsStopped) {
  7184:       button.setEnabled (false);
  7185:     }
  7186:     DisassembleList.ddpStoppedBy = null;
  7187:     System.out.println (Model.mpuNameOf (currentMPU) + (Multilingual.mlnJapanese ? " を起動します" : " starts up"));
  7188:     mpuTask = new TimerTask () {
  7189:       @Override public void run () {
  7190:         mpuContinue = true;
  7191:         mpuClockLimit = mpuClockTime + TMR_FREQ * TMR_INTERVAL / 1000;
  7192:         mpuExecuteCore ();
  7193:       }
  7194:     };
  7195:     tmrTimer.scheduleAtFixedRate (mpuTask, TMR_DELAY, TMR_INTERVAL);  //固定頻度実行
  7196:     //動作中だけ有効なボタンを有効にする
  7197:     for (AbstractButton button : mpuButtonsRunning) {
  7198:       button.setEnabled (true);
  7199:     }
  7200:   }  //mpuStart()
  7201: 
  7202:   //mpuExecuteCore ()
  7203:   //  コアを実行する
  7204:   public static void mpuExecuteCore () {
  7205:     //コアメーター計測開始
  7206:     long nanoStart = System.nanoTime ();
  7207:     //RTCを準備する
  7208:     busSuper (RP5C15.rtcFirst, 0x00e8a000, 0x00e8c000);  //RTC RTC
  7209:     //busSuperMap[0x00e8a000 >>> BUS_PAGE_BITS] = RP5C15.rtcFirst;
  7210:     //コアを呼び出す
  7211:     if (currentMPU < Model.MPU_MC68010) {
  7212:       MC68000.mpuCore ();
  7213:     } else if (currentMPU < Model.MPU_MC68020) {
  7214:       MC68010.mpuCore ();
  7215:     } else if (currentMPU < Model.MPU_MC68LC040) {
  7216:       MC68EC030.mpuCore ();
  7217:     } else {
  7218:       MC68060.mpuCore ();
  7219:     }
  7220:     //デバッグウインドウを更新する
  7221:     if (dbgVisibleMask != 0) {  //デバッグ関連ウインドウが表示されている
  7222:       dbgUpdate ();
  7223:     }
  7224:     //コアメーター計測終了
  7225:     long nanoEnd = System.nanoTime ();
  7226:     mpuTotalNano += nanoEnd - nanoStart;
  7227:     if (--mpuAdjustmentCounter == 0) {
  7228:       //本来の経過時間(ns)
  7229:       final double expectedNano = 1e+6 * (double) (TMR_INTERVAL * MPU_ADJUSTMENT_INTERVAL);
  7230:       //コアの所要時間(ns)
  7231:       double coreNano0 = (double) mpuTotalNano;
  7232:       mpuTotalNano = 0L;
  7233:       double coreNanoA = (coreNano0 * 2.0 + mpuCoreNano1 + mpuCoreNano2) * 0.25;  //コアの所要時間(ns)
  7234:       mpuCoreNano2 = mpuCoreNano1;
  7235:       mpuCoreNano1 = coreNano0;
  7236:       //現在の負荷率(%)
  7237:       //  現在の負荷率(%) = 100.0 * コアの所要時間(ns) / 本来の経過時間(ns)
  7238:       //  処理が間に合っていないとき100%よりも大きくなる
  7239:       double actualPercent = Math.max (1.0, 100.0 * coreNanoA / expectedNano);
  7240:       //負荷率の上限(%)
  7241:       double maxPercent = SoundSource.sndPlayOn ? 90.0 : 100.0;  //音声出力がONのとき90%、さもなくば100%
  7242:       //目標の動作周波数(MHz)
  7243:       //double targetMHz = mpuClockMHz;
  7244:       //現在の動作周波数(MHz)
  7245:       //double currentMHz = mpuCurrentMHz;
  7246:       if (mpuUtilOn) {  //目標の負荷率に近付ける
  7247:         //目標の負荷率(%)
  7248:         double targetPercent = Math.min (maxPercent, (double) mpuUtilRatio);
  7249:         mpuSetClockMHz ((1.2 - 0.2 * actualPercent / targetPercent) * mpuCurrentMHz);
  7250:       } else {  //目標の周波数に近づける
  7251:         mpuSetClockMHz (Math.min (maxPercent / actualPercent,
  7252:                                   1.2 - 0.2 * mpuCurrentMHz / mpuClockMHz) * mpuCurrentMHz);
  7253:       }
  7254:       Indicator.indUpdate (actualPercent);
  7255:       mpuAdjustmentCounter = MPU_ADJUSTMENT_INTERVAL;
  7256:     }
  7257:   }
  7258: 
  7259:   //mpuStop (message)
  7260:   //  コアのタスクが動いているとき、それを止める
  7261:   //  完全に止まってからデバッグダイアログを更新する
  7262:   public static void mpuStop (String message) {
  7263:     //トレース実行とステップ実行を中止する
  7264:     mpuAdvanceCount = 0;
  7265:     mpuStepCount = 0;
  7266:     mpuContinue = false;
  7267:     mpuStop1 (message);
  7268:   }  //mpuStop(String)
  7269:   public static void mpuStop1 (String message) {
  7270:     if (mpuTask == null) {  //既に停止しているか停止処理が始まっている
  7271:       return;
  7272:     }
  7273:     DisassembleList.ddpStoppedBy = message;  //停止理由
  7274:     mpuClockLimit = 0L;
  7275:     System.out.println (Multilingual.mlnJapanese ?
  7276:                         "MPU を停止します" :
  7277:                         "MPU stops");
  7278:     mpuTask.cancel ();
  7279:     mpuTask = null;
  7280:     //ステップ実行を継続する
  7281:     if (mpuStepCount != 0 && mpuContinue) {
  7282:       if (mpuStepCount == -1 || --mpuStepCount != 0) {
  7283:         mpuStep (mpuStepCount);
  7284:         return;
  7285:       }
  7286:     }
  7287:     mpuAdvanceCount = 0;
  7288:     mpuStepCount = 0;
  7289:     mpuContinue = false;
  7290:     //動作中だけ有効なボタンを無効にする
  7291:     for (AbstractButton button : mpuButtonsRunning) {
  7292:       button.setEnabled (false);
  7293:     }
  7294:     tmrTimer.schedule (new TimerTask () {
  7295:       @Override public void run () {
  7296:         mpuUpdateWindow ();
  7297:       }
  7298:     }, TMR_DELAY);
  7299:   }  //mpuStop1(message)
  7300: 
  7301:   //mpuAdvance (n)
  7302:   //  n回トレース実行する。0回は不可
  7303:   //  1ターンで実行するのであまり大きな値を指定しないこと
  7304:   //  終わってからデバッグダイアログを更新する
  7305:   //  コアが止まっていないときは何もしない
  7306:   public static void mpuAdvance (int n) {
  7307:     if (mpuTask != null) {  //コアが止まっていない
  7308:       return;
  7309:     }
  7310:     mpuAdvanceCount = n;
  7311:     DisassembleList.ddpStoppedBy = null;
  7312:     mpuTask = new TimerTask () {
  7313:       @Override public void run () {
  7314:         mpuContinue = true;
  7315:         do {
  7316:           mpuClockLimit = mpuClockTime + 1L;
  7317:           mpuExecuteCore ();
  7318:         } while (mpuContinue && --mpuAdvanceCount != 0);
  7319:         mpuClockLimit = 0L;
  7320:         if (mpuTask != null) {  //最初の命令のエラーで停止したときnullになっている場合がある
  7321:           mpuTask.cancel ();
  7322:           mpuTask = null;
  7323:         }
  7324:         if (mpuStepCount != 0 && mpuContinue) {  //ステップ実行中に分岐命令を1命令実行して自然に終了した
  7325:           if (mpuStepCount == -1 || --mpuStepCount != 0) {
  7326:             mpuStep (mpuStepCount);
  7327:             return;
  7328:           }
  7329:         }
  7330:         mpuAdvanceCount = 0;
  7331:         mpuStepCount = 0;
  7332:         mpuContinue = false;
  7333:         mpuUpdateWindow ();
  7334:       }
  7335:     };
  7336:     tmrTimer.schedule (mpuTask, TMR_DELAY);
  7337:   }  //mpuAdvance(int)
  7338: 
  7339:   //mpuStep (n)
  7340:   //  n回ステップ実行する。0回は不可。-1はステップアンティルリターン
  7341:   //  次の命令が分岐命令のときはトレース実行と同じ
  7342:   //  次の命令が分岐命令でないときはその直後まで実行する
  7343:   //  コアが止まっていないときは何もしない
  7344:   public static void mpuStep (int n) {
  7345:     if (mpuTask != null) {  //コアが止まっていない
  7346:       return;
  7347:     }
  7348:     mpuStepCount = n;
  7349:     Disassembler.disDisassemble (new StringBuilder (), regPC, regSRS);
  7350:     if ((Disassembler.disStatus & (Disassembler.DIS_ALWAYS_BRANCH | Disassembler.DIS_SOMETIMES_BRANCH)) != 0) {
  7351:       if (mpuStepCount == -1 &&  //ステップアンティルリターン
  7352:           (Disassembler.disOC == 0x4e73 ||  //RTE
  7353:            Disassembler.disOC == 0x4e74 ||  //RTD
  7354:            Disassembler.disOC == 0x4e75 ||  //RTR
  7355:            Disassembler.disOC == 0x4e77) &&  //RTS
  7356:           mpuUntilReturnSRS == regSRS &&  //ユーザモード/スーパーバイザモードが同じ
  7357:           (currentMPU < Model.MPU_MC68LC040 ||
  7358:            mpuUntilReturnRP == (regSRS != 0 ? MC68060.mmuSRP : MC68060.mmuURP)) &&  //MC68060のときルートポインタが同じ
  7359:           mpuUntilReturnPC0 != regPC0 &&  //プログラムカウンタが違う
  7360:           Integer.compareUnsigned (mpuUntilReturnSP, regRn[15]) <= 0) {  //スタックポインタが減っていない
  7361:         mpuAdvanceCount = 0;
  7362:         mpuStepCount = 0;
  7363:         mpuContinue = false;
  7364:         mpuUpdateWindow ();
  7365:         return;
  7366:       }
  7367:       mpuAdvance (1);
  7368:     } else {
  7369:       if (InstructionBreakPoint.IBP_ON) {
  7370:         InstructionBreakPoint.ibpInstant (Disassembler.disPC, DisassembleList.ddpSupervisorMode);
  7371:         mpuStart ();
  7372:       }
  7373:     }
  7374:   }  //mpuStep(int)
  7375: 
  7376:   //mpuStepUntilReturn ()
  7377:   //  ステップアンティルリターン
  7378:   //  RTD,RTE,RTR,RTSを実行する直前で
  7379:   //    ステップアンティルリターン開始時と
  7380:   //      ユーザモード/スーパーバイザモードが同じ
  7381:   //      MC68060のときルートポインタが同じ
  7382:   //      プログラムカウンタが違う
  7383:   //      スタックポインタが減っていない
  7384:   //    ならば停止する
  7385:   //  コアが止まっていないときは何もしない
  7386:   public static void mpuStepUntilReturn () {
  7387:     if (mpuTask != null) {  //コアが止まっていない
  7388:       return;
  7389:     }
  7390:     mpuUntilReturnSRS = regSRS;
  7391:     mpuUntilReturnRP = regSRS != 0 ? MC68060.mmuSRP : MC68060.mmuURP;
  7392:     mpuUntilReturnPC0 = regPC0;
  7393:     mpuUntilReturnSP = regRn[15];
  7394:     mpuStep (-1);
  7395:   }  //mpuStepUntilReturn()
  7396: 
  7397:   //mpuUpdateWindow ()
  7398:   //  停止したときデバッグ関連ウインドウやボタンを更新する
  7399:   public static void mpuUpdateWindow () {
  7400:     if (dbgVisibleMask != 0) {  //デバッグ関連ウインドウが表示されている
  7401:       if ((dbgVisibleMask & DBG_DDP_VISIBLE_MASK) != 0) {
  7402:         DisassembleList.ddpBacktraceRecord = -1L;  //分岐レコードの選択を解除する
  7403:         DisassembleList.ddpUpdate (-1, -1, false);
  7404:       }
  7405:       if (BranchLog.BLG_ON) {
  7406:         if ((dbgVisibleMask & DBG_BLG_VISIBLE_MASK) != 0) {
  7407:           BranchLog.blgUpdate (BranchLog.BLG_SELECT_NEWEST);
  7408:         }
  7409:       }
  7410:       if (ProgramFlowVisualizer.PFV_ON) {
  7411:         if ((dbgVisibleMask & DBG_PFV_VISIBLE_MASK) != 0) {
  7412:           ProgramFlowVisualizer.pfvUpdate ();
  7413:         }
  7414:       }
  7415:       if (RasterBreakPoint.RBP_ON) {
  7416:         if ((dbgVisibleMask & DBG_RBP_VISIBLE_MASK) != 0) {
  7417:           RasterBreakPoint.rbpUpdateFrame ();
  7418:         }
  7419:       }
  7420:       if (ScreenModeTest.SMT_ON) {
  7421:         if ((dbgVisibleMask & DBG_SMT_VISIBLE_MASK) != 0) {
  7422:           ScreenModeTest.smtUpdateFrame ();
  7423:         }
  7424:       }
  7425:       if (RootPointerList.RTL_ON) {
  7426:         if ((dbgVisibleMask & DBG_RTL_VISIBLE_MASK) != 0) {
  7427:           RootPointerList.rtlUpdateFrame ();
  7428:         }
  7429:       }
  7430:       if (SpritePatternViewer.SPV_ON) {
  7431:         if ((dbgVisibleMask & DBG_SPV_VISIBLE_MASK) != 0) {
  7432:           SpritePatternViewer.spvUpdateFrame ();
  7433:         }
  7434:       }
  7435:       if (PaletteViewer.PLV_ON) {
  7436:         if ((dbgVisibleMask & DBG_PLV_VISIBLE_MASK) != 0) {
  7437:           PaletteViewer.plvUpdateFrame ();
  7438:         }
  7439:       }
  7440:       if (ATCMonitor.ACM_ON) {
  7441:         if ((dbgVisibleMask & DBG_ACM_VISIBLE_MASK) != 0) {
  7442:           ATCMonitor.acmUpdateFrame ();
  7443:         }
  7444:       }
  7445:     }
  7446:     //コンソールにレジスタ一覧を表示する
  7447:     if (DebugConsole.dgtRequestRegs != 0) {
  7448:       if ((DebugConsole.dgtRequestRegs & 1) != 0) {  //整数レジスタを表示する
  7449:         ExpressionEvaluator.ElementType.ETY_COMMAND_REGS.etyEval (null, ExpressionEvaluator.EVM_COMMAND);
  7450:       }
  7451:       if ((DebugConsole.dgtRequestRegs & 2) != 0) {  //浮動小数点レジスタを表示する
  7452:         ExpressionEvaluator.ElementType.ETY_COMMAND_FLOAT_REGS.etyEval (null, ExpressionEvaluator.EVM_COMMAND);
  7453:       }
  7454:       if ((DebugConsole.dgtRequestRegs & 4) != 0) {  //プロンプトを表示する
  7455:         DebugConsole.dgtPrintPrompt ();
  7456:       }
  7457:       DebugConsole.dgtRequestRegs = 0;  //表示が完了してから0にする
  7458:     }
  7459:     //動作中だけ有効なボタンを無効にする
  7460:     for (AbstractButton button : mpuButtonsRunning) {
  7461:       button.setEnabled (false);
  7462:     }
  7463:     //停止中だけ有効なボタンを有効にする
  7464:     for (AbstractButton button : mpuButtonsStopped) {
  7465:       button.setEnabled (true);
  7466:     }
  7467:   }  //mpuUpdateWindow()
  7468: 
  7469:   //button = mpuMakeBreakButton ()
  7470:   //  停止ボタンを作る
  7471:   public static JButton mpuMakeBreakButton () {
  7472:     return mpuAddButtonRunning (
  7473:       Multilingual.mlnToolTipText (
  7474:         ComponentFactory.createImageButton (
  7475:           LnF.LNF_BREAK_IMAGE,
  7476:           LnF.LNF_BREAK_DISABLED_IMAGE,
  7477:           "Stop", mpuDebugActionListener),
  7478:         "ja", "停止")
  7479:       );
  7480:   }  //mpuMakeBreakButton()
  7481: 
  7482:   //button = mpuMakeTraceButton ()
  7483:   //  トレース実行ボタンを作る
  7484:   public static JButton mpuMakeTraceButton () {
  7485:     return mpuAddButtonStopped (
  7486:       Multilingual.mlnToolTipText (
  7487:         ComponentFactory.createImageButton (
  7488:           LnF.LNF_TRACE_IMAGE,
  7489:           LnF.LNF_TRACE_DISABLED_IMAGE,
  7490:           "Trace", mpuDebugActionListener),
  7491:         "ja", "トレース")
  7492:       );
  7493:   }  //mpuMakeTraceButton()
  7494: 
  7495:   //button = mpuMakeTrace10Button ()
  7496:   //  トレース10回ボタンを作る
  7497:   public static JButton mpuMakeTrace10Button () {
  7498:     return mpuAddButtonStopped (
  7499:       Multilingual.mlnToolTipText (
  7500:         ComponentFactory.createImageButton (
  7501:           LnF.LNF_TRACE_10_IMAGE,
  7502:           LnF.LNF_TRACE_10_DISABLED_IMAGE,
  7503:           "Trace 10 times", mpuDebugActionListener),
  7504:         "ja", "トレース 10 回")
  7505:       );
  7506:   }  //mpuMakeTrace10Button()
  7507: 
  7508:   //button = mpuMakeTrace100Button ()
  7509:   //  トレース100回ボタンを作る
  7510:   public static JButton mpuMakeTrace100Button () {
  7511:     return mpuAddButtonStopped (
  7512:       Multilingual.mlnToolTipText (
  7513:         ComponentFactory.createImageButton (
  7514:           LnF.LNF_TRACE_100_IMAGE,
  7515:           LnF.LNF_TRACE_100_DISABLED_IMAGE,
  7516:           "Trace 100 times", mpuDebugActionListener),
  7517:         "ja", "トレース 100 回")
  7518:       );
  7519:   }  //mpuMakeTrace100Button()
  7520: 
  7521:   //button = mpuMakeStepButton ()
  7522:   //  ステップ実行ボタンを作る
  7523:   public static JButton mpuMakeStepButton () {
  7524:     return mpuAddButtonStopped (
  7525:       Multilingual.mlnToolTipText (
  7526:         ComponentFactory.createImageButton (
  7527:           LnF.LNF_STEP_IMAGE,
  7528:           LnF.LNF_STEP_DISABLED_IMAGE,
  7529:           "Step", mpuDebugActionListener),
  7530:         "ja", "ステップ")
  7531:       );
  7532:   }  //mpuMakeStepButton()
  7533: 
  7534:   //button = mpuMakeStep10Button ()
  7535:   //  ステップ10回ボタンを作る
  7536:   public static JButton mpuMakeStep10Button () {
  7537:     return mpuAddButtonStopped (
  7538:       Multilingual.mlnToolTipText (
  7539:         ComponentFactory.createImageButton (
  7540:           LnF.LNF_STEP_10_IMAGE,
  7541:           LnF.LNF_STEP_10_DISABLED_IMAGE,
  7542:           "Step 10 times", mpuDebugActionListener),
  7543:         "ja", "ステップ 10 回")
  7544:       );
  7545:   }  //mpuMakeStep10Button()
  7546: 
  7547:   //button = mpuMakeStep100Button ()
  7548:   //  ステップ100回ボタンを作る
  7549:   public static JButton mpuMakeStep100Button () {
  7550:     return mpuAddButtonStopped (
  7551:       Multilingual.mlnToolTipText (
  7552:         ComponentFactory.createImageButton (
  7553:           LnF.LNF_STEP_100_IMAGE,
  7554:           LnF.LNF_STEP_100_DISABLED_IMAGE,
  7555:           "Step 100 times", mpuDebugActionListener),
  7556:         "ja", "ステップ 100 回")
  7557:       );
  7558:   }  //mpuMakeStep100Button()
  7559: 
  7560:   //button = mpuMakeReturnButton ()
  7561:   //  ステップアンティルリターンボタンを作る
  7562:   public static JButton mpuMakeReturnButton () {
  7563:     return mpuAddButtonStopped (
  7564:       Multilingual.mlnToolTipText (
  7565:         ComponentFactory.createImageButton (
  7566:           LnF.LNF_STEP_UNTIL_RETURN_IMAGE,
  7567:           LnF.LNF_STEP_UNTIL_RETURN_DISABLED_IMAGE,
  7568:           "Step until return", mpuDebugActionListener),
  7569:         "ja", "ステップアンティルリターン")
  7570:       );
  7571:   }  //mpuMakeReturnButton()
  7572: 
  7573:   //button = mpuMakeRunButton ()
  7574:   //  実行ボタンを作る
  7575:   public static JButton mpuMakeRunButton () {
  7576:     return mpuAddButtonStopped (
  7577:       Multilingual.mlnToolTipText (
  7578:         ComponentFactory.createImageButton (
  7579:           LnF.LNF_RUN_IMAGE,
  7580:           LnF.LNF_RUN_DISABLED_IMAGE,
  7581:           "Run", mpuDebugActionListener),
  7582:         "ja", "実行")
  7583:       );
  7584:   }  //mpuMakeRunButton()
  7585: 
  7586:   //button = mpuAddButtonRunning (button)
  7587:   //  MPUが動作中のときだけ有効なボタンを追加する
  7588:   public static <T extends AbstractButton> T mpuAddButtonRunning (T button) {
  7589:     button.setEnabled (mpuTask != null);
  7590:     mpuButtonsRunning.add (button);
  7591:     return button;
  7592:   }
  7593: 
  7594:   //button = mpuAddButtonStopped (button)
  7595:   //  MPUが停止中のときだけ有効なボタンを追加する
  7596:   public static <T extends AbstractButton> T mpuAddButtonStopped (T button) {
  7597:     button.setEnabled (mpuTask == null);
  7598:     mpuButtonsStopped.add (button);
  7599:     return button;
  7600:   }
  7601: 
  7602: 
  7603: 
  7604:   //========================================================================================
  7605:   //$$EMX エミュレータ拡張命令
  7606:   //  下位6bitの組み合わせで64個まで追加できる
  7607:   //  オペコードが変更される場合があるので原則としてユーザは使用禁止
  7608:   //  オペコード開始位置の上位10bitを変更するときはジャンプテーブルも修正すること
  7609:   //
  7610:   //  WAIT命令
  7611:   //    現在の割り込みマスクレベルで割り込みを受け付ける以外に何もしない
  7612:   //    やっていることはBRA *相当の無限ループだが、分岐ログは変化しない
  7613:   //    1回あたりの所要時間はMPUの種類や動作周波数に関係なく0.01msとする
  7614:   //    ホストのファイルにアクセスするといった時間のかかる処理を行うとき、
  7615:   //    コアを止めてしまうと本来ならば割り込みを用いて続けられる音楽やアニメーションが止まってしまうので、
  7616:   //    時間のかかる処理は別スレッドで行い、それが終わるまでコアはWAIT命令を繰り返して待つ
  7617:   public static final int EMX_OPCODE_BASE    = 0x4e00;  //オペコード開始位置
  7618:   public static final int EMX_OPCODE_HFSBOOT = EMX_OPCODE_BASE + 0x00;
  7619:   public static final int EMX_OPCODE_HFSINST = EMX_OPCODE_BASE + 0x01;
  7620:   public static final int EMX_OPCODE_HFSSTR  = EMX_OPCODE_BASE + 0x02;
  7621:   public static final int EMX_OPCODE_HFSINT  = EMX_OPCODE_BASE + 0x03;
  7622:   public static final int EMX_OPCODE_EMXNOP  = EMX_OPCODE_BASE + 0x04;
  7623:   public static final int EMX_OPCODE_EMXWAIT = EMX_OPCODE_BASE + 0x05;
  7624: 
  7625:   public static final String[] EMX_MNEMONIC_ARRAY = {
  7626:     "hfsboot",
  7627:     "hfsinst",
  7628:     "hfsstr",
  7629:     "hfsint",
  7630:     "emxnop",
  7631:     "emxwait",
  7632:   };
  7633: 
  7634:   //emxNop ()
  7635:   //  命令としては何もしない
  7636:   //  コードに埋め込んでパッチをあてたりするのに使う
  7637:   public static void emxNop () {
  7638:     if (MainMemory.mmrHumanVersion == 0x0302 && regPC0 == 0x00007140) {  //デバイスドライバを初期化する直前
  7639:       int head = regRn[9];  //初期化するデバイスドライバのデバイスヘッダのアドレス
  7640:       int tail = MC68060.mmuPeekLongData (0x00001c00, 1);  //デバイスドライバが使える末尾のアドレス
  7641:       //----------------------------------------------------------------
  7642:       //PCM8Aにパッチをあてる
  7643:       emxPatchPCM8A (head, tail);
  7644:       //----------------------------------------------------------------
  7645:       //RSDRV.SYS 2.02の先頭アドレスを保存する
  7646:       emxCheckRSDRV202 (head, tail);
  7647:     } else if (MainMemory.mmrHumanVersion == 0x0302 && regPC0 == 0x0000716c) {  //デバイスドライバを初期化した直後
  7648:       int head = regRn[9];  //初期化されたデバイスドライバのデバイスヘッダのアドレス
  7649:       int tail = MC68060.mmuPeekLongData (0x00001c00, 1);  //デバイスドライバが使える末尾のアドレス
  7650:       //----------------------------------------------------------------
  7651:       //060turbo.sysにパッチをあてる
  7652:       emxPatch060turbosys (head, tail);
  7653:       //----------------------------------------------------------------
  7654:       //FSX.Xのマウス受信データ処理ルーチンとマウスワークのアドレスを保存する
  7655:       if (Z8530.SCC_FSX_MOUSE) {
  7656:         emxCheckFSX (head, tail);
  7657:       }
  7658:       //----------------------------------------------------------------
  7659:       //TwentyOne.xのオプションのアドレスを保存する
  7660:       if (HFS.HFS_USE_TWENTY_ONE) {
  7661:         emxCheckTwentyOne (head, tail);
  7662:       }
  7663:       //----------------------------------------------------------------
  7664:       //ラベルをクリアする
  7665:       LabeledAddress.lblClear ();
  7666:     } else if (MainMemory.mmrHumanVersion == 0x0302 && regPC0 == 0x0000972c) {  //プロセスを起動する直前
  7667:       int head = regRn[8] + 256;  //起動するプロセスのメモリ管理テーブルのアドレス+256=プロセスの先頭
  7668:       //int tail = regRn[9];  //bssの末尾
  7669:       int tail = MC68060.mmuPeekLong (head - 208, 1);  //bssの先頭
  7670:       //----------------------------------------------------------------
  7671:       //bsio.x 0.21の先頭アドレスを保存する
  7672:       emxCheckBSIO021 (head, tail);
  7673:       //----------------------------------------------------------------
  7674:       //PCM8Aにパッチをあてる
  7675:       emxPatchPCM8A (head, tail);
  7676:       //----------------------------------------------------------------
  7677:       //tmsio.x 0.31の先頭アドレスを保存する
  7678:       emxCheckTMSIO031 (head, tail);
  7679:       //----------------------------------------------------------------
  7680:       //ラベルをクリアする
  7681:       LabeledAddress.lblClear ();
  7682:       //----------------------------------------------------------------
  7683:       //実行開始位置で停止する
  7684:       if (dbgStopAtStart) {
  7685:         InstructionBreakPoint.ibpInstant (regRn[12], 0);  //a4
  7686:       }
  7687:     } else if (MainMemory.mmrHumanVersion == 0x0302 && regPC0 == 0x0000a090) {  //プロセスが常駐した直後
  7688:       int head = regRn[8] + 256;  //常駐したプロセスのメモリ管理テーブルのアドレス+256=プロセスの先頭
  7689:       int tail = MC68060.mmuPeekLongData (regRn[8] + 8, 1);  //メモリブロックが使用している末尾
  7690:       String name = MC68060.mmuPeekStringZ (head - 60, 1);  //実行ファイル名
  7691:       if (name.equalsIgnoreCase ("fsx.x")) {
  7692:         //----------------------------------------------------------------
  7693:         //FSX.Xのマウス受信データ処理ルーチンとマウスワークのアドレスを保存する
  7694:         if (Z8530.SCC_FSX_MOUSE) {
  7695:           emxCheckFSX (head, tail);
  7696:         }
  7697:       }
  7698:       if (name.equalsIgnoreCase ("TwentyOne.x")) {
  7699:         //----------------------------------------------------------------
  7700:         //TwentyOne.xのオプションのアドレスを保存する
  7701:         if (HFS.HFS_USE_TWENTY_ONE) {
  7702:           emxCheckTwentyOne (head, tail);
  7703:         }
  7704:       }
  7705:     }
  7706:   }  //emxNop()
  7707: 
  7708:   public static final int[] emxPCM8AFFMap = {
  7709:     0x00000138, 0x000001f6, 0x00000394, 0x000011ec, 0x0000120a, 0x00001400, 0x00001814, 0x00001870, 0x00001882, 0x0000188a,
  7710:     0x00001892, 0x000018a2, 0x000018a8, 0x000018ca, 0x000018d4, 0x000018e0, 0x000018e8, 0x00001908, 0x000019e4, 0x00001afa,
  7711:     0x00001b58, 0x00001b7c, 0x00001bac, 0x00001c38, 0x00001ccc, 0x000021f8, 0x00002250, 0x00002258, 0x00002290, 0x000022a6,
  7712:     0x000022b0, 0x000022c0, 0x000022c8, 0x000022de, 0x000022ea, 0x000030c8, 0x000030de, 0x000030e6, 0x000030ea, 0x000030f6,
  7713:     0x00003112, 0x00003188, 0x0000334c, 0x0000338a, 0x000033a2, 0x000033c4, 0x000033d0, 0x0000341a, 0x00003428, 0x00003496,
  7714:     0x000034a6, 0x000034d6, 0x0000fe0e, 0x0000fec8, 0x0000feec, 0x0000ff46, 0x0000ff4e,
  7715:   };
  7716: 
  7717:   //emxPatchPCM8A (head, tail)
  7718:   //  headから始まるデバイスドライバまたはプロセスがPCM8A.X v1.02ならばパッチをあてる
  7719:   public static void emxPatchPCM8A (int head, int tail) {
  7720:     if (head + 0x0000ff60 <= tail &&
  7721:         MC68060.mmuPeekLongData (head + 0x10f8, 1) == 0x50434d38 &&  //PCM8
  7722:         MC68060.mmuPeekLongData (head + 0x10fc, 1) == 0x41313032) {  //A102
  7723:       System.out.println (Multilingual.mlnJapanese ?
  7724:                           "PCM8A.X 1.02 があります" :
  7725:                           "PCM8A.X 1.02 exists");
  7726:       int patched = 0;
  7727:       int failed = 0;
  7728:       //  I/Oポートのアドレスの上位8ビットが$FFになっているところを$00に修正します。(57箇所)
  7729:       for (int offset : emxPCM8AFFMap) {
  7730:         if (MC68060.mmuPeekByteZeroData (head + offset, 1) == 0xff) {
  7731:           MC68060.mmuPokeByteData (head + offset, 0x00, 1);
  7732:           patched++;
  7733:         } else {
  7734:           failed++;
  7735:         }
  7736:       }
  7737:       if (patched != 0) {
  7738:         System.out.printf (Multilingual.mlnJapanese ?
  7739:                            "PCM8A.X 1.02 にパッチをあてました (%d/%d)\n" :
  7740:                            "PCM8A.X 1.02 was patched (%d/%d)\n",
  7741:                            patched, patched + failed);
  7742:       }
  7743:     }
  7744:   }  //emxPatchPCM8A
  7745: 
  7746:   //emxPatch060turbosys (head, tail)
  7747:   //  060turbo.sysにパッチをあてる
  7748:   public static void emxPatch060turbosys (int head, int tail) {
  7749:     //  sysStat_8000::
  7750:     //  00000EC0  203C302E3536  move.l  #'0.56',d0
  7751:     //  00000EC6  227C30363054  movea.l #'060T',a1
  7752:     //  00000ECC  4E75          rts
  7753:     if (head + 0x00002000 <= tail &&
  7754:         MC68060.mmuPeekLongData (head + 0x00000ec0, 1) == 0x203c302e &&
  7755:         MC68060.mmuPeekLongData (head + 0x00000ec4, 1) == 0x3536227c &&
  7756:         MC68060.mmuPeekLongData (head + 0x00000ec8, 1) == 0x30363054) {  //060turbo.sys version 0.56
  7757:       System.out.println (Multilingual.mlnJapanese ?
  7758:                           "060turbo.sys 0.56 があります" :
  7759:                           "060turbo.sys 0.56 exists");
  7760:       //SCSIコールでバスエラーが出ることがある
  7761:       //  SRAMのソフト転送フラグを確認する命令がbtstではなくbsetになっている
  7762:       //  000021E6  08F9000400ED0070  bset.b  #4,$00ED0070  →  000021E6  0839000400ED0070  btst.b  #4,$00ED0070
  7763:       int patched = 0;
  7764:       int failed = 0;
  7765:       if (MC68060.mmuPeekLongData (head + 0x000021e6, 1) == 0x08f90004 &&
  7766:           MC68060.mmuPeekLongData (head + 0x000021ea, 1) == 0x00ed0070) {
  7767:         MC68060.mmuPokeWordData (head + 0x000021e6, 0x0839, 1);
  7768:         patched++;
  7769:       } else {
  7770:         failed++;
  7771:       }
  7772:       System.out.printf (Multilingual.mlnJapanese ?
  7773:                          "060turbo.sys 0.56 にパッチをあてました (%d/%d)\n" :
  7774:                          "060turbo.sys 0.56 was patched (%d/%d)\n",
  7775:                          patched, patched + failed);
  7776:     }
  7777:   }  //emxPatch060turbosys
  7778: 
  7779:   //emxCheckFSX (head, tail)
  7780:   //  headから始まるデバイスドライバまたはプロセスがFSX.Xならばマウス受信データ処理ルーチンとマウスワークのアドレスを保存する
  7781:   public static void emxCheckFSX (int head, int tail) {
  7782:     if (Z8530.SCC_FSX_MOUSE) {
  7783:       if (head + 0x00063200 <= tail &&
  7784:           "\r\nSX SYSTEM for X68000  version 3.10\r\nCopyright 1990,91,92,93,94 SHARP/First Class Technology\r\n".equals (MC68060.mmuPeekStringZ (head + 0x0001ae, 5))) {
  7785:         System.out.println (Multilingual.mlnJapanese ?
  7786:                             "FSX.X 3.10 があります" :
  7787:                             "FSX.X 3.10 exists");
  7788:         Z8530.sccFSXMouseHook = head + 0x04f82a;  //マウス受信データ処理ルーチン
  7789:         Z8530.sccFSXMouseWork = head + 0x063184;  //マウスワーク
  7790:       }
  7791:     }
  7792:   }  //emxCheckFSX
  7793: 
  7794:   //emxCheckRSDRV202 (head, tail)
  7795:   //  RSDRV.SYS 2.02の先頭アドレスを保存する
  7796:   //  あるからといって使われているとは限らない
  7797:   //  タイトル部分はバッファになるので実行前に呼び出すこと
  7798:   //  ボーレート11=76800bpsを指定できるようにパッチをあてる
  7799:   public static void emxCheckRSDRV202 (int head, int tail) {
  7800:     if (head + 0x000ea6 <= tail &&
  7801:         MC68060.mmuPeekEquals (head + 0x000e4e, "RS-232C DRIVER for X68000 version 2.02")) {
  7802:       if (RS232CTerminal.trmRSDRV202Head != head) {
  7803:         RS232CTerminal.trmRSDRV202Head = head;
  7804:         int[] patchData = {
  7805:           //                                 変更前                         変更後
  7806:           //                           05F6  B03C  cmp.b   #10,d0           B03C  cmp.b   #11,d0
  7807:           0x05f8, 0x000a, 0x000b,  //  05F8  000A                           000B
  7808:           //
  7809:           0x0600, 0xd040, 0x2048,  //  0600  D040  add.w   d0,d0            2048  movea.l a0,a0
  7810:           //
  7811:           0x060e, 0x3030, 0x4e90,  //  060E  3030  move.w  $00(a0,d0.w),d0  4E90  jsr     (a0)
  7812:           0x0610, 0x0000, 0x2048,  //  0610  0000                           2048  movea.l a0,a0
  7813:           //
  7814:           0x074e, 0x0821, 0x2041,  //  074E  0821  .dc.w   2081             2041  movea.l d1,a0
  7815:           0x0750, 0x0410, 0x3200,  //  0750  0410  .dc.w   1040             3200  move.w  d0,d1
  7816:           0x0752, 0x0207, 0x303c,  //  0752  0207  .dc.w   519              303C  move.w  #2083,d0
  7817:           0x0754, 0x0102, 0x0823,  //  0754  0102  .dc.w   258              0823
  7818:           0x0756, 0x0080, 0xe268,  //  0756  0080  .dc.w   128              E268  lsr.w   d1,d0
  7819:           0x0758, 0x003f, 0x72fe,  //  0758  003F  .dc.w   63               72FE  moveq.l #-2,d1
  7820:           0x075a, 0x001f, 0xd141,  //  075A  001F  .dc.w   31               D141  addx.w  d1,d0
  7821:           0x075c, 0x000e, 0x2208,  //  075C  000E  .dc.w   14               2208  move.l  a0,d1
  7822:           0x075e, 0x0006, 0x4e75,  //  075E  0006  .dc.w   6                4E75  rts
  7823:           //                           0760  0002  .dc.w   2
  7824:           //
  7825:           0x0ab0, 0x0040, 0x0400,  //  0AB0  0040  .dc.w   64               0400  .dc.w   1024
  7826:           0x0ad2, 0x0040, 0x0400,  //  0AD2  0040  .dc.w   64               0400  .dc.w   1024
  7827:           0x0af4, 0x0040, 0x0400,  //  0AF4  0040  .dc.w   64               0400  .dc.w   1024
  7828:           0x0b16, 0x0040, 0x0400,  //  0B16  0040  .dc.w   64               0400  .dc.w   1024
  7829:           0x0b38, 0x0040, 0x0400,  //  0B38  0040  .dc.w   64               0400  .dc.w   1024
  7830:           //
  7831:           //                           0CAC  B23C  cmp.b   #9,d1            B23C  cmp.b   #11,d1
  7832:           0x0cae, 0x0009, 0x000b,  //  0CAE  0009                           000B
  7833:         };
  7834:         int patched = 0;
  7835:         int failed = 0;
  7836:         for (int i = 0; i < patchData.length; i += 3) {
  7837:           int a = head + patchData[i];
  7838:           int b = patchData[i + 1];
  7839:           int c = patchData[i + 2];
  7840:           int d = MC68060.mmuPeekWordZeroData (a, 1);
  7841:           if (d == b) {
  7842:             MC68060.mmuPokeWordData (a, c, 1);
  7843:             patched++;
  7844:           } else if (d != c) {
  7845:             failed++;
  7846:           }
  7847:         }
  7848:         System.out.printf ("RSDRV.SYS 2.02 found at %08X and patched (%d/%d)\n", head, patched, patched + failed);
  7849:       }
  7850:     }
  7851:   }
  7852: 
  7853:   //emxCheckTMSIO031 (head, tail)
  7854:   //  tmsio.x 0.31の先頭アドレスを保存する
  7855:   //  あるからといって使われているとは限らない
  7856:   //  タイトル部分はバッファになるので実行前に呼び出すこと
  7857:   public static void emxCheckTMSIO031 (int head, int tail) {
  7858:     if (head + 0x000fc4 <= tail &&
  7859:         MC68060.mmuPeekEquals (head + 0x000d1c, "TMSIO version 0.31 Copyright (C) 1990-93 by Miki Hoshino")) {
  7860:       if (RS232CTerminal.trmTMSIO031Head != head) {
  7861:         RS232CTerminal.trmTMSIO031Head = head;
  7862:         System.out.printf ("TMSIO 0.31 found at %08X\n", head);
  7863:       }
  7864:     }
  7865:   }
  7866: 
  7867:   //emxCheckBSIO021 (head, tail)
  7868:   //  bsio.x 0.21の先頭アドレスを保存する
  7869:   //  あるからといって使われているとは限らない
  7870:   //  タイトル部分はバッファになるので実行前に呼び出すこと
  7871:   public static void emxCheckBSIO021 (int head, int tail) {
  7872:     if (head + 0x001c2c <= tail &&
  7873:         MC68060.mmuPeekEquals (head + 0x001a66, "BSIO  version 0.21 Copyright (C) 1994    By BAZU")) {
  7874:       if (RS232CTerminal.trmBSIO021Head != head) {
  7875:         RS232CTerminal.trmBSIO021Head = head;
  7876:         System.out.printf ("BSIO 0.21 found at %08X\n", head);
  7877:       }
  7878:     }
  7879:   }
  7880: 
  7881:   //emxCheckTwentyOne (head, tail)
  7882:   //  headから始まるデバイスドライバまたはプロセスがTwentyOne.xならばオプションのアドレスを保存する
  7883:   public static void emxCheckTwentyOne (int head, int tail) {
  7884:     if (HFS.HFS_USE_TWENTY_ONE &&
  7885:         head + 64 <= tail) {
  7886:       if (MainMemory.mmrTwentyOneOptionAddress != 0 ||  //TwentyOne.xのオプションのアドレスは確認済みまたは非対応のバージョン
  7887:           MainMemory.mmrHumanVersion <= 0) {  //Human68kのバージョンが未確認または未知のバージョン
  7888:         return;
  7889:       }
  7890:       int name1 = MC68060.mmuPeekLongData (head + 14, 1);
  7891:       if (name1 == ('*' << 24 | 'T' << 16 | 'w' << 8 | 'e')) {
  7892:         int name2 = MC68060.mmuPeekLongData (head + 18, 1);
  7893:         if (name2 == ('n' << 24 | 't' << 16 | 'y' << 8 | '*')) {  //TwentyOne.x v1.10まで
  7894:           MainMemory.mmrTwentyOneOptionAddress = -1;  //非対応
  7895:         }
  7896:       } else if (name1 == ('?' << 24 | 'T' << 16 | 'w' << 8 | 'e')) {
  7897:         int name2 = MC68060.mmuPeekLongData (head + 18, 1);
  7898:         if (name2 == ('n' << 24 | 't' << 16 | 'y' << 8 | '?') ||
  7899:             name2 == ('n' << 24 | 't' << 16 | 'y' << 8 | 'E')) {  //TwentyOne.x v1.11から
  7900:           System.out.println (Multilingual.mlnJapanese ?
  7901:                               "TwentyOne.x があります" :
  7902:                               "TwentyOne.x exists");
  7903:           MainMemory.mmrTwentyOneOptionAddress = head + 22;
  7904:         }
  7905:       }
  7906:     }
  7907:   }  //emxCheckTwentyOne
  7908: 
  7909: 
  7910: 
  7911:   //========================================================================================
  7912:   //$$IRP 命令の処理
  7913:   //
  7914:   //  変数名
  7915:   //    op                                   オペコード。iiii_qqq_nnn_mmm_rrr
  7916:   //    iiii  op >> 12                       命令の種類。ここでは定数
  7917:   //    qqq   (op >> 9) - (iiii << 3)        クイックイミディエイトまたはデータレジスタDqの番号
  7918:   //    aqq   (op >> 9) - ((iiii << 3) - 8)  アドレスレジスタAqの番号
  7919:   //    nnn   op >> 6 & 7                    デスティネーションの実効アドレスのモード
  7920:   //    ea    op & 63                        実効アドレスのモードとレジスタ
  7921:   //    mmm   ea >> 3                        実効アドレスのモード
  7922:   //    rrr   op & 7                         実効アドレスのレジスタ。DrまたはRrのときr[rrr]はr[ea]で代用できる
  7923:   //    cccc  op >> 8 & 15                   コンディションコード
  7924:   //    a                                    実効アドレス
  7925:   //    s                                    テンポラリ
  7926:   //    t                                    テンポラリ
  7927:   //    w                                    拡張ワード
  7928:   //    x                                    被演算数
  7929:   //    y                                    演算数
  7930:   //    z                                    結果
  7931:   //
  7932:   //  サイクル数
  7933:   //    mpuCycleCountにMC68000のサイクル数を加算する
  7934:   //      MC68030のサイクル数はMC68000のサイクル数の0.6倍とみなして計算する
  7935:   //      これはROM1.3で起動したときDBRA命令で計測される動作周波数の表示の辻褄を合わせるための係数であり、
  7936:   //      MC68000とMC68030のサイクル数の比の平均値ではない
  7937:   //        10MHzのMC68000と25MHzのMC68030の速度の比が25/10/0.6=4.17倍となるので何倍も外れてはいないと思われる
  7938:   //    MC68000に存在しない命令のサイクル数はMC68000に存在すると仮定した場合の推定値を用いる
  7939:   //      オペコードを含むリードとライトを1ワードあたり4サイクルとする
  7940:   //
  7941:   //  拡張命令
  7942:   //    差し障りのない範囲でいくつかの命令を追加してある
  7943:   //    エミュレータ拡張命令
  7944:   //      HFSBOOT                                         |-|012346|-|-----|-----|          |0100_111_000_000_000
  7945:   //      HFSINST                                         |-|012346|-|-----|-----|          |0100_111_000_000_001
  7946:   //      HFSSTR                                          |-|012346|-|-----|-----|          |0100_111_000_000_010
  7947:   //      HFSINT                                          |-|012346|-|-----|-----|          |0100_111_000_000_011
  7948:   //      EMXNOP                                          |-|012346|-|-----|-----|          |0100_111_000_000_100
  7949:   //    MC68000で欠番になっているオペコードに割り当てられているColdFireの命令
  7950:   //      BITREV.L Dr                                     |-|------|-|-----|-----|D         |0000_000_011_000_rrr (ISA_C)
  7951:   //      BYTEREV.L Dr                                    |-|------|-|-----|-----|D         |0000_001_011_000_rrr (ISA_C)
  7952:   //      FF1.L Dr                                        |-|------|-|-UUUU|-**00|D         |0000_010_011_000_rrr (ISA_C)
  7953:   //      MVS.B <ea>,Dq                                   |-|------|-|-UUUU|-**00|D M+-WXZPI|0111_qqq_100_mmm_rrr (ISA_B)
  7954:   //      MVS.W <ea>,Dq                                   |-|------|-|-UUUU|-**00|D M+-WXZPI|0111_qqq_101_mmm_rrr (ISA_B)
  7955:   //      MVZ.B <ea>,Dq                                   |-|------|-|-UUUU|-0*00|D M+-WXZPI|0111_qqq_110_mmm_rrr (ISA_B)
  7956:   //      MVZ.W <ea>,Dq                                   |-|------|-|-UUUU|-0*00|D M+-WXZPI|0111_qqq_111_mmm_rrr (ISA_B)
  7957:   //      SATS.L Dr                                       |-|------|-|-UUUU|-**00|D         |0100_110_010_000_rrr (ISA_B)
  7958: 
  7959:   public static final boolean IRP_BITREV_REVERSE = false;  //true=BITREVでInteger.reverseを使う
  7960:   public static final boolean IRP_BITREV_SHIFT = false;  //true=BITREVでシフト演算子を使う
  7961:   public static final boolean IRP_BITREV_TABLE = true;  //true=BITREVでテーブルを使う
  7962: 
  7963:   public static final boolean IRP_MOVEM_MAINMEMORY = true;  //true=000のときMOVEMでメインメモリを特別扱いにする
  7964:   public static final boolean IRP_MOVEM_EXPAND = false;  //true=MOVEMで16回展開する。遅くなる
  7965:   public static final boolean IRP_MOVEM_LOOP = false;  //true=MOVEMで16回ループする。コンパイラが展開する
  7966:   public static final boolean IRP_MOVEM_SHIFT_LEFT = false;  //true=MOVEMで0になるまで左にシフトする。reverseが入る分遅い
  7967:   public static final boolean IRP_MOVEM_SHIFT_RIGHT = true;  //true=MOVEMで0になるまで右にシフトする
  7968:   public static final boolean IRP_MOVEM_ZEROS = false;  //true=MOVEMでInteger.numberOfTrailingZerosを使う。ループ回数は少ないがスキップする処理が冗長になるので最速ではない
  7969: 
  7970:   //  リセット命令
  7971:   public static void irpReset () {
  7972:     long t = System.nanoTime ();
  7973:     //メインメモリのmmrResetとバスコントローラのbusResetはmpuResetへ
  7974:     CRTC.crtReset ();  //CRT CRTコントローラ
  7975:     VideoController.vcnReset ();  //VCN ビデオコントローラ
  7976:     HD63450.dmaReset ();  //DMA DMAコントローラ
  7977:     MC68901.mfpReset ();  //MFP MFP
  7978:     Keyboard.kbdReset ();  //KBD キーボード
  7979:     RP5C15.rtcReset ();  //RTC RTC
  7980:     PrinterPort.prnReset ();  //PRN プリンタポート
  7981:     SoundSource.sndReset ();  //SND サウンド
  7982:     OPM.opmReset ();  //OPM FM音源
  7983:     ADPCM.pcmReset ();  //PCM ADPCM音源
  7984:     FDC.fdcReset ();  //FDC FDコントローラ
  7985:     IOInterrupt.ioiReset ();  //IOI I/O割り込み
  7986:     eb2Reset ();  //EB2 拡張ボードレベル2割り込み
  7987:     if (HostCDROM.HCD_ENABLED) {  //HCD ホストCD-ROM
  7988:       HostCDROM.hcdReset ();
  7989:     }
  7990:     SPC.spcReset ();  //SPC SCSIプロトコルコントローラ
  7991:     Z8530.sccReset ();  //SCC SCC
  7992:     RS232CTerminal.trmReset ();  //TRM RS-232C設定とターミナル
  7993:     PPI.ppiReset ();  //PPI PPI
  7994:     HFS.hfsReset ();  //HFS ホストファイルシステムインタフェイス
  7995:     SpriteScreen.sprReset ();  //SPR スプライト画面
  7996:     //smrReset()はspcSCSIEXOnとspcSCSIINOnを使うのでSPC.spcReset()よりも後であること
  7997:     if (MercuryUnit.MU4_ON) {
  7998:       MercuryUnit.mu4Reset ();
  7999:     }
  8000:     xt3Reset ();  //XT3 Xellent30
  8001:     SRAM.smrReset ();  //SMR SRAM
  8002:     CONDevice.conReset ();  //CON CONデバイス制御
  8003:     TextCopy.txcReset ();  //TXC テキストコピー。romReset()より後
  8004:     //9msを上限として所要時間を仮想時間に加える
  8005:     mpuClockTime += Math.min (TMR_FREQ * 9 / 1000, (System.nanoTime () - t) * 1000L);
  8006:   }  //irpReset()
  8007: 
  8008:   //右シフト・ローテート命令
  8009:   //
  8010:   //  ASR
  8011:   //    X  countが0のとき変化しない。他は最後に押し出されたビット
  8012:   //    N  結果の最上位ビット
  8013:   //    Z  結果が0のときセット。他はクリア
  8014:   //    V  常にクリア
  8015:   //    C  countが0のときクリア。他は最後に押し出されたビット
  8016:   //    ASR.B
  8017:   //         ........................アイウエオカキク X C
  8018:   //       0 ........................アイウエオカキク X 0
  8019:   //       1 ........................アアイウエオカキ ク ク
  8020:   //       :
  8021:   //       7 ........................アアアアアアアア イ イ
  8022:   //       8 ........................アアアアアアアア ア ア
  8023:   //    ASR.W
  8024:   //         ................アイウエオカキクケコサシスセソタ X C
  8025:   //       0 ................アイウエオカキクケコサシスセソタ X 0
  8026:   //       1 ................アアイウエオカキクケコサシスセソ タ タ
  8027:   //       :
  8028:   //      15 ................アアアアアアアアアアアアアアアア イ イ
  8029:   //      16 ................アアアアアアアアアアアアアアアア ア ア
  8030:   //    ASR.L
  8031:   //         アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X C
  8032:   //       0 アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X 0
  8033:   //       1 アアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマ ミ ミ
  8034:   //       :
  8035:   //      31 アアアアアアアアアアアアアアアアアアアアアアアアアアアアアアアア イ イ
  8036:   //      32 アアアアアアアアアアアアアアアアアアアアアアアアアアアアアアアア ア ア
  8037:   //
  8038:   //  LSR
  8039:   //    X  countが0のとき変化しない。他は最後に押し出されたビット
  8040:   //    N  結果の最上位ビット
  8041:   //    Z  結果が0のときセット。他はクリア
  8042:   //    V  常にクリア
  8043:   //    C  countが0のときクリア。他は最後に押し出されたビット
  8044:   //    LSR.B
  8045:   //         ........................アイウエオカキク X C
  8046:   //       0 ........................アイウエオカキク X 0
  8047:   //       1 ........................0アイウエオカキ ク ク
  8048:   //       :
  8049:   //       7 ........................0000000ア イ イ
  8050:   //       8 ........................00000000 ア ア
  8051:   //       9 ........................00000000 0 0
  8052:   //    LSR.W
  8053:   //         ................アイウエオカキクケコサシスセソタ X C
  8054:   //       0 ................アイウエオカキクケコサシスセソタ X 0
  8055:   //       1 ................0アイウエオカキクケコサシスセソ タ タ
  8056:   //       :
  8057:   //      15 ................000000000000000ア イ イ
  8058:   //      16 ................0000000000000000 ア ア
  8059:   //      17 ................0000000000000000 0 0
  8060:   //    LSR.L
  8061:   //         アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X C
  8062:   //       0 アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X 0
  8063:   //       1 0アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマ ミ ミ
  8064:   //       :
  8065:   //      31 0000000000000000000000000000000ア イ イ
  8066:   //      32 00000000000000000000000000000000 ア ア
  8067:   //      33 00000000000000000000000000000000 0 0
  8068:   //
  8069:   //  ROXR
  8070:   //    X  countが0のとき変化しない。他は最後に押し出されたビット
  8071:   //    N  結果の最上位ビット
  8072:   //    Z  結果が0のときセット。他はクリア
  8073:   //    V  常にクリア
  8074:   //    C  countが0のときXのコピー。他は最後に押し出されたビット
  8075:   //    ROXR.B
  8076:   //         ........................アイウエオカキク X C
  8077:   //       0 ........................アイウエオカキク X X
  8078:   //       1 ........................Xアイウエオカキ ク ク
  8079:   //       2 ........................クXアイウエオカ キ キ
  8080:   //       :
  8081:   //       7 ........................ウエオカキクXア イ イ
  8082:   //       8 ........................イウエオカキクX ア ア
  8083:   //       9 ........................アイウエオカキク X X
  8084:   //    ROXR.W
  8085:   //         ................アイウエオカキクケコサシスセソタ X C
  8086:   //       0 ................アイウエオカキクケコサシスセソタ X X
  8087:   //       1 ................Xアイウエオカキクケコサシスセソ タ タ
  8088:   //       2 ................タXアイウエオカキクケコサシスセ ソ ソ
  8089:   //       :
  8090:   //      15 ................ウエオカキクケコサシスセソタXア イ イ
  8091:   //      16 ................イウエオカキクケコサシスセソタX ア ア
  8092:   //      17 ................アイウエオカキクケコサシスセソタ X X
  8093:   //    ROXR.L
  8094:   //         アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X C
  8095:   //       0 アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X X
  8096:   //       1 Xアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマ ミ ミ
  8097:   //       2 ミXアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホ マ マ
  8098:   //       :
  8099:   //      31 ウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミXア イ イ
  8100:   //      32 イウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミX ア ア
  8101:   //      33 アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X X
  8102:   //
  8103:   //  ROR
  8104:   //    X  常に変化しない
  8105:   //    N  結果の最上位ビット
  8106:   //    Z  結果が0のときセット。他はクリア
  8107:   //    V  常にクリア
  8108:   //    C  countが0のときクリア。他は結果の最上位ビット
  8109:   //    ROR.B
  8110:   //         ........................アイウエオカキク X C
  8111:   //       0 ........................アイウエオカキク X 0
  8112:   //       1 ........................クアイウエオカキ X ク
  8113:   //       :
  8114:   //       7 ........................イウエオカキクア X イ
  8115:   //       8 ........................アイウエオカキク X ア
  8116:   //    ROR.W
  8117:   //         ................アイウエオカキクケコサシスセソタ X C
  8118:   //       0 ................アイウエオカキクケコサシスセソタ X 0
  8119:   //       1 ................タアイウエオカキクケコサシスセソ X タ
  8120:   //       :
  8121:   //      15 ................イウエオカキクケコサシスセソタア X イ
  8122:   //      16 ................アイウエオカキクケコサシスセソタ X ア
  8123:   //    ROR.L
  8124:   //         アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X C
  8125:   //       0 アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X 0
  8126:   //       1 ミアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマ X ミ
  8127:   //       :
  8128:   //      31 イウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミア X イ
  8129:   //      32 アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X ア
  8130: 
  8131:   //左シフト・ローテート命令
  8132:   //
  8133:   //  ASL
  8134:   //    X  countが0のとき変化しない。他は最後に押し出されたビット
  8135:   //    N  結果の最上位ビット
  8136:   //    Z  結果が0のときセット。他はクリア
  8137:   //    V  ASRで元に戻せないときセット。他はクリア
  8138:   //    C  countが0のときクリア。他は最後に押し出されたビット
  8139:   //    ASL.B
  8140:   //         ........................アイウエオカキク X C
  8141:   //       0 ........................アイウエオカキク X 0
  8142:   //       1 ........................イウエオカキク0 ア ア
  8143:   //       :
  8144:   //       7 ........................ク0000000 キ キ
  8145:   //       8 ........................00000000 ク ク
  8146:   //       9 ........................00000000 0 0
  8147:   //    ASL.W
  8148:   //         ................アイウエオカキクケコサシスセソタ X C
  8149:   //       0 ................アイウエオカキクケコサシスセソタ X 0
  8150:   //       1 ................イウエオカキクケコサシスセソタ0 ア ア
  8151:   //       :
  8152:   //      15 ................タ000000000000000 ソ ソ
  8153:   //      16 ................0000000000000000 タ タ
  8154:   //      17 ................0000000000000000 0 0
  8155:   //    ASL.L
  8156:   //         アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X C
  8157:   //       0 アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X 0
  8158:   //       1 イウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ0 ア ア
  8159:   //       :
  8160:   //      31 ミ0000000000000000000000000000000 マ マ
  8161:   //      32 00000000000000000000000000000000 ミ ミ
  8162:   //      33 00000000000000000000000000000000 0 0
  8163:   //
  8164:   //  LSL
  8165:   //    X  countが0のとき変化しない。他は最後に押し出されたビット
  8166:   //    N  結果の最上位ビット
  8167:   //    Z  結果が0のときセット。他はクリア
  8168:   //    V  常にクリア
  8169:   //    C  countが0のときクリア。他は最後に押し出されたビット
  8170:   //    LSL.B
  8171:   //         ........................アイウエオカキク X C
  8172:   //       0 ........................アイウエオカキク X 0
  8173:   //       1 ........................イウエオカキク0 ア ア
  8174:   //       :
  8175:   //       7 ........................ク0000000 キ キ
  8176:   //       8 ........................00000000 ク ク
  8177:   //       9 ........................00000000 0 0
  8178:   //    LSL.W
  8179:   //         ................アイウエオカキクケコサシスセソタ X C
  8180:   //       0 ................アイウエオカキクケコサシスセソタ X 0
  8181:   //       1 ................イウエオカキクケコサシスセソタ0 ア ア
  8182:   //       :
  8183:   //      15 ................タ000000000000000 ソ ソ
  8184:   //      16 ................0000000000000000 タ タ
  8185:   //      17 ................0000000000000000 0 0
  8186:   //    LSL.L
  8187:   //         アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X C
  8188:   //       0 アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X 0
  8189:   //       1 イウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ0 ア ア
  8190:   //       :
  8191:   //      31 ミ0000000000000000000000000000000 マ マ
  8192:   //      32 00000000000000000000000000000000 ミ ミ
  8193:   //      33 00000000000000000000000000000000 0 0
  8194:   //
  8195:   //  ROXL
  8196:   //    X  countが0のとき変化しない。他は最後に押し出されたビット
  8197:   //    N  結果の最上位ビット
  8198:   //    Z  結果が0のときセット。他はクリア
  8199:   //    V  常にクリア
  8200:   //    C  countが0のときXのコピー。他は最後に押し出されたビット
  8201:   //    ROXL.B
  8202:   //         ........................アイウエオカキク X C
  8203:   //       0 ........................アイウエオカキク X X
  8204:   //       1 ........................イウエオカキクX ア ア
  8205:   //       2 ........................ウエオカキクXア イ イ
  8206:   //       :
  8207:   //       7 ........................クXアイウエオカ キ キ
  8208:   //       8 ........................Xアイウエオカキ ク ク
  8209:   //       9 ........................アイウエオカキク X X
  8210:   //    ROXL.W
  8211:   //         ................アイウエオカキクケコサシスセソタ X C
  8212:   //       0 ................アイウエオカキクケコサシスセソタ X X
  8213:   //       1 ................イウエオカキクケコサシスセソタX ア ア
  8214:   //       2 ................ウエオカキクケコサシスセソタXア イ イ
  8215:   //       :
  8216:   //      15 ................タXアイウエオカキクケコサシスセ ソ ソ
  8217:   //      16 ................Xアイウエオカキクケコサシスセソ タ タ
  8218:   //      17 ................アイウエオカキクケコサシスセソタ X X
  8219:   //    ROXL.L
  8220:   //         アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X C
  8221:   //       0 アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X X
  8222:   //       1 イウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミX ア ア
  8223:   //       2 ウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミXア イ イ
  8224:   //       :
  8225:   //      31 ミXアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホ マ マ
  8226:   //      32 Xアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマ ミ ミ
  8227:   //      33 アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X X
  8228:   //
  8229:   //  ROL
  8230:   //    X  常に変化しない
  8231:   //    N  結果の最上位ビット
  8232:   //    Z  結果が0のときセット。他はクリア
  8233:   //    V  常にクリア
  8234:   //    C  countが0のときクリア。他は結果の最下位ビット
  8235:   //    ROL.B
  8236:   //         ........................アイウエオカキク X C
  8237:   //       0 ........................アイウエオカキク X 0
  8238:   //       1 ........................イウエオカキクア X ア
  8239:   //       :
  8240:   //       7 ........................クアイウエオカキ X キ
  8241:   //       8 ........................アイウエオカキク X ク
  8242:   //    ROL.W
  8243:   //         ................アイウエオカキクケコサシスセソタ X C
  8244:   //       0 ................アイウエオカキクケコサシスセソタ X 0
  8245:   //       1 ................イウエオカキクケコサシスセソタア X ア
  8246:   //       :
  8247:   //      15 ................タアイウエオカキクケコサシスセソ X ソ
  8248:   //      16 ................アイウエオカキクケコサシスセソタ X タ
  8249:   //    ROL.L
  8250:   //         アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X C
  8251:   //       0 アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X 0
  8252:   //       1 イウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミア X ア
  8253:   //       :
  8254:   //      31 ミアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマ X マ
  8255:   //      32 アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミ X ミ
  8256: 
  8257: 
  8258: 
  8259:   //========================================================================================
  8260:   //以下のメソッドはインライン展開する
  8261: /*
  8262:   public static void pushb (int x) throws M68kException {
  8263:     wb (r[15] -= 2, x);  //ワードの上位側
  8264:   }  //pushb(int)
  8265:   public static void pushw (int x) throws M68kException {
  8266:     ww (r[15] -= 2, x);
  8267:   }  //pushw(int)
  8268:   public static void pushl (int x) throws M68kException {
  8269:     wl (r[15] -= 4, x);
  8270:   }  //pushl(int)
  8271: 
  8272:   public static int popbs () throws M68kException {
  8273:     return rbs ((r[15] += 2) - 2);  //ワードの上位側
  8274:   }  //popbs()
  8275:   public static int popbz () throws M68kException {
  8276:     return rbz ((r[15] += 2) - 2);  //ワードの上位側
  8277:   }  //popbz()
  8278:   public static int popws () throws M68kException {
  8279:     return rws ((r[15] += 2) - 2);
  8280:   }  //popws()
  8281:   public static int popwz () throws M68kException {
  8282:     return rwz ((r[15] += 2) - 2);
  8283:   }  //popwz()
  8284:   public static int popls () throws M68kException {
  8285:     return rls ((r[15] += 4) - 4);
  8286:   }  //popls()
  8287: 
  8288:   public static int pcbs () throws M68kException {
  8289:     return rbs ((pc += 2) - 1);  //ワードの下位側
  8290:   }  //pcbs()
  8291:   public static int pcbz () throws M68kException {
  8292:     return rbz ((pc += 2) - 1);  //ワードの下位側
  8293:   }  //pcbz()
  8294:   public static int pcws () throws M68kException {
  8295:     return rwse ((pc += 2) - 2);
  8296:   }  //pcws()
  8297:   public static int pcwz () throws M68kException {
  8298:     return rwze ((pc += 2) - 2);
  8299:   }  //pcwz()
  8300:   public static int pcls () throws M68kException {
  8301:     return rlse ((pc += 4) - 4);
  8302:   }  //pcls()
  8303: 
  8304:   public static void ccr_tst (int z) {  //Xは変化しない。VとCはクリア
  8305:     ccr = z >> 28 & CCR_N | (z == 0 ? ccr & CCR_X | CCR_Z : ccr & CCR_X);  //ccr_tst
  8306:   }  //ccr_tst(int)
  8307:   public static void ccr_btst (int z) {  //Z以外は変化しない
  8308:     ccr = (ccr & (CCR_X | CCR_N | CCR_V | CCR_C) | (z == 0 ? CCR_Z : 0));
  8309:   }  //ccr_btst(int)
  8310:   public static void ccr_clr () {  //Xは変化しない。Zはセット。NとVとCはクリア
  8311:     ccr = ccr & CCR_X | CCR_Z;  //ccr_clr
  8312:   }  //ccr_clr(int)
  8313: 
  8314:   //                  x-y V                                  x-y C
  8315:   //  x  y|  0   1   2   3  -4  -3  -2  -1   x  y|  0   1   2   3   4   5   6   7
  8316:   //  ----+--------------------------------  ----+--------------------------------
  8317:   //    0 |  0  -1  -2  -3   4*  3   2   1     0 |  0  -1* -2* -3* -4* -5* -6* -7*
  8318:   //    1 |  1   0  -1  -2   5*  4*  3   2     1 |  1   0  -1* -2* -3* -4* -5* -6*
  8319:   //    2 |  2   1   0  -1   6*  5*  4*  3     2 |  2   1   0  -1* -2* -3* -4* -5*
  8320:   //    3 |  3   2   1   0   7*  6*  5*  4*    3 |  3   2   1   0  -1* -2* -3* -4*
  8321:   //   -4 | -4  -5* -6* -7*  0  -1  -2  -3     4 |  4   3   2   1   0  -1* -2* -3*
  8322:   //   -3 | -3  -4  -5* -6*  1   0  -1  -2     5 |  5   4   3   2   1   0  -1* -2*
  8323:   //   -2 | -2  -3  -4  -5*  2   1   0  -1     6 |  6   5   4   3   2   1   0  -1*
  8324:   //   -1 | -1  -2  -3  -4   3   2   1   0     7 |  7   6   5   4   3   2   1   0
  8325:   //                 x-y-1 V                                x-y-1 C
  8326:   //  x  y|  0   1   2   3  -4  -3  -2  -1   x  y|  0   1   2   3   4   5   6   7
  8327:   //  ----+--------------------------------  ----+--------------------------------
  8328:   //    0 | -1  -2  -3  -4   3   2   1   0     0 | -1* -2* -3* -4* -5* -6* -7* -8*
  8329:   //    1 |  0  -1  -2  -3   4*  3   2   1     1 |  0  -1* -2* -3* -4* -5* -6* -7*
  8330:   //    2 |  1   0  -1  -2   5*  4*  3   2     2 |  1   0  -1* -2* -3* -4* -5* -6*
  8331:   //    3 |  2   1   0  -1   6*  5*  4*  3     3 |  2   1   0  -1* -2* -3* -4* -5*
  8332:   //   -4 | -5* -6* -7* -8* -1  -2  -3  -4     4 |  3   2   1   0  -1* -2* -3* -4*
  8333:   //   -3 | -4  -5* -6* -7*  0  -1  -2  -3     5 |  4   3   2   1   0  -1* -2* -3*
  8334:   //   -2 | -3  -4  -5* -6*  1   0  -1  -2     6 |  5   4   3   2   1   0  -1* -2*
  8335:   //   -1 | -2  -3  -4  -5*  2   1   0  -1     7 |  6   5   4   3   2   1   0  -1*
  8336:   //  x        y         z=x-y    v        c         z=x-y-1  v        c
  8337:   //  00000000 00001111  01111000 00001000 01111111  11110000 00000000 11111111
  8338:   //  00000000 00001111  00111100 00001100 00111111  01111000 00001000 01111111
  8339:   //  00000000 00001111  00011110 00001110 00011111  00111100 00001100 00111111
  8340:   //  00000000 00001111  00001111 00001111 00001111  00011110 00001110 00011111
  8341:   //  11111111 00001111  10000111 01110000 00000111  00001111 11110000 00001111
  8342:   //  11111111 00001111  11000011 00110000 00000011  10000111 01110000 00000111
  8343:   //  11111111 00001111  11100001 00010000 00000001  11000011 00110000 00000011
  8344:   //  11111111 00001111  11110000 00000000 00000000  11100001 00010000 00000001
  8345:   //  Vは右上と左下でxとzが異なる部分
  8346:   //    V = ((x ^ y) & (x ^ z)) < 0
  8347:   //  Cは右上全部および左上と右下でzがある部分
  8348:   //    C = (~x & y | ~(x ^ y) & z) < 0
  8349:   //    ~を使わずに書けるおそらく最短の等価式
  8350:   //    C = (x & (y ^ z) ^ (y | z)) < 0
  8351:   //      perl -e "for$x(0..1){for$y(0..1){for$z(0..1){print join(',',$x,$y,$z,(1^$x)&$y|(1^($x^$y))&$z,$x&($y^$z)^($y|$z)).chr(10);}}}"
  8352:   //      0,0,0,0,0
  8353:   //      0,0,1,1,1
  8354:   //      0,1,0,1,1
  8355:   //      0,1,1,1,1
  8356:   //      1,0,0,0,0
  8357:   //      1,0,1,0,0
  8358:   //      1,1,0,0,0
  8359:   //      1,1,1,1,1
  8360:   public static void ccr_sub (int x, int y, int z) {
  8361:     ccr = (z >> 28 & CCR_N | (z == 0 ? CCR_Z : 0) |
  8362:            ((x ^ y) & (x ^ z)) >>> 31 << 1 |
  8363:            (x & (y ^ z) ^ (y | z)) >> 31 & (CCR_X | CCR_C));
  8364:   }  //ccr_sub(int,int,int)
  8365:   public static void ccr_subx (int x, int y, int z) {  //Zは結果が0のとき変化しない
  8366:     ccr = (z >> 28 & CCR_N | (z == 0 ? ccr & CCR_Z : 0) |
  8367:            ((x ^ y) & (x ^ z)) >>> 31 << 1 |
  8368:            (x & (y ^ z) ^ (y | z)) >> 31 & (CCR_X | CCR_C));
  8369:   }  //ccr_subx(int,int,int)
  8370:   public static void ccr_subq (int x, int y, int z) {  //ccr_subを常にy>0としたもの。Vは負→正のとき1。Cは正→負のとき1
  8371:     ccr = (z >> 28 & CCR_N | (z == 0 ? CCR_Z : 0) |
  8372:            (x & ~z) >>> 31 << 1 |
  8373:            (~x & z) >> 31 & (CCR_X | CCR_C));
  8374:   }  //ccr_subq(int,int,int)
  8375:   public static void ccr_neg (int y, int z) {  //ccr_subを常にx==0としたもの。Vは-MAX→-MAXのみ1。Cは0→0以外1
  8376:     ccr = (z >> 28 & CCR_N | (z == 0 ? CCR_Z : 0) |
  8377:            (y & z) >>> 31 << 1 |
  8378:            (y | z) >> 31 & (CCR_X | CCR_C));
  8379:   }  //ccr_neg(int,int)
  8380:   public static void ccr_negx (int y, int z) {  //ccr_subxを常にx==0としたもの。Zは結果が0のとき変化しない
  8381:     ccr = (z >> 28 & CCR_N | (z == 0 ? ccr & CCR_Z : 0) |
  8382:            (y & z) >>> 31 << 1 |
  8383:            (y | z) >> 31 & (CCR_X | CCR_C));
  8384:   }  //ccr_negx(int,int)
  8385:   public static void ccr_cmp (int x, int y, int z) {  //Xは変化しない
  8386:     ccr = (z >> 28 & CCR_N | (z == 0 ? ccr & CCR_X | CCR_Z : ccr & CCR_X) |
  8387:            ((x ^ y) & (x ^ z)) >>> 31 << 1 |
  8388:            (x & (y ^ z) ^ (y | z)) >>> 31);
  8389:   }  //ccr_cmp(int,int,int)
  8390: 
  8391:   //                  x+y V                                  x+y C
  8392:   //  x  y|  0   1   2   3  -4  -3  -2  -1   x  y|  0   1   2   3   4   5   6   7
  8393:   //  ----+--------------------------------  ----+--------------------------------
  8394:   //    0 |  0   1   2   3  -4  -3  -2  -1     0 |  0   1   2   3   4   5   6   7
  8395:   //    1 |  1   2   3   4* -3  -2  -1   0     1 |  1   2   3   4   5   6   7   8*
  8396:   //    2 |  2   3   4*  5* -2  -1   0   1     2 |  2   3   4   5   6   7   8*  9*
  8397:   //    3 |  3   4*  5*  6* -1   0   1   2     3 |  3   4   5   6   7   8*  9* 10*
  8398:   //   -4 | -4  -3  -2  -1  -8* -7* -6* -5*    4 |  4   5   6   7   8*  9* 10* 11*
  8399:   //   -3 | -3  -2  -1   0  -7* -6* -5* -4     5 |  5   6   7   8*  9* 10* 11* 12*
  8400:   //   -2 | -2  -1   0   1  -6* -5* -4  -3     6 |  6   7   8*  9* 10* 11* 12* 13*
  8401:   //   -1 | -1   0   1   2  -5* -4  -3  -2     7 |  7   8*  9* 10* 11* 12* 13* 14*
  8402:   //                 x+y+1 V                                x+y+1 C
  8403:   //  x  y|  0   1   2   3  -4  -3  -2  -1   x  y|  0   1   2   3   4   5   6   7
  8404:   //  ----+--------------------------------  ----+--------------------------------
  8405:   //    0 |  1   2   3   4* -3  -2  -1   0     0 |  1   2   3   4   5   6   7   8*
  8406:   //    1 |  2   3   4*  5* -2  -1   0   1     1 |  2   3   4   5   6   7   8*  9*
  8407:   //    2 |  3   4*  5*  6* -1   0   1   2     2 |  3   4   5   6   7   8*  9* 10*
  8408:   //    3 |  4*  5*  6*  7*  0   1   2   3     3 |  4   5   6   7   8*  9* 10* 11*
  8409:   //   -4 | -3  -2  -1   0  -7* -6* -5* -4     4 |  5   6   7   8*  9* 10* 11* 12*
  8410:   //   -3 | -2  -1   0   1  -6* -5* -4  -3     5 |  6   7   8*  9* 10* 11* 12* 13*
  8411:   //   -2 | -1   0   1   2  -5* -4  -3  -2     6 |  7   8*  9* 10* 11* 12* 13* 14*
  8412:   //   -1 |  0   1   2   3  -4  -3  -2  -1     7 |  8*  9* 10* 11* 12* 13* 14* 15*
  8413:   //  x        y         z=x+y    v        c         z=x+y+1  v        c
  8414:   //  00000000 00001111  00001111 00000000 00000000  00011110 00010000 00000001
  8415:   //  00000000 00001111  00011110 00010000 00000001  00111100 00110000 00000011
  8416:   //  00000000 00001111  00111100 00110000 00000011  01111000 01110000 00000111
  8417:   //  00000000 00001111  01111000 01110000 00000111  11110000 11110000 00001111
  8418:   //  11111111 00001111  11110000 00001111 00001111  11100001 00001110 00011111
  8419:   //  11111111 00001111  11100001 00001110 00011111  11000011 00001100 00111111
  8420:   //  11111111 00001111  11000011 00001100 00111111  10000111 00001000 01111111
  8421:   //  11111111 00001111  10000111 00001000 01111111  00001111 00000000 11111111
  8422:   //  Vは左上と右下でxとzが異なる部分
  8423:   //    V = (~(x ^ y) & (x ^ z)) < 0
  8424:   //    ~を使わずに書けるおそらく最短の等価式
  8425:   //    V = ((x ^ z) & (y ^ z)) < 0
  8426:   //      perl -e "for$x(0..1){for$y(0..1){for$z(0..1){print join(',',$x,$y,$z,(1^($x^$y))&($x^$z),($x^$z)&($y^$z)).chr(10);}}}"
  8427:   //      0,0,0,0,0
  8428:   //      0,0,1,1,1
  8429:   //      0,1,0,0,0
  8430:   //      0,1,1,0,0
  8431:   //      1,0,0,0,0
  8432:   //      1,0,1,0,0
  8433:   //      1,1,0,1,1
  8434:   //      1,1,1,0,0
  8435:   //  Cは右下全部および右上と左下でzがない部分
  8436:   //    C = (x & y | (x ^ y) & ~z) < 0
  8437:   //    ~を使わずに書けるおそらく最短の等価式
  8438:   //    C = ((x | y) ^ (x ^ y) & z) < 0
  8439:   //      perl -e "for$x(0..1){for$y(0..1){for$z(0..1){print join(',',$x,$y,$z,$x&$y|($x^$y)&(1^$z),($x|$y)^($x^$y)&$z).chr(10);}}}"
  8440:   //      0,0,0,0,0
  8441:   //      0,0,1,0,0
  8442:   //      0,1,0,1,1
  8443:   //      0,1,1,0,0
  8444:   //      1,0,0,1,1
  8445:   //      1,0,1,0,0
  8446:   //      1,1,0,1,1
  8447:   //      1,1,1,1,1
  8448:   public static void ccr_add (int x, int y, int z) {
  8449:     ccr = (z >> 28 & CCR_N | (z == 0 ? CCR_Z : 0) |
  8450:            ((x ^ z) & (y ^ z)) >>> 31 << 1 |
  8451:            ((x | y) ^ (x ^ y) & z) >> 31 & (CCR_X | CCR_C));
  8452:   }  //ccr_add(int,int,int)
  8453:   public static void ccr_addx (int x, int y, int z) {  //Zは結果が0のとき変化しない
  8454:     ccr = (z >> 28 & CCR_N | (z == 0 ? ccr & CCR_Z : 0) |
  8455:            ((x ^ z) & (y ^ z)) >>> 31 << 1 |
  8456:            ((x | y) ^ (x ^ y) & z) >> 31 & (CCR_X | CCR_C));
  8457:   }  //ccr_addx(int,int,int)
  8458:   public static void ccr_addq (int x, int y, int z) {  //ccr_addを常にy>0としたもの。Vは正→負のとき1。Cは負→正のとき1
  8459:     ccr = (z >> 28 & CCR_N | (z == 0 ? CCR_Z : 0) |
  8460:            (~x & z) >>> 31 << 1 |
  8461:            (x & ~z) >> 31 & (CCR_X | CCR_C));
  8462:   }  //ccr_addq(int,int,int)
  8463: */
  8464: 
  8465: 
  8466: 
  8467:   //========================================================================================
  8468:   //$$EFA 実効アドレス計算
  8469:   //
  8470:   //  アドレッシングモードとサイクル数
  8471:   //    DrまたはArを指定すると不当命令になる
  8472:   //    例えばArを指定できない命令ならDrだけを特別扱いにして残りをefa~に渡せばArは自動的に不当命令になる
  8473:   //    実効アドレス計算とオペランドのアクセス1回分のサイクル数がmpuCycleCountに加算される
  8474:   //                        mmm rrr  Any Mem Mlt Cnt Clt  Byte Word Long Quad Extd  LeaPea JmpJsr
  8475:   //         -------------  --- ---  --- --- --- --- ---  ---- ---- ---- ---- ----  ------ ------
  8476:   //      M  (Ar)           010 rrr    *   *   *   *   *     4    4    8   16   24       4      8
  8477:   //      +  (Ar)+          011 rrr    *   *   *             4    4    8   16   24
  8478:   //      -  -(Ar)          100 rrr    *   *   *             6    6   10   18   26
  8479:   //      W  (d16,Ar)       101 rrr    *   *   *   *   *     8    8   12   20   28       8     10
  8480:   //      X  (d8,Ar,Rn.wl)  110 rrr    *   *   *   *   *    10   10   14   22   30      12     14
  8481:   //      Z  (xxx).W        111 000    *   *   *   *   *     8    8   12   20   28       8     10
  8482:   //      Z  (xxx).L        111 001    *   *   *   *   *    12   12   16   24   32      12     12
  8483:   //      P  (d16,PC)       111 010    *   *       *         8    8   12   20   28       8     10
  8484:   //      P  (d8,PC,Rn.wl)  111 011    *   *       *        10   10   14   22   30      12     14
  8485:   //      I  #<data>        111 100    *                     4    4    8   16   24
  8486:   //    MoveToMemByte/MoveToMemWord/MoveToMemLongはデスティネーションが-(Aq)のとき2減らす
  8487:   //    AddToRegLong/AddaLong/AndToRegLong/OrToRegLong/SubToRegLong/SubaLongはソースがDr/Ar/#<data>のとき2増やす
  8488:   //
  8489:   //  フルフォーマットの拡張ワードの処理の冗長表現
  8490:   //      t = r[ea - (0b110_000 - 8)];  //ベースレジスタ
  8491:   //      w = rwze ((pc += 2) - 2);  //pcwz。拡張ワード
  8492:   //      x = r[w >> 12];  //インデックスレジスタ
  8493:   //      if ((w & 0x0800) == 0) {  //ワードインデックス
  8494:   //        x = (short) x;
  8495:   //      }
  8496:   //      x <<= w >> 9 & 3;  //スケールファクタ。ワードインデックスのときは符号拡張してから掛ける
  8497:   //      if ((w & 0x0100) == 0) {  //短縮フォーマット
  8498:   //        t += (byte) w + x;  //8ビットディスプレースメント
  8499:   //      } else {  //フルフォーマット
  8500:   //        if ((w & 0x0080) != 0) {  //ベースサプレス
  8501:   //          t = 0;
  8502:   //        }
  8503:   //        if ((w & 0x0040) != 0) {  //インデックスサプレス
  8504:   //          x = 0;
  8505:   //        }
  8506:   //        if ((w & 0x0020) != 0) {  //ベースディスプレースメントあり
  8507:   //          if ((w & 0x0010) == 0) {  //ワードベースディスプレースメント
  8508:   //            t += rwse ((pc += 2) - 2);  //pcws
  8509:   //          } else {  //ロングベースディスプレースメント
  8510:   //            t += rlse ((pc += 4) - 4);  //pcls
  8511:   //          }
  8512:   //        }
  8513:   //        if ((w & 0x0003) == 0) {  //メモリ間接なし
  8514:   //          t += x;
  8515:   //        } else {  //メモリ間接あり
  8516:   //          if ((w & 0x0004) == 0) {  //プリインデックス
  8517:   //            t = rls (t + x);
  8518:   //          } else {  //ポストインデックス
  8519:   //            t = rls (t) + x;
  8520:   //          }
  8521:   //          if ((w & 0x0002) != 0) {  //アウタディスプレースメントあり
  8522:   //            if ((w & 0x0001) == 0) {  //ワードアウタディスプレースメント
  8523:   //              t += rwse ((pc += 2) - 2);  //pcws
  8524:   //            } else {  //ロングアウタディスプレースメント
  8525:   //              t += rlse ((pc += 4) - 4);  //pcls
  8526:   //            }
  8527:   //          }
  8528:   //        }
  8529:   //      }
  8530:   //      return t;
  8531:   //
  8532:   //  フルフォーマットの拡張ワードのサイクル数
  8533:   //    ベースディスプレースメントとメモリ間接とアウターディスプレースメントのリード回数に応じてサイクル数を加算する
  8534:   //    ベースレジスタとインデックスレジスタとスケールファクタの有無はサイクル数に影響しないものとする
  8535:   //      fedcba9876543210  bd  []  od  計
  8536:   //      .......0........               0  (d8,~)
  8537:   //      .......1..01..00               0  (~)
  8538:   //      .......1..01..01       8       8  ([~])
  8539:   //      .......1..01..10       8   4  12  ([~],od.W)
  8540:   //      .......1..01..11       8   8  16  ([~],od.L)
  8541:   //      .......1..10..00   4           4  (bd.W,~)
  8542:   //      .......1..10..01   4   8      12  ([bd.W,~])
  8543:   //      .......1..10..10   4   8   4  16  ([bd.W,~],od.W)
  8544:   //      .......1..10..11   4   8   8  20  ([bd.W,~],od.L)
  8545:   //      .......1..11..00   8           8  (bd.L,~)
  8546:   //      .......1..11..01   8   8      16  ([bd.L,~])
  8547:   //      .......1..11..10   8   8   4  20  ([bd.L,~],od.W)
  8548:   //      .......1..11..11   8   8   8  24  ([bd.L,~],od.L)
  8549:   //    1つの式で書くこともできるが冗長になるのでテーブル参照にする
  8550:   //
  8551:   //  MC68060のサイクル数
  8552:   //    ブリーフフォーマットは0、フルフォーマットのメモリ間接なしは1、フルフォーマットのメモリ間接ありは3
  8553:   //
  8554: 
  8555:   //拡張ワードのサイクル数
  8556: /*
  8557:   public static final int[] EFA_EXTENSION_CLK = {                  //fedcba9876543210
  8558:     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  //.......0........
  8559:     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  //.......0........
  8560:     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  //.......0........
  8561:     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  //.......0........
  8562:     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  //.......0........
  8563:     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  //.......0........
  8564:     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  //.......0........
  8565:     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  //.......0........
  8566:     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  //.......0........
  8567:     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  //.......0........
  8568:     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  //.......0........
  8569:     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  //.......0........
  8570:     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  //.......0........
  8571:     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  //.......0........
  8572:     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  //.......0........
  8573:     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  //.......0........
  8574:     0,  8, 12, 16,  0,  8, 12, 16,  0,  8, 12, 16,  0,  8, 12, 16,  //.......1..00....
  8575:     0,  8, 12, 16,  0,  8, 12, 16,  0,  8, 12, 16,  0,  8, 12, 16,  //.......1..01....
  8576:     4, 12, 16, 20,  4, 12, 16, 20,  4, 12, 16, 20,  4, 12, 16, 20,  //.......1..10....
  8577:     8, 16, 20, 24,  8, 16, 20, 24,  8, 16, 20, 24,  8, 16, 20, 24,  //.......1..11....
  8578:     0,  8, 12, 16,  0,  8, 12, 16,  0,  8, 12, 16,  0,  8, 12, 16,  //.......1..00....
  8579:     0,  8, 12, 16,  0,  8, 12, 16,  0,  8, 12, 16,  0,  8, 12, 16,  //.......1..01....
  8580:     4, 12, 16, 20,  4, 12, 16, 20,  4, 12, 16, 20,  4, 12, 16, 20,  //.......1..10....
  8581:     8, 16, 20, 24,  8, 16, 20, 24,  8, 16, 20, 24,  8, 16, 20, 24,  //.......1..11....
  8582:     0,  8, 12, 16,  0,  8, 12, 16,  0,  8, 12, 16,  0,  8, 12, 16,  //.......1..00....
  8583:     0,  8, 12, 16,  0,  8, 12, 16,  0,  8, 12, 16,  0,  8, 12, 16,  //.......1..01....
  8584:     4, 12, 16, 20,  4, 12, 16, 20,  4, 12, 16, 20,  4, 12, 16, 20,  //.......1..10....
  8585:     8, 16, 20, 24,  8, 16, 20, 24,  8, 16, 20, 24,  8, 16, 20, 24,  //.......1..11....
  8586:     0,  8, 12, 16,  0,  8, 12, 16,  0,  8, 12, 16,  0,  8, 12, 16,  //.......1..00....
  8587:     0,  8, 12, 16,  0,  8, 12, 16,  0,  8, 12, 16,  0,  8, 12, 16,  //.......1..01....
  8588:     4, 12, 16, 20,  4, 12, 16, 20,  4, 12, 16, 20,  4, 12, 16, 20,  //.......1..10....
  8589:     8, 16, 20, 24,  8, 16, 20, 24,  8, 16, 20, 24,  8, 16, 20, 24,  //.......1..11....
  8590:   };
  8591: */
  8592:   //  perl misc/itob.pl xeij/XEiJ.java EFA_EXTENSION_CLK
  8593:   public static final byte[] EFA_EXTENSION_CLK = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\4\f\20\24\4\f\20\24\4\f\20\24\4\f\20\24\b\20\24\30\b\20\24\30\b\20\24\30\b\20\24\30\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\4\f\20\24\4\f\20\24\4\f\20\24\4\f\20\24\b\20\24\30\b\20\24\30\b\20\24\30\b\20\24\30\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\4\f\20\24\4\f\20\24\4\f\20\24\4\f\20\24\b\20\24\30\b\20\24\30\b\20\24\30\b\20\24\30\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\0\b\f\20\4\f\20\24\4\f\20\24\4\f\20\24\4\f\20\24\b\20\24\30\b\20\24\30\b\20\24\30\b\20\24\30".getBytes (XEiJ.ISO_8859_1);
  8594: 
  8595:   public static final boolean EFA_SEPARATE_AR = false;  //true=(Ar)を(A0)~(A7)に分ける
  8596: 
  8597: 
  8598: 
  8599:   //========================================================================================
  8600:   //$$BUS バスコントローラ
  8601: 
  8602:   public static final boolean BUS_SPLIT_UNALIGNED_LONG = false;  //true=4の倍数ではない偶数アドレスへのロングワードアクセスを常に分割する
  8603: 
  8604:   //マザーボードのアドレス空間
  8605:   public static final int BUS_MOTHER_BITS = 24;  //マザーボードのアドレス空間のビット数
  8606:   public static final int BUS_MOTHER_SIZE = BUS_MOTHER_BITS < 32 ? 1 << BUS_MOTHER_BITS : 0;  //マザーボードのアドレス空間のサイズ。1<<32は1が押し出されて0になるのではなくてシフトカウントが5bitでマスクされて1<<0=1になることに注意
  8607:   public static final int BUS_MOTHER_MASK = BUS_MOTHER_SIZE - 1;  //マザーボードのアドレスのマスク。a&BUS_MOTHER_MASK
  8608:   //合計
  8609:   public static final int BUS_ARRAY_SIZE = BUS_MOTHER_SIZE;
  8610: 
  8611:   //ページ
  8612:   public static final int BUS_PAGE_BITS = 12;  //ページのビット数。a>>>BUS_PAGE_BITS
  8613:   public static final int BUS_PAGE_SIZE = 1 << BUS_PAGE_BITS;  //ページのサイズ
  8614:   public static final int BUS_PAGE_COUNT = 1 << (32 - BUS_PAGE_BITS);  //ページの数
  8615: 
  8616:   //ss
  8617:   public static final int MPU_SS_BYTE = 0;
  8618:   public static final int MPU_SS_WORD = 1;
  8619:   public static final int MPU_SS_LONG = 2;
  8620: 
  8621:   //wr
  8622:   public static final int MPU_WR_WRITE = 0;
  8623:   public static final int MPU_WR_READ = 1;
  8624: 
  8625:   //us
  8626:   public static final int MPU_US_USER = 0;
  8627:   public static final int MPU_US_SUPERVISOR = 1;
  8628: 
  8629:   //メモリマップ
  8630:   public static final MemoryMappedDevice[] busUserMap = new MemoryMappedDevice[BUS_PAGE_COUNT];  //ユーザモード用のメモリマップ
  8631:   public static final MemoryMappedDevice[] busSuperMap = new MemoryMappedDevice[BUS_PAGE_COUNT];  //スーパーバイザモード用のメモリマップ
  8632:   public static MemoryMappedDevice[] busMemoryMap;  //現在のメモリマップ。srS==0?um:sm。DataBreakPoint.DBP_ON==trueのときは使わない
  8633: 
  8634:   //X68000のハイメモリ
  8635:   public static boolean busHimem68000;  //true=060turboのハイメモリはX68000でも有効
  8636: 
  8637:   //X68030/Xellent30のハイメモリ
  8638:   public static final int BUS_HIGH_MEMORY_START = 0x01000000;  //X68030/Xellent30のハイメモリの開始アドレス
  8639:   public static int busHighMemorySize;  //X68030/Xellent30のハイメモリのサイズ
  8640:   public static byte[] busHighMemoryArray;  //X68030/Xellent30のハイメモリの配列
  8641:   public static boolean busHighMemorySaveOn;  //true=X68030/Xellent30のハイメモリの内容を保存する
  8642:   public static boolean busHighMemory060turboOn;  //true=060turboのハイメモリを使う
  8643: 
  8644:   //060turboのハイメモリ
  8645:   public static final int BUS_LOCAL_MEMORY_START = 0x10000000;  //060turboのハイメモリの開始アドレス
  8646:   public static int busLocalMemorySize;  //060turboのハイメモリのサイズ
  8647:   public static byte[] busLocalMemoryArray;  //060turboのハイメモリの配列
  8648:   public static boolean busLocalMemorySaveOn;  //true=060turboのハイメモリの内容を保存する
  8649: 
  8650:   //拡張メモリ
  8651:   public static final byte[] BUS_DUMMY_MEMORY_ARRAY = new byte[0];  //X68030と060turbo以外の拡張メモリの配列
  8652:   public static int busRequestExMemoryStart;  //次回起動時の拡張メモリの開始アドレス
  8653:   public static int busRequestExMemorySize;  //次回起動時の拡張メモリの長さ
  8654:   public static byte[] busRequestExMemoryArray;  //次回起動時の拡張メモリの配列。BUS_DUMMY_MEMORY_ARRAY,busHighMemoryArray,busLocalMemoryArrayのいずれか
  8655:   public static int busExMemoryStart;  //拡張メモリの開始アドレス
  8656:   public static int busExMemorySize;  //拡張メモリの長さ
  8657:   public static byte[] busExMemoryArray;  //拡張メモリの配列。BUS_DUMMY_MEMORY_ARRAY,busHighMemoryArray,busLocalMemoryArrayのいずれか
  8658: 
  8659:   //FC2ピンをカットする
  8660:   public static boolean busRequestCutFC2Pin;
  8661:   public static boolean busCutFC2Pin;
  8662: 
  8663:   //busInit ()
  8664:   //  バスコントローラを初期化する
  8665:   public static void busInit () {
  8666:     //um = new MMD[BUS_PAGE_COUNT];
  8667:     //sm = new MMD[BUS_PAGE_COUNT];
  8668:     if (!DataBreakPoint.DBP_ON) {
  8669:       busMemoryMap = busSuperMap;
  8670:     }
  8671: 
  8672:     //X68030/Xellent30のハイメモリ
  8673:     int highMemorySizeMB = Settings.sgsGetInt ("highmemory");  //X68030/Xellent30のハイメモリのサイズ
  8674:     busHighMemorySize = highMemorySizeMB == 16 ? highMemorySizeMB << 20 : 0 << 20;
  8675:     if (busHighMemorySize == 0) {
  8676:         System.out.println (Multilingual.mlnJapanese ?
  8677:                             "X68030/Xellent30 のハイメモリはありません" :
  8678:                             "X68030/Xellent30 high memory does not exists");
  8679:     } else {
  8680:       System.out.printf (Multilingual.mlnJapanese ?
  8681:                          "X68030/Xellent30 のハイメモリのサイズは %dMB です\n" :
  8682:                          "X68030/Xellent30 high memory size is %dMB\n",
  8683:                          busHighMemorySize >> 20);
  8684:     }
  8685:     busHighMemoryArray = new byte[busHighMemorySize];
  8686: 
  8687:     busHimem68000 = Settings.sgsGetOnOff ("himem68000");
  8688: 
  8689:     busHighMemorySaveOn = Settings.sgsGetOnOff ("highmemorysave");  //X68030/Xellent30のハイメモリの内容を保存するか
  8690:     busHighMemory060turboOn = Settings.sgsGetOnOff ("highmemory060turbo");
  8691: 
  8692:     byte[] highMemoryArray = Settings.sgsGetData ("highmemorydata");  //X68030/Xellent30のハイメモリの内容(gzip+base64)
  8693:     if (busHighMemorySize != 0) {  //X68030/Xellent30のハイメモリがある
  8694:       if (highMemoryArray.length != 0) {  //復元するデータがある
  8695:         System.out.println (Multilingual.mlnJapanese ?
  8696:                             "X68030/Xellent30 のハイメモリのデータを復元します" :
  8697:                             "X68030/Xellent30 high memory data is restored");
  8698:         System.arraycopy (highMemoryArray, 0, busHighMemoryArray, 0, Math.min (highMemoryArray.length, busHighMemorySize));
  8699:       } else {
  8700:         System.out.println (Multilingual.mlnJapanese ?
  8701:                             "X68030/Xellent30 のハイメモリをゼロクリアします" :
  8702:                             "X68030/Xellent30 high memory is zero-cleared");
  8703:       }
  8704:       if (highMemoryArray.length < busHighMemorySize) {
  8705:         Arrays.fill (busHighMemoryArray, highMemoryArray.length, busHighMemorySize, (byte) 0);  //復元されなかった部分をゼロクリアする
  8706:       }
  8707:     }
  8708: 
  8709:     //060turboのハイメモリ
  8710:     int localMemorySizeMB = Settings.sgsGetInt ("localmemory");  //060turboのハイメモリのサイズ
  8711:     busLocalMemorySize = (localMemorySizeMB == 16 ||
  8712:                           localMemorySizeMB == 32 ||
  8713:                           localMemorySizeMB == 64 ||
  8714:                           localMemorySizeMB == 128 ||
  8715:                           localMemorySizeMB == 256 ||
  8716:                           localMemorySizeMB == 384 ||
  8717:                           localMemorySizeMB == 512 ||
  8718:                           localMemorySizeMB == 768 ?
  8719:                           localMemorySizeMB << 20 :
  8720:                           128 << 20);
  8721:     if (busLocalMemorySize == 0) {
  8722:         System.out.println (Multilingual.mlnJapanese ?
  8723:                             "060turbo のハイメモリはありません" :
  8724:                             "060turbo high memory does not exists");
  8725:     } else {
  8726:       System.out.printf (Multilingual.mlnJapanese ?
  8727:                          "060turbo のハイメモリのサイズは %dMB です\n" :
  8728:                          "060turbo high memory size is %dMB\n",
  8729:                          busLocalMemorySize >> 20);
  8730:     }
  8731:     busLocalMemoryArray = new byte[busLocalMemorySize];
  8732: 
  8733:     busLocalMemorySaveOn = Settings.sgsGetOnOff ("localmemorysave");  //060turboのハイメモリの内容を保存するか
  8734: 
  8735:     byte[] localMemoryArray = Settings.sgsGetData ("localmemorydata");  //060turboのハイメモリの内容(gzip+base64)
  8736:     if (busLocalMemorySize != 0) {  //060turboのハイメモリがある
  8737:       if (localMemoryArray.length != 0) {  //復元するデータがある
  8738:         System.out.println (Multilingual.mlnJapanese ?
  8739:                             "060turbo のハイメモリのデータを復元します" :
  8740:                             "060turbo high memory data is restored");
  8741:         System.arraycopy (localMemoryArray, 0, busLocalMemoryArray, 0, Math.min (localMemoryArray.length, busLocalMemorySize));
  8742:       } else {
  8743:         System.out.println (Multilingual.mlnJapanese ?
  8744:                             "060turbo のハイメモリをゼロクリアします" :
  8745:                             "060turbo high memory is zero-cleared");
  8746:       }
  8747:       if (localMemoryArray.length < busLocalMemorySize) {
  8748:         Arrays.fill (busLocalMemoryArray, localMemoryArray.length, busLocalMemorySize, (byte) 0);  //復元されなかった部分をゼロクリアする
  8749:       }
  8750:     }
  8751: 
  8752:     //現在の拡張メモリ
  8753:     busExMemoryStart = busRequestExMemoryStart = 0x10000000;
  8754:     busExMemorySize = busRequestExMemorySize = 0 << 20;
  8755:     busExMemoryArray = busRequestExMemoryArray = BUS_DUMMY_MEMORY_ARRAY;
  8756: 
  8757:     //FC2ピンをカットする
  8758:     busRequestCutFC2Pin = Settings.sgsGetOnOff ("cutfc2pin");  //FC2ピンをカットする(on/off)
  8759:     busCutFC2Pin = !busRequestCutFC2Pin;
  8760: 
  8761:     busUpdateMemoryMap ();
  8762: 
  8763:   }  //busInit()
  8764: 
  8765:   //busTini ()
  8766:   //  後始末
  8767:   public static void busTini () {
  8768:     Settings.sgsPutOnOff ("himem68000", busHimem68000);
  8769:     Settings.sgsPutInt ("highmemory", busHighMemorySize >>> 20);
  8770:     Settings.sgsPutOnOff ("highmemorysave", busHighMemorySaveOn);
  8771:     Settings.sgsPutOnOff ("highmemory060turbo", busHighMemory060turboOn);
  8772:     Settings.sgsPutData ("highmemorydata",
  8773:                          busHighMemorySaveOn ?
  8774:                          Arrays.copyOf (busHighMemoryArray, busHighMemoryArray.length) :
  8775:                          new byte[0]);
  8776:     Settings.sgsPutInt ("localmemory", busLocalMemorySize >>> 20);
  8777:     Settings.sgsPutOnOff ("localmemorysave", busLocalMemorySaveOn);
  8778:     Settings.sgsPutData ("localmemorydata",
  8779:                          busLocalMemorySaveOn ?
  8780:                          Arrays.copyOf (busLocalMemoryArray, busLocalMemoryArray.length) :
  8781:                          new byte[0]);
  8782:     Settings.sgsPutOnOff ("cutfc2pin", busRequestCutFC2Pin);
  8783:   }  //busTini
  8784: 
  8785:   public static void busUpdateMemoryMap () {
  8786:     if (busExMemoryStart == busRequestExMemoryStart &&
  8787:         busExMemorySize == busRequestExMemorySize &&
  8788:         busExMemoryArray == busRequestExMemoryArray &&
  8789:         busExMemoryArray.length == busExMemorySize &&
  8790:         busCutFC2Pin == busRequestCutFC2Pin) {
  8791:       return;
  8792:     }
  8793:     //拡張メモリ
  8794:     busExMemoryStart = busRequestExMemoryStart;
  8795:     busExMemorySize = busRequestExMemorySize;
  8796:     busExMemoryArray = busRequestExMemoryArray;
  8797:     if (busExMemoryArray.length != busExMemorySize) {
  8798:       byte[] newArray = new byte[busExMemorySize];
  8799:       int copySize = Math.min (busExMemoryArray.length, busExMemorySize);
  8800:       if (copySize > 0) {
  8801:         System.arraycopy (busExMemoryArray, 0, newArray, 0, copySize);
  8802:       }
  8803:       if (busExMemoryArray == busHighMemoryArray) {
  8804:         busHighMemoryArray = newArray;
  8805:       } else if (busExMemoryArray == busLocalMemoryArray) {
  8806:         busLocalMemoryArray = newArray;
  8807:       }
  8808:       busExMemoryArray = newArray;
  8809:     }
  8810:     //FC2ピンをカットする
  8811:     busCutFC2Pin = busRequestCutFC2Pin;
  8812:     //メモリマップを作る
  8813:     //  すべてのページにデバイスを割り当てること
  8814: 
  8815:     //  MMR  メインメモリ
  8816:     //  $00000000~$000FFFFF  1MB
  8817:     //  $00000000~$001FFFFF  2MB
  8818:     //  $00000000~$003FFFFF  4MB
  8819:     //  $00000000~$005FFFFF  6MB
  8820:     //  $00000000~$007FFFFF  8MB
  8821:     //  $00000000~$009FFFFF  10MB
  8822:     //  $00000000~$00BFFFFF  12MB
  8823:     //  $00000000  メインメモリ
  8824:     busSuper (MemoryMappedDevice.MMD_MMR, 0x00000000, 0x00002000);  //MMR メインメモリ
  8825:     busUser ( MemoryMappedDevice.MMD_MMR, 0x00002000, 0x00c00000);  //MMR メインメモリ
  8826: 
  8827:     //  GE0  グラフィック画面(512ドット16色ページ0)
  8828:     //  $00C00000~$00C7FFFF  512KB
  8829:     //  GE1  グラフィック画面(512ドット16色ページ1)
  8830:     //  $00C80000~$00CFFFFF  512KB
  8831:     //  GE2  グラフィック画面(512ドット16色ページ2)
  8832:     //  $00D00000~$00D7FFFF  512KB
  8833:     //  GE3  グラフィック画面(512ドット16色ページ3)
  8834:     //  $00D80000~$00DFFFFF  512KB
  8835:     //  GF0  グラフィック画面(512ドット256色ページ0)
  8836:     //  $00C00000~$00C7FFFF  512KB
  8837:     //  GF1  グラフィック画面(512ドット256色ページ1)
  8838:     //  $00C80000~$00CFFFFF  512KB
  8839:     //  GM2  グラフィック画面(メモリモード2)
  8840:     //  $00C00000~$00DFFFFF  2MB
  8841:     //  GG0  グラフィック画面(512ドット65536色)
  8842:     //  $00C00000~$00C7FFFF  512KB
  8843:     //  GH0  グラフィック画面(1024ドット16色)
  8844:     //  $00C00000~$00DFFFFF  2MB
  8845:     //  GI0  グラフィック画面(1024ドット256色)
  8846:     //  $00C00000~$00DFFFFF  2MB
  8847:     //  GJ0  グラフィック画面(1024ドット65536色)
  8848:     //  $00C00000~$00DFFFFF  2MB
  8849:     //  $00C00000  グラフィックVRAM
  8850:     busSuper (MemoryMappedDevice.MMD_GE0, 0x00c00000, 0x00c80000);  //GE0 グラフィック画面(512ドット16色ページ0)
  8851:     busSuper (MemoryMappedDevice.MMD_GE1, 0x00c80000, 0x00d00000);  //GE1 グラフィック画面(512ドット16色ページ1)
  8852:     busSuper (MemoryMappedDevice.MMD_GE2, 0x00d00000, 0x00d80000);  //GE2 グラフィック画面(512ドット16色ページ2)
  8853:     busSuper (MemoryMappedDevice.MMD_GE3, 0x00d80000, 0x00e00000);  //GE3 グラフィック画面(512ドット16色ページ3)
  8854: 
  8855:     //  TXT  テキスト画面
  8856:     //  $00E00000~$00E7FFFF  512KB
  8857:     //  $00E00000  テキストVRAM
  8858:     busSuper (MemoryMappedDevice.MMD_TXT, 0x00e00000, 0x00e80000);  //TXT テキスト画面
  8859: 
  8860:     //  CRT  CRTコントローラ
  8861:     //  $00E80000~$00E81FFF  8KB
  8862:     //  $00E80000  CRTコントローラ
  8863:     busSuper (MemoryMappedDevice.MMD_CRT, 0x00e80000, 0x00e82000);  //CRT CRTコントローラ
  8864: 
  8865:     //  VCN  ビデオコントローラ
  8866:     //  $00E82000~$00E83FFF  8KB
  8867:     //  $00E82000  パレットレジスタ
  8868:     //  $00E82400  ビデオコントローラ
  8869:     busSuper (MemoryMappedDevice.MMD_VCN, 0x00e82000, 0x00e84000);  //VCN ビデオコントローラ
  8870: 
  8871:     //  DMA  DMAコントローラ
  8872:     //  $00E84000~$00E85FFF  8KB
  8873:     //  $00E84000  DMAコントローラ
  8874:     busSuper (MemoryMappedDevice.MMD_DMA, 0x00e84000, 0x00e86000);  //DMA DMAコントローラ
  8875: 
  8876:     //  SVS  スーパーバイザ領域設定
  8877:     //  $00E86000~$00E87FFF  8KB
  8878:     //  $00E86000  スーパーバイザ領域設定
  8879:     busSuper (MemoryMappedDevice.MMD_SVS, 0x00e86000, 0x00e88000);  //SVS スーパーバイザ領域設定
  8880: 
  8881:     //  MFP  マルチファンクションペリフェラル
  8882:     //  $00E88000~$00E89FFF  8KB
  8883:     //  $00E88000  MFP
  8884:     busSuper (MemoryMappedDevice.MMD_MFP, 0x00e88000, 0x00e8a000);  //MFP MFP
  8885: 
  8886:     //  RTC  リアルタイムクロック
  8887:     //  $00E8A000~$00E8BFFF  8KB
  8888:     //  $00E8A000  RTC
  8889:     busSuper (MemoryMappedDevice.MMD_RTC_FIRST, 0x00e8a000, 0x00e8c000);  //RTC RTC
  8890: 
  8891:     //  PRT  プリンタポート
  8892:     //  $00E8C000~$00E8DFFF  8KB
  8893:     //  $00E8C000  プリンタポート
  8894:     busSuper (MemoryMappedDevice.MMD_PRN, 0x00e8c000, 0x00e8e000);  //PRN プリンタポート
  8895: 
  8896:     //  SYP  システムポート
  8897:     //  $00E8E000~$00E8FFFF  8KB
  8898:     //  $00E8E000  システムポート
  8899:     busSuper (MemoryMappedDevice.MMD_SYS, 0x00e8e000, 0x00e90000);  //SYS システムポート
  8900: 
  8901:     //  OPM  FM音源
  8902:     //  $00E90000~$00E91FFF  8KB
  8903:     //  $00E90000  FM音源
  8904:     busSuper (MemoryMappedDevice.MMD_OPM, 0x00e90000, 0x00e92000);  //OPM FM音源
  8905: 
  8906:     //  PCM  ADPCM音源
  8907:     //  $00E92000~$00E93FFF  8KB
  8908:     //  $00E92000  ADPCM音源
  8909:     busSuper (MemoryMappedDevice.MMD_PCM, 0x00e92000, 0x00e94000);  //PCM ADPCM音源
  8910: 
  8911:     //  FDC  FDコントローラ
  8912:     //  $00E94000~$00E95FFF  8KB
  8913:     //  $00E94000  FDC
  8914:     busSuper (MemoryMappedDevice.MMD_FDC, 0x00e94000, 0x00e96000);  //FDC FDコントローラ
  8915: 
  8916:     //  HDC  SASI HDコントローラ
  8917:     //  $00E96000~$00E97FFF  8KB
  8918:     //  $00E96000  HDC SASI HDコントローラ
  8919:     //  $00E96020  SPC 内蔵SCSIプロトコルコントローラ
  8920:     busSuper (MemoryMappedDevice.MMD_HDC, 0x00e96000, 0x00e98000);  //HDC SASI HDコントローラ
  8921: 
  8922:     //  SCC  シリアルコミュニケーションコントローラ
  8923:     //  $00E98000~$00E99FFF  8KB
  8924:     //  $00E98000  SCC
  8925:     busSuper (MemoryMappedDevice.MMD_SCC, 0x00e98000, 0x00e9a000);  //SCC SCC
  8926: 
  8927:     //  PPI  プログラマブルペリフェラルインタフェイス
  8928:     //  $00E9A000~$00E9BFFF  8KB
  8929:     //  $00E9A000  PPI
  8930:     busSuper (MemoryMappedDevice.MMD_PPI, 0x00e9a000, 0x00e9c000);  //PPI PPI
  8931: 
  8932:     //  IOI  I/O割り込み
  8933:     //  $00E9C000~$00E9DFFF  8KB
  8934:     //  $00E9C000  I/O割り込み
  8935:     busSuper (MemoryMappedDevice.MMD_IOI, 0x00e9c000, 0x00e9e000);  //IOI I/O割り込み
  8936: 
  8937:     //  XB1  拡張ボード領域1
  8938:     //  $00E9E000~$00E9FFFF  8KB
  8939:     //  $00E9E000  数値演算プロセッサボード(CZ-6BP1/CZ-6BP1A)
  8940:     //  $00E9E200  ツクモグラフィックアクセラレータPCMボード(TS-6BGA)
  8941:     //  $00E9F000  WINDRV
  8942:     //  $00E9F000  040Excel
  8943:     //  $00E9F020  HFS ホストファイルシステムインタフェイス
  8944:     //  $00E9F040~$00E9F047  Zキーボード
  8945:     busSuper (MemoryMappedDevice.MMD_XB1, 0x00e9e000, 0x00ea0000);  //XB1 拡張ボード領域1
  8946: 
  8947:     //  XSC  拡張SCSI
  8948:     //  $00EA0000~$00EA1FFF  8KB
  8949:     //  $00EA0000  拡張SCSI(SCSIボードCZ-6BS1/Mach-2)
  8950:     //  $00EA1FF0  TS-6BS1
  8951:     busSuper (MemoryMappedDevice.MMD_NUL, 0x00ea0000, 0x00eae000);  //MemoryMappedDevice.MMD_EXSはSPC.spcReset()で必要なときだけ接続する
  8952: 
  8953:     //  XB2  拡張ボード領域2
  8954:     //  $00EA2000~$00EAFFFF  56KB
  8955:     //  $00EA8000~$00EA9FFF  PhantomX
  8956:     //  $00EAA000~$00EAAFFF  HaumeaX I/O
  8957:     //  $00EAB000~$00EABFFF  HaumeaX ROM
  8958:     //  $00EAF900  FAXボード(CZ-6BC1)
  8959:     //  $00EAFA00  MIDIボード(CZ-6BM1)
  8960:     //  $00EAFB00  パラレルボード(CZ-6BN1)
  8961:     //  $00EAFC00  RS-232Cボード(CZ-6BF1)
  8962:     //  $00EAFD00  ユニバーサルI/Oボード(CZ-6BU1)
  8963:     //  $00EAFE00  GP-IBボード(CZ-6BG1)
  8964:     //  $00EAFF00  スーパーバイザエリア設定
  8965:     //  拡張
  8966:     //  $00EAFF7F  バンクメモリのページ番号
  8967:     busSuper (MemoryMappedDevice.MMD_XB2, 0x00eae000, 0x00eb0000);  //拡張ボード領域2
  8968: 
  8969:     //  SPR  スプライト画面
  8970:     //  $00EB0000~$00EBFFFF  64KB
  8971:     //  $00EB0000  スプライトレジスタ
  8972:     //  $00EB0800  スプライトコントローラ
  8973:     //  $00EB8000  スプライトPCGエリア
  8974:     //  $00EBC000  スプライトテキストエリア0
  8975:     //  $00EBE000  スプライトテキストエリア1
  8976:     busSuper (MemoryMappedDevice.MMD_SPR, 0x00eb0000, 0x00ec0000);  //SPR スプライト画面
  8977: 
  8978:     //  XB3  拡張ボード領域3
  8979:     //  $00EC0000~$00ECFFFF  64KB
  8980:     //  $00EC0000  ユーザI/Oエリア
  8981:     //  $00EC0000  Awesome
  8982:     //  $00EC0000~$00EC3FFF  Xellent30 #0
  8983:     //  $00EC0000~$00EC7FFF  ZUSB
  8984:     //  $00EC4000~$00EC7FFF  Xellent30 #1
  8985:     //  $00EC8000~$00ECBFFF  Xellent30 #2
  8986:     //  $00ECC000~$00ECFFFF  Xellent30 #3
  8987:     //  $00ECC080~$00ECC0FF  MercuryUnit
  8988:     //  $00ECE000  Neptune
  8989:     //  $00ECF000  Venus-X/030
  8990:     busSuper (MemoryMappedDevice.MMD_XB3, 0x00ec0000, 0x00ed0000);  //拡張ボード領域3
  8991: 
  8992:     //  SMR  SRAM
  8993:     //  $00ED0000~$00ED3FFF  16KB
  8994:     //  $00ED0000~$00ED7FFF  32KB。改造したとき
  8995:     //  $00ED0000~$00EDFFFF  64KB。改造したとき
  8996:     //  $00ED0000  SRAM
  8997:     busSuper (MemoryMappedDevice.MMD_SMR, 0x00ed0000, 0x00ed0000 + 16384);  //SMR SRAM
  8998:     busSuper (MemoryMappedDevice.MMD_NUL, 0x00ed0000 + 16384, 0x00ed0000 + 65536);  //空き
  8999: 
  9000:     //  XB4  拡張ボード領域4
  9001:     //  $00EE0000~$00EFFFFF  128KB
  9002:     //  $00EE0000  GAフレームバッファウインドウ(サブ)
  9003:     //  $00EF0000  GAフレームバッファウインドウ(メイン)
  9004:     //  $00EFFF00  PSX16550
  9005:     //  拡張
  9006:     //  $00EE0000~$00EFFFFF  バンクメモリ
  9007:     busSuper (MemoryMappedDevice.MMD_XB4, 0x00ee0000, 0x00f00000);  //拡張ボード領域4
  9008: 
  9009:     //  CG1  CGROM1
  9010:     //  $00F00000~$00F3FFFF  256KB。CGROM作成前
  9011:     //  $00F00000  KNJ16x16フォント(1~8区,非漢字752文字)
  9012:     //  $00F05E00  KNJ16x16フォント(16~47区,第1水準漢字3008文字)
  9013:     //  $00F1D600  KNJ16x16フォント(48~84区,第2水準漢字3478文字)
  9014:     //  $00F3A000  ANK8x8フォント(256文字)
  9015:     //  $00F3A800  ANK8x16フォント(256文字)
  9016:     //  $00F3B800  ANK12x12フォント(256文字)
  9017:     //  $00F3D000  ANK12x24フォント(256文字)
  9018:     busSuper (MemoryMappedDevice.MMD_ROM, 0x00f00000, 0x00f40000);
  9019: 
  9020:     //  CG2  CGROM2
  9021:     //  $00F40000~$00FBFFFF  512KB。CGROM作成前
  9022:     //  $00F40000  KNJ24x24フォント(1~8区,非漢字752文字)
  9023:     //  $00F4D380  KNJ24x24フォント(16~47区,第1水準漢字3008文字)
  9024:     //  $00F82180  KNJ24x24フォント(48~84区,第2水準漢字3478文字)
  9025:     //  $00FBF400  [13]ANK6x12フォント(256文字)
  9026:     busSuper (MemoryMappedDevice.MMD_ROM, 0x00f40000, 0x00fc0000);
  9027: 
  9028:     //  ROM  ROM
  9029:     //  $00FC0000~$00FFFFFF  256KB
  9030:     //  $00FC0000  [11,12]内蔵SCSI BIOS,[13]内蔵SCSIハンドル
  9031:     //  $00FC0200  [13]ROM Human
  9032:     //  $00FCE000  [13]ROM Float
  9033:     //  $00FD3800  [13]ROMデバッガ
  9034:     //  $00FE0000  [10,11,12]ROMデバッガ
  9035:     //  $00FE5000  [10,11,12]ROM Human
  9036:     //  $00FF0000  IPLROM
  9037:     //  $00FFD018  [10]ANK6x12フォント(254文字)
  9038:     //  $00FFD344  [11]ANK6x12フォント(254文字)
  9039:     //  $00FFD45E  [12]ANK6x12フォント(254文字)
  9040:     //  $00FFDC00  [10]ROMディスク
  9041:     busSuper (MemoryMappedDevice.MMD_ROM, 0x00fc0000, 0x01000000);  //ROM ROM
  9042: 
  9043:   }  //busUpdateMemoryMap()
  9044: 
  9045:   public static void busReset () {
  9046:     if (regSRS != 0) {  //スーパーバイザモード
  9047:       if (DataBreakPoint.DBP_ON) {
  9048:         DataBreakPoint.dbpMemoryMap = DataBreakPoint.dbpSuperMap;
  9049:       } else {
  9050:         busMemoryMap = busSuperMap;
  9051:       }
  9052:     } else {  //ユーザモード
  9053:       if (DataBreakPoint.DBP_ON) {
  9054:         DataBreakPoint.dbpMemoryMap = DataBreakPoint.dbpUserMap;
  9055:       } else {
  9056:         busMemoryMap = busUserMap;
  9057:       }
  9058:     }
  9059:   }  //busReset()
  9060: 
  9061:   //busUser (mmd, motherStartAddress, motherEndAddress)
  9062:   //  ユーザ領域にデバイスを割り当てる
  9063:   //  motherStartAddress  マザーボード開始アドレス。BUS_PAGE_SIZEで割り切れること
  9064:   //  motherEndAddress    マザーボード終了アドレス。BUS_PAGE_SIZEで割り切れること
  9065:   public static void busUser (MemoryMappedDevice mmd, int motherStartAddress, int motherEndAddress) {
  9066:     if (MC68060.CAT_ON) {
  9067:       if (Model.MPU_MC68LC060 <= currentMPU) {
  9068:         mmd = (mmd == MemoryMappedDevice.MMD_MMR ? MemoryMappedDevice.MMD_MM6 :
  9069:                mmd == MemoryMappedDevice.MMD_ROM ? MemoryMappedDevice.MMD_RO6 :
  9070:                mmd);
  9071:       }
  9072:     }
  9073:     int motherStartPage = motherStartAddress >>> BUS_PAGE_BITS;  //マザーボード開始ページ
  9074:     int motherEndPage = motherEndAddress >>> BUS_PAGE_BITS;  //マザーボード終了ページ
  9075:     if (false &&
  9076:         (motherStartPage << BUS_PAGE_BITS != motherStartAddress ||
  9077:          motherEndPage << BUS_PAGE_BITS != motherEndAddress)) {  //開始アドレスまたは終了アドレスがページサイズで割り切れない
  9078:       System.out.printf ("ERROR: busUser (\"%s\", 0x%08x, 0x%08x)\n", mmd.toString (), motherStartAddress, motherEndAddress);
  9079:     }
  9080:     int exMemoryStartPage = busExMemoryStart >>> BUS_PAGE_BITS;  //拡張メモリ開始ページ
  9081:     int exMemoryEndPage = exMemoryStartPage + (busExMemorySize >>> BUS_PAGE_BITS);  //拡張メモリ終了ページ
  9082:     for (int block = 0; block < 1 << 32 - BUS_MOTHER_BITS; block++) {  //ブロック
  9083:       int blockStartPage = block << BUS_MOTHER_BITS - BUS_PAGE_BITS;  //ブロック開始ページ
  9084:       int startPage = blockStartPage + motherStartPage;  //デバイス開始ページ
  9085:       int endPage = blockStartPage + motherEndPage;  //デバイス終了ページ
  9086:       for (int page = startPage; page < endPage; page++) {  //デバイスページ
  9087:         boolean isExMemory = exMemoryStartPage <= page && page < exMemoryEndPage;
  9088:         MemoryMappedDevice superMmd = isExMemory ? MemoryMappedDevice.MMD_XMM : mmd;
  9089:         if (MC68060.CAT_ON) {
  9090:           if (Model.MPU_MC68LC060 <= currentMPU &&  //68060で
  9091:               isExMemory) {  //拡張メモリのとき
  9092:             superMmd = MemoryMappedDevice.MMD_XM6;  //拡張メモリ(68060)に変更する
  9093:           }
  9094:         }
  9095:         busUserMap[page] = busSuperMap[page] = superMmd;
  9096:         if (InstructionBreakPoint.IBP_ON) {
  9097:           if (InstructionBreakPoint.ibpUserMap[page] != MemoryMappedDevice.MMD_IBP) {  //命令ブレークポイントがない
  9098:             InstructionBreakPoint.ibpUserMap[page] = superMmd;
  9099:           }
  9100:           if (InstructionBreakPoint.ibpSuperMap[page] != MemoryMappedDevice.MMD_IBP) {  //命令ブレークポイントがない
  9101:             InstructionBreakPoint.ibpSuperMap[page] = superMmd;
  9102:           }
  9103:         }
  9104:         if (DataBreakPoint.DBP_ON) {
  9105:           if (DataBreakPoint.dbpUserMap[page] != MemoryMappedDevice.MMD_DBP) {  //データブレークポイントがない
  9106:             DataBreakPoint.dbpUserMap[page] = superMmd;
  9107:           }
  9108:           if (DataBreakPoint.dbpSuperMap[page] != MemoryMappedDevice.MMD_DBP) {  //データブレークポイントがない
  9109:             DataBreakPoint.dbpSuperMap[page] = superMmd;
  9110:           }
  9111:         }
  9112:       }
  9113:     }
  9114:   }  //busUser(MMD,int,int)
  9115: 
  9116:   //busSuper (mmd, motherStartAddress, motherEndAddress)
  9117:   //  スーパーバイザ領域にデバイスを割り当てる
  9118:   //  motherStartAddress  マザーボード開始アドレス。BUS_PAGE_SIZEで割り切れること
  9119:   //  motherEndAddress    マザーボード終了アドレス。BUS_PAGE_SIZEで割り切れること
  9120:   public static void busSuper (MemoryMappedDevice mmd, int motherStartAddress, int motherEndAddress) {
  9121:     if (MC68060.CAT_ON) {
  9122:       if (Model.MPU_MC68LC060 <= currentMPU) {
  9123:         mmd = (mmd == MemoryMappedDevice.MMD_MMR ? MemoryMappedDevice.MMD_MM6 :
  9124:                mmd == MemoryMappedDevice.MMD_ROM ? MemoryMappedDevice.MMD_RO6 :
  9125:                mmd);
  9126:       }
  9127:     }
  9128:     int motherStartPage = motherStartAddress >>> BUS_PAGE_BITS;  //マザーボード開始ページ
  9129:     int motherEndPage = motherEndAddress >>> BUS_PAGE_BITS;  //マザーボード終了ページ
  9130:     if (false &&
  9131:         (motherStartPage << BUS_PAGE_BITS != motherStartAddress ||
  9132:          motherEndPage << BUS_PAGE_BITS != motherEndAddress)) {  //開始アドレスまたは終了アドレスがページサイズで割り切れない
  9133:       System.out.printf ("ERROR: busSuper (\"%s\", 0x%08x, 0x%08x)\n", mmd.toString (), motherStartAddress, motherEndAddress);
  9134:     }
  9135:     int exMemoryStartPage = busExMemoryStart >>> BUS_PAGE_BITS;  //拡張メモリ開始ページ
  9136:     int exMemoryEndPage = exMemoryStartPage + (busExMemorySize >>> BUS_PAGE_BITS);  //拡張メモリ終了ページ
  9137:     for (int block = 0; block < 1 << 32 - BUS_MOTHER_BITS; block++) {  //ブロック
  9138:       int blockStartPage = block << BUS_MOTHER_BITS - BUS_PAGE_BITS;  //ブロック開始ページ
  9139:       int startPage = blockStartPage + motherStartPage;  //デバイス開始ページ
  9140:       int endPage = blockStartPage + motherEndPage;  //デバイス終了ページ
  9141:       for (int page = startPage; page < endPage; page++) {  //デバイスページ
  9142:         boolean isExMemory = exMemoryStartPage <= page && page < exMemoryEndPage;
  9143:         MemoryMappedDevice userMmd = isExMemory ? MemoryMappedDevice.MMD_XMM : busCutFC2Pin ? mmd : MemoryMappedDevice.MMD_NUL;
  9144:         MemoryMappedDevice superMmd = isExMemory ? MemoryMappedDevice.MMD_XMM : mmd;
  9145:         if (MC68060.CAT_ON) {
  9146:           if (Model.MPU_MC68LC060 <= currentMPU &&  //68060で
  9147:               isExMemory) {  //拡張メモリのとき
  9148:             userMmd = MemoryMappedDevice.MMD_XM6;  //拡張メモリ(68060)に変更する
  9149:             superMmd = MemoryMappedDevice.MMD_XM6;  //拡張メモリ(68060)に変更する
  9150:           }
  9151:         }
  9152:         busUserMap[page] = userMmd;
  9153:         busSuperMap[page] = superMmd;
  9154:         if (InstructionBreakPoint.IBP_ON) {
  9155:           if (InstructionBreakPoint.ibpUserMap[page] != MemoryMappedDevice.MMD_IBP) {  //命令ブレークポイントがない
  9156:             InstructionBreakPoint.ibpUserMap[page] = userMmd;
  9157:           }
  9158:           if (InstructionBreakPoint.ibpSuperMap[page] != MemoryMappedDevice.MMD_IBP) {  //命令ブレークポイントがない
  9159:             InstructionBreakPoint.ibpSuperMap[page] = superMmd;
  9160:           }
  9161:         }
  9162:         if (DataBreakPoint.DBP_ON) {
  9163:           if (DataBreakPoint.dbpUserMap[page] != MemoryMappedDevice.MMD_DBP) {  //データブレークポイントがない
  9164:             DataBreakPoint.dbpUserMap[page] = userMmd;
  9165:           }
  9166:           if (DataBreakPoint.dbpSuperMap[page] != MemoryMappedDevice.MMD_DBP) {  //データブレークポイントがない
  9167:             DataBreakPoint.dbpSuperMap[page] = superMmd;
  9168:           }
  9169:         }
  9170:       }
  9171:     }
  9172:   }  //busSuper(MMD,int,int)
  9173: 
  9174:   //d = busPbs (a)
  9175:   //  ピークバイト符号拡張
  9176:   public static byte busPbs (int a) {
  9177:     return busSuperMap[a >>> BUS_PAGE_BITS].mmdPbs (a);
  9178:   }  //busPbs(int)
  9179: 
  9180:   //d = busPbz (a)
  9181:   //  ピークバイトゼロ拡張
  9182:   public static int busPbz (int a) {
  9183:     return busSuperMap[a >>> BUS_PAGE_BITS].mmdPbz (a);
  9184:   }  //busPbz(int)
  9185: 
  9186:   //d = busPws (a)
  9187:   //  ピークワード符号拡張
  9188:   public static int busPws (int a) {
  9189:     if (TEST_BIT_0_SHIFT ? a << 31 - 0 >= 0 : (a & 1) == 0) {  //偶数
  9190:       return busSuperMap[a >>> BUS_PAGE_BITS].mmdPws (a);
  9191:     } else {  //奇数
  9192:       int a1 = a + 1;
  9193:       return busSuperMap[a >>> BUS_PAGE_BITS].mmdPbs (a) << 8 | busSuperMap[a1 >>> BUS_PAGE_BITS].mmdPbz (a1);
  9194:     }
  9195:   }  //busPws(int)
  9196: 
  9197:   //d = busPwse (a)
  9198:   //  ピークワード符号拡張(偶数)
  9199:   public static int busPwse (int a) {
  9200:     return busSuperMap[a >>> BUS_PAGE_BITS].mmdPws (a);
  9201:   }  //busPwse(int)
  9202: 
  9203:   //d = busPwz (a)
  9204:   //  ピークワードゼロ拡張
  9205:   public static int busPwz (int a) {
  9206:     if (TEST_BIT_0_SHIFT ? a << 31 - 0 >= 0 : (a & 1) == 0) {  //偶数
  9207:       return busSuperMap[a >>> BUS_PAGE_BITS].mmdPwz (a);
  9208:     } else {  //奇数
  9209:       int a1 = a + 1;
  9210:       return busSuperMap[a >>> BUS_PAGE_BITS].mmdPbz (a) << 8 | busSuperMap[a1 >>> BUS_PAGE_BITS].mmdPbz (a1);
  9211:     }
  9212:   }  //busPwz(int)
  9213: 
  9214:   //d = busPwze (a)
  9215:   //  ピークワードゼロ拡張(偶数)
  9216:   public static int busPwze (int a) {
  9217:     return busSuperMap[a >>> BUS_PAGE_BITS].mmdPwz (a);
  9218:   }  //busPwze(int)
  9219: 
  9220:   //d = busPls (a)
  9221:   //  ピークロング符号拡張
  9222:   public static int busPls (int a) {
  9223:     if (TEST_BIT_0_SHIFT && TEST_BIT_1_SHIFT ? a << 30 == 0 : (a & 3) == 0) {  //4の倍数
  9224:       return busSuperMap[a >>> BUS_PAGE_BITS].mmdPls (a);
  9225:     } else if (TEST_BIT_0_SHIFT ? a << 31 - 0 >= 0 : (a & 1) == 0) {  //4の倍数ではない偶数
  9226:       int a2 = a + 2;
  9227:       return busSuperMap[a >>> BUS_PAGE_BITS].mmdPws (a) << 16 | busSuperMap[a2 >>> BUS_PAGE_BITS].mmdPwz (a2);
  9228:     } else {  //奇数
  9229:       int a1 = a + 1;
  9230:       int a3 = a + 3;
  9231:       return busSuperMap[a >>> BUS_PAGE_BITS].mmdPbs (a) << 24 | busSuperMap[a1 >>> BUS_PAGE_BITS].mmdPwz (a1) << 8 | busSuperMap[a3 >>> BUS_PAGE_BITS].mmdPbz (a3);
  9232:     }
  9233:   }  //busPls(int)
  9234: 
  9235:   //d = busPlsf (a)
  9236:   //  ピークロング符号拡張(4の倍数)
  9237:   public static int busPlsf (int a) {
  9238:     return busSuperMap[a >>> BUS_PAGE_BITS].mmdPls (a);
  9239:   }  //busPlsf(int)
  9240: 
  9241:   //d = busPqs (a)
  9242:   //  ピーククワッド符号拡張
  9243:   public static long busPqs (int a) {
  9244:     return (long) busPls (a) << 32 | busPls (a + 4) & 0xffffffffL;
  9245:   }  //busPqs(int)
  9246: 
  9247: 
  9248:   //検索
  9249:   public static int busSearchByte (int start, int end, int c) {
  9250:     for (int a = start; a < end; a++) {
  9251:       if (busSuperMap[a >>> BUS_PAGE_BITS].mmdPbz (a) == c) {
  9252:         return a;
  9253:       }
  9254:     }
  9255:     return -1;
  9256:   }
  9257:   public static int busSearchWord (int start, int end, int c) {
  9258:     for (int a = start; a < end; a += 2) {
  9259:       if (busSuperMap[a >>> BUS_PAGE_BITS].mmdPwz (a) == c) {
  9260:         return a;
  9261:       }
  9262:     }
  9263:     return -1;
  9264:   }
  9265:   public static int busSearchByteArray (int start, int end, int[] array) {
  9266:     int l = array.length;
  9267:     end -= l;
  9268:     int c = array[0];
  9269:   a:
  9270:     for (int a = start; a <= end; a++) {
  9271:       if (busSuperMap[a >>> BUS_PAGE_BITS].mmdPbz (a) != c) {
  9272:         continue a;
  9273:       }
  9274:       for (int i = 1, b = a + 1; i < l; i++, b++) {
  9275:         if (busSuperMap[b >>> BUS_PAGE_BITS].mmdPbz (b) != array[i]) {
  9276:           continue a;
  9277:         }
  9278:       }
  9279:       return a;
  9280:     }
  9281:     return -1;
  9282:   }
  9283:   public static int busSearchWordArray (int start, int end, int[] array) {
  9284:     int l = array.length;
  9285:     end -= l;
  9286:     int c = array[0];
  9287:   a:
  9288:     for (int a = start; a <= end; a += 2) {
  9289:       if (busSuperMap[a >>> BUS_PAGE_BITS].mmdPwz (a) != c) {
  9290:           continue a;
  9291:       }
  9292:       for (int i = 1, b = a + 2; i < l; i++, b += 2) {
  9293:         if (busSuperMap[b >>> BUS_PAGE_BITS].mmdPwz (b) != array[i]) {
  9294:           continue a;
  9295:         }
  9296:       }
  9297:       return a;
  9298:     }
  9299:     return -1;
  9300:   }
  9301: 
  9302: 
  9303:   //d = busRbs (a)
  9304:   //  リードバイト符号拡張
  9305:   public static byte busRbs (int a) throws M68kException {
  9306:     if (DataBreakPoint.DBP_ON) {
  9307:       return DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdRbs (a);
  9308:     } else {
  9309:       return busMemoryMap[a >>> BUS_PAGE_BITS].mmdRbs (a);
  9310:     }
  9311:   }  //busRbs(int)
  9312: 
  9313:   //d = busRbz (a)
  9314:   //  リードバイトゼロ拡張
  9315:   public static int busRbz (int a) throws M68kException {
  9316:     if (DataBreakPoint.DBP_ON) {
  9317:       return DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdRbz (a);
  9318:     } else {
  9319:       return busMemoryMap[a >>> BUS_PAGE_BITS].mmdRbz (a);
  9320:     }
  9321:   }  //busRbz(int)
  9322: 
  9323:   //d = busRws (a)
  9324:   //  リードワード符号拡張
  9325:   public static int busRws (int a) throws M68kException {
  9326:     if (TEST_BIT_0_SHIFT ? a << 31 - 0 >= 0 : (a & 1) == 0) {  //偶数
  9327:       if (DataBreakPoint.DBP_ON) {
  9328:         return DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdRws (a);
  9329:       } else {
  9330:         return busMemoryMap[a >>> BUS_PAGE_BITS].mmdRws (a);
  9331:       }
  9332:     } else if (mpuIgnoreAddressError) {  //奇数でアドレスエラーを検出しない
  9333:       int a1 = a + 1;
  9334:       if (DataBreakPoint.DBP_ON) {
  9335:         return DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdRbs (a) << 8 | DataBreakPoint.dbpMemoryMap[a1 >>> BUS_PAGE_BITS].mmdRbz (a1);
  9336:       } else {
  9337:         return busMemoryMap[a >>> BUS_PAGE_BITS].mmdRbs (a) << 8 | busMemoryMap[a1 >>> BUS_PAGE_BITS].mmdRbz (a1);
  9338:       }
  9339:     } else {  //奇数でアドレスエラーを検出する
  9340:       M68kException.m6eNumber = M68kException.M6E_ADDRESS_ERROR;
  9341:       M68kException.m6eAddress = a;
  9342:       M68kException.m6eDirection = MPU_WR_READ;
  9343:       M68kException.m6eSize = MPU_SS_WORD;
  9344:       throw M68kException.m6eSignal;
  9345:     }
  9346:   }  //busRws(int)
  9347: 
  9348:   //d = busRwse (a)
  9349:   //  リードワード符号拡張(偶数限定)
  9350:   //  MOVEM命令の2ワード目以降など、アドレスが偶数であることが分かっている場合
  9351:   public static int busRwse (int a) throws M68kException {
  9352:     if (DataBreakPoint.DBP_ON) {
  9353:       return DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdRws (a);
  9354:     } else {
  9355:       return busMemoryMap[a >>> BUS_PAGE_BITS].mmdRws (a);
  9356:     }
  9357:   }  //busRwse(int)
  9358: 
  9359:   //d = busRwz (a)
  9360:   //  リードワードゼロ拡張
  9361:   public static int busRwz (int a) throws M68kException {
  9362:     if (TEST_BIT_0_SHIFT ? a << 31 - 0 >= 0 : (a & 1) == 0) {  //偶数
  9363:       if (DataBreakPoint.DBP_ON) {
  9364:         return DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdRwz (a);
  9365:       } else {
  9366:         return busMemoryMap[a >>> BUS_PAGE_BITS].mmdRwz (a);
  9367:       }
  9368:     } else if (mpuIgnoreAddressError) {  //奇数でアドレスエラーを検出しない
  9369:       int a1 = a + 1;
  9370:       if (DataBreakPoint.DBP_ON) {
  9371:         return DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdRbz (a) << 8 | DataBreakPoint.dbpMemoryMap[a1 >>> BUS_PAGE_BITS].mmdRbz (a1);
  9372:       } else {
  9373:         return busMemoryMap[a >>> BUS_PAGE_BITS].mmdRbz (a) << 8 | busMemoryMap[a1 >>> BUS_PAGE_BITS].mmdRbz (a1);
  9374:       }
  9375:     } else {  //奇数でアドレスエラーを検出する
  9376:       M68kException.m6eNumber = M68kException.M6E_ADDRESS_ERROR;
  9377:       M68kException.m6eAddress = a;
  9378:       M68kException.m6eDirection = MPU_WR_READ;
  9379:       M68kException.m6eSize = MPU_SS_WORD;
  9380:       throw M68kException.m6eSignal;
  9381:     }
  9382:   }  //busRwz(int)
  9383: 
  9384:   //d = busRwze (a)
  9385:   //  リードワードゼロ拡張(偶数限定)
  9386:   //  MOVEM命令の2ワード目以降など、アドレスが偶数であることが分かっている場合
  9387:   public static int busRwze (int a) throws M68kException {
  9388:     if (DataBreakPoint.DBP_ON) {
  9389:       return DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdRwz (a);
  9390:     } else {
  9391:       return busMemoryMap[a >>> BUS_PAGE_BITS].mmdRwz (a);
  9392:     }
  9393:   }  //busRwze(int)
  9394: 
  9395:   //d = busRls (a)
  9396:   //  リードロング符号拡張
  9397:   public static int busRls (int a) throws M68kException {
  9398:     if (TEST_BIT_0_SHIFT && TEST_BIT_1_SHIFT ? a << 30 == 0 : (a & 3) == 0) {  //4の倍数
  9399:       if (DataBreakPoint.DBP_ON) {
  9400:         return DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdRls (a);
  9401:       } else {
  9402:         return busMemoryMap[a >>> BUS_PAGE_BITS].mmdRls (a);
  9403:       }
  9404:     } else if (TEST_BIT_0_SHIFT ? a << 31 - 0 >= 0 : (a & 1) == 0) {  //4の倍数ではない偶数
  9405:       int a2 = a + 2;
  9406:       if (BUS_SPLIT_UNALIGNED_LONG) {  //常に分割する
  9407:         if (DataBreakPoint.DBP_ON) {
  9408:           return DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdRws (a) << 16 | DataBreakPoint.dbpMemoryMap[a2 >>> BUS_PAGE_BITS].mmdRwz (a2);
  9409:         } else {
  9410:           return busMemoryMap[a >>> BUS_PAGE_BITS].mmdRws (a) << 16 | busMemoryMap[a2 >>> BUS_PAGE_BITS].mmdRwz (a2);
  9411:         }
  9412:       } else {  //デバイスを跨がないとき分割しない
  9413:         MemoryMappedDevice mmd;
  9414:         MemoryMappedDevice mmd2;
  9415:         if (DataBreakPoint.DBP_ON) {
  9416:           mmd = DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS];
  9417:           mmd2 = DataBreakPoint.dbpMemoryMap[a2 >>> BUS_PAGE_BITS];
  9418:         } else {
  9419:           mmd = busMemoryMap[a >>> BUS_PAGE_BITS];
  9420:           mmd2 = busMemoryMap[a2 >>> BUS_PAGE_BITS];
  9421:         }
  9422:         return mmd == mmd2 ? mmd.mmdRls (a) : mmd.mmdRws (a) << 16 | mmd2.mmdRwz (a2);  //デバイスを跨がない/デバイスを跨ぐ
  9423:       }
  9424:     } else if (mpuIgnoreAddressError) {  //奇数でアドレスエラーを検出しない
  9425:       int a1 = a + 1;
  9426:       int a3 = a + 3;
  9427:       if (DataBreakPoint.DBP_ON) {
  9428:         return DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdRbs (a) << 24 | DataBreakPoint.dbpMemoryMap[a1 >>> BUS_PAGE_BITS].mmdRwz (a1) << 8 | DataBreakPoint.dbpMemoryMap[a3 >>> BUS_PAGE_BITS].mmdRbz (a3);
  9429:       } else {
  9430:         return busMemoryMap[a >>> BUS_PAGE_BITS].mmdRbs (a) << 24 | busMemoryMap[a1 >>> BUS_PAGE_BITS].mmdRwz (a1) << 8 | busMemoryMap[a3 >>> BUS_PAGE_BITS].mmdRbz (a3);
  9431:       }
  9432:     } else {  //奇数でアドレスエラーを検出する
  9433:       M68kException.m6eNumber = M68kException.M6E_ADDRESS_ERROR;
  9434:       M68kException.m6eAddress = a;
  9435:       M68kException.m6eDirection = MPU_WR_READ;
  9436:       M68kException.m6eSize = MPU_SS_LONG;
  9437:       throw M68kException.m6eSignal;
  9438:     }
  9439:   }  //busRls(int)
  9440: 
  9441:   //d = busRlse (a)
  9442:   //  リードロング符号拡張(偶数限定)
  9443:   //  MOVEM命令の2ワード目以降など、アドレスが偶数であることが分かっている場合
  9444:   public static int busRlse (int a) throws M68kException {
  9445:     if (TEST_BIT_0_SHIFT && TEST_BIT_1_SHIFT ? a << 30 == 0 : (a & 3) == 0) {  //4の倍数
  9446:       if (DataBreakPoint.DBP_ON) {
  9447:         return DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdRls (a);
  9448:       } else {
  9449:         return busMemoryMap[a >>> BUS_PAGE_BITS].mmdRls (a);
  9450:       }
  9451:     } else {  //4の倍数ではない偶数
  9452:       int a2 = a + 2;
  9453:       if (BUS_SPLIT_UNALIGNED_LONG) {  //常に分割する
  9454:         if (DataBreakPoint.DBP_ON) {
  9455:           return DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdRws (a) << 16 | DataBreakPoint.dbpMemoryMap[a2 >>> BUS_PAGE_BITS].mmdRwz (a2);
  9456:         } else {
  9457:           return busMemoryMap[a >>> BUS_PAGE_BITS].mmdRws (a) << 16 | busMemoryMap[a2 >>> BUS_PAGE_BITS].mmdRwz (a2);
  9458:         }
  9459:       } else {  //デバイスを跨がないとき分割しない
  9460:         MemoryMappedDevice mmd;
  9461:         MemoryMappedDevice mmd2;
  9462:         if (DataBreakPoint.DBP_ON) {
  9463:           mmd = DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS];
  9464:           mmd2 = DataBreakPoint.dbpMemoryMap[a2 >>> BUS_PAGE_BITS];
  9465:         } else {
  9466:           mmd = busMemoryMap[a >>> BUS_PAGE_BITS];
  9467:           mmd2 = busMemoryMap[a2 >>> BUS_PAGE_BITS];
  9468:         }
  9469:         return mmd == mmd2 ? mmd.mmdRls (a) : mmd.mmdRws (a) << 16 | mmd2.mmdRwz (a2);  //デバイスを跨がない/デバイスを跨ぐ
  9470:       }
  9471:     }
  9472:   }  //busRlse(int)
  9473: 
  9474:   //d = busRlsf (a)
  9475:   //  リードロング符号拡張(4の倍数限定)
  9476:   //  例外ベクタテーブルなど、アドレスが4の倍数であることが分かっている場合
  9477:   public static int busRlsf (int a) throws M68kException {
  9478:     if (DataBreakPoint.DBP_ON) {
  9479:       return DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdRls (a);
  9480:     } else {
  9481:       return busMemoryMap[a >>> BUS_PAGE_BITS].mmdRls (a);
  9482:     }
  9483:   }  //busRlsf(int)
  9484: 
  9485:   //d = busRqs (a)
  9486:   //  リードクワッド符号拡張
  9487:   public static long busRqs (int a) throws M68kException {
  9488:     return (long) busRls (a) << 32 | busRls (a + 4) & 0xffffffffL;
  9489:   }  //busRqs(int)
  9490: 
  9491:   //busWb (a, d)
  9492:   //  ライトバイト
  9493:   public static void busWb (int a, int d) throws M68kException {
  9494:     if (DataBreakPoint.DBP_ON) {
  9495:       DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdWb (a, d);
  9496:     } else {
  9497:       busMemoryMap[a >>> BUS_PAGE_BITS].mmdWb (a, d);
  9498:     }
  9499:   }  //busWb(int,int)
  9500: 
  9501:   //busWw (a, d)
  9502:   //  ライトワード
  9503:   public static void busWw (int a, int d) throws M68kException {
  9504:     if (TEST_BIT_0_SHIFT ? a << 31 - 0 >= 0 : (a & 1) == 0) {  //偶数
  9505:       if (DataBreakPoint.DBP_ON) {
  9506:         DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdWw (a, d);
  9507:       } else {
  9508:         busMemoryMap[a >>> BUS_PAGE_BITS].mmdWw (a, d);
  9509:       }
  9510:     } else if (mpuIgnoreAddressError) {  //奇数でアドレスエラーを検出しない
  9511:       int a1 = a + 1;
  9512:       if (DataBreakPoint.DBP_ON) {
  9513:         DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdWb (a, d >> 8);
  9514:         DataBreakPoint.dbpMemoryMap[a1 >>> BUS_PAGE_BITS].mmdWb (a1, d);
  9515:       } else {
  9516:         busMemoryMap[a >>> BUS_PAGE_BITS].mmdWb (a, d >> 8);
  9517:         busMemoryMap[a1 >>> BUS_PAGE_BITS].mmdWb (a1, d);
  9518:       }
  9519:     } else {  //奇数でアドレスエラーを検出する
  9520:       M68kException.m6eNumber = M68kException.M6E_ADDRESS_ERROR;
  9521:       M68kException.m6eAddress = a;
  9522:       M68kException.m6eDirection = MPU_WR_WRITE;
  9523:       M68kException.m6eSize = MPU_SS_WORD;
  9524:       throw M68kException.m6eSignal;
  9525:     }
  9526:   }  //busWw(int,int)
  9527: 
  9528:   //busWwe (a, d)
  9529:   //  ライトワード(偶数限定)
  9530:   //  MOVEM命令の2ワード目以降など、アドレスが偶数であることが分かっている場合
  9531:   public static void busWwe (int a, int d) throws M68kException {
  9532:     if (DataBreakPoint.DBP_ON) {
  9533:       DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdWw (a, d);
  9534:     } else {
  9535:       busMemoryMap[a >>> BUS_PAGE_BITS].mmdWw (a, d);
  9536:     }
  9537:   }  //busWwe(int,int)
  9538: 
  9539:   //busWl (a, d)
  9540:   //  ライトロング
  9541:   public static void busWl (int a, int d) throws M68kException {
  9542:     if (TEST_BIT_0_SHIFT && TEST_BIT_1_SHIFT ? a << 30 == 0 : (a & 3) == 0) {  //4の倍数
  9543:       if (DataBreakPoint.DBP_ON) {
  9544:         DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdWl (a, d);
  9545:       } else {
  9546:         busMemoryMap[a >>> BUS_PAGE_BITS].mmdWl (a, d);
  9547:       }
  9548:     } else if (TEST_BIT_0_SHIFT ? a << 31 - 0 >= 0 : (a & 1) == 0) {  //4の倍数ではない偶数
  9549:       int a2 = a + 2;
  9550:       if (BUS_SPLIT_UNALIGNED_LONG) {  //常に分割する
  9551:         if (DataBreakPoint.DBP_ON) {
  9552:           DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdWw (a, d >> 16);
  9553:           DataBreakPoint.dbpMemoryMap[a2 >>> BUS_PAGE_BITS].mmdWw (a2, d);
  9554:         } else {
  9555:           busMemoryMap[a >>> BUS_PAGE_BITS].mmdWw (a, d >> 16);
  9556:           busMemoryMap[a2 >>> BUS_PAGE_BITS].mmdWw (a2, d);
  9557:         }
  9558:       } else {  //デバイスを跨がないとき分割しない
  9559:         MemoryMappedDevice mmd;
  9560:         MemoryMappedDevice mmd2;
  9561:         if (DataBreakPoint.DBP_ON) {
  9562:           mmd = DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS];
  9563:           mmd2 = DataBreakPoint.dbpMemoryMap[a2 >>> BUS_PAGE_BITS];
  9564:         } else {
  9565:           mmd = busMemoryMap[a >>> BUS_PAGE_BITS];
  9566:           mmd2 = busMemoryMap[a2 >>> BUS_PAGE_BITS];
  9567:         }
  9568:         if (mmd == mmd2) {  //デバイスを跨がない
  9569:           mmd.mmdWl (a, d);
  9570:         } else {  //デバイスを跨ぐ
  9571:           mmd.mmdWw (a, d >> 16);
  9572:           mmd2.mmdWw (a2, d);
  9573:         }
  9574:       }
  9575:     } else if (mpuIgnoreAddressError) {  //奇数でアドレスエラーを検出しない
  9576:       int a1 = a + 1;
  9577:       int a3 = a + 3;
  9578:       if (DataBreakPoint.DBP_ON) {
  9579:         DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdWb (a, d >> 24);
  9580:         DataBreakPoint.dbpMemoryMap[a1 >>> BUS_PAGE_BITS].mmdWw (a1, d >> 8);
  9581:         DataBreakPoint.dbpMemoryMap[a3 >>> BUS_PAGE_BITS].mmdWb (a3, d);
  9582:       } else {
  9583:         busMemoryMap[a >>> BUS_PAGE_BITS].mmdWb (a, d >> 24);
  9584:         busMemoryMap[a1 >>> BUS_PAGE_BITS].mmdWw (a1, d >> 8);
  9585:         busMemoryMap[a3 >>> BUS_PAGE_BITS].mmdWb (a3, d);
  9586:       }
  9587:     } else {  //奇数でアドレスエラーを検出する
  9588:       M68kException.m6eNumber = M68kException.M6E_ADDRESS_ERROR;
  9589:       M68kException.m6eAddress = a;
  9590:       M68kException.m6eDirection = MPU_WR_WRITE;
  9591:       M68kException.m6eSize = MPU_SS_LONG;
  9592:       throw M68kException.m6eSignal;
  9593:     }
  9594:   }  //busWl(int,int)
  9595: 
  9596:   //busWlf (a, d)
  9597:   //  ライトロング(4の倍数限定)
  9598:   //  例外ベクタテーブルなど、アドレスが4の倍数であることが分かっている場合
  9599:   public static void busWlf (int a, int d) throws M68kException {
  9600:     if (DataBreakPoint.DBP_ON) {
  9601:       DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdWl (a, d);
  9602:     } else {
  9603:       busMemoryMap[a >>> BUS_PAGE_BITS].mmdWl (a, d);
  9604:     }
  9605:   }  //busWlf(int,int)
  9606: 
  9607:   //busWle (a, d)
  9608:   //  ライトロング(偶数限定)
  9609:   //  MOVEM命令の2ワード目以降など、アドレスが偶数であることが分かっている場合
  9610:   public static void busWle (int a, int d) throws M68kException {
  9611:     if (TEST_BIT_0_SHIFT && TEST_BIT_1_SHIFT ? a << 30 == 0 : (a & 3) == 0) {  //4の倍数
  9612:       if (DataBreakPoint.DBP_ON) {
  9613:         DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdWl (a, d);
  9614:       } else {
  9615:         busMemoryMap[a >>> BUS_PAGE_BITS].mmdWl (a, d);
  9616:       }
  9617:     } else {  //4の倍数ではない偶数
  9618:       int a2 = a + 2;
  9619:       if (BUS_SPLIT_UNALIGNED_LONG) {  //常に分割する
  9620:         if (DataBreakPoint.DBP_ON) {
  9621:           DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS].mmdWw (a, d >> 16);
  9622:           DataBreakPoint.dbpMemoryMap[a2 >>> BUS_PAGE_BITS].mmdWw (a2, d);
  9623:         } else {
  9624:           busMemoryMap[a >>> BUS_PAGE_BITS].mmdWw (a, d >> 16);
  9625:           busMemoryMap[a2 >>> BUS_PAGE_BITS].mmdWw (a2, d);
  9626:         }
  9627:       } else {  //デバイスを跨がないとき分割しない
  9628:         MemoryMappedDevice mmd;
  9629:         MemoryMappedDevice mmd2;
  9630:         if (DataBreakPoint.DBP_ON) {
  9631:           mmd = DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS];
  9632:           mmd2 = DataBreakPoint.dbpMemoryMap[a2 >>> BUS_PAGE_BITS];
  9633:         } else {
  9634:           mmd = busMemoryMap[a >>> BUS_PAGE_BITS];
  9635:           mmd2 = busMemoryMap[a2 >>> BUS_PAGE_BITS];
  9636:         }
  9637:         if (mmd == mmd2) {  //デバイスを跨がない
  9638:           mmd.mmdWl (a, d);
  9639:         } else {  //デバイスを跨ぐ
  9640:           mmd.mmdWw (a, d >> 16);
  9641:           mmd2.mmdWw (a2, d);
  9642:         }
  9643:       }
  9644:     }
  9645:   }  //busWle(int,int)
  9646: 
  9647:   //busWq (a, d)
  9648:   //  ライトクワッド
  9649:   public static void busWq (int a, long d) throws M68kException {
  9650:     busWl (a, (int) (d >>> 32));
  9651:     busWl (a + 4, (int) d);
  9652:   }  //busWq(int,long)
  9653: 
  9654:   //以下は拡張
  9655: 
  9656:   //busRbb (a, bb, o, l)
  9657:   //  リードバイトバッファ
  9658:   public static void busRbb (int a, byte[] bb, int o, int l) throws M68kException {
  9659:     if (false) {
  9660:       for (int i = 0; i < l; i++) {
  9661:         int ai = a + i;
  9662:         if (DataBreakPoint.DBP_ON) {
  9663:           bb[o + i] = DataBreakPoint.dbpMemoryMap[ai >>> BUS_PAGE_BITS].mmdRbs (ai);
  9664:         } else {
  9665:           bb[o + i] = busMemoryMap[ai >>> BUS_PAGE_BITS].mmdRbs (ai);
  9666:         }
  9667:       }
  9668:     } else {
  9669:       int r = (~a & BUS_PAGE_SIZE - 1) + 1;  //最初のページの残りの長さ。1~BUS_PAGE_SIZE
  9670:       while (l > 0) {
  9671:         MemoryMappedDevice mmd;
  9672:         if (DataBreakPoint.DBP_ON) {
  9673:           mmd = DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS];  //ページのデバイス
  9674:         } else {
  9675:           mmd = busMemoryMap[a >>> BUS_PAGE_BITS];  //ページのデバイス
  9676:         }
  9677:         int s = l <= r ? l : r;  //このページで転送する長さ
  9678:         l -= s;
  9679:         if (true) {
  9680:           for (s -= 16; s >= 0; s -= 16) {
  9681:             bb[o     ] = mmd.mmdRbs (a     );
  9682:             bb[o +  1] = mmd.mmdRbs (a +  1);
  9683:             bb[o +  2] = mmd.mmdRbs (a +  2);
  9684:             bb[o +  3] = mmd.mmdRbs (a +  3);
  9685:             bb[o +  4] = mmd.mmdRbs (a +  4);
  9686:             bb[o +  5] = mmd.mmdRbs (a +  5);
  9687:             bb[o +  6] = mmd.mmdRbs (a +  6);
  9688:             bb[o +  7] = mmd.mmdRbs (a +  7);
  9689:             bb[o +  8] = mmd.mmdRbs (a +  8);
  9690:             bb[o +  9] = mmd.mmdRbs (a +  9);
  9691:             bb[o + 10] = mmd.mmdRbs (a + 10);
  9692:             bb[o + 11] = mmd.mmdRbs (a + 11);
  9693:             bb[o + 12] = mmd.mmdRbs (a + 12);
  9694:             bb[o + 13] = mmd.mmdRbs (a + 13);
  9695:             bb[o + 14] = mmd.mmdRbs (a + 14);
  9696:             bb[o + 15] = mmd.mmdRbs (a + 15);
  9697:             a += 16;
  9698:             o += 16;
  9699:           }
  9700:           s += 16;
  9701:         }
  9702:         for (int i = 0; i < s; i++) {
  9703:           bb[o + i] = mmd.mmdRbs (a + i);
  9704:         }
  9705:         a += s;
  9706:         o += s;
  9707:         r = BUS_PAGE_SIZE;
  9708:       }
  9709:     }
  9710:   }  //busRbb(int,byte[],int,int)
  9711: 
  9712:   //busWbb (a, bb, o, l)
  9713:   //  ライトバイトバッファ
  9714:   public static void busWbb (int a, byte[] bb, int o, int l) throws M68kException {
  9715:     if (false) {
  9716:       for (int i = 0; i < l; i++) {
  9717:         int ai = a + i;
  9718:         if (DataBreakPoint.DBP_ON) {
  9719:           DataBreakPoint.dbpMemoryMap[ai >>> BUS_PAGE_BITS].mmdWb (ai, bb[o + i]);
  9720:         } else {
  9721:           busMemoryMap[ai >>> BUS_PAGE_BITS].mmdWb (ai, bb[o + i]);
  9722:         }
  9723:       }
  9724:     } else {
  9725:       int r = (~a & BUS_PAGE_SIZE - 1) + 1;  //最初のページの残りの長さ。1~BUS_PAGE_SIZE
  9726:       while (l > 0) {
  9727:         MemoryMappedDevice mmd;
  9728:         if (DataBreakPoint.DBP_ON) {
  9729:           mmd = DataBreakPoint.dbpMemoryMap[a >>> BUS_PAGE_BITS];  //ページのデバイス
  9730:         } else {
  9731:           mmd = busMemoryMap[a >>> BUS_PAGE_BITS];  //ページのデバイス
  9732:         }
  9733:         int s = l <= r ? l : r;  //このページで転送する長さ
  9734:         l -= s;
  9735:         if (true) {
  9736:           for (s -= 16; s >= 0; s -= 16) {
  9737:             mmd.mmdWb (a     , bb[o     ]);
  9738:             mmd.mmdWb (a +  1, bb[o +  1]);
  9739:             mmd.mmdWb (a +  2, bb[o +  2]);
  9740:             mmd.mmdWb (a +  3, bb[o +  3]);
  9741:             mmd.mmdWb (a +  4, bb[o +  4]);
  9742:             mmd.mmdWb (a +  5, bb[o +  5]);
  9743:             mmd.mmdWb (a +  6, bb[o +  6]);
  9744:             mmd.mmdWb (a +  7, bb[o +  7]);
  9745:             mmd.mmdWb (a +  8, bb[o +  8]);
  9746:             mmd.mmdWb (a +  9, bb[o +  9]);
  9747:             mmd.mmdWb (a + 10, bb[o + 10]);
  9748:             mmd.mmdWb (a + 11, bb[o + 11]);
  9749:             mmd.mmdWb (a + 12, bb[o + 12]);
  9750:             mmd.mmdWb (a + 13, bb[o + 13]);
  9751:             mmd.mmdWb (a + 14, bb[o + 14]);
  9752:             mmd.mmdWb (a + 15, bb[o + 15]);
  9753:             a += 16;
  9754:             o += 16;
  9755:           }
  9756:           s += 16;
  9757:         }
  9758:         for (int i = 0; i < s; i++) {
  9759:           mmd.mmdWb (a + i, bb[o + i]);
  9760:         }
  9761:         a += s;
  9762:         o += s;
  9763:         r = BUS_PAGE_SIZE;
  9764:       }
  9765:     }
  9766:   }  //busWbb(int,byte[],int,int)
  9767: 
  9768:   //busVb (a, d)
  9769:   //  ライトバイト(エラーなし)
  9770:   public static void busVb (int a, int d) {
  9771:     try {
  9772:       if (DataBreakPoint.DBP_ON) {
  9773:         (regSRS != 0 ? busSuperMap : busUserMap)[a >>> BUS_PAGE_BITS].mmdWb (a, d);
  9774:       } else {
  9775:         busMemoryMap[a >>> BUS_PAGE_BITS].mmdWb (a, d);
  9776:       }
  9777:     } catch (M68kException e) {
  9778:     }
  9779:   }  //busVb(int,int)
  9780: 
  9781:   //busVw (a, d)
  9782:   //  ライトワード(エラーなし)
  9783:   public static void busVw (int a, int d) {
  9784:     try {
  9785:       if (TEST_BIT_0_SHIFT ? a << 31 - 0 >= 0 : (a & 1) == 0) {  //偶数
  9786:         if (DataBreakPoint.DBP_ON) {
  9787:           (regSRS != 0 ? busSuperMap : busUserMap)[a >>> BUS_PAGE_BITS].mmdWw (a, d);
  9788:         } else {
  9789:           busMemoryMap[a >>> BUS_PAGE_BITS].mmdWw (a, d);
  9790:         }
  9791:       }
  9792:     } catch (M68kException e) {
  9793:     }
  9794:   }  //busVw(int,int)
  9795: 
  9796:   //busVl (a, d)
  9797:   //  ライトロング(エラーなし)
  9798:   public static void busVl (int a, int d) {
  9799:     try {
  9800:       if (TEST_BIT_0_SHIFT && TEST_BIT_1_SHIFT ? a << 30 == 0 : (a & 3) == 0) {  //4の倍数
  9801:         if (DataBreakPoint.DBP_ON) {
  9802:           (regSRS != 0 ? busSuperMap : busUserMap)[a >>> BUS_PAGE_BITS].mmdWl (a, d);
  9803:         } else {
  9804:           busMemoryMap[a >>> BUS_PAGE_BITS].mmdWl (a, d);
  9805:         }
  9806:       } else if (TEST_BIT_0_SHIFT ? a << 31 - 0 >= 0 : (a & 1) == 0) {  //4の倍数ではない偶数
  9807:         int a2 = a + 2;
  9808:         MemoryMappedDevice mmd;
  9809:         MemoryMappedDevice mmd2;
  9810:         if (DataBreakPoint.DBP_ON) {
  9811:           mmd = (regSRS != 0 ? busSuperMap : busUserMap)[a >>> BUS_PAGE_BITS];
  9812:           mmd2 = (regSRS != 0 ? busSuperMap : busUserMap)[a2 >>> BUS_PAGE_BITS];
  9813:         } else {
  9814:           mmd = busMemoryMap[a >>> BUS_PAGE_BITS];
  9815:           mmd2 = busMemoryMap[a2 >>> BUS_PAGE_BITS];
  9816:         }
  9817:         if (mmd == mmd2) {  //4の倍数ではない偶数でデバイスを跨がない
  9818:           mmd.mmdWl (a, d);
  9819:         } else {  //4の倍数ではない偶数でデバイスを跨ぐ
  9820:           mmd.mmdWw (a, d >> 16);
  9821:           mmd2.mmdWw (a2, d);
  9822:         }
  9823:       }
  9824:     } catch (M68kException e) {
  9825:     }
  9826:   }  //busVl(int,int)
  9827: 
  9828: 
  9829: 
  9830:   //========================================================================================
  9831:   //$$SVS スーパーバイザ領域設定
  9832:   public static final int SVS_AREASET = 0x00e86001;  //0x00 0x00000000~0x00002000
  9833:   //                                                      0x01 0x00000000~0x00004000
  9834:   //                                                      0x02 0x00000000~0x00008000
  9835:   //                                                      0x04 0x00000000~0x00010000
  9836:   //                                                      0x08 0x00000000~0x00020000
  9837:   //                                                      0x10 0x00000000~0x00040000
  9838:   //                                                      0x20 0x00000000~0x00080000
  9839:   //                                                      0x40 0x00000000~0x00100000
  9840:   //                                                      0x80 0x00000000~0x00200000
  9841: 
  9842:   public static void svsInit () {
  9843:   }
  9844: 
  9845: 
  9846: 
  9847:   //========================================================================================
  9848:   //$$SYS システムポート
  9849:   //
  9850:   //     アドレス   bit  RW  名前   X68030
  9851:   //    0x00e8e001  0-3  RW           13    コントラスト(0=最も暗い,15=最も明るい)
  9852:   //    0x00e8e003   3   R             1    TV ON/OFFステータス(0=ON,1=OFF)
  9853:   //                      W                 TVリモコン信号
  9854:   //                 2   R   FIELD     0
  9855:   //                 1   RW  3D-L      0    (3Dスコープ)シャッター左(0=CLOSE,1=OPEN)
  9856:   //                 0   RW  3D-R      0    (3Dスコープ)シャッター右(0=CLOSE,1=OPEN)
  9857:   //    0x00e8e005  4-0   W                 (カラーイメージユニット(デジタイズテロッパ))画像入力コントロール
  9858:   //                                          bit4  IMAGE IN bit17
  9859:   //                                          bit3  IMAGE IN bit18
  9860:   //                                          bit2  IMAGE IN bit19
  9861:   //                                          bit1  IMAGE IN bit20
  9862:   //                                          bit0  IMAGE IN bit21
  9863:   //    0x00e8e007   3   R             1    キージャックステータス(0=抜かれている,1=差し込まれている)
  9864:   //                      W                 キーレディ(0=キーデータ送信禁止,1=キーデータ送信許可)
  9865:   //                 2    W            1    1=NMIリセット
  9866:   //                 1   RW            0    HRL。詳細はCRTCを参照
  9867:   //                 0   RW            0    (現在は使用されていない)解像度LED(0=消灯,1=点灯)
  9868:   //    0x00e8e009  7-4   W                 (X68030のみ)ROMアクセスウェイト
  9869:   //                3-0   W                 (X68030のみ)RAMアクセスウェイト(0=25MHz,4=16MHz相当,10=10MHz相当)
  9870:   //    0x00e8e00b  7-4  R            13    機種(13=MC68030,15=MC68000)
  9871:   //                3-0  R            12    動作周波数(12=25MHz,14=16MHz,15=10MHz)
  9872:   //    0x00e8e00d  7-0   W                 SRAM WRITE ENABLE(49=SRAM書き込み可)
  9873:   //    0x00e8e00f  3-0   W                 フロント電源スイッチがOFFになっているとき0→15→15で電源OFF
  9874:   //
  9875:   //    未定義のbitはリードすると1、ライトしてもバスエラーは発生しない
  9876:   //    アドレスのbit12-4はデコードされない。0x00e8e000~0x00e8ffffの範囲に16バイトのポートが512回繰り返し現れる
  9877:   //
  9878: 
  9879:   public static boolean sysNMIFlag;  //true=INTERRUPTスイッチが押された
  9880: 
  9881:   //sysInit ()
  9882:   //  初期化
  9883:   public static void sysInit () {
  9884:     sysNMIFlag = false;
  9885:   }  //sysInit()
  9886: 
  9887:   //割り込み受付
  9888:   //  コアが割り込み要求を受け付けたときに呼び出す
  9889:   //  割り込みベクタ番号を返す
  9890:   //  割り込み要求を取り下げる場合は0を返す
  9891:   //  オートベクタを使用するデバイスはオートベクタの番号を返すこと
  9892:   public static int sysAcknowledge () {
  9893:     return M68kException.M6E_LEVEL_7_INTERRUPT_AUTOVECTOR;
  9894:   }  //sysAcknowledge()
  9895: 
  9896:   //割り込み終了
  9897:   //  コアが割り込み処理を終了したときに呼び出す
  9898:   //  まだ処理されていない割り込みが残っていたら再度割り込み要求を出す
  9899:   public static void sysDone () {
  9900:     if (sysNMIFlag) {  //NMIリセットされていない
  9901:       mpuIRR |= MPU_SYS_INTERRUPT_MASK;
  9902:     }
  9903:   }  //sysDone()
  9904: 
  9905:   //sysInterrupt ()
  9906:   //  INTERRUPTスイッチが押された
  9907:   public static void sysInterrupt () {
  9908:     sysNMIFlag = true;
  9909:     mpuIRR |= MPU_SYS_INTERRUPT_MASK;
  9910:   }  //sysInterrupt()
  9911: 
  9912:   //sysResetNMI ()
  9913:   //  NMIリセット
  9914:   public static void sysResetNMI () {
  9915:     sysNMIFlag = false;
  9916:   }  //sysResetNMI()
  9917: 
  9918: 
  9919: 
  9920:   //========================================================================================
  9921:   //$$EB2 拡張ボードレベル2割り込み
  9922: 
  9923:   public static final int EB2_SPC_REQUEST = 0x4000;  //拡張SCSI
  9924:   public static final int EB2_SPC_VECTOR = 0xf6;  //拡張SCSI
  9925: 
  9926:   //割り込み要求
  9927:   //  0b00010000_00000000  SPC割り込み要求あり
  9928:   public static int eb2Request;  //割り込み要求。デバイスは操作しないこと
  9929: 
  9930:   //eb2Reset ()
  9931:   //  拡張ボードレベル2割り込みをリセットする
  9932:   public static void eb2Reset () {
  9933:     eb2Request = 0;
  9934:   }  //eb2Reset()
  9935: 
  9936:   //eb2Interrupt (mask)
  9937:   //  割り込み要求
  9938:   //  デバイスが割り込みを要求するときに呼び出す
  9939:   //  mask  EB2_SPC_VECTOR  拡張SCSI割り込みを要求する
  9940:   public static void eb2Interrupt (int mask) {
  9941:     eb2Request |= mask;
  9942:     mpuIRR |= MPU_EB2_INTERRUPT_MASK;
  9943:   }  //eb2Interrupt(int)
  9944: 
  9945:   //vector = eb2Acknowledge ()
  9946:   //  割り込み受付
  9947:   //  コアが割り込み要求を受け付けたときに呼び出す
  9948:   //  割り込みベクタ番号を返す
  9949:   //  割り込み要求を取り下げる場合は0を返す
  9950:   //  オートベクタを使用するデバイスはオートベクタの番号を返すこと
  9951:   public static int eb2Acknowledge () {
  9952:     if ((eb2Request & EB2_SPC_REQUEST) != 0) {
  9953:       eb2Request &= ~EB2_SPC_REQUEST;
  9954:       return EB2_SPC_VECTOR;
  9955:     }
  9956:     return 0;
  9957:   }  //eb2Acknowledge()
  9958: 
  9959:   //eb2Done ()
  9960:   //  割り込み終了
  9961:   //  コアが割り込み処理を終了したときに呼び出す
  9962:   //  まだ処理されていない割り込みが残っていたら再度割り込み要求を出す
  9963:   public static void eb2Done () {
  9964:     if (eb2Request != 0) {
  9965:       mpuIRR |= MPU_EB2_INTERRUPT_MASK;
  9966:     }
  9967:   }  //eb2Done()
  9968: 
  9969: 
  9970: 
  9971:   //========================================================================================
  9972:   //$$XB2 拡張ボード領域2
  9973:   //  0x00eaf900  FAXボード(CZ-6BC1)
  9974:   //  0x00eafa00  MIDIボード(CZ-6BM1)
  9975:   //  0x00eafb00  パラレルボード(CZ-6BN1)
  9976:   //  0x00eafc00  RS-232Cボード(CZ-6BF1)
  9977:   //  0x00eafd00  ユニバーサルI/Oボード(CZ-6BU1)
  9978:   //  0x00eafe00  GP-IBボード(CZ-6BG1)
  9979:   //  0x00eaff00  スーパーバイザエリア設定
  9980:   //
  9981:   //  スーパーバイザエリア設定のみ対応
  9982: 
  9983:   //スーパーバイザエリア設定ポート
  9984:   //  0x00eaff81  bit0  0x00200000~0x0023ffff
  9985:   //              bit1  0x00240000~0x0027ffff
  9986:   //              bit2  0x00280000~0x002bffff
  9987:   //              bit3  0x002c0000~0x002fffff
  9988:   //              bit4  0x00300000~0x0033ffff
  9989:   //              bit5  0x00340000~0x0037ffff
  9990:   //              bit6  0x00380000~0x003bffff
  9991:   //              bit7  0x003c0000~0x003fffff
  9992:   //  0x00eaff83  bit0  0x00400000~0x0043ffff
  9993:   //              bit1  0x00440000~0x0047ffff
  9994:   //              bit2  0x00480000~0x004bffff
  9995:   //              bit3  0x004c0000~0x004fffff
  9996:   //              bit4  0x00500000~0x0053ffff
  9997:   //              bit5  0x00540000~0x0057ffff
  9998:   //              bit6  0x00580000~0x005bffff
  9999:   //              bit7  0x005c0000~0x005fffff
 10000:   //  0x00eaff85  bit0  0x00600000~0x0063ffff
 10001:   //              bit1  0x00640000~0x0067ffff
 10002:   //              bit2  0x00680000~0x006bffff
 10003:   //              bit3  0x006c0000~0x006fffff
 10004:   //              bit4  0x00700000~0x0073ffff
 10005:   //              bit5  0x00740000~0x0077ffff
 10006:   //              bit6  0x00780000~0x007bffff
 10007:   //              bit7  0x007c0000~0x007fffff
 10008:   //  0x00eaff87  bit0  0x00800000~0x0083ffff
 10009:   //              bit1  0x00840000~0x0087ffff
 10010:   //              bit2  0x00880000~0x008bffff
 10011:   //              bit3  0x008c0000~0x008fffff
 10012:   //              bit4  0x00900000~0x0093ffff
 10013:   //              bit5  0x00940000~0x0097ffff
 10014:   //              bit6  0x00980000~0x009bffff
 10015:   //              bit7  0x009c0000~0x009fffff
 10016:   //  0x00eaff89  bit0  0x00a00000~0x00a3ffff
 10017:   //              bit1  0x00a40000~0x00a7ffff
 10018:   //              bit2  0x00a80000~0x00abffff
 10019:   //              bit3  0x00ac0000~0x00afffff
 10020:   //              bit4  0x00b00000~0x00b3ffff
 10021:   //              bit5  0x00b40000~0x00b7ffff
 10022:   //              bit6  0x00b80000~0x00bbffff
 10023:   //              bit7  0x00bc0000~0x00bfffff
 10024: 
 10025: 
 10026: 
 10027:   //========================================================================================
 10028:   //$$BNK バンクメモリ
 10029:   //  $00EAFF7F  バンクメモリのページ番号。0~255
 10030:   //  $00EE0000~$00EFFFFF  バンクメモリ
 10031: 
 10032:   public static final int BNK_SIZE = 1024 * 1024 * 32;  //サイズ
 10033:   public static byte[] bnkMemory;  //メモリの配列
 10034:   public static int bnkPageStart;  //ページの先頭のインデックス。ページ番号<<17
 10035:   public static boolean bnkOn;  //true=バンクメモリが有効
 10036: 
 10037:   public static void bnkInit () {
 10038:     bnkMemory = new byte[BNK_SIZE];
 10039:     byte[] array = Settings.sgsGetData ("bankdata");
 10040:     if (array.length != 0) {
 10041:       System.arraycopy (array, 0, bnkMemory, 0, Math.min (array.length, BNK_SIZE));
 10042:     }
 10043:     bnkPageStart = 0;
 10044:     //bnkOn = true;
 10045:     bnkOn = false;
 10046:   }
 10047: 
 10048:   public static void bnkTini () {
 10049:     Settings.sgsPutData ("bankdata",
 10050:                          Arrays.copyOf (bnkMemory, BNK_SIZE));
 10051:   }
 10052: 
 10053: 
 10054: 
 10055:   //========================================================================================
 10056:   //$$FPU FPU
 10057: 
 10058:   //FPU/FPCP
 10059:   public static ExpressionEvaluator fpuMotherboardCoprocessor;  //マザーボードコプロセッサ
 10060:   public static ExpressionEvaluator fpuOnChipFPU;  //on-chip FPU
 10061:   public static ExpressionEvaluator fpuBox;  //浮動小数点命令を実行するFPU/FPCP
 10062: 
 10063:   //数値演算プロセッサボード
 10064:   public static EFPBox fpuCoproboard1;  //数値演算プロセッサボード1
 10065:   public static EFPBox fpuCoproboard2;  //数値演算プロセッサボード2
 10066: 
 10067:   //浮動小数点レジスタ
 10068:   public static EFPBox.EFP[] fpuFPn;
 10069: 
 10070:   //FPCR control register
 10071:   //  exception enable byte
 10072:   public static final int FPU_FPCR_BSUN   = 0b00000000_00000000_10000000_00000000;  //branch/set on unordered
 10073:   public static final int FPU_FPCR_SNAN   = 0b00000000_00000000_01000000_00000000;  //signaling not a number
 10074:   public static final int FPU_FPCR_OPERR  = 0b00000000_00000000_00100000_00000000;  //operand error
 10075:   public static final int FPU_FPCR_OVFL   = 0b00000000_00000000_00010000_00000000;  //overflow
 10076:   public static final int FPU_FPCR_UNFL   = 0b00000000_00000000_00001000_00000000;  //underflow
 10077:   public static final int FPU_FPCR_DZ     = 0b00000000_00000000_00000100_00000000;  //divide by zero
 10078:   public static final int FPU_FPCR_INEX2  = 0b00000000_00000000_00000010_00000000;  //inexact operation
 10079:   public static final int FPU_FPCR_INEX1  = 0b00000000_00000000_00000001_00000000;  //inexact decimal input
 10080:   //  mode control byte
 10081:   //    rounding precision
 10082:   public static final int FPU_FPCR_PE     = 0b00000000_00000000_00000000_00000000;  //extended
 10083:   public static final int FPU_FPCR_PS     = 0b00000000_00000000_00000000_01000000;  //single
 10084:   public static final int FPU_FPCR_PD     = 0b00000000_00000000_00000000_10000000;  //double
 10085:   //    rounding mode
 10086:   public static final int FPU_FPCR_RN     = 0b00000000_00000000_00000000_00000000;  //to nearest
 10087:   public static final int FPU_FPCR_RZ     = 0b00000000_00000000_00000000_00010000;  //toward zero
 10088:   public static final int FPU_FPCR_RM     = 0b00000000_00000000_00000000_00100000;  //toward minus infinity
 10089:   public static final int FPU_FPCR_RP     = 0b00000000_00000000_00000000_00110000;  //toward plus infinity
 10090: 
 10091:   //FPSR status register
 10092:   //  condition code byte
 10093:   public static final int FPU_FPSR_N         = 0b00001000_00000000_00000000_00000000;  //negative
 10094:   public static final int FPU_FPSR_Z         = 0b00000100_00000000_00000000_00000000;  //zero
 10095:   public static final int FPU_FPSR_I         = 0b00000010_00000000_00000000_00000000;  //infinity
 10096:   public static final int FPU_FPSR_NAN       = 0b00000001_00000000_00000000_00000000;  //not a number or unordered
 10097:   //  quotient byte
 10098:   public static final int FPU_FPSR_S         = 0b00000000_10000000_00000000_00000000;  //sign of quotient
 10099:   public static final int FPU_FPSR_QUOTIENT  = 0b00000000_01111111_00000000_00000000;  //quotient
 10100:   //  exception status byte
 10101:   public static final int FPU_FPSR_EXC_BSUN  = 0b00000000_00000000_10000000_00000000;  //branch/set on unordered
 10102:   public static final int FPU_FPSR_EXC_SNAN  = 0b00000000_00000000_01000000_00000000;  //signaling not a number
 10103:   public static final int FPU_FPSR_EXC_OPERR = 0b00000000_00000000_00100000_00000000;  //operand error
 10104:   public static final int FPU_FPSR_EXC_OVFL  = 0b00000000_00000000_00010000_00000000;  //overflow
 10105:   public static final int FPU_FPSR_EXC_UNFL  = 0b00000000_00000000_00001000_00000000;  //underflow
 10106:   public static final int FPU_FPSR_EXC_DZ    = 0b00000000_00000000_00000100_00000000;  //divide by zero
 10107:   public static final int FPU_FPSR_EXC_INEX2 = 0b00000000_00000000_00000010_00000000;  //inexact operation
 10108:   public static final int FPU_FPSR_EXC_INEX1 = 0b00000000_00000000_00000001_00000000;  //inexact decimal input
 10109:   //  accrued exception byte
 10110:   public static final int FPU_FPSR_AEXC_IOP  = 0b00000000_00000000_00000000_10000000;  //invalid operation
 10111:   public static final int FPU_FPSR_AEXC_OVFL = 0b00000000_00000000_00000000_01000000;  //overflow
 10112:   public static final int FPU_FPSR_AEXC_UNFL = 0b00000000_00000000_00000000_00100000;  //underflow
 10113:   public static final int FPU_FPSR_AEXC_DZ   = 0b00000000_00000000_00000000_00010000;  //divide by zero
 10114:   public static final int FPU_FPSR_AEXC_INEX = 0b00000000_00000000_00000000_00001000;  //inexact
 10115: 
 10116:   //  EXCからAEXCへの変換
 10117:   //    AEXC_IOP |= EXC_BSUN | EXC_SNAN | EXC_OPERR
 10118:   //    AEXC_OVFL |= EXC_OVFL
 10119:   //    AEXC_UNFL |= EXC_UNFL & EXC_INEX2
 10120:   //    AEXC_DZ |= EXC_DZ
 10121:   //    AEXC_INEX |= EXC_OVFL | EXC_INEX2 | EXC_INEX1
 10122:   public static final int[] FPU_FPSR_EXC_TO_AEXC = new int[256];
 10123: 
 10124:   //コンディション
 10125:   //
 10126:   //  fpsrのbit27-24
 10127:   //    MZIN
 10128:   //    0000  0<x
 10129:   //    0001  NaN
 10130:   //    0010  +Inf
 10131:   //    0100  +0
 10132:   //    1000  x<0
 10133:   //    1010  -Inf
 10134:   //    1100  -0
 10135:   //
 10136:   //  FPU_CCMAP_882[(オペコードまたは拡張ワード&63)<<4|fpsr>>24&15]==trueならば条件成立
 10137:   //  FPU_CCMAP_060[(オペコードまたは拡張ワード&63)<<4|fpsr>>24&15]==trueならば条件成立
 10138:   //
 10139:   //  MC68882とMC68060ではOR,NE,GLE,SNEの条件が異なる
 10140: 
 10141:   //MC68882
 10142:   //  perl -e "@a=();for$a(0..15){$m=$a>>3&1;$z=$a>>2&1;$n=$a&1;@b=map{$_&1}(0,$z,~($n|$z|$m),$z|~($n|$m),$m&~($n|$z),$z|($m&~$n),~($n|$z),$z|~$n,$n,$n|$z,$n|~($m|$z),$n|($z|~$m),$n|($m&~$z),$n|$z|$m,$n|~$z,1);push@a,@b,@b,@b,@b}for$y(0..63){print'    ';$t=0;for$x(0..15){$c=$a[$x<<6|$y];$t=($t<<1)+$c;print(($c?'T':'F').',');}printf'  //%04x %06b%c',$t,$y,10;}
 10143:   //
 10144:   //F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,T,  //N
 10145:   //F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //Z
 10146:   //F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //NAN
 10147:   public static final boolean[] FPU_CCMAP_882 = {
 10148:     //                                       cccccc  cc    等式          意味
 10149:     //IEEEアウェアテスト
 10150:     F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //0000 000000  F     0             偽
 10151:     F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //0f0f 000001  EQ    Z             等しい
 10152:     T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,  //a000 000010  OGT   ~(NAN|Z|N)    比較可能でより大きい
 10153:     T,F,T,F,T,T,T,T,F,F,F,F,T,T,T,T,  //af0f 000011  OGE   Z|~(NAN|N)    等しいか比較可能でより大きい
 10154:     F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,  //00a0 000100  OLT   N&~(NAN|Z)    比較可能でより小さい
 10155:     F,F,F,F,T,T,T,T,T,F,T,F,T,T,T,T,  //0faf 000101  OLE   Z|(N&~NAN)    等しいか比較可能でより小さい
 10156:     T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //a0a0 000110  OGL   ~(NAN|Z)      比較可能で等しくない
 10157:     T,F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,  //afaf 000111  OR    Z|~NAN        等しいか比較可能
 10158:     F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //5555 001000  UN    NAN           比較不能
 10159:     F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //5f5f 001001  UEQ   NAN|Z         比較不能か等しい
 10160:     T,T,T,T,F,T,F,T,F,T,F,T,F,T,F,T,  //f555 001010  UGT   NAN|~(N|Z)    比較不能かより大きい
 10161:     T,T,T,T,T,T,T,T,F,T,F,T,T,T,T,T,  //ff5f 001011  UGE   NAN|(Z|~N)    比較不能かより大きいか等しい
 10162:     F,T,F,T,F,T,F,T,T,T,T,T,F,T,F,T,  //55f5 001100  ULT   NAN|(N&~Z)    比較不能かより小さい
 10163:     F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,  //5fff 001101  ULE   NAN|Z|N       比較不能かより小さいか等しい
 10164:     T,T,T,T,F,T,F,T,T,T,T,T,F,T,F,T,  //f5f5 001110  NE    NAN|~Z        比較不能か等しくない
 10165:     T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //ffff 001111  T     1             真
 10166:     //IEEEノンアウェアテスト
 10167:     //  NANがセットされているとき、FPSRのBSUNがセットされ、許可されていれば例外が発生する
 10168:     F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //0000 010000  SF    0             偽(シグナリング)
 10169:     F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //0f0f 010001  SEQ   Z             等しい(シグナリング)
 10170:     T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,  //a000 010010  GT    ~(NAN|Z|N)    より大きい
 10171:     T,F,T,F,T,T,T,T,F,F,F,F,T,T,T,T,  //af0f 010011  GE    Z|~(NAN|N)    より大きいか等しい
 10172:     F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,  //00a0 010100  LT    N&~(NAN|Z)    より小さい
 10173:     F,F,F,F,T,T,T,T,T,F,T,F,T,T,T,T,  //0faf 010101  LE    Z|(N&~NAN)    より小さいか等しい
 10174:     T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //a0a0 010110  GL    ~(NAN|Z)      等しくない
 10175:     T,F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,  //afaf 010111  GLE   Z|~NAN        より大きいか小さいか等しい
 10176:     F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //5555 011000  NGLE  NAN           GLEでない
 10177:     F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //5f5f 011001  NGL   NAN|Z         GLでない
 10178:     T,T,T,T,F,T,F,T,F,T,F,T,F,T,F,T,  //f555 011010  NLE   NAN|~(N|Z)    LEでない
 10179:     T,T,T,T,T,T,T,T,F,T,F,T,T,T,T,T,  //ff5f 011011  NLT   NAN|(Z|~N)    LTでない
 10180:     F,T,F,T,F,T,F,T,T,T,T,T,F,T,F,T,  //55f5 011100  NGE   NAN|(N&~Z)    GEでない
 10181:     F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,  //5fff 011101  NGT   NAN|Z|N       GTでない
 10182:     T,T,T,T,F,T,F,T,T,T,T,T,F,T,F,T,  //f5f5 011110  SNE   NAN|~Z        等しくない(シグナリング)
 10183:     T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //ffff 011111  ST    1             真(シグナリング)
 10184:     //
 10185:     F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //0000 100000
 10186:     F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //0f0f 100001
 10187:     T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,  //a000 100010
 10188:     T,F,T,F,T,T,T,T,F,F,F,F,T,T,T,T,  //af0f 100011
 10189:     F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,  //00a0 100100
 10190:     F,F,F,F,T,T,T,T,T,F,T,F,T,T,T,T,  //0faf 100101
 10191:     T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //a0a0 100110
 10192:     T,F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,  //afaf 100111
 10193:     F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //5555 101000
 10194:     F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //5f5f 101001
 10195:     T,T,T,T,F,T,F,T,F,T,F,T,F,T,F,T,  //f555 101010
 10196:     T,T,T,T,T,T,T,T,F,T,F,T,T,T,T,T,  //ff5f 101011
 10197:     F,T,F,T,F,T,F,T,T,T,T,T,F,T,F,T,  //55f5 101100
 10198:     F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,  //5fff 101101
 10199:     T,T,T,T,F,T,F,T,T,T,T,T,F,T,F,T,  //f5f5 101110
 10200:     T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //ffff 101111
 10201:     //
 10202:     F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //0000 110000
 10203:     F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //0f0f 110001
 10204:     T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,  //a000 110010
 10205:     T,F,T,F,T,T,T,T,F,F,F,F,T,T,T,T,  //af0f 110011
 10206:     F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,  //00a0 110100
 10207:     F,F,F,F,T,T,T,T,T,F,T,F,T,T,T,T,  //0faf 110101
 10208:     T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //a0a0 110110
 10209:     T,F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,  //afaf 110111
 10210:     F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //5555 111000
 10211:     F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //5f5f 111001
 10212:     T,T,T,T,F,T,F,T,F,T,F,T,F,T,F,T,  //f555 111010
 10213:     T,T,T,T,T,T,T,T,F,T,F,T,T,T,T,T,  //ff5f 111011
 10214:     F,T,F,T,F,T,F,T,T,T,T,T,F,T,F,T,  //55f5 111100
 10215:     F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,  //5fff 111101
 10216:     T,T,T,T,F,T,F,T,T,T,T,T,F,T,F,T,  //f5f5 111110
 10217:     T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //ffff 111111
 10218:   };
 10219: 
 10220:   //MC68060
 10221:   //  perl -e "@a=();for$a(0..15){$m=$a>>3&1;$z=$a>>2&1;$n=$a&1;@b=map{$_&1}(0,$z,~($n|$z|$m),$z|~($n|$m),$m&~($n|$z),$z|($m&~$n),~($n|$z),~$n,$n,$n|$z,$n|~($m|$z),$n|($z|~$m),$n|($m&~$z),$n|$z|$m,~$z,1);push@a,@b,@b,@b,@b}for$y(0..63){print'    ';$t=0;for$x(0..15){$c=$a[$x<<6|$y];$t=($t<<1)+$c;print(($c?'T':'F').',');}printf'  //%04x %06b%c',$t,$y,10;}
 10222:   //
 10223:   //F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,T,  //N
 10224:   //F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //Z
 10225:   //F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //NAN
 10226:   public static final boolean[] FPU_CCMAP_060 = {
 10227:     //                                       cccccc  cc    等式          意味
 10228:     //IEEEアウェアテスト
 10229:     F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //0000 000000  F     0             偽
 10230:     F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //0f0f 000001  EQ    Z             等しい
 10231:     T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,  //a000 000010  OGT   ~(NAN|Z|N)    比較可能でより大きい
 10232:     T,F,T,F,T,T,T,T,F,F,F,F,T,T,T,T,  //af0f 000011  OGE   Z|~(NAN|N)    等しいか比較可能でより大きい
 10233:     F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,  //00a0 000100  OLT   N&~(NAN|Z)    比較可能でより小さい
 10234:     F,F,F,F,T,T,T,T,T,F,T,F,T,T,T,T,  //0faf 000101  OLE   Z|(N&~NAN)    等しいか比較可能でより小さい
 10235:     T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //a0a0 000110  OGL   ~(NAN|Z)      比較可能で等しくない
 10236:     T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,  //aaaa 000111  OR    ~NAN          比較可能
 10237:     F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //5555 001000  UN    NAN           比較不能
 10238:     F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //5f5f 001001  UEQ   NAN|Z         比較不能か等しい
 10239:     T,T,T,T,F,T,F,T,F,T,F,T,F,T,F,T,  //f555 001010  UGT   NAN|~(N|Z)    比較不能かより大きい
 10240:     T,T,T,T,T,T,T,T,F,T,F,T,T,T,T,T,  //ff5f 001011  UGE   NAN|(Z|~N)    比較不能かより大きいか等しい
 10241:     F,T,F,T,F,T,F,T,T,T,T,T,F,T,F,T,  //55f5 001100  ULT   NAN|(N&~Z)    比較不能かより小さい
 10242:     F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,  //5fff 001101  ULE   NAN|Z|N       比較不能かより小さいか等しい
 10243:     T,T,T,T,F,F,F,F,T,T,T,T,F,F,F,F,  //f0f0 001110  NE    ~Z            等しくない
 10244:     T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //ffff 001111  T     1             真
 10245:     //IEEEノンアウェアテスト
 10246:     //  NANがセットされているとき、FPSRのBSUNがセットされ、許可されていれば例外が発生する
 10247:     F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //0000 010000  SF    0             偽(シグナリング)
 10248:     F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //0f0f 010001  SEQ   Z             等しい(シグナリング)
 10249:     T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,  //a000 010010  GT    ~(NAN|Z|N)    より大きい
 10250:     T,F,T,F,T,T,T,T,F,F,F,F,T,T,T,T,  //af0f 010011  GE    Z|~(NAN|N)    より大きいか等しい
 10251:     F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,  //00a0 010100  LT    N&~(NAN|Z)    より小さい
 10252:     F,F,F,F,T,T,T,T,T,F,T,F,T,T,T,T,  //0faf 010101  LE    Z|(N&~NAN)    より小さいか等しい
 10253:     T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //a0a0 010110  GL    ~(NAN|Z)      等しくない
 10254:     T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,  //aaaa 010111  GLE   ~NAN          より大きいか小さいか等しい
 10255:     F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //5555 011000  NGLE  NAN           GLEでない
 10256:     F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //5f5f 011001  NGL   NAN|Z         GLでない
 10257:     T,T,T,T,F,T,F,T,F,T,F,T,F,T,F,T,  //f555 011010  NLE   NAN|~(N|Z)    LEでない
 10258:     T,T,T,T,T,T,T,T,F,T,F,T,T,T,T,T,  //ff5f 011011  NLT   NAN|(Z|~N)    LTでない
 10259:     F,T,F,T,F,T,F,T,T,T,T,T,F,T,F,T,  //55f5 011100  NGE   NAN|(N&~Z)    GEでない
 10260:     F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,  //5fff 011101  NGT   NAN|Z|N       GTでない
 10261:     T,T,T,T,F,F,F,F,T,T,T,T,F,F,F,F,  //f0f0 011110  SNE   ~Z            等しくない(シグナリング)
 10262:     T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //ffff 011111  ST    1             真(シグナリング)
 10263:     //
 10264:     F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //0000 100000
 10265:     F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //0f0f 100001
 10266:     T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,  //a000 100010
 10267:     T,F,T,F,T,T,T,T,F,F,F,F,T,T,T,T,  //af0f 100011
 10268:     F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,  //00a0 100100
 10269:     F,F,F,F,T,T,T,T,T,F,T,F,T,T,T,T,  //0faf 100101
 10270:     T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //a0a0 100110
 10271:     T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,  //aaaa 100111
 10272:     F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //5555 101000
 10273:     F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //5f5f 101001
 10274:     T,T,T,T,F,T,F,T,F,T,F,T,F,T,F,T,  //f555 101010
 10275:     T,T,T,T,T,T,T,T,F,T,F,T,T,T,T,T,  //ff5f 101011
 10276:     F,T,F,T,F,T,F,T,T,T,T,T,F,T,F,T,  //55f5 101100
 10277:     F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,  //5fff 101101
 10278:     T,T,T,T,F,F,F,F,T,T,T,T,F,F,F,F,  //f0f0 101110
 10279:     T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //ffff 101111
 10280:     //
 10281:     F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //0000 110000
 10282:     F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //0f0f 110001
 10283:     T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,  //a000 110010
 10284:     T,F,T,F,T,T,T,T,F,F,F,F,T,T,T,T,  //af0f 110011
 10285:     F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,  //00a0 110100
 10286:     F,F,F,F,T,T,T,T,T,F,T,F,T,T,T,T,  //0faf 110101
 10287:     T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //a0a0 110110
 10288:     T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,  //aaaa 110111
 10289:     F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //5555 111000
 10290:     F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //5f5f 111001
 10291:     T,T,T,T,F,T,F,T,F,T,F,T,F,T,F,T,  //f555 111010
 10292:     T,T,T,T,T,T,T,T,F,T,F,T,T,T,T,T,  //ff5f 111011
 10293:     F,T,F,T,F,T,F,T,T,T,T,T,F,T,F,T,  //55f5 111100
 10294:     F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,  //5fff 111101
 10295:     T,T,T,T,F,F,F,F,T,T,T,T,F,F,F,F,  //f0f0 111110
 10296:     T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //ffff 111111
 10297:   };
 10298: 
 10299:   //fpuInit ()
 10300:   //  FPUを初期化する
 10301:   //  これはmpuInit()から呼ばれる
 10302:   public static void fpuInit () {
 10303:     for (int i = 0; i < 256; i++) {
 10304:       FPU_FPSR_EXC_TO_AEXC[i] = (((i << 8 & (FPU_FPSR_EXC_BSUN | FPU_FPSR_EXC_SNAN | FPU_FPSR_EXC_OPERR)) != 0 ? FPU_FPSR_AEXC_IOP : 0) |
 10305:                                  ((i << 8 & FPU_FPSR_EXC_OVFL) != 0 ? FPU_FPSR_AEXC_OVFL : 0) |
 10306:                                  ((i << 8 & (FPU_FPSR_EXC_UNFL | FPU_FPSR_EXC_INEX2)) == (FPU_FPSR_EXC_UNFL | FPU_FPSR_EXC_INEX2) ? FPU_FPSR_AEXC_UNFL : 0) |
 10307:                                  ((i << 8 & FPU_FPSR_EXC_DZ) != 0 ? FPU_FPSR_AEXC_DZ : 0) |
 10308:                                  ((i << 8 & (FPU_FPSR_EXC_OVFL | FPU_FPSR_EXC_INEX2 | FPU_FPSR_EXC_INEX1)) != 0 ? FPU_FPSR_AEXC_INEX : 0));
 10309:     }
 10310:     //マザーボードコプロセッサ
 10311:     fpuMotherboardCoprocessor = new ExpressionEvaluator ();
 10312:     //on-chip FPU
 10313:     fpuOnChipFPU = new ExpressionEvaluator ();
 10314:     //浮動小数点命令を実行するFPU/FPCP
 10315:     fpuBox = currentMPU < Model.MPU_MC68LC040 ? fpuMotherboardCoprocessor : fpuOnChipFPU;
 10316:     //浮動小数点レジスタ
 10317:     fpuFPn = fpuBox.epbFPn;
 10318:     //数値演算プロセッサボード
 10319:     fpuCoproboard1 = new EFPBox ();
 10320:     fpuCoproboard2 = new EFPBox ();
 10321:   }  //fpuInit()
 10322: 
 10323: 
 10324: 
 10325:   //========================================================================================
 10326:   //$$DBG デバッガ共通コンポーネント
 10327: 
 10328:   public static final boolean DBG_ORI_BYTE_ZERO_D0 = true;  //true=ORI.B #$00,D0(オペコード0x0000)を不当命令とみなす機能を有効にする。暴走をなるべく早く検出することで暴走の原因を特定しやすくする
 10329: 
 10330:   public static boolean dbgHexSelected;  //true=16進数が選択されている
 10331:   public static int dbgHexValue;  //選択されている16進数の値
 10332:   public static int dbgSupervisorMode;  //0=ユーザモード,0以外=スーパーバイザモード
 10333:   public static JPopupMenu dbgPopupMenu;  //ポップアップメニュー
 10334:   public static JMenu dbgPopupIBPMenu;  //命令ブレークポイントメニュー
 10335:   public static SpinnerNumberModel dbgPopupIBPCurrentModel;  //現在値のスピナーモデル
 10336:   public static int dbgPopupIBPCurrentValue;  //現在値
 10337:   public static SpinnerNumberModel dbgPopupIBPThresholdModel;  //閾値のスピナーモデル
 10338:   public static int dbgPopupIBPThresholdValue;  //閾値
 10339:   public static JMenuItem dbgPopupIBPClearMenuItem;  //解除
 10340:   public static JMenu dbgPopupHexMenu;  //16進数メニュー
 10341:   public static JMenuItem dbgPopupDisMenuItem;  //逆アセンブル
 10342:   public static JMenuItem dbgPopupMemMenuItem;  //メモリダンプ
 10343:   public static JMenuItem dbgPopupCopyMenuItem;  //コピー
 10344:   public static JMenuItem dbgPopupSelectAllMenuItem;  //すべて選択
 10345:   public static JTextArea dbgPopupTextArea;  //ポップアップメニューを表示したテキストエリア
 10346:   public static int dbgEventMask;  //イベントマスク。0でないときチェンジリスナーとキャレットリスナーを無効化
 10347:   public static boolean dbgStopOnError;  //true=エラーが発生したときコアを止める
 10348:   public static boolean dbgOriByteZeroD0;  //true=ORI.B #$00,D0を不当命令とみなす。普段はOFFにしておくこと
 10349:   public static boolean dbgStopAtStart;  //true=実行開始位置で停止する
 10350: 
 10351:   //共通
 10352:   //  sb.append(DBG_SPACES,0,length)でStringBuilderに連続する空白を追加するための配列
 10353:   public static final char[] DBG_SPACES = (
 10354:     //         11111111112222222222333333333344444444445555555555666666666677777777778
 10355:     //12345678901234567890123456789012345678901234567890123456789012345678901234567890
 10356:     "                                                                                ").toCharArray ();
 10357: 
 10358:   public static final int DBG_DRP_VISIBLE_MASK = 1;  //レジスタウインドウが表示されている
 10359:   public static final int DBG_DDP_VISIBLE_MASK = 2;  //逆アセンブルリストウインドウが表示されている
 10360:   public static final int DBG_DMP_VISIBLE_MASK = 4;  //メモリダンプウインドウが表示されている
 10361:   public static final int DBG_BLG_VISIBLE_MASK = 8;  //分岐ログが表示されている
 10362:   public static final int DBG_PFV_VISIBLE_MASK = 16;  //プログラムフロービジュアライザが表示されている
 10363:   public static final int DBG_RBP_VISIBLE_MASK = 32;  //ラスタブレークポイントウインドウが表示されている
 10364:   public static final int DBG_DBP_VISIBLE_MASK = 64;  //データブレークポイントウインドウが表示されている
 10365:   public static final int DBG_SMT_VISIBLE_MASK = 128;  //表示モードテストが表示されている
 10366:   public static final int DBG_ATW_VISIBLE_MASK = 256;  //アドレス変換ウインドウが表示されている
 10367:   public static final int DBG_PAA_VISIBLE_MASK = 512;  //物理アドレス空間ウインドウが表示されている
 10368:   public static final int DBG_RTL_VISIBLE_MASK = 1024;  //ルートポインタリストが表示されている
 10369:   public static final int DBG_SPV_VISIBLE_MASK = 2048;  //スプライトパターンビュアが表示されている
 10370:   public static final int DBG_PLV_VISIBLE_MASK = 4096;  //スプライトパターンビュアが表示されている
 10371:   public static final int DBG_ACM_VISIBLE_MASK = 8192;  //アドレス変換キャッシュモニタが表示されている
 10372:   public static int dbgVisibleMask;  //表示されているデバッグ関連ウインドウのマスク
 10373: 
 10374:   //dbgInit ()
 10375:   //  初期化
 10376:   public static void dbgInit () {
 10377:     dbgVisibleMask = 0;
 10378:     dbgHexSelected = false;
 10379:     dbgHexValue = 0;
 10380:     dbgSupervisorMode = 1;
 10381:     dbgPopupMenu = null;
 10382:     dbgPopupDisMenuItem = null;
 10383:     dbgPopupMemMenuItem = null;
 10384:     dbgPopupCopyMenuItem = null;
 10385:     dbgPopupSelectAllMenuItem = null;
 10386:     dbgPopupIBPMenu = null;
 10387:     dbgPopupIBPCurrentModel = null;
 10388:     dbgPopupIBPCurrentValue = 0;
 10389:     dbgPopupIBPThresholdModel = null;
 10390:     dbgPopupIBPThresholdValue = 0;
 10391:     dbgPopupHexMenu = null;
 10392:     dbgPopupTextArea = null;
 10393:     dbgEventMask = 0;
 10394:     dbgStopOnError = false;  //ウインドウを表示する前にも必要なのでここで初期化すること
 10395:     if (DBG_ORI_BYTE_ZERO_D0) {
 10396:       dbgOriByteZeroD0 = false;
 10397:     }
 10398:     dbgStopAtStart = false;
 10399:   }  //dbgInit()
 10400: 
 10401:   //dbgMakePopup ()
 10402:   //  デバッグ関連ウインドウの共通コンポーネントを作る
 10403:   public static void dbgMakePopup () {
 10404: 
 10405:     //ポップアップメニュー
 10406:     ActionListener popupActionListener = new ActionListener () {
 10407:       @Override public void actionPerformed (ActionEvent ae) {
 10408:         switch (ae.getActionCommand ()) {
 10409:         case "Disassemble":
 10410:           DisassembleList.ddpBacktraceRecord = -1L;  //分岐レコードの選択を解除する
 10411:           DisassembleList.ddpOpen (dbgHexValue, dbgSupervisorMode, false);
 10412:           break;
 10413:         case "Memory Dump":
 10414:           MemoryDumpList.dmpOpen (dbgHexValue, dbgSupervisorMode != 0 ? 5 : 1, false);
 10415:           break;
 10416:         case "Run to Here":
 10417:           if (InstructionBreakPoint.IBP_ON) {
 10418:             if (mpuTask == null) {
 10419:               InstructionBreakPoint.ibpInstant (DisassembleList.ddpPopupAddress, DisassembleList.ddpSupervisorMode);
 10420:               mpuStart ();
 10421:             }
 10422:           }
 10423:           break;
 10424:         case "Set Breakpoint":
 10425:           if (InstructionBreakPoint.IBP_ON) {
 10426:             InstructionBreakPoint.ibpPut (DisassembleList.ddpPopupAddress, DisassembleList.ddpSupervisorMode, dbgPopupIBPCurrentValue, dbgPopupIBPThresholdValue, null);
 10427:             DisassembleList.ddpOpen (0, DisassembleList.ddpSupervisorMode, true);
 10428:           }
 10429:           break;
 10430:         case "Clear Breakpoint":
 10431:           if (InstructionBreakPoint.IBP_ON) {
 10432:             InstructionBreakPoint.ibpRemove (DisassembleList.ddpPopupAddress, DisassembleList.ddpSupervisorMode);
 10433:             DisassembleList.ddpOpen (0, DisassembleList.ddpSupervisorMode, true);
 10434:           }
 10435:           break;
 10436:         case "Copy":
 10437:           dbgCopy ();
 10438:           break;
 10439:         case "Select All":
 10440:           dbgSelectAll ();
 10441:           break;
 10442:         }
 10443:       }
 10444:     };
 10445:     dbgPopupMenu = ComponentFactory.createPopupMenu (
 10446:       dbgPopupIBPMenu =
 10447:       InstructionBreakPoint.IBP_ON ?
 10448:       ComponentFactory.createMenu (
 10449:         "XXXXXXXX", KeyEvent.VK_UNDEFINED,
 10450:         Multilingual.mlnText (ComponentFactory.createMenuItem ("Run to Here", 'R', popupActionListener), "ja", "ここまで実行"),
 10451:         ComponentFactory.createHorizontalSeparator (),
 10452:         Multilingual.mlnText (ComponentFactory.createMenuItem ("Set Breakpoint", 'S', popupActionListener), "ja", "ブレークポイントを設定"),
 10453:         ComponentFactory.createHorizontalBox (
 10454:           Box.createHorizontalStrut (7),
 10455:           Box.createHorizontalGlue (),
 10456:           ComponentFactory.setPreferredSize (
 10457:             Multilingual.mlnText (ComponentFactory.createLabel ("current"), "ja", "現在値"),
 10458:             60, 16),
 10459:           ComponentFactory.createNumberSpinner (dbgPopupIBPCurrentModel = new SpinnerNumberModel (0, 0, 0x7fffffff, 1), 10, new ChangeListener () {
 10460:             @Override public void stateChanged (ChangeEvent ce) {
 10461:               dbgPopupIBPCurrentValue = dbgPopupIBPCurrentModel.getNumber ().intValue ();
 10462:             }
 10463:           }),
 10464:           Box.createHorizontalGlue ()
 10465:           ),
 10466:         ComponentFactory.createHorizontalBox (
 10467:           Box.createHorizontalStrut (7),
 10468:           Box.createHorizontalGlue (),
 10469:           ComponentFactory.setPreferredSize (
 10470:             Multilingual.mlnText (ComponentFactory.createLabel ("threshold"), "ja", "閾値"),
 10471:             60, 16),
 10472:           ComponentFactory.createNumberSpinner (dbgPopupIBPThresholdModel = new SpinnerNumberModel (0, 0, 0x7fffffff, 1), 10, new ChangeListener () {
 10473:             @Override public void stateChanged (ChangeEvent ce) {
 10474:               dbgPopupIBPThresholdValue = dbgPopupIBPThresholdModel.getNumber ().intValue ();
 10475:             }
 10476:           }),
 10477:           Box.createHorizontalGlue ()
 10478:           ),
 10479:         dbgPopupIBPClearMenuItem =
 10480:         Multilingual.mlnText (ComponentFactory.createMenuItem ("Clear Breakpoint", 'C', popupActionListener), "ja", "ブレークポイントを消去")
 10481:         ) :
 10482:       null,
 10483:       dbgPopupHexMenu =
 10484:       ComponentFactory.createMenu (
 10485:         "XXXXXXXX", KeyEvent.VK_UNDEFINED,
 10486:         dbgPopupDisMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Disassemble", 'D', popupActionListener), "ja", "逆アセンブル"),
 10487:         dbgPopupMemMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Memory Dump", 'M', popupActionListener), "ja", "メモリダンプ")
 10488:         ),
 10489:       dbgPopupCopyMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Copy", 'C', popupActionListener), "ja", "コピー"),
 10490:       dbgPopupSelectAllMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Select All", 'A', popupActionListener), "ja", "すべて選択")
 10491:       );
 10492: 
 10493:   }  //dbgMakePopup()
 10494: 
 10495:   //dbgShowPopup (me, textArea, dis)
 10496:   //  ポップアップメニューを表示する
 10497:   public static void dbgShowPopup (MouseEvent me, JTextArea textArea, boolean dis) {
 10498:     dbgEventMask++;
 10499:     int x = me.getX ();
 10500:     int y = me.getY ();
 10501:     //int p = textArea.viewToModel (me.getPoint ());  //クリックされた位置。viewToModel2Dは9から
 10502:     int p = textArea.viewToModel2D (me.getPoint ());  //クリックされた位置。viewToModel2Dは9から
 10503:     DisassembleList.ddpPopupAddress = -1;  //クリックされた行のアドレス
 10504:     if (dis) {
 10505:       int i = Arrays.binarySearch (DisassembleList.ddpSplitArray, 1, DisassembleList.ddpItemCount, p + 1);
 10506:       i = (i >> 31 ^ i) - 1;  //クリックされた項目の番号
 10507:       DisassembleList.ddpPopupAddress = DisassembleList.ddpAddressArray[i];  //クリックされた項目の先頭アドレス
 10508:     }
 10509:     int start = textArea.getSelectionStart ();  //選択範囲の開始位置
 10510:     int end = textArea.getSelectionEnd ();  //選択範囲の終了位置
 10511:     String text = textArea.getText ();  //テキスト全体
 10512:     int length = text.length ();  //テキスト全体の長さ
 10513:     if ((start == end ||  //選択範囲がないか
 10514:          p < start || end <= p) &&  //選択範囲の外側がクリックされて
 10515:         0 <= p && p < length && isWord (text.charAt (p))) {  //クリックされた位置に単語があるとき
 10516:       //クリックされた位置にある単語を選択する
 10517:       for (start = p; 0 < start && isWord (text.charAt (start - 1)); start--) {
 10518:       }
 10519:       for (end = p + 1; end < length && isWord (text.charAt (end)); end++) {
 10520:       }
 10521:       textArea.select (start, end);
 10522:     }
 10523:     dbgHexSelected = false;
 10524:     if (start < end) {  //選択範囲があるとき
 10525:       textArea.requestFocusInWindow ();  //フォーカスがないと選択範囲が見えない
 10526:       //選択範囲にある16進数の文字を取り出す
 10527:       //  以下の条件を加える
 10528:       //    選択範囲に16進数以外の単語の文字がないこと
 10529:       //    選択範囲に16進数の文字が9文字以上ないこと
 10530:       //    16進数の文字が偶数文字ずつの塊になっていること
 10531:       dbgHexValue = 0;
 10532:       int n = 0;
 10533:       for (int i = start; i < end; i++) {
 10534:         int t;
 10535:         if ((t = Character.digit (text.charAt (i), 16)) >= 0) {  //16進数の文字
 10536:           dbgHexValue = dbgHexValue << 4 | t;
 10537:           if (n >= 8 ||  //選択範囲に16進数の文字が9文字以上ある
 10538:               i + 1 >= end || (t = Character.digit (text.charAt (i + 1), 16)) < 0) {  //16進数の文字が偶数文字ずつの塊になっていない
 10539:             n = 0;
 10540:             break;
 10541:           }
 10542:           dbgHexValue = dbgHexValue << 4 | t;
 10543:           n += 2;
 10544:           i++;
 10545:         } else if (isWord (text.charAt (i))) {  //16進数以外の単語の文字
 10546:           n = 0;
 10547:           break;
 10548:         }
 10549:       }
 10550:       dbgHexSelected = n > 0;
 10551:       try {
 10552:         //Rectangle r = textArea.modelToView (start).getBounds ();  //modelToView2Dは9から
 10553:         Rectangle r = textArea.modelToView2D (start).getBounds ();  //modelToView2Dは9から
 10554:         //Rectangle s = textArea.modelToView (end - 1).getBounds ();  //modelToView2Dは9から
 10555:         Rectangle s = textArea.modelToView2D (end - 1).getBounds ();  //modelToView2Dは9から
 10556:         if (r.y == s.y) {  //選択範囲が1行だけのとき
 10557:           //選択範囲を隠してしまわないようにポップアップを選択範囲の下側に表示する
 10558:           y = r.y + r.height;
 10559:         }
 10560:       } catch (BadLocationException ble) {
 10561:       }
 10562:     }
 10563:     //逆アセンブルリストでコアが止まっていて選択範囲がなくてクリックされた行のアドレスがわかるとき命令ブレークポイントメニューが有効
 10564:     if (InstructionBreakPoint.IBP_ON) {
 10565:       if (dis && mpuTask == null && DisassembleList.ddpPopupAddress != -1) {
 10566:         ComponentFactory.setText (dbgPopupIBPMenu, fmtHex8 (DisassembleList.ddpPopupAddress));
 10567:         TreeMap<Integer,InstructionBreakPoint.InstructionBreakRecord> pointTable = InstructionBreakPoint.ibpPointTable;
 10568:         InstructionBreakPoint.InstructionBreakRecord r = pointTable.get (DisassembleList.ddpPopupAddress);
 10569:         if (r != null) {  //命令ブレークポイントがあるとき
 10570:           dbgPopupIBPCurrentModel.setValue (Integer.valueOf (dbgPopupIBPCurrentValue = r.ibrValue));  //現在値
 10571:           dbgPopupIBPThresholdModel.setValue (Integer.valueOf (dbgPopupIBPThresholdValue = r.ibrThreshold));  //閾値
 10572:           dbgPopupIBPClearMenuItem.setEnabled (true);  //消去できる
 10573:         } else {  //命令ブレークポイントがないとき
 10574:           dbgPopupIBPCurrentModel.setValue (Integer.valueOf (dbgPopupIBPCurrentValue = 0));  //現在値
 10575:           dbgPopupIBPThresholdModel.setValue (Integer.valueOf (dbgPopupIBPThresholdValue = 0));  //閾値
 10576:           dbgPopupIBPClearMenuItem.setEnabled (false);  //消去できない
 10577:         }
 10578:         ComponentFactory.setVisible (dbgPopupIBPMenu, true);
 10579:       } else {
 10580:         ComponentFactory.setVisible (dbgPopupIBPMenu, false);
 10581:       }
 10582:     }
 10583:     //16進数が選択されていれば16進数メニューが有効
 10584:     if (dbgHexSelected) {
 10585:       ComponentFactory.setText (dbgPopupHexMenu, fmtHex8 (dbgHexValue));
 10586:       ComponentFactory.setVisible (dbgPopupHexMenu, true);
 10587:     } else {
 10588:       ComponentFactory.setVisible (dbgPopupHexMenu, false);
 10589:     }
 10590:     //選択範囲があればコピーが有効
 10591:     ComponentFactory.setEnabled (dbgPopupCopyMenuItem, clpClipboard != null && start < end);
 10592:     //クリップボードがあればすべて選択が有効
 10593:     ComponentFactory.setEnabled (dbgPopupSelectAllMenuItem, clpClipboard != null);
 10594:     //ポップアップメニューを表示する
 10595:     dbgPopupTextArea = textArea;
 10596:     dbgPopupMenu.show (textArea, x, y);
 10597:     dbgEventMask--;
 10598:   }  //dbgShowPopup(MouseEvent,JTextArea,boolean)
 10599: 
 10600:   public static boolean isWord (char c) {
 10601:     return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '_';
 10602:   }  //isWord(char)
 10603: 
 10604:   //dbgCopy ()
 10605:   //  コピー
 10606:   public static void dbgCopy () {
 10607:     clpCopy (dbgPopupTextArea.getSelectedText ());
 10608:   }  //dbgCopy()
 10609: 
 10610:   //dbgSelectAll ()
 10611:   //  すべて選択
 10612:   public static void dbgSelectAll () {
 10613:     if (clpClipboard != null) {
 10614:       //すべて選択する
 10615:       dbgEventMask++;
 10616:       dbgPopupTextArea.selectAll ();
 10617:       dbgPopupTextArea.requestFocusInWindow ();
 10618:       dbgEventMask--;
 10619:     }
 10620:   }  //dbgSelectAll()
 10621: 
 10622:   //dbgUpdate ()
 10623:   //  デバッグウインドウを更新する
 10624:   //  コアのrun()の末尾でdbgVisibleMask!=0のとき呼び出す
 10625:   public static void dbgUpdate () {
 10626:     if ((dbgVisibleMask & DBG_DRP_VISIBLE_MASK) != 0) {
 10627:       RegisterList.drpUpdate ();  //レジスタウインドウを更新する
 10628:     }
 10629:     if (ProgramFlowVisualizer.PFV_ON) {
 10630:       if ((dbgVisibleMask & DBG_PFV_VISIBLE_MASK) != 0) {
 10631:         if (ProgramFlowVisualizer.pfvTimer == 0) {
 10632:           ProgramFlowVisualizer.pfvUpdate ();  //プログラムフロービジュアライザを更新する
 10633:         } else {
 10634:           ProgramFlowVisualizer.pfvTimer--;
 10635:         }
 10636:       }
 10637:     }
 10638:     if (RasterBreakPoint.RBP_ON) {
 10639:       if ((dbgVisibleMask & DBG_RBP_VISIBLE_MASK) != 0) {
 10640:         if (RasterBreakPoint.rbpTimer == 0) {
 10641:           RasterBreakPoint.rbpUpdateFrame ();  //ラスタブレークポイントウインドウを更新する
 10642:         } else {
 10643:           RasterBreakPoint.rbpTimer--;
 10644:         }
 10645:       }
 10646:     }
 10647:     if (ScreenModeTest.SMT_ON) {
 10648:       if ((dbgVisibleMask & DBG_SMT_VISIBLE_MASK) != 0) {
 10649:         if (ScreenModeTest.smtTimer == 0) {
 10650:           ScreenModeTest.smtUpdateFrame ();  //表示モードテストウインドウを更新する
 10651:         } else {
 10652:           ScreenModeTest.smtTimer--;
 10653:         }
 10654:       }
 10655:     }
 10656:     if (RootPointerList.RTL_ON) {
 10657:       if ((dbgVisibleMask & DBG_RTL_VISIBLE_MASK) != 0) {
 10658:         if (RootPointerList.rtlTimer == 0) {
 10659:           RootPointerList.rtlTimer = RootPointerList.RTL_INTERVAL - 1;
 10660:           RootPointerList.rtlUpdateFrame ();  //ルートポインタリストを更新する
 10661:         } else {
 10662:           RootPointerList.rtlTimer--;
 10663:         }
 10664:       }
 10665:     }
 10666:     if (SpritePatternViewer.SPV_ON) {
 10667:       if ((dbgVisibleMask & DBG_SPV_VISIBLE_MASK) != 0) {
 10668:         if (SpritePatternViewer.spvTimer == 0) {
 10669:           SpritePatternViewer.spvTimer = SpritePatternViewer.SPV_INTERVAL - 1;
 10670:           SpritePatternViewer.spvUpdateFrame ();  //スプライトパターンビュアを更新する
 10671:         } else {
 10672:           SpritePatternViewer.spvTimer--;
 10673:         }
 10674:       }
 10675:     }
 10676:     if (PaletteViewer.PLV_ON) {
 10677:       if ((dbgVisibleMask & DBG_PLV_VISIBLE_MASK) != 0) {
 10678:         if (PaletteViewer.plvTimer == 0) {
 10679:           PaletteViewer.plvTimer = PaletteViewer.PLV_INTERVAL - 1;
 10680:           PaletteViewer.plvUpdateFrame ();  //スプライトパターンビュアを更新する
 10681:         } else {
 10682:           PaletteViewer.plvTimer--;
 10683:         }
 10684:       }
 10685:     }
 10686:     if (ATCMonitor.ACM_ON) {
 10687:       if ((dbgVisibleMask & DBG_ACM_VISIBLE_MASK) != 0) {
 10688:         if (ATCMonitor.acmTimer == 0) {
 10689:           ATCMonitor.acmTimer = ATCMonitor.ACM_INTERVAL - 1;
 10690:           ATCMonitor.acmUpdateFrame ();  //アドレス変換キャッシュモニタを更新する
 10691:         } else {
 10692:           ATCMonitor.acmTimer--;
 10693:         }
 10694:       }
 10695:     }
 10696:   }  //dbgUpdate()
 10697: 
 10698:   //dbgDoStopOnError ()
 10699:   //  エラーで停止する
 10700:   //  エラーを検出して例外スタックフレームを構築した後にdbgStopOnErrorならば呼び出してコアを停止させる
 10701:   //
 10702:   //  Human68kの_BUS_ERRの中では停止させない
 10703:   //  human302のシステムディスクで起動した場合、
 10704:   //  SCSIボード、RS-232Cボード、MIDIボードのテストで_BUS_ERRが呼び出されてバスエラーが発生する
 10705:   //    bus error on reading from 00EA0044 at 0000E2F4
 10706:   //    bus error on reading from 00EAFC04 at 0002D04A
 10707:   //    bus error on reading from 00EAFC14 at 0002D04A
 10708:   //    bus error on reading from 00EAFA01 at 0005CD54
 10709:   //  _BUS_ERRはレベル0で入ったDOSコールの番号を更新しないので、_BUS_ERRの中かどうかはpcで判断する
 10710:   //    0x0000e342 <= pc0 && pc0 < 0x0000e3b6  human200/human201の_BUS_ERR
 10711:   //    0x0000e3c8 <= pc0 && pc0 < 0x0000e43c  human202の_BUS_ERR
 10712:   //    0x0000e1a8 <= pc0 && pc0 < 0x0000e21c  human203の_BUS_ERR
 10713:   //    0x0000e256 <= pc0 && pc0 < 0x0000e2ca  human215の_BUS_ERR
 10714:   //    0x0000e174 <= pc0 && pc0 < 0x0000e1e8  human301の_BUS_ERR
 10715:   //    0x0000e28a <= pc0 && pc0 < 0x0000e2fe  human302の_BUS_ERR
 10716:   //
 10717:   //  DOSコールで発生した特権違反では停止させない
 10718:   //
 10719:   public static boolean dbgDoStopOnError () {
 10720:     if (MainMemory.mmrHumanVersion <= 0) {  //Human68kでないか未確認
 10721:       return true;
 10722:     }
 10723:     if ((regOC & 0xff00) == 0xff00 &&  //DOSコールで発生した
 10724:         M68kException.m6eNumber == M68kException.M6E_PRIVILEGE_VIOLATION) {  //特権違反
 10725:       return false;
 10726:     }
 10727:     String message = (
 10728:       M68kException.m6eNumber < 0 ?
 10729:       fmtHex8 (new StringBuilder ("breaked").append (" at "), regPC0).toString () :
 10730:       M68kException.m6eNumber <= M68kException.M6E_ADDRESS_ERROR ?
 10731:       fmtHex8 (fmtHex8 (new StringBuilder ("ERROR: ").append (M68kException.M6E_ERROR_NAME[M68kException.m6eNumber])
 10732:                         .append (M68kException.m6eDirection == 0 ? " on writing to " : " on reading from "), M68kException.m6eAddress)
 10733:                .append (" at "), regPC0).toString () :
 10734:       fmtHex8 (new StringBuilder (M68kException.M6E_ERROR_NAME[M68kException.m6eNumber])
 10735:                .append (" at "), regPC0).toString ()
 10736:       );
 10737:     System.out.println (message);
 10738:     if (!(M68kException.m6eNumber == M68kException.M6E_ACCESS_FAULT &&
 10739:           0x0000e100 <= regPC0 && regPC0 < 0x0000e500)) {  //_BUS_ERRの中で発生したバスエラーでないとき
 10740:       mpuStop (message);
 10741:       return true;
 10742:     }
 10743:     return false;
 10744:   }  //dbgDoStopOnError()
 10745: 
 10746:   //dbgDoubleBusFault ()
 10747:   //  ダブルバスフォルト
 10748:   public static void dbgDoubleBusFault () {
 10749:     String message =
 10750:       fmtHex8 (fmtHex8 (new StringBuilder ("FATAL ERROR: ").append (M68kException.M6E_ERROR_NAME[M68kException.m6eNumber])
 10751:                         .append (M68kException.m6eDirection == 0 ? " on writing to " : " on reading from "), M68kException.m6eAddress)
 10752:                .append (" at "), regPC0).toString ();
 10753:     System.out.println (message);
 10754:     mpuStop (message);
 10755:   }  //dbgDoubleBusFault()
 10756: 
 10757: 
 10758: 
 10759:   //========================================================================================
 10760:   //$$RSC ResourceFile
 10761: 
 10762:   public static final HashMap<String,byte[]> rscResourceCache = new HashMap<String,byte[]> ();
 10763: 
 10764:   //array = rscGetResource (name, sizes...)
 10765:   //  リソースファイルを読み込む。null=読み込めなかった
 10766:   //  ファイル名をコンマで区切る機能はない。XEiJ.jarの中なので必要ない
 10767:   //  *.zipや*.gzは非対応。XEiJ.jarの中なので必要ない
 10768:   //  キャッシュした配列をそのまま返すので書き換えないように注意すること
 10769:   public static byte[] rscGetResource (String name, int... sizes) {
 10770:     byte[] array = rscResourceCache.get (name);  //キャッシュから出す
 10771:     if (array != null) {  //読み込み済み
 10772:       return array;
 10773:     }
 10774:     array = new byte[1024 * 64];  //最初は64KB
 10775:     int size = 0;  //これまでに読み込んだ長さ
 10776:     try (BufferedInputStream bis = new BufferedInputStream (XEiJ.class.getResourceAsStream ("../data/" + name))) {
 10777:       for (;;) {
 10778:         if (size == array.length) {  //配列が一杯
 10779:           byte[] newArray = new byte[array.length * 2];  //2倍に伸ばした配列を作る
 10780:           System.arraycopy (array, 0, newArray, 0, size);  //読み込んだ部分を新しい配列に移す
 10781:           array = newArray;  //新しい配列に移行する
 10782:         }
 10783:         int step = bis.read (array, size, array.length - size);  //続きを読み込む。今回読み込んだ長さ
 10784:         if (step == -1) {  //終わり
 10785:           break;
 10786:         }
 10787:         size += step;  //これまでに読み込んだ長さ
 10788:       }
 10789:       if (size < array.length) {  //配列が長すぎる
 10790:         byte[] newArray = new byte[size];  //切り詰めた配列を作る
 10791:         System.arraycopy (array, 0, newArray, 0, size);  //読み込んだ部分を新しい配列に移す
 10792:         array = newArray;  //新しい配列に移行する
 10793:       }
 10794:       boolean fit = sizes.length == 0;
 10795:       if (!fit) {
 10796:         for (int i = 0; i < sizes.length; i++) {
 10797:           if (size == sizes[i]) {  //サイズが合っている
 10798:             fit = true;
 10799:             break;
 10800:           }
 10801:         }
 10802:       }
 10803:       if (fit) {
 10804:         System.out.println (Multilingual.mlnJapanese ?
 10805:                             name + " を読み込みました" :
 10806:                             name + " was read");
 10807:         rscResourceCache.put (name, array);  //キャッシュに入れる
 10808:         return array;  //try-with-resourcesなのでここでクローズされる
 10809:       }
 10810:       System.out.println (Multilingual.mlnJapanese ?
 10811:                           name + " のサイズが違います" :
 10812:                           name + " has wrong size");
 10813:       return null;  //try-with-resourcesなのでここでクローズされる
 10814:     } catch (IOException ioe) {
 10815:     }
 10816:     //try-with-resourcesなのでここでクローズされる
 10817:     System.out.println (Multilingual.mlnJapanese ?
 10818:                         name + " を読み込めません" :
 10819:                         name + " cannot be read");
 10820:     return null;
 10821:   }
 10822: 
 10823:   //string = rscGetResourceText (name, charset)
 10824:   //  リソースファイルからテキストを読み込む
 10825:   public static String rscGetResourceText (String name) {
 10826:     return rscGetResourceText (name, "UTF-8");
 10827:   }
 10828:   public static String rscGetResourceText (String name, String charset) {
 10829:     byte[] array = rscGetResource (name);
 10830:     if (name != null) {
 10831:       try {
 10832:         return new String (array, charset);
 10833:       } catch (UnsupportedEncodingException uee) {
 10834:       }
 10835:     }
 10836:     return "";
 10837:   }
 10838: 
 10839:   public static final Pattern RSC_ZIP_SEPARATOR = Pattern.compile ("(?<=\\.(?:jar|zip))(?:/|\\\\)(?=.)", Pattern.CASE_INSENSITIVE);
 10840:   public static String rscLastFileName = null;  //最後に読み込んだファイル名
 10841: 
 10842:   //array = rscGetFile (names, sizes...)
 10843:   //  ファイルを読み込む。null=読み込めなかった
 10844:   //  コンマで区切られたファイルを順に探して最初に読み込めたものを返す
 10845:   //  *.zip/entryを指定するとエントリを読み込む
 10846:   //  *.gzを指定すると解凍する
 10847:   public static byte[] rscGetFile (String names, int... sizes) {
 10848:     for (String name : names.split (",")) {  //コンマで区切る
 10849:       name = name.trim ();  //前後の空白を削除する
 10850:       if (name.length () == 0 || name.equalsIgnoreCase ("none")) {
 10851:         continue;
 10852:       }
 10853:       String[] zipSplittedName = RSC_ZIP_SEPARATOR.split (name, 2);  // *.zip/entryを*.zipとentryに分ける
 10854:       InputStream is = null;
 10855:       if (zipSplittedName.length < 2) {  // *.zip/entryではない
 10856:         File file = new File (name);
 10857:         if (file.isFile ()) {  //ファイルがある
 10858:           try {
 10859:             is = new FileInputStream (file);  //ファイルを開く
 10860:           } catch (IOException ioe) {
 10861:           }
 10862:         } else {  //ファイルがない
 10863:           System.out.println (Multilingual.mlnJapanese ?
 10864:                               name + " がありません" :
 10865:                               name + " does not exist");
 10866:           continue;
 10867:         }
 10868:       } else {  // *.zip/entry
 10869:         String zipName = zipSplittedName[0];  // *.zip
 10870:         String entryName = zipSplittedName[1];  //entry
 10871:         if (new File (zipName).isFile ()) {  //ファイルがある
 10872:           try {
 10873:             ZipFile zipFile = new ZipFile (zipName);  //ファイル
 10874:             ZipEntry zipEntry = zipFile.getEntry (entryName);  //エントリ
 10875:             if (zipEntry != null) {  //エントリがある
 10876:               is = zipFile.getInputStream (zipEntry);  //エントリを開く
 10877:             } else {  //エントリがない
 10878:               System.out.println (Multilingual.mlnJapanese ?
 10879:                                   zipName + " に " + zipEntry + " がありません" :
 10880:                                   zipName + " does not include " + zipEntry);
 10881:             }
 10882:           } catch (IOException ioe) {
 10883:           }
 10884:         } else {  //ファイルがない
 10885:           System.out.println (Multilingual.mlnJapanese ?
 10886:                               zipName + " がありません" :
 10887:                               zipName + " does not exist");
 10888:           continue;
 10889:         }
 10890:       }
 10891:       if (is != null) {  //開けた
 10892:         try {
 10893:           is = new BufferedInputStream (is);
 10894:           if (name.toLowerCase ().endsWith (".gz")) {  // *.gz
 10895:             is = new GZIPInputStream (is);  //展開する
 10896:           }
 10897:           byte[] array = new byte[1024 * 64];  //最初は64KB
 10898:           int size = 0;  //これまでに読み込んだ長さ
 10899:           for (;;) {
 10900:             if (size == array.length) {  //配列が一杯
 10901:               byte[] newArray = new byte[array.length * 2];  //2倍に伸ばした配列を作る
 10902:               System.arraycopy (array, 0, newArray, 0, size);  //読み込んだ部分を新しい配列に移す
 10903:               array = newArray;  //新しい配列に移行する
 10904:             }
 10905:             int step = is.read (array, size, array.length - size);  //続きを読み込む。今回読み込んだ長さ
 10906:             if (step == -1) {  //終わり
 10907:               break;
 10908:             }
 10909:             size += step;  //これまでに読み込んだ長さ
 10910:           }
 10911:           is.close ();  //ここはtry-with-resourcesではないので明示的にクローズすること
 10912:           is = null;
 10913:           if (size < array.length) {  //配列が長すぎる
 10914:             byte[] newArray = new byte[size];  //切り詰めた配列を作る
 10915:             System.arraycopy (array, 0, newArray, 0, size);  //読み込んだ部分を新しい配列に移す
 10916:             array = newArray;  //新しい配列に移行する
 10917:           }
 10918:           boolean fit = sizes.length == 0;
 10919:           if (!fit) {
 10920:             for (int i = 0; i < sizes.length; i++) {
 10921:               if (size == sizes[i]) {  //サイズが合っている
 10922:                 fit = true;
 10923:                 break;
 10924:               }
 10925:             }
 10926:           }
 10927:           if (fit) {
 10928:             System.out.println (Multilingual.mlnJapanese ?
 10929:                                 name + " を読み込みました" :
 10930:                                 name + " was read");
 10931:             rscLastFileName = name;  //最後に読み込んだファイル名
 10932:             return array;  //配列を返す
 10933:           }
 10934:           System.out.println (Multilingual.mlnJapanese ?
 10935:                               name + " のサイズが違います" :
 10936:                               name + " has wrong size");
 10937:           continue;
 10938:         } catch (IOException ioe) {
 10939:         }
 10940:         if (is != null) {
 10941:           try {
 10942:             is.close ();  //ここはtry-with-resourcesではないので明示的にクローズすること
 10943:             is = null;
 10944:           } catch (IOException ioe) {
 10945:           }
 10946:         }
 10947:       }  //if 開けた
 10948:       System.out.println (Multilingual.mlnJapanese ?
 10949:                           name + " を読み込めません" :
 10950:                           name + " cannot be read");
 10951:     }  //for name
 10952:     //読み込めなかった
 10953:     //ファイル名が指定されたときはメッセージが表示される
 10954:     //ファイル名が指定されなかったときはエラーメッセージも表示されない
 10955:     return null;
 10956:   }
 10957: 
 10958:   //string = rscGetTextFile (name)
 10959:   //string = rscGetTextFile (name, charset)
 10960:   //  テキストファイルを読み込む
 10961:   public static String rscGetTextFile (String name) {
 10962:     return rscGetTextFile (name, "UTF-8");
 10963:   }
 10964:   public static String rscGetTextFile (String name, String charset) {
 10965:     byte[] array = rscGetFile (name);
 10966:     if (array != null) {
 10967:       try {
 10968:         return new String (array, charset);
 10969:       } catch (UnsupportedEncodingException uee) {
 10970:       }
 10971:     }
 10972:     return "";
 10973:   }
 10974: 
 10975:   //mask = rscShowError (message, mask)
 10976:   //  ファイル操作に失敗したときに表示するダイアログ
 10977:   public static final int RSC_A_MASK = 1;  //中止
 10978:   public static final int RSC_R_MASK = 2;  //再実行
 10979:   public static final int RSC_I_MASK = 4;  //無視
 10980:   public static final String RSC_A_EN = "Abort";
 10981:   public static final String RSC_R_EN = "Retry";
 10982:   public static final String RSC_I_EN = "Ignore";
 10983:   public static final String RSC_A_JA = "中止";
 10984:   public static final String RSC_R_JA = "再実行";
 10985:   public static final String RSC_I_JA = "無視";
 10986:   public static final String[][] RSC_EN_OPTIONS = {
 10987:     { RSC_A_EN                     },
 10988:     { RSC_A_EN                     },
 10989:     {           RSC_R_EN           },
 10990:     { RSC_A_EN, RSC_R_EN           },
 10991:     {                     RSC_I_EN },
 10992:     { RSC_A_EN,           RSC_I_EN },
 10993:     {           RSC_R_EN, RSC_I_EN },
 10994:     { RSC_A_EN, RSC_R_EN, RSC_I_EN },
 10995:   };
 10996:   public static final String[][] RSC_JA_OPTIONS = {
 10997:     { RSC_A_JA                     },
 10998:     { RSC_A_JA                     },
 10999:     {           RSC_R_JA           },
 11000:     { RSC_A_JA, RSC_R_JA           },
 11001:     {                     RSC_I_JA },
 11002:     { RSC_A_JA,           RSC_I_JA },
 11003:     {           RSC_R_JA, RSC_I_JA },
 11004:     { RSC_A_JA, RSC_R_JA, RSC_I_JA },
 11005:   };
 11006:   public static int rscShowError (String message, int mask) {
 11007:     System.out.println (message);
 11008:     mask &= RSC_A_MASK | RSC_R_MASK | RSC_I_MASK;
 11009:     if (mask == 0) {
 11010:       mask = RSC_A_MASK;
 11011:     }
 11012:     String[] options = (Multilingual.mlnJapanese ? RSC_JA_OPTIONS : RSC_EN_OPTIONS)[mask];
 11013:     int def = Integer.numberOfTrailingZeros (mask);  //デフォルトの選択肢。0,1,2。中止、再実行、無視の順で最初に見つかったもの
 11014:     pnlExitFullScreen (true);
 11015:     int bit = JOptionPane.showOptionDialog (
 11016:       null,  //parentComponent
 11017:       message,  //message
 11018:       Multilingual.mlnJapanese ? "ファイル操作エラー" : "File operation error",  //title
 11019:       JOptionPane.YES_NO_CANCEL_OPTION,  //optionType
 11020:       JOptionPane.ERROR_MESSAGE,  //messageType
 11021:       null,  //icon
 11022:       options,  //options
 11023:       options[def]);  //initialValue
 11024:     if (bit == JOptionPane.CLOSED_OPTION) {  //閉じた。-1
 11025:       bit = def;
 11026:     }
 11027:     return 1 << bit;
 11028:   }
 11029: 
 11030:   //success = rscPutTextFile (name, string)
 11031:   //success = rscPutTextFile (name, strings)
 11032:   //success = rscPutTextFile (name, string, charset)
 11033:   //success = rscPutTextFile (name, strings, charset)
 11034:   //  テキストファイルに書き出す
 11035:   public static boolean rscPutTextFile (String name, String string) {
 11036:     return rscPutTextFile (name, string, "UTF-8");
 11037:   }
 11038:   public static boolean rscPutTextFile (String name, ArrayList<String> strings) {
 11039:     return rscPutTextFile (name, strings, "UTF-8");
 11040:   }
 11041:   public static boolean rscPutTextFile (String name, String string, String charset) {
 11042:     ArrayList<String> strings = new ArrayList<String> ();
 11043:     strings.add (string);
 11044:     return rscPutTextFile (name, strings, charset);
 11045:   }
 11046:   public static boolean rscPutTextFile (String name, ArrayList<String> strings, String charset) {
 11047:     String nameTmp = name + ".tmp";
 11048:     String nameBak = name + ".bak";
 11049:     File file = new File (name);
 11050:     File fileTmp = new File (nameTmp);
 11051:     File fileBak = new File (nameBak);
 11052:     //親ディレクトリがなければ作る
 11053:     File parentDirectory = file.getParentFile ();  //親ディレクトリ
 11054:     if (parentDirectory != null && !parentDirectory.isDirectory ()) {  //親ディレクトリがない
 11055:       if (!parentDirectory.mkdirs ()) {  //親ディレクトリを作る。必要ならば遡って作る。作れなかった
 11056:         System.out.println (parentDirectory.getPath () + (Multilingual.mlnJapanese ? " を作れません" : " cannot be created"));
 11057:         return false;
 11058:       }
 11059:     }
 11060:     //name.tmpがあればname.tmpを削除する
 11061:     if (fileTmp.exists ()) {  //name.tmpがある
 11062:       if (!fileTmp.delete ()) {  //name.tmpを削除する。削除できなかった
 11063:         System.out.println (nameTmp + (Multilingual.mlnJapanese ? " を削除できません" : " cannot be deleted"));
 11064:         return false;
 11065:       }
 11066:     }
 11067:     //name.tmpに出力する
 11068:     try (BufferedWriter bw = new BufferedWriter (new FileWriter (nameTmp, Charset.forName (charset)))) {
 11069:       for (String string : strings) {
 11070:         bw.write (string);
 11071:       }
 11072:     } catch (IOException ioe) {
 11073:       ioe.printStackTrace ();
 11074:       System.out.println (nameTmp + (Multilingual.mlnJapanese ? " に書き出せません" : " cannot be written"));
 11075:       return false;
 11076:     }
 11077:     //nameがあればnameをname.bakにリネームする
 11078:     boolean fileExists = file.exists ();
 11079:     if (fileExists) {  //nameがある
 11080:       //name.bakがあればname.bakを削除する
 11081:       if (fileBak.exists ()) {  //name.bakがある
 11082:         if (!fileBak.delete ()) {  //name.bakを削除する。削除できなかった
 11083:           System.out.println (nameBak + (Multilingual.mlnJapanese ? " を削除できません" : " cannot be deleted"));
 11084:           return false;
 11085:         }
 11086:       }
 11087:       //nameをname.bakにリネームする
 11088:       if (!file.renameTo (fileBak)) {  //nameをname.bakにリネームする。リネームできなかった
 11089:         System.out.println (name + (Multilingual.mlnJapanese ? " を " : " cannot be renamed to ") + nameBak + (Multilingual.mlnJapanese ? " にリネームできません" : ""));
 11090:         return false;
 11091:       }
 11092:     }
 11093:     //name.tmpをnameにリネームする
 11094:     if (!fileTmp.renameTo (file)) {  //name.tmpをnameにリネームする。リネームできなかった
 11095:       System.out.println (nameTmp + (Multilingual.mlnJapanese ? " を " : " cannot be renamed to ") + name + (Multilingual.mlnJapanese ? " にリネームできません" : ""));
 11096:       return false;
 11097:     }
 11098:     if (fileExists) {  //nameがあった
 11099:       System.out.println (name + (Multilingual.mlnJapanese ? " を更新しました" : " was updated"));
 11100:     } else {  //nameがあった
 11101:       System.out.println (name + (Multilingual.mlnJapanese ? " を作りました" : " was created"));
 11102:     }
 11103:     return true;
 11104:   }
 11105: 
 11106:   //success = rscPutFile (name, array)
 11107:   //success = rscPutFile (name, array, offset, length)
 11108:   //success = rscPutFile (name, array, offset, length, longLength2)
 11109:   //  ファイルに書き出す
 11110:   //  nameにarray[offset..offset+length-1]とlongLength2-length個の0を書き出す
 11111:   //  親ディレクトリがなければ作る
 11112:   //  同じ内容のファイルが既にあるときは更新しない
 11113:   //  *.zip/entryは非対応
 11114:   public static boolean rscPutFile (String name, byte[] array) {
 11115:     return rscPutFile (name, array, 0, array.length, (long) array.length);
 11116:   }
 11117:   public static boolean rscPutFile (String name, byte[] array, int offset, int length) {
 11118:     return rscPutFile (name, array, offset, length, (long) length);
 11119:   }
 11120:   public static boolean rscPutFile (String name, byte[] array, int offset, int length, long longLength2) {
 11121:     if (RSC_ZIP_SEPARATOR.matcher (name).matches ()) {  // *.zip/entry
 11122:       // *.zip/entryのとき確実に弾かないとファイルを破壊するおそれがある
 11123:       return false;
 11124:     }
 11125:     File file = new File (name);
 11126:     boolean fileExists = file.isFile ();  //true=同じ名前のファイルがある
 11127:     if (fileExists && file.length () == longLength2) {  //同じ名前で同じ長さのファイルがある
 11128:     comparison:
 11129:       {
 11130:         try (BufferedInputStream bis = new BufferedInputStream (new FileInputStream (file))) {
 11131:           byte[] buffer = new byte[(int) Math.min (Math.max ((long) length, longLength2 - (long) length), (long) (1024 * 1024))];  //最大1MBずつ読み込んで比較する
 11132:           int position = 0;
 11133:           while (position < length) {
 11134:             int step = bis.read (buffer, 0, Math.min (buffer.length, length - position));
 11135:             if (step == -1) {  //足りない。長さを確認してから始めたのだから途中で終わるはずがない
 11136:               break comparison;
 11137:             }
 11138:             int offsetPosition = offset + position;
 11139:             for (int i = 0; i < step; i++) {
 11140:               if (buffer[i] != array[offsetPosition + i]) {  //一致しない
 11141:                 break comparison;
 11142:               }
 11143:             }
 11144:             position += step;
 11145:           }
 11146:           long longPosition2 = (long) length;
 11147:           while (longPosition2 < longLength2) {
 11148:             int step = bis.read (buffer, 0, (int) Math.min ((long) buffer.length, longLength2 - longPosition2));
 11149:             if (step == -1) {  //足りない。長さを確認してから始めたのだから途中で終わるはずがない
 11150:               break comparison;
 11151:             }
 11152:             for (int i = 0; i < step; i++) {
 11153:               if (buffer[i] != 0) {  //一致しない
 11154:                 break comparison;
 11155:               }
 11156:             }
 11157:             longPosition2 += (long) step;
 11158:           }
 11159:           return true;  //一致した
 11160:         } catch (IOException ioe) {
 11161:         }
 11162:       }  //match
 11163:     }  //if 同じ名前で同じ長さのファイルがある
 11164:     String nameTmp = name + ".tmp";
 11165:     File fileTmp = new File (nameTmp);
 11166:     String nameBak = name + ".bak";
 11167:     File fileBak = new File (nameBak);
 11168:   retry:
 11169:     for (;;) {
 11170:       File parentDirectory = file.getParentFile ();  //親ディレクトリ
 11171:       if (parentDirectory != null && !parentDirectory.isDirectory ()) {  //親ディレクトリがない
 11172:         String parentName = parentDirectory.getPath ();
 11173:         if (parentDirectory.mkdirs ()) {  //親ディレクトリを作る。必要ならば遡って作る。作れた
 11174:           System.out.println (Multilingual.mlnJapanese ?
 11175:                               parentName + " を作りました" :
 11176:                               parentName + " was created");
 11177:         } else {  //作れなかった
 11178:           switch (rscShowError (Multilingual.mlnJapanese ?
 11179:                                 parentName + " を作れません" :
 11180:                                 parentName + " cannot be created",
 11181:                                 RSC_A_MASK | RSC_R_MASK | RSC_I_MASK)) {
 11182:           case RSC_A_MASK:
 11183:             break retry;
 11184:           case RSC_R_MASK:
 11185:             continue retry;
 11186:           }
 11187:         }
 11188:       }
 11189:       if (fileTmp.isFile ()) {  //name.tmpがある。前回異常終了して残骸が残っている場合など
 11190:         if (!fileTmp.delete ()) {  //name.tmpを削除する。削除できない
 11191:           switch (rscShowError (Multilingual.mlnJapanese ?
 11192:                                 nameTmp + " を削除できません" :
 11193:                                 nameTmp + " cannot be deleted",
 11194:                                 RSC_A_MASK | RSC_R_MASK | RSC_I_MASK)) {
 11195:           case RSC_A_MASK:
 11196:             break retry;
 11197:           case RSC_R_MASK:
 11198:             continue retry;
 11199:           }
 11200:         }
 11201:       }
 11202:       try (OutputStream os = name.toLowerCase ().endsWith (".gz") ?
 11203:            new GZIPOutputStream (new BufferedOutputStream (new FileOutputStream (fileTmp))) {
 11204:              {
 11205:                //def.setLevel (Deflater.BEST_COMPRESSION);
 11206:                def.setLevel (Deflater.DEFAULT_COMPRESSION);
 11207:                //def.setLevel (Deflater.BEST_SPEED);
 11208:              }
 11209:            } :
 11210:            new BufferedOutputStream (new FileOutputStream (fileTmp))) {  //name.tmpに書き出す
 11211:         //array[offset..offset+length-1]を書き出す
 11212:         os.write (array, offset, length);
 11213:         //longLength2-length個の0を書き出す
 11214:         //  RandomAccessFile.setLength()は拡張部分の内容が定義されていないので使えない
 11215:         if ((long) length < longLength2) {
 11216:           byte[] buffer = new byte[(int) Math.min (longLength2 - (long) length, (long) (1024 * 1024))];  //最大1MBずつ書き出す
 11217:           Arrays.fill (buffer, 0, buffer.length, (byte) 0);  //念の為
 11218:           long longPosition2 = (long) length;
 11219:           while (longPosition2 < longLength2) {
 11220:             int step = (int) Math.min ((long) buffer.length, longLength2 - longPosition2);
 11221:             os.write (buffer, 0, step);
 11222:             longPosition2 += (long) step;
 11223:           }
 11224:         }
 11225:       } catch (IOException ioe) {
 11226:         switch (rscShowError (Multilingual.mlnJapanese ?
 11227:                               nameTmp + " に書き出せません" :
 11228:                               nameTmp + " cannot be written",
 11229:                               RSC_A_MASK | RSC_R_MASK | RSC_I_MASK)) {
 11230:         case RSC_A_MASK:
 11231:           break retry;
 11232:         case RSC_R_MASK:
 11233:           continue retry;
 11234:         }
 11235:       }
 11236:       if (fileExists && file.isFile ()) {  //同じ名前で内容が異なるファイルがある。リトライでなくなった可能性があるので確認し直す
 11237:         if (fileBak.isFile ()) {  //name.bakがある
 11238:           if (!fileBak.delete ()) {  //name.bakを削除する。削除できない
 11239:             switch (rscShowError (Multilingual.mlnJapanese ?
 11240:                                   nameBak + " を削除できません" :
 11241:                                   nameBak + " cannot be deleted",
 11242:                                   RSC_A_MASK | RSC_R_MASK | RSC_I_MASK)) {
 11243:             case RSC_A_MASK:
 11244:               break retry;
 11245:             case RSC_R_MASK:
 11246:               continue retry;
 11247:             }
 11248:           }
 11249:         }
 11250:         if (!file.renameTo (fileBak)) {  //nameをname.bakにリネームする。リネームできない
 11251:           switch (rscShowError (Multilingual.mlnJapanese ?
 11252:                                 name + " を " + nameBak + " にリネームできません" :
 11253:                                 name + " cannot be renamed to " + nameBak,
 11254:                                 RSC_A_MASK | RSC_R_MASK | RSC_I_MASK)) {
 11255:           case RSC_A_MASK:
 11256:             break retry;
 11257:           case RSC_R_MASK:
 11258:             continue retry;
 11259:           }
 11260:         }
 11261:       }
 11262:       if (fileTmp.renameTo (file)) {  //name.tmpをnameにリネームする。リネームできた
 11263:         if (fileExists) {  //同じ名前のファイルがあった
 11264:           System.out.println (Multilingual.mlnJapanese ?
 11265:                               name + " を更新しました" :
 11266:                               name + " was updated");
 11267:         } else {  //同じ名前のファイルがなかった
 11268:           System.out.println (Multilingual.mlnJapanese ?
 11269:                               name + " を作りました" :
 11270:                               name + " was created");
 11271:         }
 11272:         return true;  //成功
 11273:       } else {  //リネームできない
 11274:         switch (rscShowError (Multilingual.mlnJapanese ?
 11275:                               nameTmp + " を " + name + " にリネームできません" :
 11276:                               nameTmp + " cannot be renamed to " + name,
 11277:                               RSC_A_MASK | RSC_R_MASK | RSC_I_MASK)) {
 11278:         case RSC_A_MASK:
 11279:           break retry;
 11280:         case RSC_R_MASK:
 11281:           continue retry;
 11282:         }
 11283:       }
 11284:       break;
 11285:     }  //retry
 11286:     if (fileExists) {  //同じ名前のファイルがあった
 11287:       System.out.println (Multilingual.mlnJapanese ?
 11288:                           name + " を更新できません" :
 11289:                           name + " cannot be updated");
 11290:     } else {  //同じ名前のファイルがなかった
 11291:       System.out.println (Multilingual.mlnJapanese ?
 11292:                           name + " を作れません" :
 11293:                           name + " cannot be created");
 11294:     }
 11295:     return false;  //失敗
 11296:   }
 11297: 
 11298: 
 11299: 
 11300:   //========================================================================================
 11301:   //$$ISM InputStream
 11302: 
 11303:   public static final Pattern ISM_ZIP_SEPARATOR = Pattern.compile ("(?<=\\.(?:jar|zip))(?:/|\\\\)(?=.)", Pattern.CASE_INSENSITIVE);
 11304: 
 11305:   //in = ismOpen (name)
 11306:   //  InputStreamを開く
 11307:   //  InputStreamを返す
 11308:   //    失敗したときはnullを返す
 11309:   //  ZIPファイルの中のファイルを指定できる
 11310:   //    ZIPファイルの中のファイルはZipInputStreamで開く
 11311:   //    ZIPファイルの中のファイル名は{ZIPファイル名}/{ZIPファイルの中のファイル名}で指定する
 11312:   //    JARファイルもZIPファイルとして開くことができる
 11313:   //  GZIPで圧縮されているファイルを指定できる
 11314:   //    GZIPで圧縮されているファイルはGZIPInputStreamで開く
 11315:   public static InputStream ismOpen (String name) {
 11316:     InputStream in = null;
 11317:     in = ismOpen (name, false);  //ファイルを開く
 11318:     if (in == null && name.indexOf ('/') < 0 && name.indexOf ('\\') < 0) {  //ファイルがないとき
 11319:       in = ismOpen (name, true);  //リソースを開く
 11320:     }
 11321:     return in;
 11322:   }  //ismOpen(String)
 11323:   public static InputStream ismOpen (String name, boolean useGetResource) {
 11324:     boolean gzipped = name.toLowerCase ().endsWith (".gz");  //true=GZIPファイルが指定された
 11325:     String[] zipSplittedName = ISM_ZIP_SEPARATOR.split (name, 2);  //ZIPファイル名とZIPファイルの中のファイル名に分ける
 11326:     String fileName = zipSplittedName[0];  //通常のファイル名またはZIPファイル名
 11327:     String zipEntryName = zipSplittedName.length < 2 ? null : zipSplittedName[1];  //ZIPファイルの中のファイル名
 11328:     InputStream in = null;
 11329:     try {
 11330:       if (useGetResource) {  //getResourceを使うとき
 11331:         if (false) {
 11332:           URL url = XEiJ.class.getResource (fileName);
 11333:           if (url != null) {  //ファイルがある
 11334:             in = url.openStream ();
 11335:           }
 11336:         } else {
 11337:           in = XEiJ.class.getResourceAsStream (fileName);
 11338:         }
 11339:       } else {
 11340:         File file = new File (fileName);
 11341:         if (file.exists ()) {  //ファイルがある
 11342:           in = new FileInputStream (file);
 11343:         }
 11344:       }
 11345:       if (in != null && zipEntryName != null) {  //ZIPファイルの中のファイルが指定されたとき
 11346:         ZipInputStream zin = new ZipInputStream (in);
 11347:         in = null;
 11348:         ZipEntry entry;
 11349:         while ((entry = zin.getNextEntry ()) != null) {  //指定されたファイル名のエントリを探す
 11350:           if (zipEntryName.equals (entry.getName ())) {  //エントリが見つかった
 11351:             in = zin;
 11352:             break;
 11353:           }
 11354:         }
 11355:         if (in == null) {
 11356:           System.out.println (Multilingual.mlnJapanese ? fileName + " の中に " + zipEntryName + " がありません" :
 11357:                               zipEntryName + " does not exist in " + fileName);
 11358:         }
 11359:       }
 11360:       if (in != null && gzipped) {  //GZIPで圧縮されたファイルが指定されたとき
 11361:         in = new GZIPInputStream (in);
 11362:       }
 11363:       if (in != null) {
 11364:         System.out.println (Multilingual.mlnJapanese ? (useGetResource ? "リソースファイル " : "ファイル ") + name + " を読み込みます" :
 11365:                             (useGetResource ? "Reading resource file " : "Reading file ") + name);
 11366:         return new BufferedInputStream (in);
 11367:       }
 11368:     } catch (Exception ioe) {
 11369:       if (prgVerbose) {
 11370:         prgPrintStackTraceOf (ioe);
 11371:       }
 11372:     }
 11373:     System.out.println (Multilingual.mlnJapanese ? (useGetResource ? "リソースファイル " : "ファイル ") + name + " が見つかりません" :
 11374:                         (useGetResource ? "Resource file " : "File ") + name + " is not found");
 11375:     return null;  //失敗
 11376:   }  //ismOpen(String,boolean)
 11377: 
 11378:   //k = ismRead (in, bb, o, l)
 11379:   //  InputStreamからバイトバッファに読み込む
 11380:   //  読み込んだ長さを返す
 11381:   //    エラーのときは-1を返す
 11382:   //  指定されたサイズまたはファイルの末尾まで読み込む
 11383:   //    k=in.read(bb,o,l)は1回で指定されたサイズを読み込めるとは限らない
 11384:   //  ブロックされる可能性があるのでコアの動作中にコアのスレッドから呼ばないほうがよい
 11385:   public static int ismRead (InputStream in, byte[] bb, int o, int l) {
 11386:     try {
 11387:       int k = 0;
 11388:       while (k < l) {
 11389:         int t = in.read (bb, o + k, l - k);
 11390:         if (t < 0) {
 11391:           break;
 11392:         }
 11393:         k += t;
 11394:       }
 11395:       return k;
 11396:     } catch (IOException ioe) {
 11397:       if (prgVerbose) {
 11398:         prgPrintStackTraceOf (ioe);
 11399:       }
 11400:     }
 11401:     return -1;
 11402:   }  //ismRead(InputStream,byte[],int,int)
 11403: 
 11404:   //k = ismSkip (in, l)
 11405:   //  InputStreamを読み飛ばす
 11406:   //  読み飛ばした長さを返す
 11407:   //    エラーのときは-1を返す
 11408:   //  指定されたサイズまたはファイルの末尾まで読み飛ばす
 11409:   //    k=in.skip(l)は1回で指定されたサイズを読み飛ばせるとは限らない
 11410:   //  ブロックされる可能性があるのでコアの動作中にコアのスレッドから呼ばないほうがよい
 11411:   public static int ismSkip (InputStream in, int l) {
 11412:     try {
 11413:       int k = 0;
 11414:       while (k < l) {
 11415:         //skip(long)はファイルの末尾でなくても0を返す可能性があるのでファイルの末尾の判定はread()で行う
 11416:         //skip(long)する前に毎回read()しないとskip()がファイルの末尾で止まらなくなるらしい
 11417:         if (in.read () < 0) {
 11418:           break;
 11419:         }
 11420:         k++;
 11421:         if (k < l) {
 11422:           int t = (int) in.skip ((long) (l - k));
 11423:           if (t < 0) {
 11424:             break;
 11425:           }
 11426:           k += t;
 11427:         }
 11428:       }
 11429:       return k;
 11430:     } catch (IOException ioe) {
 11431:       if (prgVerbose) {
 11432:         prgPrintStackTraceOf (ioe);
 11433:       }
 11434:     }
 11435:     return -1;
 11436:   }  //ismSkip(InputStream,int)
 11437: 
 11438:   //ismClose (in)
 11439:   //  InputStreamを閉じる
 11440:   //  in==nullのときは何もしない
 11441:   //  in.close()でIOExceptionを無視するだけ
 11442:   public static void ismClose (InputStream in) {
 11443:     try {
 11444:       if (in != null) {
 11445:         in.close ();
 11446:       }
 11447:     } catch (IOException ioe) {
 11448:       if (prgVerbose) {
 11449:         prgPrintStackTraceOf (ioe);
 11450:       }
 11451:     }
 11452:   }  //ismClose(InputStream)
 11453: 
 11454:   //length = ismLength (name, maxLength)
 11455:   //  ファイルの長さを数える
 11456:   //  ZIPファイルの中のファイルを指定できる
 11457:   //  GZIPで圧縮されているファイルを指定できる
 11458:   //  -1  ファイルがない
 11459:   public static int ismLength (String name, int maxLength) {
 11460:     int length;
 11461:     InputStream in = ismOpen (name);
 11462:     if (in == null) {  //ファイルがない
 11463:       length = -1;
 11464:     } else {  //ファイルがある
 11465:       length = ismSkip (in, maxLength);
 11466:       ismClose (in);
 11467:     }
 11468:     return length;
 11469:   }  //ismLength(String,int)
 11470: 
 11471:   //success = ismLoad (bb, o, l, names)
 11472:   //  ファイルからバイトバッファに読み込む
 11473:   //  ファイル名を,で区切って複数指定できる
 11474:   //    先頭から順に指定されたサイズまで読み込めるファイルを探す
 11475:   //    1つでも読み込むことができればその時点で成功、1つも読み込めなければ失敗
 11476:   //  成功したときtrueを返す
 11477:   //  ZIPファイルの中のファイルを指定できる
 11478:   //    ZIPファイルの中のファイルはZipInputStreamで開く
 11479:   //    ZIPファイルの中のファイル名は{ZIPファイル名}/{ZIPファイルの中のファイル名}で指定する
 11480:   //    JARファイルもZIPファイルとして開くことができる
 11481:   //  GZIPで圧縮されているファイルを指定できる
 11482:   //    GZIPで圧縮されているファイルはGZIPInputStreamで開く
 11483:   //  ブロックされることがあるのでコアの動作中にコアのスレッドから呼ばないほうがよい
 11484:   public static boolean ismLoad (byte[] bb, int o, int l, String names) {
 11485:     for (String name : names.split (",")) {  //先頭から順に
 11486:       if (name.length () != 0) {  //ファイル名が指定されているとき
 11487:         InputStream in = ismOpen (name);  //開く
 11488:         if (in != null) {  //開けたら
 11489:           int k = ismRead (in, bb, o, l);  //読み込んで
 11490:           ismClose (in);  //閉じる
 11491:           if (k == l) {  //指定されたサイズまで読み込めたら
 11492:             return true;  //成功
 11493:           }
 11494:         }
 11495:       }
 11496:     }
 11497:     return false;  //1つも読み込めなかったので失敗
 11498:   }  //ismLoad(byte[],int,int,String)
 11499: 
 11500:   //success = ismSave (bb, offset, length, path, verbose)
 11501:   //  バイトバッファからファイルに書き出す
 11502:   //  出力範囲がバッファに収まっているとき
 11503:   //    ファイルが既に存在していてファイルサイズと内容が一致しているときは更新しない
 11504:   //  出力範囲がバッファに収まっていないとき
 11505:   //    バッファからはみ出した部分をゼロクリアする
 11506:   //    RandomAccessFileのsetLengthを使うとファイルサイズを簡単に変更できるが、ファイルを伸ばしたときに書き込まれる内容が仕様で定義されていない
 11507:   //    同じ手順で同じ内容のファイルができない可能性があるのは困るので明示的に0を書き込んでクリアする
 11508:   public static boolean ismSave (byte[] bb, int offset, long length, String path, boolean verbose) {
 11509:     if (ISM_ZIP_SEPARATOR.split (path, 2).length != 1) {  //ZIPファイルの中のファイル
 11510:       if (verbose) {
 11511:         pnlExitFullScreen (true);
 11512:         JOptionPane.showMessageDialog (null, Multilingual.mlnJapanese ? path + " に書き出せません" : "Cannot write " + path);
 11513:       }
 11514:       return false;
 11515:     }
 11516:     long step = 0;  //一度にゼロクリアする長さ。0=バッファに収まっている
 11517:     byte[] zz = null;  //ゼロクリア用の配列
 11518:     long pointer = (long) (bb.length - offset);  //バッファから出力できる長さ
 11519:     if (pointer < length) {  //バッファに収まっていない
 11520:       step = Math.min (1024L * 512, length - pointer);  //一度にゼロクリアする長さ。最大512KB
 11521:       zz = new byte[(int) step];  //ゼロクリア用の配列
 11522:       Arrays.fill (zz, (byte) 0);
 11523:     }
 11524:     //ファイル
 11525:     File file = new File (path);  //ファイル
 11526:     //ファイルが既に存在しているときはファイルサイズと内容が一致しているかどうか確認する
 11527:     if (step == 0 &&  //バッファに収まっている
 11528:         file.exists () && file.length () == length) {  //ファイルサイズが一致している
 11529:       //ファイルを読み込む
 11530:       if (length == 0L) {  //ファイルサイズが0で一致しているので成功
 11531:         return true;
 11532:       }
 11533:       InputStream in = ismOpen (path);
 11534:       if (in != null) {
 11535:         int l = (int) length;  //バッファに収まっているのだからintの範囲内
 11536:         byte[] tt = new byte[l];
 11537:         int k = ismRead (in, tt, 0, l);
 11538:         ismClose (in);
 11539:         if (k == l &&
 11540:             Arrays.equals (tt, bb.length == l ? bb : Arrays.copyOfRange (bb, offset, offset + l))) {  //内容が一致している
 11541:           return true;  //更新する必要がないので成功
 11542:         }
 11543:       }
 11544:     }  //check
 11545:     // *.tmpと*.bak
 11546:     String pathTmp = path + ".tmp";  // *.tmp
 11547:     String pathBak = path + ".bak";  // *.bak
 11548:     File fileTmp = new File (pathTmp);  // *.tmp
 11549:     File fileBak = new File (pathBak);  // *.bak
 11550:     // *.tmpを削除する
 11551:     if (fileTmp.exists ()) {  // *.tmpがあるとき
 11552:       if (!fileTmp.delete ()) {  // *.tmpを削除する
 11553:         if (verbose) {
 11554:           pnlExitFullScreen (true);
 11555:           JOptionPane.showMessageDialog (null, Multilingual.mlnJapanese ? pathTmp + " を削除できません" : "Cannot delete " + pathTmp);
 11556:         }
 11557:         return false;
 11558:       }
 11559:     }
 11560:     // *.tmpに書き出す
 11561:     try (OutputStream out = path.toLowerCase ().endsWith (".gz") ?  //pathの末尾が".gz"のときpathTmpの末尾は".gz.tmp"であることに注意
 11562:          new GZIPOutputStream (new BufferedOutputStream (new FileOutputStream (fileTmp))) {
 11563:            {
 11564:              //def.setLevel (Deflater.BEST_COMPRESSION);
 11565:              def.setLevel (Deflater.DEFAULT_COMPRESSION);
 11566:              //def.setLevel (Deflater.BEST_SPEED);
 11567:            }
 11568:          } :
 11569:          new BufferedOutputStream (new FileOutputStream (fileTmp))) {  //try-with-resourcesは1.7から
 11570:       if (step == 0) {  //バッファに収まっている
 11571:         out.write (bb, offset, (int) length);  //OutputStreamのwriteの返り値はvoid。エラーが出なければ1回で最後まで書き出される
 11572:       } else {  //バッファに収まっていない
 11573:         out.write (bb, offset, (int) pointer);  //バッファから出力できる範囲
 11574:         for (; pointer < length; pointer += step) {
 11575:           out.write (zz, 0, (int) Math.min (step, length - pointer));  //バッファから出力できない範囲
 11576:         }
 11577:       }
 11578:     } catch (IOException ioe) {
 11579:       if (verbose) {
 11580:         prgPrintStackTraceOf (ioe);
 11581:         pnlExitFullScreen (true);
 11582:         JOptionPane.showMessageDialog (null, Multilingual.mlnJapanese ? pathTmp + " に書き出せません" : "Cannot write " + pathTmp);
 11583:       }
 11584:       return false;
 11585:     }
 11586:     //ファイルを*.bakにリネームする
 11587:     //  javaのFileのrenameToはPerlと違って上書きしてくれないので明示的に削除またはリネームする必要がある
 11588:     if (file.exists ()) {  //ファイルがあるとき
 11589:       if (fileBak.exists ()) {  // *.bakがあるとき
 11590:         if (!fileBak.delete ()) {  // *.bakを削除する
 11591:           if (verbose) {
 11592:             pnlExitFullScreen (true);
 11593:             JOptionPane.showMessageDialog (null, Multilingual.mlnJapanese ? pathBak + " を削除できません" : "Cannot delete " + pathBak);
 11594:           }
 11595:           return false;
 11596:         }
 11597:       }
 11598:       if (!file.renameTo (fileBak)) {  //ファイルを*.bakにリネームする
 11599:         if (verbose) {
 11600:           pnlExitFullScreen (true);
 11601:           JOptionPane.showMessageDialog (
 11602:             null, Multilingual.mlnJapanese ? path + " を " + pathBak + " にリネームできません" : "Cannot rename " + path + " to " + pathBak);
 11603:         }
 11604:         return false;
 11605:       }
 11606:     }
 11607:     // *.tmpをファイルにリネームする
 11608:     //  javaのFileのrenameToはPerlと違って上書きしてくれないので明示的に削除またはリネームする必要がある
 11609:     if (!fileTmp.renameTo (file)) {  // *.tmpをファイルにリネームする
 11610:       if (verbose) {
 11611:         pnlExitFullScreen (true);
 11612:         JOptionPane.showMessageDialog (
 11613:           null, Multilingual.mlnJapanese ? pathTmp + " を " + path + " にリネームできません" : "Cannot rename " + pathTmp + " to " + path);
 11614:       }
 11615:       return false;
 11616:     }
 11617:     return true;
 11618:   }  //ismSave(byte[],int,long,String,boolean)
 11619: 
 11620: 
 11621: 
 11622:   //========================================================================================
 11623:   //$$FMT フォーマット変換
 11624:   //  Formatterは遅いので自前で展開する
 11625: 
 11626:   public static final char[] FMT_TEMP = new char[32];
 11627: 
 11628:   //--------------------------------------------------------------------------------
 11629:   //2進数変換
 11630:   //  ainNは'.'と'*'、binNは'0'と'1'に変換する
 11631:   //
 11632:   //  x          00 01
 11633:   //  x<<2       00 04
 11634:   //  x<<2&4     00 04
 11635:   //  x<<2&4^46  2e 2a
 11636:   //              .  *
 11637: 
 11638:   public static final char[] FMT_AIN4_BASE = ".......*..*...**.*...*.*.**..****...*..**.*.*.****..**.****.****".toCharArray ();
 11639:   public static final char[] FMT_BIN4_BASE = "0000000100100011010001010110011110001001101010111100110111101111".toCharArray ();
 11640: 
 11641:   //fmtAin4 (a, o, x)
 11642:   //fmtBin4 (a, o, x)
 11643:   //s = fmtAin4 (x)
 11644:   //s = fmtBin4 (x)
 11645:   //sb = fmtAin4 (sb, x)
 11646:   //sb = fmtBin4 (sb, x)
 11647:   //  4桁2進数変換
 11648:   public static void fmtAin4 (char[] a, int o, int x) {
 11649:     a[o     ] = (char) (x >>  1 & 4 ^ 46);
 11650:     a[o +  1] = (char) (x       & 4 ^ 46);
 11651:     a[o +  2] = (char) (x <<  1 & 4 ^ 46);
 11652:     a[o +  3] = (char) (x <<  2 & 4 ^ 46);
 11653:   }  //fmtAin4(char[],int,int)
 11654:   public static void fmtBin4 (char[] a, int o, int x) {
 11655:     a[o     ] = (char) (x >>>  3 & 1 | 48);
 11656:     a[o +  1] = (char) (x >>>  2 & 1 | 48);
 11657:     a[o +  2] = (char) (x >>>  1 & 1 | 48);
 11658:     a[o +  3] = (char) (x        & 1 | 48);
 11659:   }  //fmtBin4(char[],int,int)
 11660:   public static String fmtAin4 (int x) {
 11661:     return String.valueOf (FMT_AIN4_BASE, (x & 15) << 2, 4);
 11662:   }  //fmtAin4(int)
 11663:   public static String fmtBin4 (int x) {
 11664:     return String.valueOf (FMT_BIN4_BASE, (x & 15) << 2, 4);
 11665:   }  //fmtBin4(int)
 11666:   public static StringBuilder fmtAin4 (StringBuilder sb, int x) {
 11667:     return sb.append (FMT_AIN4_BASE, (x & 15) << 2, 6);
 11668:   }  //fmtAin4(StringBuilder,int)
 11669:   public static StringBuilder fmtBin4 (StringBuilder sb, int x) {
 11670:     return sb.append (FMT_BIN4_BASE, (x & 15) << 2, 6);
 11671:   }  //fmtBin4(StringBuilder,int)
 11672: 
 11673:   //fmtAin6 (a, o, x)
 11674:   //fmtBin6 (a, o, x)
 11675:   //s = fmtAin6 (x)
 11676:   //s = fmtBin6 (x)
 11677:   //sb = fmtAin6 (sb, x)
 11678:   //sb = fmtBin6 (sb, x)
 11679:   //  6桁2進数変換
 11680:   public static void fmtAin6 (char[] a, int o, int x) {
 11681:     a[o     ] = (char) (x >>  3 & 4 ^ 46);
 11682:     a[o +  1] = (char) (x >>  2 & 4 ^ 46);
 11683:     a[o +  2] = (char) (x >>  1 & 4 ^ 46);
 11684:     a[o +  3] = (char) (x       & 4 ^ 46);
 11685:     a[o +  4] = (char) (x <<  1 & 4 ^ 46);
 11686:     a[o +  5] = (char) (x <<  2 & 4 ^ 46);
 11687:   }  //fmtAin6(char[],int,int)
 11688:   public static void fmtBin6 (char[] a, int o, int x) {
 11689:     a[o     ] = (char) (x >>>  5 & 1 | 48);
 11690:     a[o +  1] = (char) (x >>>  4 & 1 | 48);
 11691:     a[o +  2] = (char) (x >>>  3 & 1 | 48);
 11692:     a[o +  3] = (char) (x >>>  2 & 1 | 48);
 11693:     a[o +  4] = (char) (x >>>  1 & 1 | 48);
 11694:     a[o +  5] = (char) (x        & 1 | 48);
 11695:   }  //fmtBin6(char[],int,int)
 11696:   public static String fmtAin6 (int x) {
 11697:     FMT_TEMP[ 0] = (char) (x >>  3 & 4 ^ 46);
 11698:     FMT_TEMP[ 1] = (char) (x >>  2 & 4 ^ 46);
 11699:     FMT_TEMP[ 2] = (char) (x >>  1 & 4 ^ 46);
 11700:     FMT_TEMP[ 3] = (char) (x       & 4 ^ 46);
 11701:     FMT_TEMP[ 4] = (char) (x <<  1 & 4 ^ 46);
 11702:     FMT_TEMP[ 5] = (char) (x <<  2 & 4 ^ 46);
 11703:     return String.valueOf (FMT_TEMP, 0, 6);
 11704:   }  //fmtAin6(int)
 11705:   public static String fmtBin6 (int x) {
 11706:     FMT_TEMP[ 0] = (char) (x >>>  5 & 1 | 48);
 11707:     FMT_TEMP[ 1] = (char) (x >>>  4 & 1 | 48);
 11708:     FMT_TEMP[ 2] = (char) (x >>>  3 & 1 | 48);
 11709:     FMT_TEMP[ 3] = (char) (x >>>  2 & 1 | 48);
 11710:     FMT_TEMP[ 4] = (char) (x >>>  1 & 1 | 48);
 11711:     FMT_TEMP[ 5] = (char) (x        & 1 | 48);
 11712:     return String.valueOf (FMT_TEMP, 0, 6);
 11713:   }  //fmtBin6(int)
 11714:   public static StringBuilder fmtAin6 (StringBuilder sb, int x) {
 11715:     FMT_TEMP[ 0] = (char) (x >>  3 & 4 ^ 46);
 11716:     FMT_TEMP[ 1] = (char) (x >>  2 & 4 ^ 46);
 11717:     FMT_TEMP[ 2] = (char) (x >>  1 & 4 ^ 46);
 11718:     FMT_TEMP[ 3] = (char) (x       & 4 ^ 46);
 11719:     FMT_TEMP[ 4] = (char) (x <<  1 & 4 ^ 46);
 11720:     FMT_TEMP[ 5] = (char) (x <<  2 & 4 ^ 46);
 11721:     return sb.append (FMT_TEMP, 0, 6);
 11722:   }  //fmtAin6(StringBuilder,int)
 11723:   public static StringBuilder fmtBin6 (StringBuilder sb, int x) {
 11724:     FMT_TEMP[ 0] = (char) (x >>>  5 & 1 | 48);
 11725:     FMT_TEMP[ 1] = (char) (x >>>  4 & 1 | 48);
 11726:     FMT_TEMP[ 2] = (char) (x >>>  3 & 1 | 48);
 11727:     FMT_TEMP[ 3] = (char) (x >>>  2 & 1 | 48);
 11728:     FMT_TEMP[ 4] = (char) (x >>>  1 & 1 | 48);
 11729:     FMT_TEMP[ 5] = (char) (x        & 1 | 48);
 11730:     return sb.append (FMT_TEMP, 0, 6);
 11731:   }  //fmtBin6(StringBuilder,int)
 11732: 
 11733:   //fmtAin8 (a, o, x)
 11734:   //fmtBin8 (a, o, x)
 11735:   //s = fmtAin8 (x)
 11736:   //s = fmtBin8 (x)
 11737:   //sb = fmtAin8 (sb, x)
 11738:   //sb = fmtBin8 (sb, x)
 11739:   //  8桁2進数変換
 11740:   public static void fmtAin8 (char[] a, int o, int x) {
 11741:     a[o     ] = (char) (x >>  5 & 4 ^ 46);
 11742:     a[o +  1] = (char) (x >>  4 & 4 ^ 46);
 11743:     a[o +  2] = (char) (x >>  3 & 4 ^ 46);
 11744:     a[o +  3] = (char) (x >>  2 & 4 ^ 46);
 11745:     a[o +  4] = (char) (x >>  1 & 4 ^ 46);
 11746:     a[o +  5] = (char) (x       & 4 ^ 46);
 11747:     a[o +  6] = (char) (x <<  1 & 4 ^ 46);
 11748:     a[o +  7] = (char) (x <<  2 & 4 ^ 46);
 11749:   }  //fmtAin8(char[],int,int)
 11750:   public static void fmtBin8 (char[] a, int o, int x) {
 11751:     a[o     ] = (char) (x >>>  7 & 1 | 48);
 11752:     a[o +  1] = (char) (x >>>  6 & 1 | 48);
 11753:     a[o +  2] = (char) (x >>>  5 & 1 | 48);
 11754:     a[o +  3] = (char) (x >>>  4 & 1 | 48);
 11755:     a[o +  4] = (char) (x >>>  3 & 1 | 48);
 11756:     a[o +  5] = (char) (x >>>  2 & 1 | 48);
 11757:     a[o +  6] = (char) (x >>>  1 & 1 | 48);
 11758:     a[o +  7] = (char) (x        & 1 | 48);
 11759:   }  //fmtBin8(char[],int,int)
 11760:   public static String fmtAin8 (int x) {
 11761:     FMT_TEMP[ 0] = (char) (x >>  5 & 4 ^ 46);
 11762:     FMT_TEMP[ 1] = (char) (x >>  4 & 4 ^ 46);
 11763:     FMT_TEMP[ 2] = (char) (x >>  3 & 4 ^ 46);
 11764:     FMT_TEMP[ 3] = (char) (x >>  2 & 4 ^ 46);
 11765:     FMT_TEMP[ 4] = (char) (x >>  1 & 4 ^ 46);
 11766:     FMT_TEMP[ 5] = (char) (x       & 4 ^ 46);
 11767:     FMT_TEMP[ 6] = (char) (x <<  1 & 4 ^ 46);
 11768:     FMT_TEMP[ 7] = (char) (x <<  2 & 4 ^ 46);
 11769:     return String.valueOf (FMT_TEMP, 0, 8);
 11770:   }  //fmtAin8(int)
 11771:   public static String fmtBin8 (int x) {
 11772:     FMT_TEMP[ 0] = (char) (x >>>  7 & 1 | 48);
 11773:     FMT_TEMP[ 1] = (char) (x >>>  6 & 1 | 48);
 11774:     FMT_TEMP[ 2] = (char) (x >>>  5 & 1 | 48);
 11775:     FMT_TEMP[ 3] = (char) (x >>>  4 & 1 | 48);
 11776:     FMT_TEMP[ 4] = (char) (x >>>  3 & 1 | 48);
 11777:     FMT_TEMP[ 5] = (char) (x >>>  2 & 1 | 48);
 11778:     FMT_TEMP[ 6] = (char) (x >>>  1 & 1 | 48);
 11779:     FMT_TEMP[ 7] = (char) (x        & 1 | 48);
 11780:     return String.valueOf (FMT_TEMP, 0, 8);
 11781:   }  //fmtBin8(int)
 11782:   public static StringBuilder fmtAin8 (StringBuilder sb, int x) {
 11783:     FMT_TEMP[ 0] = (char) (x >>  5 & 4 ^ 46);
 11784:     FMT_TEMP[ 1] = (char) (x >>  4 & 4 ^ 46);
 11785:     FMT_TEMP[ 2] = (char) (x >>  3 & 4 ^ 46);
 11786:     FMT_TEMP[ 3] = (char) (x >>  2 & 4 ^ 46);
 11787:     FMT_TEMP[ 4] = (char) (x >>  1 & 4 ^ 46);
 11788:     FMT_TEMP[ 5] = (char) (x       & 4 ^ 46);
 11789:     FMT_TEMP[ 6] = (char) (x <<  1 & 4 ^ 46);
 11790:     FMT_TEMP[ 7] = (char) (x <<  2 & 4 ^ 46);
 11791:     return sb.append (FMT_TEMP, 0, 8);
 11792:   }  //fmtAin8(StringBuilder,int)
 11793:   public static StringBuilder fmtBin8 (StringBuilder sb, int x) {
 11794:     FMT_TEMP[ 0] = (char) (x >>>  7 & 1 | 48);
 11795:     FMT_TEMP[ 1] = (char) (x >>>  6 & 1 | 48);
 11796:     FMT_TEMP[ 2] = (char) (x >>>  5 & 1 | 48);
 11797:     FMT_TEMP[ 3] = (char) (x >>>  4 & 1 | 48);
 11798:     FMT_TEMP[ 4] = (char) (x >>>  3 & 1 | 48);
 11799:     FMT_TEMP[ 5] = (char) (x >>>  2 & 1 | 48);
 11800:     FMT_TEMP[ 6] = (char) (x >>>  1 & 1 | 48);
 11801:     FMT_TEMP[ 7] = (char) (x        & 1 | 48);
 11802:     return sb.append (FMT_TEMP, 0, 8);
 11803:   }  //fmtBin8(StringBuilder,int)
 11804: 
 11805:   //fmtAin12 (a, o, x)
 11806:   //fmtBin12 (a, o, x)
 11807:   //s = fmtAin12 (x)
 11808:   //s = fmtBin12 (x)
 11809:   //sb = fmtAin12 (sb, x)
 11810:   //sb = fmtBin12 (sb, x)
 11811:   //  12桁2進数変換
 11812:   public static void fmtAin12 (char[] a, int o, int x) {
 11813:     a[o     ] = (char) (x >>  9 & 4 ^ 46);
 11814:     a[o +  1] = (char) (x >>  8 & 4 ^ 46);
 11815:     a[o +  2] = (char) (x >>  7 & 4 ^ 46);
 11816:     a[o +  3] = (char) (x >>  6 & 4 ^ 46);
 11817:     a[o +  4] = (char) (x >>  5 & 4 ^ 46);
 11818:     a[o +  5] = (char) (x >>  4 & 4 ^ 46);
 11819:     a[o +  6] = (char) (x >>  3 & 4 ^ 46);
 11820:     a[o +  7] = (char) (x >>  2 & 4 ^ 46);
 11821:     a[o +  8] = (char) (x >>  1 & 4 ^ 46);
 11822:     a[o +  9] = (char) (x       & 4 ^ 46);
 11823:     a[o + 10] = (char) (x <<  1 & 4 ^ 46);
 11824:     a[o + 11] = (char) (x <<  2 & 4 ^ 46);
 11825:   }  //fmtAin12(char[],int,int)
 11826:   public static void fmtBin12 (char[] a, int o, int x) {
 11827:     a[o     ] = (char) (x >>> 11 & 1 | 48);
 11828:     a[o +  1] = (char) (x >>> 10 & 1 | 48);
 11829:     a[o +  2] = (char) (x >>>  9 & 1 | 48);
 11830:     a[o +  3] = (char) (x >>>  8 & 1 | 48);
 11831:     a[o +  4] = (char) (x >>>  7 & 1 | 48);
 11832:     a[o +  5] = (char) (x >>>  6 & 1 | 48);
 11833:     a[o +  6] = (char) (x >>>  5 & 1 | 48);
 11834:     a[o +  7] = (char) (x >>>  4 & 1 | 48);
 11835:     a[o +  8] = (char) (x >>>  3 & 1 | 48);
 11836:     a[o +  9] = (char) (x >>>  2 & 1 | 48);
 11837:     a[o + 10] = (char) (x >>>  1 & 1 | 48);
 11838:     a[o + 11] = (char) (x        & 1 | 48);
 11839:   }  //fmtBin12(char[],int,int)
 11840:   public static String fmtAin12 (int x) {
 11841:     FMT_TEMP[ 0] = (char) (x >>  9 & 4 ^ 46);
 11842:     FMT_TEMP[ 1] = (char) (x >>  8 & 4 ^ 46);
 11843:     FMT_TEMP[ 2] = (char) (x >>  7 & 4 ^ 46);
 11844:     FMT_TEMP[ 3] = (char) (x >>  6 & 4 ^ 46);
 11845:     FMT_TEMP[ 4] = (char) (x >>  5 & 4 ^ 46);
 11846:     FMT_TEMP[ 5] = (char) (x >>  4 & 4 ^ 46);
 11847:     FMT_TEMP[ 6] = (char) (x >>  3 & 4 ^ 46);
 11848:     FMT_TEMP[ 7] = (char) (x >>  2 & 4 ^ 46);
 11849:     FMT_TEMP[ 8] = (char) (x >>  1 & 4 ^ 46);
 11850:     FMT_TEMP[ 9] = (char) (x       & 4 ^ 46);
 11851:     FMT_TEMP[10] = (char) (x <<  1 & 4 ^ 46);
 11852:     FMT_TEMP[11] = (char) (x <<  2 & 4 ^ 46);
 11853:     return String.valueOf (FMT_TEMP, 0, 12);
 11854:   }  //fmtAin12(int)
 11855:   public static String fmtBin12 (int x) {
 11856:     FMT_TEMP[ 0] = (char) (x >>> 11 & 1 | 48);
 11857:     FMT_TEMP[ 1] = (char) (x >>> 10 & 1 | 48);
 11858:     FMT_TEMP[ 2] = (char) (x >>>  9 & 1 | 48);
 11859:     FMT_TEMP[ 3] = (char) (x >>>  8 & 1 | 48);
 11860:     FMT_TEMP[ 4] = (char) (x >>>  7 & 1 | 48);
 11861:     FMT_TEMP[ 5] = (char) (x >>>  6 & 1 | 48);
 11862:     FMT_TEMP[ 6] = (char) (x >>>  5 & 1 | 48);
 11863:     FMT_TEMP[ 7] = (char) (x >>>  4 & 1 | 48);
 11864:     FMT_TEMP[ 8] = (char) (x >>>  3 & 1 | 48);
 11865:     FMT_TEMP[ 9] = (char) (x >>>  2 & 1 | 48);
 11866:     FMT_TEMP[10] = (char) (x >>>  1 & 1 | 48);
 11867:     FMT_TEMP[11] = (char) (x        & 1 | 48);
 11868:     return String.valueOf (FMT_TEMP, 0, 12);
 11869:   }  //fmtBin12(int)
 11870:   public static StringBuilder fmtAin12 (StringBuilder sb, int x) {
 11871:     FMT_TEMP[ 0] = (char) (x >>  9 & 4 ^ 46);
 11872:     FMT_TEMP[ 1] = (char) (x >>  8 & 4 ^ 46);
 11873:     FMT_TEMP[ 2] = (char) (x >>  7 & 4 ^ 46);
 11874:     FMT_TEMP[ 3] = (char) (x >>  6 & 4 ^ 46);
 11875:     FMT_TEMP[ 4] = (char) (x >>  5 & 4 ^ 46);
 11876:     FMT_TEMP[ 5] = (char) (x >>  4 & 4 ^ 46);
 11877:     FMT_TEMP[ 6] = (char) (x >>  3 & 4 ^ 46);
 11878:     FMT_TEMP[ 7] = (char) (x >>  2 & 4 ^ 46);
 11879:     FMT_TEMP[ 8] = (char) (x >>  1 & 4 ^ 46);
 11880:     FMT_TEMP[ 9] = (char) (x       & 4 ^ 46);
 11881:     FMT_TEMP[10] = (char) (x <<  1 & 4 ^ 46);
 11882:     FMT_TEMP[11] = (char) (x <<  2 & 4 ^ 46);
 11883:     return sb.append (FMT_TEMP, 0, 12);
 11884:   }  //fmtAin12(StringBuilder,int)
 11885:   public static StringBuilder fmtBin12 (StringBuilder sb, int x) {
 11886:     FMT_TEMP[ 0] = (char) (x >>> 11 & 1 | 48);
 11887:     FMT_TEMP[ 1] = (char) (x >>> 10 & 1 | 48);
 11888:     FMT_TEMP[ 2] = (char) (x >>>  9 & 1 | 48);
 11889:     FMT_TEMP[ 3] = (char) (x >>>  8 & 1 | 48);
 11890:     FMT_TEMP[ 4] = (char) (x >>>  7 & 1 | 48);
 11891:     FMT_TEMP[ 5] = (char) (x >>>  6 & 1 | 48);
 11892:     FMT_TEMP[ 6] = (char) (x >>>  5 & 1 | 48);
 11893:     FMT_TEMP[ 7] = (char) (x >>>  4 & 1 | 48);
 11894:     FMT_TEMP[ 8] = (char) (x >>>  3 & 1 | 48);
 11895:     FMT_TEMP[ 9] = (char) (x >>>  2 & 1 | 48);
 11896:     FMT_TEMP[10] = (char) (x >>>  1 & 1 | 48);
 11897:     FMT_TEMP[11] = (char) (x        & 1 | 48);
 11898:     return sb.append (FMT_TEMP, 0, 12);
 11899:   }  //fmtBin12(StringBuilder,int)
 11900: 
 11901:   //fmtAin16 (a, o, x)
 11902:   //fmtBin16 (a, o, x)
 11903:   //s = fmtAin16 (x)
 11904:   //s = fmtBin16 (x)
 11905:   //sb = fmtAin16 (sb, x)
 11906:   //sb = fmtBin16 (sb, x)
 11907:   //  16桁2進数変換
 11908:   public static void fmtAin16 (char[] a, int o, int x) {
 11909:     a[o     ] = (char) (x >> 13 & 4 ^ 46);
 11910:     a[o +  1] = (char) (x >> 12 & 4 ^ 46);
 11911:     a[o +  2] = (char) (x >> 11 & 4 ^ 46);
 11912:     a[o +  3] = (char) (x >> 10 & 4 ^ 46);
 11913:     a[o +  4] = (char) (x >>  9 & 4 ^ 46);
 11914:     a[o +  5] = (char) (x >>  8 & 4 ^ 46);
 11915:     a[o +  6] = (char) (x >>  7 & 4 ^ 46);
 11916:     a[o +  7] = (char) (x >>  6 & 4 ^ 46);
 11917:     a[o +  8] = (char) (x >>  5 & 4 ^ 46);
 11918:     a[o +  9] = (char) (x >>  4 & 4 ^ 46);
 11919:     a[o + 10] = (char) (x >>  3 & 4 ^ 46);
 11920:     a[o + 11] = (char) (x >>  2 & 4 ^ 46);
 11921:     a[o + 12] = (char) (x >>  1 & 4 ^ 46);
 11922:     a[o + 13] = (char) (x       & 4 ^ 46);
 11923:     a[o + 14] = (char) (x <<  1 & 4 ^ 46);
 11924:     a[o + 15] = (char) (x <<  2 & 4 ^ 46);
 11925:   }  //fmtAin16(char[],int,int)
 11926:   public static void fmtBin16 (char[] a, int o, int x) {
 11927:     a[o     ] = (char) (x >>> 15 & 1 | 48);
 11928:     a[o +  1] = (char) (x >>> 14 & 1 | 48);
 11929:     a[o +  2] = (char) (x >>> 13 & 1 | 48);
 11930:     a[o +  3] = (char) (x >>> 12 & 1 | 48);
 11931:     a[o +  4] = (char) (x >>> 11 & 1 | 48);
 11932:     a[o +  5] = (char) (x >>> 10 & 1 | 48);
 11933:     a[o +  6] = (char) (x >>>  9 & 1 | 48);
 11934:     a[o +  7] = (char) (x >>>  8 & 1 | 48);
 11935:     a[o +  8] = (char) (x >>>  7 & 1 | 48);
 11936:     a[o +  9] = (char) (x >>>  6 & 1 | 48);
 11937:     a[o + 10] = (char) (x >>>  5 & 1 | 48);
 11938:     a[o + 11] = (char) (x >>>  4 & 1 | 48);
 11939:     a[o + 12] = (char) (x >>>  3 & 1 | 48);
 11940:     a[o + 13] = (char) (x >>>  2 & 1 | 48);
 11941:     a[o + 14] = (char) (x >>>  1 & 1 | 48);
 11942:     a[o + 15] = (char) (x        & 1 | 48);
 11943:   }  //fmtBin16(char[],int,int)
 11944:   public static String fmtAin16 (int x) {
 11945:     FMT_TEMP[ 0] = (char) (x >> 13 & 4 ^ 46);
 11946:     FMT_TEMP[ 1] = (char) (x >> 12 & 4 ^ 46);
 11947:     FMT_TEMP[ 2] = (char) (x >> 11 & 4 ^ 46);
 11948:     FMT_TEMP[ 3] = (char) (x >> 10 & 4 ^ 46);
 11949:     FMT_TEMP[ 4] = (char) (x >>  9 & 4 ^ 46);
 11950:     FMT_TEMP[ 5] = (char) (x >>  8 & 4 ^ 46);
 11951:     FMT_TEMP[ 6] = (char) (x >>  7 & 4 ^ 46);
 11952:     FMT_TEMP[ 7] = (char) (x >>  6 & 4 ^ 46);
 11953:     FMT_TEMP[ 8] = (char) (x >>  5 & 4 ^ 46);
 11954:     FMT_TEMP[ 9] = (char) (x >>  4 & 4 ^ 46);
 11955:     FMT_TEMP[10] = (char) (x >>  3 & 4 ^ 46);
 11956:     FMT_TEMP[11] = (char) (x >>  2 & 4 ^ 46);
 11957:     FMT_TEMP[12] = (char) (x >>  1 & 4 ^ 46);
 11958:     FMT_TEMP[13] = (char) (x       & 4 ^ 46);
 11959:     FMT_TEMP[14] = (char) (x <<  1 & 4 ^ 46);
 11960:     FMT_TEMP[15] = (char) (x <<  2 & 4 ^ 46);
 11961:     return String.valueOf (FMT_TEMP, 0, 16);
 11962:   }  //fmtAin16(int)
 11963:   public static String fmtBin16 (int x) {
 11964:     FMT_TEMP[ 0] = (char) (x >>> 15 & 1 | 48);
 11965:     FMT_TEMP[ 1] = (char) (x >>> 14 & 1 | 48);
 11966:     FMT_TEMP[ 2] = (char) (x >>> 13 & 1 | 48);
 11967:     FMT_TEMP[ 3] = (char) (x >>> 12 & 1 | 48);
 11968:     FMT_TEMP[ 4] = (char) (x >>> 11 & 1 | 48);
 11969:     FMT_TEMP[ 5] = (char) (x >>> 10 & 1 | 48);
 11970:     FMT_TEMP[ 6] = (char) (x >>>  9 & 1 | 48);
 11971:     FMT_TEMP[ 7] = (char) (x >>>  8 & 1 | 48);
 11972:     FMT_TEMP[ 8] = (char) (x >>>  7 & 1 | 48);
 11973:     FMT_TEMP[ 9] = (char) (x >>>  6 & 1 | 48);
 11974:     FMT_TEMP[10] = (char) (x >>>  5 & 1 | 48);
 11975:     FMT_TEMP[11] = (char) (x >>>  4 & 1 | 48);
 11976:     FMT_TEMP[12] = (char) (x >>>  3 & 1 | 48);
 11977:     FMT_TEMP[13] = (char) (x >>>  2 & 1 | 48);
 11978:     FMT_TEMP[14] = (char) (x >>>  1 & 1 | 48);
 11979:     FMT_TEMP[15] = (char) (x        & 1 | 48);
 11980:     return String.valueOf (FMT_TEMP, 0, 16);
 11981:   }  //fmtBin16(int)
 11982:   public static StringBuilder fmtAin16 (StringBuilder sb, int x) {
 11983:     FMT_TEMP[ 0] = (char) (x >> 13 & 4 ^ 46);
 11984:     FMT_TEMP[ 1] = (char) (x >> 12 & 4 ^ 46);
 11985:     FMT_TEMP[ 2] = (char) (x >> 11 & 4 ^ 46);
 11986:     FMT_TEMP[ 3] = (char) (x >> 10 & 4 ^ 46);
 11987:     FMT_TEMP[ 4] = (char) (x >>  9 & 4 ^ 46);
 11988:     FMT_TEMP[ 5] = (char) (x >>  8 & 4 ^ 46);
 11989:     FMT_TEMP[ 6] = (char) (x >>  7 & 4 ^ 46);
 11990:     FMT_TEMP[ 7] = (char) (x >>  6 & 4 ^ 46);
 11991:     FMT_TEMP[ 8] = (char) (x >>  5 & 4 ^ 46);
 11992:     FMT_TEMP[ 9] = (char) (x >>  4 & 4 ^ 46);
 11993:     FMT_TEMP[10] = (char) (x >>  3 & 4 ^ 46);
 11994:     FMT_TEMP[11] = (char) (x >>  2 & 4 ^ 46);
 11995:     FMT_TEMP[12] = (char) (x >>  1 & 4 ^ 46);
 11996:     FMT_TEMP[13] = (char) (x       & 4 ^ 46);
 11997:     FMT_TEMP[14] = (char) (x <<  1 & 4 ^ 46);
 11998:     FMT_TEMP[15] = (char) (x <<  2 & 4 ^ 46);
 11999:     return sb.append (FMT_TEMP, 0, 16);
 12000:   }  //fmtAin16(StringBuilder,int)
 12001:   public static StringBuilder fmtBin16 (StringBuilder sb, int x) {
 12002:     FMT_TEMP[ 0] = (char) (x >>> 15 & 1 | 48);
 12003:     FMT_TEMP[ 1] = (char) (x >>> 14 & 1 | 48);
 12004:     FMT_TEMP[ 2] = (char) (x >>> 13 & 1 | 48);
 12005:     FMT_TEMP[ 3] = (char) (x >>> 12 & 1 | 48);
 12006:     FMT_TEMP[ 4] = (char) (x >>> 11 & 1 | 48);
 12007:     FMT_TEMP[ 5] = (char) (x >>> 10 & 1 | 48);
 12008:     FMT_TEMP[ 6] = (char) (x >>>  9 & 1 | 48);
 12009:     FMT_TEMP[ 7] = (char) (x >>>  8 & 1 | 48);
 12010:     FMT_TEMP[ 8] = (char) (x >>>  7 & 1 | 48);
 12011:     FMT_TEMP[ 9] = (char) (x >>>  6 & 1 | 48);
 12012:     FMT_TEMP[10] = (char) (x >>>  5 & 1 | 48);
 12013:     FMT_TEMP[11] = (char) (x >>>  4 & 1 | 48);
 12014:     FMT_TEMP[12] = (char) (x >>>  3 & 1 | 48);
 12015:     FMT_TEMP[13] = (char) (x >>>  2 & 1 | 48);
 12016:     FMT_TEMP[14] = (char) (x >>>  1 & 1 | 48);
 12017:     FMT_TEMP[15] = (char) (x        & 1 | 48);
 12018:     return sb.append (FMT_TEMP, 0, 16);
 12019:   }  //fmtBin16(StringBuilder,int)
 12020: 
 12021:   //fmtAin24 (a, o, x)
 12022:   //fmtBin24 (a, o, x)
 12023:   //s = fmtAin24 (x)
 12024:   //s = fmtBin24 (x)
 12025:   //sb = fmtAin24 (sb, x)
 12026:   //sb = fmtBin24 (sb, x)
 12027:   //  24桁2進数変換
 12028:   public static void fmtAin24 (char[] a, int o, int x) {
 12029:     a[o     ] = (char) (x >> 21 & 4 ^ 46);
 12030:     a[o +  1] = (char) (x >> 20 & 4 ^ 46);
 12031:     a[o +  2] = (char) (x >> 19 & 4 ^ 46);
 12032:     a[o +  3] = (char) (x >> 18 & 4 ^ 46);
 12033:     a[o +  4] = (char) (x >> 17 & 4 ^ 46);
 12034:     a[o +  5] = (char) (x >> 16 & 4 ^ 46);
 12035:     a[o +  6] = (char) (x >> 15 & 4 ^ 46);
 12036:     a[o +  7] = (char) (x >> 14 & 4 ^ 46);
 12037:     a[o +  8] = (char) (x >> 13 & 4 ^ 46);
 12038:     a[o +  9] = (char) (x >> 12 & 4 ^ 46);
 12039:     a[o + 10] = (char) (x >> 11 & 4 ^ 46);
 12040:     a[o + 11] = (char) (x >> 10 & 4 ^ 46);
 12041:     a[o + 12] = (char) (x >>  9 & 4 ^ 46);
 12042:     a[o + 13] = (char) (x >>  8 & 4 ^ 46);
 12043:     a[o + 14] = (char) (x >>  7 & 4 ^ 46);
 12044:     a[o + 15] = (char) (x >>  6 & 4 ^ 46);
 12045:     a[o + 16] = (char) (x >>  5 & 4 ^ 46);
 12046:     a[o + 17] = (char) (x >>  4 & 4 ^ 46);
 12047:     a[o + 18] = (char) (x >>  3 & 4 ^ 46);
 12048:     a[o + 19] = (char) (x >>  2 & 4 ^ 46);
 12049:     a[o + 20] = (char) (x >>  1 & 4 ^ 46);
 12050:     a[o + 21] = (char) (x       & 4 ^ 46);
 12051:     a[o + 22] = (char) (x <<  1 & 4 ^ 46);
 12052:     a[o + 23] = (char) (x <<  2 & 4 ^ 46);
 12053:   }  //fmtAin24(char[],int,int)
 12054:   public static void fmtBin24 (char[] a, int o, int x) {
 12055:     a[o     ] = (char) (x >>> 23 & 1 | 48);
 12056:     a[o +  1] = (char) (x >>> 22 & 1 | 48);
 12057:     a[o +  2] = (char) (x >>> 21 & 1 | 48);
 12058:     a[o +  3] = (char) (x >>> 20 & 1 | 48);
 12059:     a[o +  4] = (char) (x >>> 19 & 1 | 48);
 12060:     a[o +  5] = (char) (x >>> 18 & 1 | 48);
 12061:     a[o +  6] = (char) (x >>> 17 & 1 | 48);
 12062:     a[o +  7] = (char) (x >>> 16 & 1 | 48);
 12063:     a[o +  8] = (char) (x >>> 15 & 1 | 48);
 12064:     a[o +  9] = (char) (x >>> 14 & 1 | 48);
 12065:     a[o + 10] = (char) (x >>> 13 & 1 | 48);
 12066:     a[o + 11] = (char) (x >>> 12 & 1 | 48);
 12067:     a[o + 12] = (char) (x >>> 11 & 1 | 48);
 12068:     a[o + 13] = (char) (x >>> 10 & 1 | 48);
 12069:     a[o + 14] = (char) (x >>>  9 & 1 | 48);
 12070:     a[o + 15] = (char) (x >>>  8 & 1 | 48);
 12071:     a[o + 16] = (char) (x >>>  7 & 1 | 48);
 12072:     a[o + 17] = (char) (x >>>  6 & 1 | 48);
 12073:     a[o + 18] = (char) (x >>>  5 & 1 | 48);
 12074:     a[o + 19] = (char) (x >>>  4 & 1 | 48);
 12075:     a[o + 20] = (char) (x >>>  3 & 1 | 48);
 12076:     a[o + 21] = (char) (x >>>  2 & 1 | 48);
 12077:     a[o + 22] = (char) (x >>>  1 & 1 | 48);
 12078:     a[o + 23] = (char) (x        & 1 | 48);
 12079:   }  //fmtBin24(char[],int,int)
 12080:   public static String fmtAin24 (int x) {
 12081:     FMT_TEMP[ 0] = (char) (x >> 21 & 4 ^ 46);
 12082:     FMT_TEMP[ 1] = (char) (x >> 20 & 4 ^ 46);
 12083:     FMT_TEMP[ 2] = (char) (x >> 19 & 4 ^ 46);
 12084:     FMT_TEMP[ 3] = (char) (x >> 18 & 4 ^ 46);
 12085:     FMT_TEMP[ 4] = (char) (x >> 17 & 4 ^ 46);
 12086:     FMT_TEMP[ 5] = (char) (x >> 16 & 4 ^ 46);
 12087:     FMT_TEMP[ 6] = (char) (x >> 15 & 4 ^ 46);
 12088:     FMT_TEMP[ 7] = (char) (x >> 14 & 4 ^ 46);
 12089:     FMT_TEMP[ 8] = (char) (x >> 13 & 4 ^ 46);
 12090:     FMT_TEMP[ 9] = (char) (x >> 12 & 4 ^ 46);
 12091:     FMT_TEMP[10] = (char) (x >> 11 & 4 ^ 46);
 12092:     FMT_TEMP[11] = (char) (x >> 10 & 4 ^ 46);
 12093:     FMT_TEMP[12] = (char) (x >>  9 & 4 ^ 46);
 12094:     FMT_TEMP[13] = (char) (x >>  8 & 4 ^ 46);
 12095:     FMT_TEMP[14] = (char) (x >>  7 & 4 ^ 46);
 12096:     FMT_TEMP[15] = (char) (x >>  6 & 4 ^ 46);
 12097:     FMT_TEMP[16] = (char) (x >>  5 & 4 ^ 46);
 12098:     FMT_TEMP[17] = (char) (x >>  4 & 4 ^ 46);
 12099:     FMT_TEMP[18] = (char) (x >>  3 & 4 ^ 46);
 12100:     FMT_TEMP[19] = (char) (x >>  2 & 4 ^ 46);
 12101:     FMT_TEMP[20] = (char) (x >>  1 & 4 ^ 46);
 12102:     FMT_TEMP[21] = (char) (x       & 4 ^ 46);
 12103:     FMT_TEMP[22] = (char) (x <<  1 & 4 ^ 46);
 12104:     FMT_TEMP[23] = (char) (x <<  2 & 4 ^ 46);
 12105:     return String.valueOf (FMT_TEMP, 0, 24);
 12106:   }  //fmtAin24(int)
 12107:   public static String fmtBin24 (int x) {
 12108:     FMT_TEMP[ 0] = (char) (x >>> 23 & 1 | 48);
 12109:     FMT_TEMP[ 1] = (char) (x >>> 22 & 1 | 48);
 12110:     FMT_TEMP[ 2] = (char) (x >>> 21 & 1 | 48);
 12111:     FMT_TEMP[ 3] = (char) (x >>> 20 & 1 | 48);
 12112:     FMT_TEMP[ 4] = (char) (x >>> 19 & 1 | 48);
 12113:     FMT_TEMP[ 5] = (char) (x >>> 18 & 1 | 48);
 12114:     FMT_TEMP[ 6] = (char) (x >>> 17 & 1 | 48);
 12115:     FMT_TEMP[ 7] = (char) (x >>> 16 & 1 | 48);
 12116:     FMT_TEMP[ 8] = (char) (x >>> 15 & 1 | 48);
 12117:     FMT_TEMP[ 9] = (char) (x >>> 14 & 1 | 48);
 12118:     FMT_TEMP[10] = (char) (x >>> 13 & 1 | 48);
 12119:     FMT_TEMP[11] = (char) (x >>> 12 & 1 | 48);
 12120:     FMT_TEMP[12] = (char) (x >>> 11 & 1 | 48);
 12121:     FMT_TEMP[13] = (char) (x >>> 10 & 1 | 48);
 12122:     FMT_TEMP[14] = (char) (x >>>  9 & 1 | 48);
 12123:     FMT_TEMP[15] = (char) (x >>>  8 & 1 | 48);
 12124:     FMT_TEMP[16] = (char) (x >>>  7 & 1 | 48);
 12125:     FMT_TEMP[17] = (char) (x >>>  6 & 1 | 48);
 12126:     FMT_TEMP[18] = (char) (x >>>  5 & 1 | 48);
 12127:     FMT_TEMP[19] = (char) (x >>>  4 & 1 | 48);
 12128:     FMT_TEMP[20] = (char) (x >>>  3 & 1 | 48);
 12129:     FMT_TEMP[21] = (char) (x >>>  2 & 1 | 48);
 12130:     FMT_TEMP[22] = (char) (x >>>  1 & 1 | 48);
 12131:     FMT_TEMP[23] = (char) (x        & 1 | 48);
 12132:     return String.valueOf (FMT_TEMP, 0, 24);
 12133:   }  //fmtBin24(int)
 12134:   public static StringBuilder fmtAin24 (StringBuilder sb, int x) {
 12135:     FMT_TEMP[ 0] = (char) (x >> 21 & 4 ^ 46);
 12136:     FMT_TEMP[ 1] = (char) (x >> 20 & 4 ^ 46);
 12137:     FMT_TEMP[ 2] = (char) (x >> 19 & 4 ^ 46);
 12138:     FMT_TEMP[ 3] = (char) (x >> 18 & 4 ^ 46);
 12139:     FMT_TEMP[ 4] = (char) (x >> 17 & 4 ^ 46);
 12140:     FMT_TEMP[ 5] = (char) (x >> 16 & 4 ^ 46);
 12141:     FMT_TEMP[ 6] = (char) (x >> 15 & 4 ^ 46);
 12142:     FMT_TEMP[ 7] = (char) (x >> 14 & 4 ^ 46);
 12143:     FMT_TEMP[ 8] = (char) (x >> 13 & 4 ^ 46);
 12144:     FMT_TEMP[ 9] = (char) (x >> 12 & 4 ^ 46);
 12145:     FMT_TEMP[10] = (char) (x >> 11 & 4 ^ 46);
 12146:     FMT_TEMP[11] = (char) (x >> 10 & 4 ^ 46);
 12147:     FMT_TEMP[12] = (char) (x >>  9 & 4 ^ 46);
 12148:     FMT_TEMP[13] = (char) (x >>  8 & 4 ^ 46);
 12149:     FMT_TEMP[14] = (char) (x >>  7 & 4 ^ 46);
 12150:     FMT_TEMP[15] = (char) (x >>  6 & 4 ^ 46);
 12151:     FMT_TEMP[16] = (char) (x >>  5 & 4 ^ 46);
 12152:     FMT_TEMP[17] = (char) (x >>  4 & 4 ^ 46);
 12153:     FMT_TEMP[18] = (char) (x >>  3 & 4 ^ 46);
 12154:     FMT_TEMP[19] = (char) (x >>  2 & 4 ^ 46);
 12155:     FMT_TEMP[20] = (char) (x >>  1 & 4 ^ 46);
 12156:     FMT_TEMP[21] = (char) (x       & 4 ^ 46);
 12157:     FMT_TEMP[22] = (char) (x <<  1 & 4 ^ 46);
 12158:     FMT_TEMP[23] = (char) (x <<  2 & 4 ^ 46);
 12159:     return sb.append (FMT_TEMP, 0, 24);
 12160:   }  //fmtAin24(StringBuilder,int)
 12161:   public static StringBuilder fmtBin24 (StringBuilder sb, int x) {
 12162:     FMT_TEMP[ 0] = (char) (x >>> 23 & 1 | 48);
 12163:     FMT_TEMP[ 1] = (char) (x >>> 22 & 1 | 48);
 12164:     FMT_TEMP[ 2] = (char) (x >>> 21 & 1 | 48);
 12165:     FMT_TEMP[ 3] = (char) (x >>> 20 & 1 | 48);
 12166:     FMT_TEMP[ 4] = (char) (x >>> 19 & 1 | 48);
 12167:     FMT_TEMP[ 5] = (char) (x >>> 18 & 1 | 48);
 12168:     FMT_TEMP[ 6] = (char) (x >>> 17 & 1 | 48);
 12169:     FMT_TEMP[ 7] = (char) (x >>> 16 & 1 | 48);
 12170:     FMT_TEMP[ 8] = (char) (x >>> 15 & 1 | 48);
 12171:     FMT_TEMP[ 9] = (char) (x >>> 14 & 1 | 48);
 12172:     FMT_TEMP[10] = (char) (x >>> 13 & 1 | 48);
 12173:     FMT_TEMP[11] = (char) (x >>> 12 & 1 | 48);
 12174:     FMT_TEMP[12] = (char) (x >>> 11 & 1 | 48);
 12175:     FMT_TEMP[13] = (char) (x >>> 10 & 1 | 48);
 12176:     FMT_TEMP[14] = (char) (x >>>  9 & 1 | 48);
 12177:     FMT_TEMP[15] = (char) (x >>>  8 & 1 | 48);
 12178:     FMT_TEMP[16] = (char) (x >>>  7 & 1 | 48);
 12179:     FMT_TEMP[17] = (char) (x >>>  6 & 1 | 48);
 12180:     FMT_TEMP[18] = (char) (x >>>  5 & 1 | 48);
 12181:     FMT_TEMP[19] = (char) (x >>>  4 & 1 | 48);
 12182:     FMT_TEMP[20] = (char) (x >>>  3 & 1 | 48);
 12183:     FMT_TEMP[21] = (char) (x >>>  2 & 1 | 48);
 12184:     FMT_TEMP[22] = (char) (x >>>  1 & 1 | 48);
 12185:     FMT_TEMP[23] = (char) (x        & 1 | 48);
 12186:     return sb.append (FMT_TEMP, 0, 24);
 12187:   }  //fmtBin24(StringBuilder,int)
 12188: 
 12189:   //--------------------------------------------------------------------------------
 12190:   //16進数変換
 12191:   //
 12192:   //       x               00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
 12193:   //     9-x               09 08 07 06 05 04 03 02 01 00 ff fe fd fc fb fa
 12194:   //    (9-x)>>4           00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff
 12195:   //   ((9-x)>>4)&7        00 00 00 00 00 00 00 00 00 00 07 07 07 07 07 07
 12196:   //  (((9-x)>>4)&7)+48    30 30 30 30 30 30 30 30 30 30 37 37 37 37 37 37
 12197:   //  (((9-x)>>4)&7)+48+x  30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46
 12198:   //                        0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
 12199:   //
 12200:   //       x                00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
 12201:   //     9-x                09 08 07 06 05 04 03 02 01 00 ff fe fd fc fb fa
 12202:   //    (9-x)>>4            00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff
 12203:   //   ((9-x)>>4)&39        00 00 00 00 00 00 00 00 00 00 27 27 27 27 27 27
 12204:   //  (((9-x)>>4)&39)+48    30 30 30 30 30 30 30 30 30 30 57 57 57 57 57 57
 12205:   //  (((9-x)>>4)&39)+48+x  30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66
 12206:   //                         0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
 12207:   //
 12208:   //                c               30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 61 62 63 64 65 66
 12209:   //             64-c               10 0f 0e 0d 0c 0b 0a 09 08 07 ff fe fd fc fb fa df de dd dc db da
 12210:   //            (64-c)>>8           00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff
 12211:   //           ((64-c)>>8)&39       00 00 00 00 00 00 00 00 00 00 27 27 27 27 27 27 27 27 27 27 27 27
 12212:   //          (((64-c)>>8)&39)+48   30 30 30 30 30 30 30 30 30 30 57 57 57 57 57 57 57 57 57 57 57 57
 12213:   //   c|32                         30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66 61 62 63 64 65 66
 12214:   //  (c|32)-((((64-c)>>8)&39)+48)  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 0a 0b 0c 0d 0e 0f
 12215: 
 12216:   //c = fmtHexc (x)
 12217:   //a = fmtHex1 (a, o, x)
 12218:   //s = fmtHex1 (x)
 12219:   //sb = fmtHex1 (sb, x)
 12220:   //  1桁16進数変換
 12221:   public static char fmtHexc (int x) {
 12222:     x &= 15;
 12223:     return (char) ((((9 - x) >> 4) & 7) + 48 + x);
 12224:   }  //fmtHexc(int)
 12225:   public static void fmtHex1 (char[] a, int o, int x) {
 12226:     x &= 15;
 12227:     a[o] = (char) ((((9 - x) >> 4) & 7) + 48 + x);
 12228:   }  //fmtHex1(char[],int,int)
 12229:   public static String fmtHex1 (int x) {
 12230:     x &= 15;
 12231:     return Character.toString ((char) ((((9 - x) >> 4) & 7) + 48 + x));
 12232:   }  //fmtHex1(int)
 12233:   public static StringBuilder fmtHex1 (StringBuilder sb, int x) {
 12234:     x &= 15;
 12235:     return sb.append ((char) ((((9 - x) >> 4) & 7) + 48 + x));
 12236:   }  //fmtHex1(StringBuilder,int)
 12237: 
 12238:   //fmtHex2 (a, o, x)
 12239:   //s = fmtHex2 (x)
 12240:   //sb = fmtHex2 (sb, x)
 12241:   //  2桁16進数変換
 12242:   //  byte用
 12243:   public static void fmtHex2 (char[] a, int o, int x) {
 12244:     int x0 = x        & 15;
 12245:     int x1 = x >>>  4 & 15;
 12246:     a[o    ] = (char) ((((9 - x1) >> 4) & 7) + 48 + x1);
 12247:     a[o + 1] = (char) ((((9 - x0) >> 4) & 7) + 48 + x0);
 12248:   }  //fmtHex2(char[],int,int)
 12249:   public static String fmtHex2 (int x) {
 12250:     //fmtHex2 (FMT_TEMP, 0, x);
 12251:     int x0 = x        & 15;
 12252:     int x1 = x >>>  4 & 15;
 12253:     FMT_TEMP[0] = (char) ((((9 - x1) >> 4) & 7) + 48 + x1);
 12254:     FMT_TEMP[1] = (char) ((((9 - x0) >> 4) & 7) + 48 + x0);
 12255:     return String.valueOf (FMT_TEMP, 0, 2);
 12256:   }  //fmtHex2(int)
 12257:   public static StringBuilder fmtHex2 (StringBuilder sb, int x) {
 12258:     int x0 = x        & 15;
 12259:     int x1 = x >>>  4 & 15;
 12260:     return (sb.
 12261:             append ((char) ((((9 - x1) >> 4) & 7) + 48 + x1)).
 12262:             append ((char) ((((9 - x0) >> 4) & 7) + 48 + x0)));
 12263:   }  //fmtHex2(StringBuilder,int)
 12264: 
 12265:   //fmtHex4 (a, o, x)
 12266:   //s = fmtHex4 (x)
 12267:   //sb = fmtHex4 (sb, x)
 12268:   //  4桁16進数変換
 12269:   //  word用
 12270:   public static void fmtHex4 (char[] a, int o, int x) {
 12271:     int t;
 12272:     t = (char) x >>> 12;
 12273:     a[o    ] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12274:     t =        x >>>  8 & 15;
 12275:     a[o + 1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12276:     t =        x >>>  4 & 15;
 12277:     a[o + 2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12278:     t =        x        & 15;
 12279:     a[o + 3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12280:   }  //fmtHex4(char[],int,int)
 12281:   public static String fmtHex4 (int x) {
 12282:     //fmtHex4 (FMT_TEMP, 0, x);
 12283:     int t;
 12284:     t = (char) x >>> 12;
 12285:     FMT_TEMP[0] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12286:     t =        x >>>  8 & 15;
 12287:     FMT_TEMP[1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12288:     t =        x >>>  4 & 15;
 12289:     FMT_TEMP[2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12290:     t =        x        & 15;
 12291:     FMT_TEMP[3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12292:     return String.valueOf (FMT_TEMP, 0, 4);
 12293:   }  //fmtHex4(int)
 12294:   public static StringBuilder fmtHex4 (StringBuilder sb, int x) {
 12295:     //fmtHex4 (FMT_TEMP, 0, x);
 12296:     int t;
 12297:     t = (char) x >>> 12;
 12298:     FMT_TEMP[0] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12299:     t =        x >>>  8 & 15;
 12300:     FMT_TEMP[1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12301:     t =        x >>>  4 & 15;
 12302:     FMT_TEMP[2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12303:     t =        x        & 15;
 12304:     FMT_TEMP[3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12305:     return sb.append (FMT_TEMP, 0, 4);
 12306:   }  //fmtHex4(StringBuilder,int)
 12307: 
 12308:   //fmtHex6 (a, o, x)
 12309:   //s = fmtHex6 (x)
 12310:   //sb = fmtHex6 (sb, x)
 12311:   //  6桁16進数変換
 12312:   //  rgb用
 12313:   public static void fmtHex6 (char[] a, int o, int x) {
 12314:     int t;
 12315:     t =        x >>> 20 & 15;
 12316:     a[o    ] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12317:     t =        x >>> 16 & 15;
 12318:     a[o + 1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12319:     t = (char) x >>> 12;
 12320:     a[o + 2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12321:     t =        x >>>  8 & 15;
 12322:     a[o + 3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12323:     t =        x >>>  4 & 15;
 12324:     a[o + 4] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12325:     t =        x        & 15;
 12326:     a[o + 5] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12327:   }  //fmtHex6(char[],int,int)
 12328:   public static String fmtHex6 (int x) {
 12329:     //fmtHex6 (FMT_TEMP, 0, x);
 12330:     int t;
 12331:     t =        x >>> 20 & 15;
 12332:     FMT_TEMP[0] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12333:     t =        x >>> 16 & 15;
 12334:     FMT_TEMP[1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12335:     t = (char) x >>> 12;
 12336:     FMT_TEMP[2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12337:     t =        x >>>  8 & 15;
 12338:     FMT_TEMP[3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12339:     t =        x >>>  4 & 15;
 12340:     FMT_TEMP[4] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12341:     t =        x        & 15;
 12342:     FMT_TEMP[5] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12343:     return String.valueOf (FMT_TEMP, 0, 6);
 12344:   }  //fmtHex6(int)
 12345:   public static StringBuilder fmtHex6 (StringBuilder sb, int x) {
 12346:     //fmtHex6 (FMT_TEMP, 0, x);
 12347:     int t;
 12348:     t =        x >>> 20 & 15;
 12349:     FMT_TEMP[0] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12350:     t =        x >>> 16 & 15;
 12351:     FMT_TEMP[1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12352:     t = (char) x >>> 12;
 12353:     FMT_TEMP[2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12354:     t =        x >>>  8 & 15;
 12355:     FMT_TEMP[3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12356:     t =        x >>>  4 & 15;
 12357:     FMT_TEMP[4] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12358:     t =        x        & 15;
 12359:     FMT_TEMP[5] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12360:     return sb.append (FMT_TEMP, 0, 6);
 12361:   }  //fmtHex6(StringBuilder,int)
 12362: 
 12363:   //fmtHex8 (a, o, x)
 12364:   //s = fmtHex8 (x)
 12365:   //sb = fmtHex8 (sb, x)
 12366:   //  8桁16進数変換
 12367:   //  argb,long用
 12368:   public static void fmtHex8 (char[] a, int o, int x) {
 12369:     int t;
 12370:     t =        x >>> 28;
 12371:     a[o    ] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12372:     t =        x >>> 24 & 15;
 12373:     a[o + 1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12374:     t =        x >>> 20 & 15;
 12375:     a[o + 2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12376:     t =        x >>> 16 & 15;
 12377:     a[o + 3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12378:     t = (char) x >>> 12;
 12379:     a[o + 4] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12380:     t =        x >>>  8 & 15;
 12381:     a[o + 5] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12382:     t =        x >>>  4 & 15;
 12383:     a[o + 6] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12384:     t =        x        & 15;
 12385:     a[o + 7] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12386:   }  //fmtHex8(char[],int,int)
 12387:   public static String fmtHex8 (int x) {
 12388:     //fmtHex8 (FMT_TEMP, 0, x);
 12389:     int t;
 12390:     t =        x >>> 28;
 12391:     FMT_TEMP[0] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12392:     t =        x >>> 24 & 15;
 12393:     FMT_TEMP[1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12394:     t =        x >>> 20 & 15;
 12395:     FMT_TEMP[2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12396:     t =        x >>> 16 & 15;
 12397:     FMT_TEMP[3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12398:     t = (char) x >>> 12;
 12399:     FMT_TEMP[4] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12400:     t =        x >>>  8 & 15;
 12401:     FMT_TEMP[5] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12402:     t =        x >>>  4 & 15;
 12403:     FMT_TEMP[6] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12404:     t =        x        & 15;
 12405:     FMT_TEMP[7] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12406:     return String.valueOf (FMT_TEMP, 0, 8);
 12407:   }  //fmtHex8(int)
 12408:   public static StringBuilder fmtHex8 (StringBuilder sb, int x) {
 12409:     //fmtHex8 (FMT_TEMP, 0, x);
 12410:     int t;
 12411:     t =        x >>> 28;
 12412:     FMT_TEMP[0] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12413:     t =        x >>> 24 & 15;
 12414:     FMT_TEMP[1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12415:     t =        x >>> 20 & 15;
 12416:     FMT_TEMP[2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12417:     t =        x >>> 16 & 15;
 12418:     FMT_TEMP[3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12419:     t = (char) x >>> 12;
 12420:     FMT_TEMP[4] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12421:     t =        x >>>  8 & 15;
 12422:     FMT_TEMP[5] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12423:     t =        x >>>  4 & 15;
 12424:     FMT_TEMP[6] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12425:     t =        x        & 15;
 12426:     FMT_TEMP[7] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12427:     return sb.append (FMT_TEMP, 0, 8);
 12428:   }  //fmtHex8(StringBuilder,int)
 12429: 
 12430:   public static StringBuilder fmtHex16 (StringBuilder sb, long x) {
 12431:     //fmtHex16 (FMT_TEMP, 0, x);
 12432:     int s, t;
 12433:     s = (int) (x >>> 32);
 12434:     t =        s >>> 28;
 12435:     FMT_TEMP[ 0] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12436:     t =        s >>> 24 & 15;
 12437:     FMT_TEMP[ 1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12438:     t =        s >>> 20 & 15;
 12439:     FMT_TEMP[ 2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12440:     t =        s >>> 16 & 15;
 12441:     FMT_TEMP[ 3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12442:     t = (char) s >>> 12;
 12443:     FMT_TEMP[ 4] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12444:     t =        s >>>  8 & 15;
 12445:     FMT_TEMP[ 5] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12446:     t =        s >>>  4 & 15;
 12447:     FMT_TEMP[ 6] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12448:     t =        s        & 15;
 12449:     FMT_TEMP[ 7] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12450:     s = (int)  x;
 12451:     t =        s >>> 28;
 12452:     FMT_TEMP[ 8] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12453:     t =        s >>> 24 & 15;
 12454:     FMT_TEMP[ 9] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12455:     t =        s >>> 20 & 15;
 12456:     FMT_TEMP[10] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12457:     t =        s >>> 16 & 15;
 12458:     FMT_TEMP[11] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12459:     t = (char) s >>> 12;
 12460:     FMT_TEMP[12] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12461:     t =        s >>>  8 & 15;
 12462:     FMT_TEMP[13] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12463:     t =        s >>>  4 & 15;
 12464:     FMT_TEMP[14] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12465:     t =        s        & 15;
 12466:     FMT_TEMP[15] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
 12467:     return sb.append (FMT_TEMP, 0, 16);
 12468:   }  //fmtHex16(StringBuilder,long)
 12469: 
 12470:   //--------------------------------------------------------------------------------
 12471:   //10進数変換
 12472:   //  除算は遅いので逆数乗算で商と余りを求めて下位から充填する
 12473:   //  x/yを計算する代わりにceil(pow(2,n)/y)を掛けてから右にnビットシフトする
 12474:   //  m=((1<<n)+y-1)/yとおくと0<=x<=((((m-1)/(m*y-(1<<n))+1)<<n)-1)/mの範囲でx/yはm*x>>nに置き換えられる
 12475:   //    >perl -e "use GMP::Mpz qw(:all);$y=mpz(10);for($n=mpz(0);$n<=31;$n++){$m=((1<<$n)+$y-1)/$y;$l=(((($m-1)/($m*$y-(1<<$n))+1)<<$n)-1)/$m;printf'x*%s>>%s (0<=x<=%s)%c',$m,$n,$l,10;}"
 12476:   //    x*1>>0 (0<=x<=0)
 12477:   //    x*1>>1 (0<=x<=1)
 12478:   //    x*1>>2 (0<=x<=3)
 12479:   //    x*1>>3 (0<=x<=7)
 12480:   //    x*2>>4 (0<=x<=7)
 12481:   //    x*4>>5 (0<=x<=7)
 12482:   //    x*7>>6 (0<=x<=18)
 12483:   //    x*13>>7 (0<=x<=68)
 12484:   //    x*26>>8 (0<=x<=68)
 12485:   //    x*52>>9 (0<=x<=68)
 12486:   //    x*103>>10 (0<=x<=178)  2桁
 12487:   //    x*205>>11 (0<=x<=1028)  3桁
 12488:   //    x*410>>12 (0<=x<=1028)
 12489:   //    x*820>>13 (0<=x<=1028)
 12490:   //    x*1639>>14 (0<=x<=2738)
 12491:   //    x*3277>>15 (0<=x<=16388)  4桁
 12492:   //    x*6554>>16 (0<=x<=16388)
 12493:   //    x*13108>>17 (0<=x<=16388)
 12494:   //    x*26215>>18 (0<=x<=43698)
 12495:   //    x*52429>>19 (0<=x<=262148)  5桁。ここからlong
 12496:   //    x*104858>>20 (0<=x<=262148)
 12497:   //    x*209716>>21 (0<=x<=262148)
 12498:   //    x*419431>>22 (0<=x<=699058)
 12499:   //    x*838861>>23 (0<=x<=4194308)  6桁
 12500:   //    x*1677722>>24 (0<=x<=4194308)
 12501:   //    x*3355444>>25 (0<=x<=4194308)
 12502:   //    x*6710887>>26 (0<=x<=11184818)  7桁
 12503:   //    x*13421773>>27 (0<=x<=67108868)
 12504:   //    x*26843546>>28 (0<=x<=67108868)
 12505:   //    x*53687092>>29 (0<=x<=67108868)
 12506:   //    x*107374183>>30 (0<=x<=178956978)  8桁
 12507:   //    x*214748365>>31 (0<=x<=1073741828)  9桁
 12508:   //
 12509:   //  検算
 12510:   //    >perl -e "use GMP::Mpz qw(:all);$y=mpz(10);for($n=mpz(0);$n<=23;$n++){$m=((1<<$n)+$y-1)/$y;$l=(((($m-1)/($m*$y-(1<<$n))+1)<<$n)-1)/$m;for($x=mpz(0);$x<=$l+1;$x++){$t=$m*$x>>$n;$z=$x/$y;if($z!=$t){printf'n=%d,m=%d,l=%d,x=%d,y=%d,z=%d,t=%d%c',$n,$m,$l,$x,$y,$z,$t,10;}}}"
 12511:   //    n=0,m=1,l=0,x=1,y=10,z=0,t=1
 12512:   //    n=1,m=1,l=1,x=2,y=10,z=0,t=1
 12513:   //    n=2,m=1,l=3,x=4,y=10,z=0,t=1
 12514:   //    n=3,m=1,l=7,x=8,y=10,z=0,t=1
 12515:   //    n=4,m=2,l=7,x=8,y=10,z=0,t=1
 12516:   //    n=5,m=4,l=7,x=8,y=10,z=0,t=1
 12517:   //    n=6,m=7,l=18,x=19,y=10,z=1,t=2
 12518:   //    n=7,m=13,l=68,x=69,y=10,z=6,t=7
 12519:   //    n=8,m=26,l=68,x=69,y=10,z=6,t=7
 12520:   //    n=9,m=52,l=68,x=69,y=10,z=6,t=7
 12521:   //    n=10,m=103,l=178,x=179,y=10,z=17,t=18
 12522:   //    n=11,m=205,l=1028,x=1029,y=10,z=102,t=103
 12523:   //    n=12,m=410,l=1028,x=1029,y=10,z=102,t=103
 12524:   //    n=13,m=820,l=1028,x=1029,y=10,z=102,t=103
 12525:   //    n=14,m=1639,l=2738,x=2739,y=10,z=273,t=274
 12526:   //    n=15,m=3277,l=16388,x=16389,y=10,z=1638,t=1639
 12527:   //    n=16,m=6554,l=16388,x=16389,y=10,z=1638,t=1639
 12528:   //    n=17,m=13108,l=16388,x=16389,y=10,z=1638,t=1639
 12529:   //    n=18,m=26215,l=43698,x=43699,y=10,z=4369,t=4370
 12530:   //    n=19,m=52429,l=262148,x=262149,y=10,z=26214,t=26215
 12531:   //    n=20,m=104858,l=262148,x=262149,y=10,z=26214,t=26215
 12532:   //    n=21,m=209716,l=262148,x=262149,y=10,z=26214,t=26215
 12533:   //    n=22,m=419431,l=699058,x=699059,y=10,z=69905,t=69906
 12534:   //    n=23,m=838861,l=4194308,x=4194309,y=10,z=419430,t=419431
 12535: 
 12536:   //  4桁まではあらかじめテーブルに展開しておく
 12537:   public static final int[] FMT_BCD4 = new int[10000];
 12538:   public static final int[] FMT_DCB4 = new int[65536];
 12539: 
 12540:   //--------------------------------------------------------------------------------
 12541:   //fmtInit ()
 12542:   //  初期化
 12543:   public static void fmtInit () {
 12544:     Arrays.fill (FMT_DCB4, -1);
 12545:     int i = 0;
 12546:     int x = 0;
 12547:     for (int a = 0; a < 10; a++) {
 12548:       for (int b = 0; b < 10; b++) {
 12549:         for (int c = 0; c < 10; c++) {
 12550:           FMT_DCB4[FMT_BCD4[i    ] = x    ] = i;
 12551:           FMT_DCB4[FMT_BCD4[i + 1] = x + 1] = i + 1;
 12552:           FMT_DCB4[FMT_BCD4[i + 2] = x + 2] = i + 2;
 12553:           FMT_DCB4[FMT_BCD4[i + 3] = x + 3] = i + 3;
 12554:           FMT_DCB4[FMT_BCD4[i + 4] = x + 4] = i + 4;
 12555:           FMT_DCB4[FMT_BCD4[i + 5] = x + 5] = i + 5;
 12556:           FMT_DCB4[FMT_BCD4[i + 6] = x + 6] = i + 6;
 12557:           FMT_DCB4[FMT_BCD4[i + 7] = x + 7] = i + 7;
 12558:           FMT_DCB4[FMT_BCD4[i + 8] = x + 8] = i + 8;
 12559:           FMT_DCB4[FMT_BCD4[i + 9] = x + 9] = i + 9;
 12560:           i += 10;
 12561:           x += 1 << 4;
 12562:         }
 12563:         x += 6 << 4;
 12564:       }
 12565:       x += 6 << 8;
 12566:     }
 12567:   }  //fmtInit()
 12568: 
 12569:   //y = fmtBcd4 (x)
 12570:   //  xを0~9999にクリッピングしてから4桁のBCDに変換する
 12571:   public static int fmtBcd4 (int x) {
 12572:     //x = Math.max (0, Math.min (9999, x));
 12573:     //perl optdiv.pl 9999 10
 12574:     //  x/10==x*3277>>>15 (0<=x<=16388) [9999*3277==32766723]
 12575:     //int t = x * 3277 >> 15;  //x/10
 12576:     //int y = x - t * 10;  //1の位
 12577:     //x = t * 3277 >> 15;  //x/100
 12578:     //y |= t - x * 10 << 4;  //10の位
 12579:     //t = x * 3277 >> 15;  //x/1000
 12580:     //return t << 12 | x - t * 10 << 8 | y;  //1000の位,100の位
 12581:     return FMT_BCD4[Math.max (0, Math.min (9999, x))];
 12582:   }  //fmtBcd4(int)
 12583: 
 12584:   //y = fmtBcd8 (x)
 12585:   //  xを0~99999999にクリッピングしてから8桁のBCDに変換する
 12586:   public static int fmtBcd8 (int x) {
 12587:     x = Math.max (0, Math.min (99999999, x));
 12588:     //perl optdiv.pl 99999999 10000
 12589:     //  x/10000==x*109951163>>>40 (0<=x<=494389998) [99999999*109951163==10995116190048837]
 12590:     int q = (int) ((long) x * 109951163L >>> 40);  //x/10000。1.6ns@2000000000
 12591:     //int q = x / 10000;  //2.0ns@2000000000
 12592:     return FMT_BCD4[q] << 16 | FMT_BCD4[x - 10000 * q];
 12593:   }  //fmtBcd8(int)
 12594: 
 12595:   //y = fmtBcd12 (x)
 12596:   //  xを0~999999999999Lにクリッピングしてから12桁のBCDに変換する
 12597:   public static long fmtBcd12 (long x) {
 12598:     x = Math.max (0L, Math.min (999999999999L, x));
 12599:     int q = (int) ((double) x / 100000000.0);  //(int) (x / 100000000L);
 12600:     int r = (int) (x - 100000000L * q);
 12601:     //perl optdiv.pl 99999999 10000
 12602:     //  x/10000==x*109951163>>>40 (0<=x<=494389998) [99999999*109951163==10995116190048837]
 12603:     int rq = (int) ((long) r * 109951163L >>> 40);  //r/10000
 12604:     //int rq = r / 10000;
 12605:     return (long) FMT_BCD4[q] << 32 | 0xffffffffL & (FMT_BCD4[rq] << 16 | FMT_BCD4[r - 10000 * rq]);
 12606:   }  //fmtBcd12(long)
 12607: 
 12608:   //y = fmtBcd16 (x)
 12609:   //  xを0~9999999999999999Lにクリッピングしてから16桁のBCDに変換する
 12610:   public static long fmtBcd16 (long x) {
 12611:     x = Math.max (0L, Math.min (9999999999999999L, x));
 12612:     int q = x <= (1L << 53) ? (int) ((double) x / 100000000.0) : (int) (x / 100000000L);
 12613:     int r = (int) (x - 100000000L * q);
 12614:     //perl optdiv.pl 99999999 10000
 12615:     //  x/10000==x*109951163>>>40 (0<=x<=494389998) [99999999*109951163==10995116190048837]
 12616:     int qq = (int) ((long) q * 109951163L >>> 40);  //q/10000
 12617:     //int qq = q / 10000;
 12618:     //perl optdiv.pl 99999999 10000
 12619:     //  x/10000==x*109951163>>>40 (0<=x<=494389998) [99999999*109951163==10995116190048837]
 12620:     int rq = (int) ((long) r * 109951163L >>> 40);  //r/10000
 12621:     //int rq = r / 10000;
 12622:     return (long) (FMT_BCD4[qq] << 16 | FMT_BCD4[q - 10000 * qq]) << 32 | 0xffffffffL & (FMT_BCD4[rq] << 16 | FMT_BCD4[r - 10000 * rq]);
 12623:   }  //fmtBcd16(long)
 12624: 
 12625:   //--------------------------------------------------------------------------------
 12626:   //o = fmtCA02u (a, o, x)
 12627:   //sb = fmtSB02u (sb, x)
 12628:   //  %02u
 12629:   //  2桁10進数変換(符号なし,ゼロサプレスなし)
 12630:   public static int fmtCA02u (char[] a, int o, int x) {
 12631:     if (x < 0 || 99 < x) {
 12632:       x = 99;
 12633:     }
 12634:     x = FMT_BCD4[x];
 12635:     a[o    ] = (char) ('0' | x >>> 4);
 12636:     a[o + 1] = (char) ('0' | x        & 15);
 12637:     return o + 2;
 12638:   }  //fmtCA02u(char[],int,int)
 12639:   public static StringBuilder fmtSB02u (StringBuilder sb, int x) {
 12640:     return sb.append (FMT_TEMP, 0, fmtCA02u (FMT_TEMP, 0, x));
 12641:   }  //fmtSB02u(StringBuilder,int)
 12642: 
 12643:   //o = fmtCA2u (a, o, x)
 12644:   //sb = fmtSB2u (sb, x)
 12645:   //  %2u
 12646:   //  2桁10進数変換(符号なし,ゼロサプレスあり)
 12647:   public static int fmtCA2u (char[] a, int o, int x) {
 12648:     if (x < 0 || 99 < x) {
 12649:       x = 99;
 12650:     }
 12651:     x = FMT_BCD4[x];
 12652:     if (x <= 0x000f) {  //1桁
 12653:       a[o++] = (char) ('0' | x);
 12654:     } else {  //2桁
 12655:       a[o++] = (char) ('0' | x >>>  4);
 12656:       a[o++] = (char) ('0' | x        & 15);
 12657:     }
 12658:     return o;
 12659:   }  //fmtCA2u(char[],int,int)
 12660:   public static StringBuilder fmtSB2u (StringBuilder sb, int x) {
 12661:     return sb.append (FMT_TEMP, 0, fmtCA2u (FMT_TEMP, 0, x));
 12662:   }  //fmtSB2u(StringBuilder,int)
 12663: 
 12664:   //o = fmtCA04u (a, o, x)
 12665:   //sb = fmtSB04u (sb, x)
 12666:   //  %04u
 12667:   //  4桁10進数変換(符号なし,ゼロサプレスなし)
 12668:   public static int fmtCA04u (char[] a, int o, int x) {
 12669:     if (x < 0 || 9999 < x) {
 12670:       x = 9999;
 12671:     }
 12672:     x = FMT_BCD4[x];
 12673:     a[o    ] = (char) ('0' | x >>> 12);
 12674:     a[o + 1] = (char) ('0' | x >>>  8 & 15);
 12675:     a[o + 2] = (char) ('0' | x >>>  4 & 15);
 12676:     a[o + 3] = (char) ('0' | x        & 15);
 12677:     return o + 4;
 12678:   }  //fmtCA04u(char[],int,int)
 12679:   public static StringBuilder fmtSB04u (StringBuilder sb, int x) {
 12680:     return sb.append (FMT_TEMP, 0, fmtCA04u (FMT_TEMP, 0, x));
 12681:   }  //fmtSB04u(StringBuilder,int)
 12682: 
 12683:   //o = fmtCA4u (a, o, x)
 12684:   //sb = fmtSB4u (sb, x)
 12685:   //  %4u
 12686:   //  4桁10進数変換(符号なし,ゼロサプレスあり)
 12687:   public static int fmtCA4u (char[] a, int o, int x) {
 12688:     if (x < 0 || 9999 < x) {
 12689:       x = 9999;
 12690:     }
 12691:     x = FMT_BCD4[x];
 12692:     if (x <= 0x000f) {  //1桁
 12693:       a[o++] = (char) ('0' | x);
 12694:     } else if (x <= 0x00ff) {  //2桁
 12695:       a[o++] = (char) ('0' | x >>>  4);
 12696:       a[o++] = (char) ('0' | x        & 15);
 12697:     } else if (x <= 0x0fff) {  //3桁
 12698:       a[o++] = (char) ('0' | x >>>  8);
 12699:       a[o++] = (char) ('0' | x >>>  4 & 15);
 12700:       a[o++] = (char) ('0' | x        & 15);
 12701:     } else {  //4桁
 12702:       a[o++] = (char) ('0' | x >>> 12);
 12703:       a[o++] = (char) ('0' | x >>>  8 & 15);
 12704:       a[o++] = (char) ('0' | x >>>  4 & 15);
 12705:       a[o++] = (char) ('0' | x        & 15);
 12706:     }
 12707:     return o;
 12708:   }  //fmtCA4u(char[],int,int)
 12709:   public static StringBuilder fmtSB4u (StringBuilder sb, int x) {
 12710:     return sb.append (FMT_TEMP, 0, fmtCA4u (FMT_TEMP, 0, x));
 12711:   }  //fmtSB4u(StringBuilder,int)
 12712: 
 12713:   //o = fmtCA08u (a, o, x)
 12714:   //sb = fmtSB08u (sb, x)
 12715:   //  %08u
 12716:   //  8桁10進数変換(符号なし,ゼロサプレスなし)
 12717:   public static int fmtCA08u (char[] a, int o, int x) {
 12718:     if (x < 0 || 99999999 < x) {
 12719:       x = 99999999;
 12720:     }
 12721:     //perl optdiv.pl 99999999 10000
 12722:     //  x/10000==x*109951163>>>40 (0<=x<=494389998) [99999999*109951163==10995116190048837]
 12723:     int h = (int) ((long) x * 109951163L >>> 40);  //x/10000
 12724:     return fmtCA04u (a, fmtCA04u (a, o, h), x - h * 10000);
 12725:   }  //fmtCA08u(char[],int,int)
 12726:   public static StringBuilder fmtSB08u (StringBuilder sb, int x) {
 12727:     return sb.append (FMT_TEMP, 0, fmtCA08u (FMT_TEMP, 0, x));
 12728:   }  //fmtSB08u(StringBuilder,int)
 12729: 
 12730:   //o = fmtCA8u (a, o, x)
 12731:   //sb = fmtSB8u (sb, x)
 12732:   //  %8u
 12733:   //  8桁10進数変換(符号なし,ゼロサプレスあり)
 12734:   public static int fmtCA8u (char[] a, int o, int x) {
 12735:     if (x < 0 || 99999999 < x) {
 12736:       x = 99999999;
 12737:     }
 12738:     if (x <= 9999) {  //1~4桁
 12739:       return fmtCA4u (a, o, x);
 12740:     } else {  //5~8桁
 12741:       //perl optdiv.pl 99999999 10000
 12742:       //  x/10000==x*109951163>>>40 (0<=x<=494389998) [99999999*109951163==10995116190048837]
 12743:       int h = (int) ((long) x * 109951163L >>> 40);  //x/10000
 12744:       return fmtCA04u (a, fmtCA4u (a, o, h), x - h * 10000);
 12745:     }
 12746:   }  //fmtCA8u(char[],int,int)
 12747:   public static StringBuilder fmtSB8u (StringBuilder sb, int x) {
 12748:     return sb.append (FMT_TEMP, 0, fmtCA8u (FMT_TEMP, 0, x));
 12749:   }  //fmtSB8u(StringBuilder,int)
 12750: 
 12751:   //o = fmtCAd (a, o, x)
 12752:   //sb = fmtSBd (sb, x)
 12753:   //  %d
 12754:   //  10進数変換(符号あり,ゼロサプレスあり)
 12755:   public static int fmtCAd (char[] a, int o, long x) {
 12756:     if (x < 0L) {
 12757:       x = -x;
 12758:       a[o++] = '-';
 12759:     }
 12760:     if (x <= 99999999L) {  //1~8桁
 12761:       return fmtCA8u (a, o, (int) x);
 12762:     } else if (x <= 9999999999999999L) {  //9~16桁
 12763:       long h = x / 100000000L;
 12764:       return fmtCA08u (a, fmtCA8u (a, o, (int) h), (int) (x - h * 100000000L));
 12765:     } else {  //17~19桁
 12766:       long hh = x / 10000000000000000L;
 12767:       x -= hh * 10000000000000000L;
 12768:       long h = x / 100000000L;
 12769:       return fmtCA08u (a, fmtCA08u (a, fmtCA4u (a, o, (int) hh), (int) h), (int) (x - h * 100000000L));
 12770:     }
 12771:   }  //fmtCAd(char[],int,long)
 12772:   public static StringBuilder fmtSBd (StringBuilder sb, long x) {
 12773:     return sb.append (FMT_TEMP, 0, fmtCAd (FMT_TEMP, 0, x));
 12774:   }  //fmtSBd(StringBuilder,long)
 12775: 
 12776:   //o = fmtCAnd (a, o, n, x)
 12777:   //sb = fmtSBnd (sb, n, x)
 12778:   //  %*d
 12779:   //  n桁10進数変換(符号あり,ゼロサプレスあり)
 12780:   //  n桁に収まらないとき右側にはみ出すのでバッファのサイズに注意
 12781:   public static int fmtCAnd (char[] a, int o, int n, long x) {
 12782:     int t = fmtCAd (a, o, x);  //現在の末尾
 12783:     n += o;  //必要な末尾
 12784:     if (t < n) {  //余っている
 12785:       int i = n;
 12786:       while (o < t) {  //右から順に右にずらす
 12787:         a[--i] = a[--t];
 12788:       }
 12789:       while (o < i) {  //左にできた隙間を' 'で埋める
 12790:         a[--i] = ' ';
 12791:       }
 12792:       t = n;
 12793:     }
 12794:     return t;
 12795:   }  //fmtnu(char[],int,int,long)
 12796:   public static StringBuilder fmtSBnd (StringBuilder sb, int n, int x) {
 12797:     return sb.append (FMT_TEMP, 0, fmtCAnd (FMT_TEMP, 0, n, x));
 12798:   }  //fmtSBnu(StringBuilder,int,long)
 12799: 
 12800:   //--------------------------------------------------------------------------------
 12801:   //10進数文字列解析
 12802: 
 12803:   //x = fmtParseInt (s, i, min, max, err)
 12804:   //  文字列sのインデックスiから基数10で整数xを読み取る
 12805:   //x = fmtParseIntRadix (s, i, min, max, err, radix)
 12806:   //  文字列sのインデックスiから基数radixで整数xを読み取る
 12807:   //  基数radixは2,8,10,16のいずれかに限る
 12808:   //  1文字も読み取れないかmin<=x&&x<=maxでないときはerrを返す
 12809:   //  先頭の空白を読み飛ばす
 12810:   //  数値の先頭の'$'は16進数の強制指定とみなす
 12811:   //  数値の後のゴミは無視する
 12812:   public static int fmtParseInt (String s, int i, int min, int max, int err) {
 12813:     return fmtParseIntRadix (s, i, min, max, err, 10);
 12814:   }  //fmtParseInt(String,int,int,int,int)
 12815:   public static int fmtParseIntRadix (String s, int i, int min, int max, int err, int radix) {
 12816:     if (s == null) {
 12817:       return err;
 12818:     }
 12819:     int l = s.length ();
 12820:     int c = i < l ? s.charAt (i++) : -1;
 12821:     //空白を読み飛ばす
 12822:     while (c == ' ' || c == '\t') {
 12823:       c = i < l ? s.charAt (i++) : -1;
 12824:     }
 12825:     //符号を読み取る
 12826:     int n = 0;
 12827:     if (c == '+') {
 12828:       c = i < l ? s.charAt (i++) : -1;
 12829:     } else if (c == '-') {
 12830:       n = 1;
 12831:       c = i < l ? s.charAt (i++) : -1;
 12832:     }
 12833:     //基数を読み取る
 12834:     //        2進数の範囲        8進数の範囲       10進数の範囲        16進数の範囲
 12835:     //  +    0x3fffffff*2+1     0x0fffffff*8+7     214748364*10+7     0x07ffffff*16+15
 12836:     //  -  -(0x40000000*2+0)  -(0x10000000*8+0)  -(214748364*10+8)  -(0x08000000*16+ 0)
 12837:     int o;
 12838:     int p;
 12839:     if (c == '$') {  //16進数
 12840:       o = 0x07ffffff + n;
 12841:       p = 15 + n & 15;
 12842:       radix = 16;
 12843:       c = i < l ? s.charAt (i++) : -1;
 12844:     } else if (radix == 16) {  //16進数
 12845:       o = 0x07ffffff + n;
 12846:       p = 15 + n & 15;
 12847:     } else if (radix == 8) {  //8進数
 12848:       o = 0x0fffffff + n;
 12849:       p = 7 + n & 7;
 12850:     } else if (radix == 2) {  //2進数
 12851:       o = 0x3fffffff + n;
 12852:       p = 1 + n & 1;
 12853:     } else {  //10進数
 12854:       o = 214748364;
 12855:       p = 7 + n;
 12856:       radix = 10;
 12857:     }
 12858:     //数値を読み取る
 12859:     int x = Character.digit (c, radix);
 12860:     if (x < 0) {
 12861:       return err;
 12862:     }
 12863:     c = i < l ? Character.digit (s.charAt (i++), radix) : -1;
 12864:     while (c >= 0) {
 12865:       int t = x - o;
 12866:       if (t > 0 || t == 0 && c > p) {
 12867:         return err;
 12868:       }
 12869:       x = x * radix + c;
 12870:       c = i < l ? Character.digit (s.charAt (i++), radix) : -1;
 12871:     }
 12872:     if (n != 0) {
 12873:       x = -x;
 12874:     }
 12875:     return min <= x && x <= max ? x : err;
 12876:   }  //fmtParseIntRadix(String,int,int,int,int,int)
 12877: 
 12878: 
 12879: 
 12880:   //========================================================================================
 12881:   //$$MAT 数学関数
 12882: 
 12883:   //x = matMax3 (x1, x2, x3)
 12884:   //x = matMax4 (x1, x2, x3, x4)
 12885:   //x = matMax5 (x1, x2, x3, x4, x5)
 12886:   //  最大値
 12887:   public static long matMax3 (long x1, long x2, long x3) {
 12888:     return Math.max (Math.max (x1, x2), x3);
 12889:   }  //matMax3(long,long,long)
 12890:   public static long matMax4 (long x1, long x2, long x3, long x4) {
 12891:     return Math.max (Math.max (x1, x2), Math.max (x3, x4));
 12892:   }  //matMax4(long,long,long,long)
 12893:   public static long matMax5 (long x1, long x2, long x3, long x4, long x5) {
 12894:     return Math.max (Math.max (Math.max (x1, x2), Math.max (x3, x4)), x5);
 12895:   }  //matMax5(long,long,long,long,long)
 12896: 
 12897:   //x = matMin3 (x1, x2, x3)
 12898:   //x = matMin4 (x1, x2, x3, x4)
 12899:   //x = matMin5 (x1, x2, x3, x4, x5)
 12900:   //  最小値
 12901:   public static long matMin3 (long x1, long x2, long x3) {
 12902:     return Math.min (Math.min (x1, x2), x3);
 12903:   }  //matMin3(long,long,long)
 12904:   public static long matMin4 (long x1, long x2, long x3, long x4) {
 12905:     return Math.min (Math.min (x1, x2), Math.min (x3, x4));
 12906:   }  //matMin4(long,long,long,long)
 12907:   public static long matMin5 (long x1, long x2, long x3, long x4, long x5) {
 12908:     return Math.min (Math.min (Math.min (x1, x2), Math.min (x3, x4)), x5);
 12909:   }  //matMin5(long,long,long,long,long)
 12910: 
 12911: 
 12912: 
 12913:   //========================================================================================
 12914:   //$$STR 文字列
 12915: 
 12916:   //s = encodeUTF8 (s)
 12917:   //  UTF-8変換
 12918:   //  00000000 00000000 00000000 0xxxxxxx => 00000000 00000000 00000000 0xxxxxxx
 12919:   //  00000000 00000000 00000xxx xxyyyyyy => 00000000 00000000 110xxxxx 10yyyyyy
 12920:   //  00000000 00000000 xxxxyyyy yyzzzzzz => 00000000 1110xxxx 10yyyyyy 10zzzzzz
 12921:   //  00000000 000xxxyy yyyyzzzz zzxxxxxx => 11110xxx 10yyyyyy 10zzzzzz 10xxxxxx
 12922:   public static String strEncodeUTF8 (String s) {
 12923:     StringBuilder sb = new StringBuilder ();
 12924:     int l = s.length ();
 12925:     for (int i = 0; i < l; i++) {
 12926:       int u = s.charAt (i);
 12927:       if (0xd800 <= u && u <= 0xdbff && i + 1 < l) {
 12928:         int v = s.charAt (i + 1);
 12929:         if (0xdc00 <= v && v <= 0xdfff) {  //surrogate pair
 12930:           u = 0x10000 + ((u & 0x3ff) << 10) + (v & 0x3ff);
 12931:           i++;
 12932:         }
 12933:       }
 12934:       if ((u & 0xffffff80) == 0) {  //7bit
 12935:         sb.append ((char) u);
 12936:       } else if ((u & 0xfffff800) == 0) {  //11bit
 12937:         u = (0x0000c080 |
 12938:              (u & 0x000007c0) << 2 |
 12939:              (u & 0x0000003f));
 12940:         sb.append ((char) (u >> 8)).append ((char) (u & 0xff));
 12941:       } else if ((u & 0xffff0000) == 0 && !(0xd800 <= u && u <= 0xdfff)) {  //16bit except broken surrogate pair
 12942:         u = (0x00e08080 |
 12943:              (u & 0x0000f000) << 4 |
 12944:              (u & 0x00000fc0) << 2 |
 12945:              (u & 0x0000003f));
 12946:         sb.append ((char) (u >> 16)).append ((char) ((u >> 8) & 0xff)).append ((char) (u & 0xff));
 12947:       } else if ((u & 0xffe00000) == 0) {  //21bit
 12948:         u = (0xf0808080 |
 12949:              (u & 0x001c0000) << 6 |
 12950:              (u & 0x0003f000) << 4 |
 12951:              (u & 0x00000fc0) << 2 |
 12952:              (u & 0x0000003f));
 12953:         sb.append ((char) ((u >> 24) & 0xff)).append ((char) ((u >> 16) & 0xff)).append ((char) ((u >> 8) & 0xff)).append ((char) (u & 0xff));
 12954:       } else {  //out of range or broken surrogate pair
 12955:         sb.append ((char) 0xef).append ((char) 0xbf).append ((char) 0xbd);  //U+FFFD REPLACEMENT CHARACTER
 12956:       }
 12957:     }
 12958:     return sb.toString ();
 12959:   }  //encodeUTF8(String)
 12960: 
 12961:   //s = decodeUTF8 (s)
 12962:   //  UTF-8逆変換
 12963:   //  00000000 00000000 00000000 0xxxxxxx => 00000000 00000000 00000000 0xxxxxxx
 12964:   //  00000000 00000000 110xxxxx 10yyyyyy => 00000000 00000000 00000xxx xxyyyyyy
 12965:   //  00000000 1110xxxx 10yyyyyy 10zzzzzz => 00000000 00000000 xxxxyyyy yyzzzzzz
 12966:   //  11110xxx 10yyyyyy 10zzzzzz 10xxxxxx => 00000000 000xxxyy yyyyzzzz zzxxxxxx
 12967:   public static String strDecodeUTF8 (String s) {
 12968:     StringBuilder sb = new StringBuilder ();
 12969:     int l = s.length ();
 12970:     for (int i = 0; i < l; i++) {
 12971:       int c = s.charAt (i) & 0xff;
 12972:       for (int k = ((c & 0x80) == 0x00 ? 0 :  //0xxxxxxx 7bit
 12973:                     (c & 0xe0) == 0xc0 ? 1 :  //110xxxxx 11bit
 12974:                     (c & 0xf0) == 0xe0 ? 2 :  //1110xxxx 16bit
 12975:                     (c & 0xf8) == 0xf0 ? 3 :  //11110xxx 21bit
 12976:                     -1);  //not supported
 12977:            --k >= 0; ) {
 12978:         c = c << 8 | (i + 1 < l ? s.charAt (++i) & 0xff : 0);
 12979:       }
 12980:       int u = ((c & 0xffffff80) == 0x00000000 ? c :
 12981:                (c & 0xffffe0c0) == 0x0000c080 ? ((c & 0x00001f00) >> 2 |
 12982:                                                  (c & 0x0000003f)) :
 12983:                (c & 0xfff0c0c0) == 0x00e08080 ? ((c & 0x000f0000) >> 4 |
 12984:                                                  (c & 0x00003f00) >> 2 |
 12985:                                                  (c & 0x0000003f)) :
 12986:                (c & 0xf8c0c0c0) == 0xf0808080 ? ((c & 0x07000000) >> 6 |
 12987:                                                  (c & 0x003f0000) >> 4 |
 12988:                                                  (c & 0x00003f00) >> 2 |
 12989:                                                  (c & 0x0000003f)) :
 12990:                0xfffd);  //U+FFFD REPLACEMENT CHARACTER
 12991:       if (u <= 0x0000ffff) {
 12992:         sb.append (0xd800 <= u && u <= 0xdfff ? '\ufffd' :  //U+FFFD REPLACEMENT CHARACTER
 12993:                    (char) u);
 12994:       } else if (u <= 0x0010ffff) {
 12995:         u -= 0x000010000;
 12996:         sb.append ((char) (0xd800 + ((u >> 10) & 0x3ff))).append ((char) (0xdc00 + (u & 0x3ff)));
 12997:       }
 12998:     }
 12999:     return sb.toString ();
 13000:   }  //decodeUTF8(String)
 13001: 
 13002:   //uri = strEncodeURI (s)
 13003:   //  URI変換
 13004:   //  UTF-8変換を行ってからRFC3986のPercent-Encodingを行う
 13005:   //  フォームの送信に使用されるapplication/x-www-form-urlencodedではない。" "は"+"ではなく"%20"に変換される
 13006:   public static final int[] IsURIChar = {  //URIに使える文字。RFC3986のUnreserved Characters。[-.0-9A-Z_a-z~]
 13007:     //00000000 00000000 11111111 11111111
 13008:     //01234567 89abcdef 01234567 89abcdef
 13009:     0b00000000_00000000_00000000_00000000,  //0x00..0x1f
 13010:     0b00000000_00000110_11111111_11000000,  //0x20..0x3f [-.0-9]
 13011:     0b01111111_11111111_11111111_11100001,  //0x40..0x5f [A-Z_]
 13012:     0b01111111_11111111_11111111_11100010,  //0x60..0x7f [a-z~]
 13013:   };
 13014:   public static String strEncodeURI (String s) {
 13015:     s = strEncodeUTF8 (s);  //UTF-8変換
 13016:     StringBuilder sb = new StringBuilder ();
 13017:     int l = s.length ();
 13018:     for (int i = 0; i < l; i++) {
 13019:       int c = s.charAt (i);
 13020:       if (c < 0x80 && IsURIChar[c >> 5] << c < 0) {  //URIに使える文字
 13021:         sb.append ((char) c);
 13022:       } else {
 13023:         fmtHex2 (sb.append ('%'), c);
 13024:       }
 13025:     }
 13026:     return sb.toString ();
 13027:   }  //encodeURI(String)
 13028: 
 13029:   //s = strDecodeURI (s)
 13030:   //  URI逆変換
 13031:   //  RFC3986のPercent-Encodingの逆変換を行ってからUTF-8逆変換を行う
 13032:   //  フォームの送信に使用されるapplication/x-www-form-urlencodedではない。"+"は" "に変換されない
 13033:   public static final byte[] strIsHexChar = {  //16進数に使えるASCII文字。[0-9A-Fa-f]
 13034:     // 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
 13035:     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  //0x00..0x1f
 13036:     -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,  //0x20..0x3f [0-9]
 13037:     -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  //0x40..0x5f [A-F]
 13038:     -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  //0x60..0x7f [a-f]
 13039:   };
 13040:   public static String strDecodeURI (String s) {
 13041:     StringBuilder sb = new StringBuilder ();
 13042:     int l = s.length ();
 13043:     for (int i = 0; i < l; i++) {
 13044:       int c = s.charAt (i);
 13045:       if (c == '%' && i + 2 < l) {
 13046:         int d = s.charAt (i + 1);
 13047:         int e = s.charAt (i + 2);
 13048:         if (d < 0x80 && (d = strIsHexChar[d]) >= 0 &&
 13049:             e < 0x80 && (e = strIsHexChar[e]) >= 0) {
 13050:           sb.append ((char) (d << 4 | e));
 13051:         } else {
 13052:           sb.append ((char) c);
 13053:         }
 13054:       } else {
 13055:         sb.append ((char) c);
 13056:       }
 13057:     }
 13058:     return sb.toString ();
 13059:   }  //decodeURI(String)
 13060: 
 13061: 
 13062: 
 13063:   //========================================================================================
 13064:   //$$IMG イメージ
 13065: 
 13066:   //image = createImage (width, height, pattern, rgb, ...)
 13067:   //  イメージを作る
 13068:   public static BufferedImage createImage (int width, int height, String pattern, int... rgbs) {
 13069:     BufferedImage image = new BufferedImage (width, height, BufferedImage.TYPE_INT_RGB);
 13070:     int[] bitmap = ((DataBufferInt) image.getRaster ().getDataBuffer ()).getData ();
 13071:     int length = width * height;
 13072:     for (int i = 0; i < length; i++) {
 13073:       char c = pattern.charAt (i);
 13074:       bitmap[i] = rgbs[c < '0' ? 0 : Character.digit (c, 16)];
 13075:     }
 13076:     return image;
 13077:   }  //createImage(int,int,String,int...)
 13078: 
 13079:   //icon = createImageIcon (width, height, pattern, rgb, ...)
 13080:   //  イメージアイコンを作る
 13081:   public static ImageIcon createImageIcon (int width, int height, String pattern, int... rgbs) {
 13082:     return new ImageIcon (createImage (width, height, pattern, rgbs));
 13083:   }  //createImageIcon(int,int,String,int...)
 13084: 
 13085:   //paint = createTexturePaint (width, height, pattern, rgb, ...)
 13086:   //  テクスチャペイントを作る
 13087:   public static TexturePaint createTexturePaint (int width, int height, String pattern, int... rgbs) {
 13088:     return new TexturePaint (createImage (width, height, pattern, rgbs), new Rectangle (0, 0, width, height));
 13089:   }  //createTexturePaint(int,int,String,int...)
 13090: 
 13091:   //image = loadImage (name)
 13092:   //  イメージを読み込む
 13093:   public static BufferedImage loadImage (String name) {
 13094:     BufferedImage image = null;
 13095:     try {
 13096:       image = ImageIO.read (new File (name));
 13097:     } catch (Exception e) {
 13098:     }
 13099:     return image;
 13100:   }  //loadImage(String)
 13101: 
 13102:   //sucess = saveImage (image, name)
 13103:   //sucess = saveImage (image, name, quality)
 13104:   //  イメージを書き出す
 13105:   public static boolean saveImage (BufferedImage image, String name) {
 13106:     return saveImage (image, name, 0.75F);
 13107:   }  //saveImage(BufferedImage,String)
 13108:   public static boolean saveImage (BufferedImage image, String name, float quality) {
 13109:     int index = name.lastIndexOf (".");
 13110:     if (index < 0) {  //拡張子がない
 13111:       return false;
 13112:     }
 13113:     if (name.substring (index).equalsIgnoreCase (".ico")) {  //アイコンファイルの作成
 13114:       return saveIcon (name, image);
 13115:     }
 13116:     Iterator<ImageWriter> iterator = ImageIO.getImageWritersBySuffix (name.substring (index + 1));  //拡張子に対応するImageWriterがないときは空のIteratorを返す
 13117:     if (!iterator.hasNext ()) {  //拡張子に対応するImageWriterがない
 13118:       return false;
 13119:     }
 13120:     ImageWriter imageWriter = iterator.next ();
 13121:     ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam ();
 13122:     if (imageWriteParam.canWriteCompressed ()) {
 13123:       imageWriteParam.setCompressionMode (ImageWriteParam.MODE_EXPLICIT);
 13124:       imageWriteParam.setCompressionQuality (quality);
 13125:     }
 13126:     try {
 13127:       File file = new File (name);
 13128:       ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream (file);
 13129:       imageWriter.setOutput (imageOutputStream);
 13130:       imageWriter.write (null, new IIOImage (image, null, null), imageWriteParam);
 13131:       imageOutputStream.close ();
 13132:     } catch (Exception e) {
 13133:       //e.printStackTrace ();
 13134:       return false;
 13135:     }
 13136:     return true;
 13137:   }  //saveImage(BufferedImage,String,float)
 13138: 
 13139: 
 13140: 
 13141:   //========================================================================================
 13142:   //$$ICO アイコンファイル
 13143:   //  サイズの異なる複数のアイコンを格納することができる
 13144:   //  ワードサイズとロングサイズのデータはすべてリトルエンディアン
 13145:   //
 13146:   //  アイコンファイル(.ico)
 13147:   //    ファイルヘッダ
 13148:   //    エントリデータ0
 13149:   //           :
 13150:   //    エントリデータn-1
 13151:   //    イメージデータ0
 13152:   //           :
 13153:   //    イメージデータn-1
 13154:   //
 13155:   //  ファイルヘッダ
 13156:   //    0000  .iw  0=予約
 13157:   //    0002  .iw  1=アイコン
 13158:   //    0004  .iw  n=アイコン数
 13159:   //    0006
 13160:   //
 13161:   //  エントリデータ
 13162:   //    0000  .b   幅
 13163:   //    0001  .b   高さ
 13164:   //    0002  .b   色数(0=256以上)
 13165:   //    0003  .b   0=予約
 13166:   //    0004  .iw  1=プレーン数
 13167:   //    0006  .iw  ピクセル毎のビット数
 13168:   //    0008  .il  イメージデータの長さ
 13169:   //    000c  .il  ファイルヘッダからイメージデータまでのオフセット
 13170:   //    0010
 13171:   //
 13172:   //  イメージデータ
 13173:   //    イメージヘッダ
 13174:   //    パレットテーブル
 13175:   //    パターンデータ
 13176:   //    マスクデータ
 13177:   //
 13178:   //  イメージヘッダ
 13179:   //    0000  .il  40=イメージヘッダの長さ
 13180:   //    0004  .il  幅
 13181:   //    0008  .il  高さ*2
 13182:   //    000c  .iw  1=プレーン数
 13183:   //    000e  .iw  ピクセル毎のビット数
 13184:   //    0010  .il  0=無圧縮
 13185:   //    0014  .il  0=画像データサイズ(省略)
 13186:   //    0018  .il  0=横解像度(省略)
 13187:   //    001c  .il  0=縦解像度(省略)
 13188:   //    0020  .il  p=パレット数
 13189:   //    0024  .il  0=重要なパレットのインデックス(省略)
 13190:   //    0028
 13191:   //
 13192:   //  パレットテーブル
 13193:   //    0000  .il  パレット0(BGR0)
 13194:   //                   :
 13195:   //          .il  パレットp-1(BGR0)
 13196:   //    4*p
 13197:   //
 13198:   //  パターンデータ
 13199:   //    ピクセルの順序は左下から右上
 13200:   //    バイト内のビットの順序は上位から下位
 13201:   //    1ラインのデータ長は4の倍数
 13202:   //
 13203:   //  マスクデータ
 13204:   //    0=描画,1=透過
 13205:   //    ピクセルの順序は左下から右上
 13206:   //    バイト内のビットの順序は上位から下位
 13207:   //    1ラインのデータ長は4の倍数
 13208: 
 13209:   //success = saveIcon (name, image, ...);
 13210:   //  アイコンファイルを出力する
 13211:   public static boolean saveIcon (String fileName, BufferedImage... arrayImage) {
 13212:     int iconCount = arrayImage.length;
 13213:     int[][] arrayPaletTable = new int[iconCount][];  //パレットテーブル
 13214:     int[] arrayPaletCount = new int[iconCount];  //パレット数。0=パレットを使わない
 13215:     int[] arrayPixelBits = new int[iconCount];  //ピクセル毎のビット数。24,8,4,2,1のいずれか
 13216:     int[] arrayPatternLineSize = new int[iconCount];  //パターンデータの1ラインのバイト数
 13217:     int[] arrayMaskLineSize = new int[iconCount];  //マスクデータの1ラインのバイト数
 13218:     int[] arrayImageSize = new int[iconCount];  //イメージデータの長さ
 13219:     int[] arrayImageOffset = new int[iconCount];  //ファイルヘッダからイメージデータまでのオフセット
 13220:     int fileSize = 6 + 16 * iconCount;
 13221:     for (int iconNumber = 0; iconNumber < iconCount; iconNumber++) {
 13222:       BufferedImage image = arrayImage[iconNumber];
 13223:       int width = image.getWidth ();
 13224:       int height = image.getHeight ();
 13225:       //パレットテーブルを作る
 13226:       int[] paletTable = new int[256];
 13227:       int paletCount = 0;
 13228:     countPalet:
 13229:       for (int y = height - 1; y >= 0; y--) {
 13230:         for (int x = 0; x < width; x++) {
 13231:           int rgb = image.getRGB (x, y);
 13232:           if (rgb >>> 24 != 0xff) {  //alphaが0xffでなければred,green,blueを無視して透過色とみなす
 13233:             continue;
 13234:           }
 13235:           int l = 0;
 13236:           int r = paletCount;
 13237:           while (l < r) {
 13238:             int m = l + r >> 1;
 13239:             if (paletTable[m] < rgb) {
 13240:               l = m + 1;
 13241:             } else {
 13242:               r = m;
 13243:             }
 13244:           }
 13245:           if (l == paletCount || paletTable[l] != rgb) {  //新しい色
 13246:             if (paletCount == 256) {  //色数が多すぎる
 13247:               paletCount = 0;
 13248:               break countPalet;
 13249:             }
 13250:             for (int i = paletCount; i > l; i--) {
 13251:               paletTable[i] = paletTable[i - 1];
 13252:             }
 13253:             paletTable[l] = rgb;
 13254:             paletCount++;
 13255:           }
 13256:         }  //for x
 13257:       }  //for y
 13258:       int pixelBits = (paletCount == 0 ? 24 :
 13259:                        paletCount > 16 ? 8 :
 13260:                        paletCount > 4 ? 4 :
 13261:                        paletCount > 2 ? 2 :
 13262:                        1);
 13263:       int patternLineSize = pixelBits * width + 31 >> 5 << 2;
 13264:       int maskLineSize = width + 31 >> 5 << 2;
 13265:       int imageSize = 40 + 4 * paletCount + patternLineSize * height + maskLineSize * height;
 13266:       arrayPaletTable[iconNumber] = paletTable;
 13267:       arrayPaletCount[iconNumber] = paletCount;
 13268:       arrayPixelBits[iconNumber] = pixelBits;
 13269:       arrayPatternLineSize[iconNumber] = patternLineSize;
 13270:       arrayMaskLineSize[iconNumber] = maskLineSize;
 13271:       arrayImageSize[iconNumber] = imageSize;
 13272:       arrayImageOffset[iconNumber] = fileSize;
 13273:       fileSize += imageSize;
 13274:     }  //for iconNumber
 13275:     byte[] bb = new byte[fileSize];
 13276:     //ファイルヘッダ
 13277:     ByteArray.byaWiw (bb, 0, 0);
 13278:     ByteArray.byaWiw (bb, 2, 1);
 13279:     ByteArray.byaWiw (bb, 4, iconCount);
 13280:     for (int iconNumber = 0; iconNumber < iconCount; iconNumber++) {
 13281:       BufferedImage image = arrayImage[iconNumber];
 13282:       int width = image.getWidth ();
 13283:       int height = image.getHeight ();
 13284:       int[] paletTable = arrayPaletTable[iconNumber];
 13285:       int paletCount = arrayPaletCount[iconNumber];
 13286:       int pixelBits = arrayPixelBits[iconNumber];
 13287:       int patternLineSize = arrayPatternLineSize[iconNumber];
 13288:       int maskLineSize = arrayMaskLineSize[iconNumber];
 13289:       int imageSize = arrayImageSize[iconNumber];
 13290:       int imageOffset = arrayImageOffset[iconNumber];
 13291:       //エントリデータ
 13292:       int o = 6 + 16 * iconNumber;
 13293:       ByteArray.byaWb (bb, o, width);
 13294:       ByteArray.byaWb (bb, o + 1, height);
 13295:       ByteArray.byaWb (bb, o + 2, paletCount);
 13296:       ByteArray.byaWb (bb, o + 3, 0);
 13297:       ByteArray.byaWiw (bb, o + 4, 1);
 13298:       ByteArray.byaWiw (bb, o + 6, pixelBits);
 13299:       ByteArray.byaWil (bb, o + 8, imageSize);
 13300:       ByteArray.byaWil (bb, o + 12, imageOffset);
 13301:       //イメージヘッダ
 13302:       o = imageOffset;
 13303:       ByteArray.byaWil (bb, o, 40);
 13304:       ByteArray.byaWil (bb, o + 4, width);
 13305:       ByteArray.byaWil (bb, o + 8, height * 2);
 13306:       ByteArray.byaWiw (bb, o + 12, 1);
 13307:       ByteArray.byaWiw (bb, o + 14, pixelBits);
 13308:       ByteArray.byaWil (bb, o + 16, 0);
 13309:       ByteArray.byaWil (bb, o + 20, 0);
 13310:       ByteArray.byaWil (bb, o + 24, 0);
 13311:       ByteArray.byaWil (bb, o + 28, 0);
 13312:       ByteArray.byaWil (bb, o + 32, paletCount);
 13313:       ByteArray.byaWil (bb, o + 36, 0);
 13314:       //パレットテーブル
 13315:       o += 40;
 13316:       for (int i = 0; i < paletCount; i++) {
 13317:         ByteArray.byaWil (bb, o, paletTable[i] & 0x00ffffff);
 13318:         o += 4;
 13319:       }
 13320:       //パターンデータ
 13321:       for (int y = height - 1; y >= 0; y--) {
 13322:         for (int x = 0; x < width; x++) {
 13323:           int rgb = image.getRGB (x, y);
 13324:           if (rgb >>> 24 != 0xff) {  //alphaが0xffでなければred,green,blueを無視して透過色とみなす
 13325:             continue;
 13326:           }
 13327:           if (pixelBits == 24) {  //パレットなし
 13328:             bb[o + 3 * x] = (byte) rgb;  //blue
 13329:             bb[o + 3 * x + 1] = (byte) (rgb >> 8);  //green
 13330:             bb[o + 3 * x + 2] = (byte) (rgb >> 16);  //red
 13331:             continue;
 13332:           }
 13333:           int l = 0;
 13334:           int r = paletCount;
 13335:           while (l < r) {
 13336:             int m = l + r >> 1;
 13337:             if (paletTable[m] < rgb) {
 13338:               l = m + 1;
 13339:             } else {
 13340:               r = m;
 13341:             }
 13342:           }
 13343:           if (l != 0) {
 13344:             if (pixelBits == 8) {
 13345:               bb[o + x] = (byte) l;
 13346:             } else if (pixelBits == 4) {
 13347:               bb[o + (x >> 1)] |= (byte) (l << ((~x & 1) << 2));
 13348:             } else if (pixelBits == 2) {
 13349:               bb[o + (x >> 2)] |= (byte) (l << ((~x & 3) << 1));
 13350:             } else {
 13351:               bb[o + (x >> 3)] |= (byte) (l << (~x & 7));
 13352:             }
 13353:           }
 13354:         }  //for x
 13355:         o += patternLineSize;
 13356:       }  //for y
 13357:       //マスクデータ
 13358:       for (int y = height - 1; y >= 0; y--) {
 13359:         for (int x = 0; x < width; x++) {
 13360:           int rgb = image.getRGB (x, y);
 13361:           if (rgb >>> 24 != 0xff) {  //alphaが0xffでなければred,green,blueを無視して透過色とみなす
 13362:             bb[o + (x >> 3)] |= (byte) (1 << (~x & 7));
 13363:           }
 13364:         }
 13365:         o += maskLineSize;
 13366:       }
 13367:     }  //for iconNumber
 13368:     return rscPutFile (fileName, bb, 0, fileSize);
 13369:   }  //saveIcon(String,BufferedImage...)
 13370: 
 13371: 
 13372: 
 13373: }  //class XEiJ
 13374: 
 13375: 
 13376: