DebugConsole.java
     1: //========================================================================================
     2: //  DebugConsole.java
     3: //    en:Debug console -- An interactive debugger
     4: //    ja:デバッグコンソール -- 対話型デバッガ
     5: //  Copyright (C) 2003-2019 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.*;  //BasicStroke,BorderLayout,BoxLayout,Color,Component,Container,Cursor,Desktop,Dimension,Font,FlowLayout,Frame,Graphics,Graphics2D,GraphicsDevice,GraphicsEnvironment,GridLayout,Image,Insets,Paint,Point,Rectangle,RenderingHints,Robot,Shape,Stroke,TexturePaint,Toolkit
    16: import java.awt.datatransfer.*;  //Clipboard,DataFlavor,FlavorEvent,FlavorListener,Transferable,UnsupportedFlavorException
    17: import java.awt.event.*;  //ActionEvent,ActionListener,ComponentAdapter,ComponentEvent,ComponentListener,FocusAdapter,FocusEvent,FocusListener,InputEvent,KeyAdapter,KeyEvent,KeyListener,MouseAdapter,MouseEvent,MouseListener,MouseMotionAdapter,MouseWheelEvent,WindowAdapter,WindowEvent,WindowListener,WindowStateListener
    18: import java.lang.*;  //Boolean,Character,Class,Comparable,Double,Exception,Float,IllegalArgumentException,Integer,Long,Math,Number,Object,Runnable,SecurityException,String,StringBuilder,System
    19: import java.util.*;  //ArrayList,Arrays,Calendar,GregorianCalendar,HashMap,Map,Map.Entry,LinkedList,TimeZone,Timer,TimerTask,TreeMap
    20: import javax.swing.*;  //AbstractButton,AbstractSpinnerModel,Box,ButtonGroup,DefaultListModel,ImageIcon,JApplet,JButton,JCheckBox,JCheckBoxMenuItem,JComponent,JDialog,JFileChooser,JFrame,JLabel,JList,JMenu,JMenuBar,JMenuItem,JPanel,JRadioButton,JScrollPane,JSpinner,JTextArea,JTextField,JTextPane,JViewport,ScrollPaneConstants,SpinnerListModel,SpinnerNumberModel,SwingConstants,SwingUtilities,UIManager,UIDefaults,UnsupportedLookAndFeelException
    21: import javax.swing.event.*;  //CaretEvent,CaretListener,ChangeEvent,ChangeListener,DocumentEvent,DocumentListener,ListSelectionListener
    22: 
    23: public class DebugConsole {
    24: 
    25:   public static final int DGT_MAX_OUTPUT_LENGTH = 1024 * 64;  //出力の上限を64KBとする
    26:   public static final int DGT_CUT_OUTPUT_LENGTH = DGT_MAX_OUTPUT_LENGTH + 1024 * 4;  //出力が上限よりも4KB以上長くなったら上限でカットする
    27: 
    28:   //入力モード
    29:   public static final int DGT_INPUT_MODE_COMMAND   = 1;  //コマンドモード
    30:   public static final int DGT_INPUT_MODE_PAGE      = 2;  //ページモード
    31:   public static final int DGT_INPUT_MODE_ASSEMBLER = 3;  //アセンブラモード
    32:   public static int dgtInputMode;  //入力モード
    33:   public static LinkedList<String> dgtPageList;
    34: 
    35:   //プロンプト
    36:   public static final String DGT_COMMAND_PROMPT = "> ";
    37:   public static final String DGT_PAGE_PROMPT = "-- more -- [y/n] ";
    38:   public static String dgtCurrentPrompt;  //現在のプロンプト
    39: 
    40:   //コンポーネント
    41:   public static JFrame dgtFrame;  //ウインドウ
    42:   public static ScrollTextArea dgtBoard;  //テキストエリア
    43:   public static JPopupMenu dgtPopupMenu;  //ポップアップメニュー
    44:   public static JMenuItem dgtPopupCutMenuItem;  //切り取り
    45:   public static JMenuItem dgtPopupCopyMenuItem;  //コピー
    46:   public static JMenuItem dgtPopupPasteMenuItem;  //貼り付け
    47:   public static JMenuItem dgtPopupSelectAllMenuItem;  //すべて選択
    48:   public static int dgtOutputEnd;  //出力された文字列の末尾。リターンキーが押されたらこれ以降に書かれた文字列をまとめて入力する
    49: 
    50:   public static boolean dgtRequestRegs;  //true=コアが停止したらコンソールにレジスタ一覧とプロンプトを表示する
    51: 
    52:   //アセンブル
    53:   public static int dgtAssemblePC;  //次にアセンブルするアドレス
    54:   public static int dgtAssembleFC;  //次にアセンブルするファンクションコード
    55: 
    56:   //逆アセンブル
    57:   public static int dgtDisassembleLastTail;  //前回逆アセンブルした範囲の終了アドレス
    58:   public static int dgtDisassemblePC;  //前回逆アセンブルした範囲の直後のアドレス。0=PCを使う
    59:   public static int dgtDisassembleFC;  //前回逆アセンブルした範囲のファンクションコード
    60: 
    61:   //ダンプ
    62:   public static int dgtDumpAddress;  //次回のダンプ開始アドレス
    63:   public static int dgtDumpFunctionCode;  //ファンクションコード
    64: 
    65:   //dgtInit ()
    66:   //  デバッグコンソールを初期化する
    67:   public static void dgtInit () {
    68:     dgtInputMode = DGT_INPUT_MODE_COMMAND;
    69:     dgtPageList = null;
    70:     dgtCurrentPrompt = DGT_COMMAND_PROMPT;
    71:     dgtFrame = null;
    72:     dgtBoard = null;
    73:     dgtPopupMenu = null;
    74:     dgtPopupCutMenuItem = null;
    75:     dgtPopupCopyMenuItem = null;
    76:     dgtPopupPasteMenuItem = null;
    77:     dgtPopupSelectAllMenuItem = null;
    78:     dgtOutputEnd = dgtCurrentPrompt.length ();
    79:     dgtRequestRegs = false;
    80:     dgtAssemblePC = 0;
    81:     dgtAssembleFC = 6;
    82:     dgtDisassembleLastTail = 0;
    83:     dgtDisassemblePC = 0;
    84:     dgtDisassembleFC = 6;
    85:     dgtDumpAddress = 0;
    86:     dgtDumpFunctionCode = 5;
    87:   }  //dgtInit()
    88: 
    89:   //dgtMake ()
    90:   //  デバッグコンソールを作る
    91:   //  ここでは開かない
    92:   public static void dgtMake () {
    93: 
    94:     //テキストエリア
    95:     String initialText = (Multilingual.mlnJapanese ?
    96:                           "[ h で使用法を表示]\n" :
    97:                           "[enter h to display usage]\n") + dgtCurrentPrompt;
    98:     dgtOutputEnd = initialText.length ();
    99:     dgtBoard = ComponentFactory.createScrollTextArea (initialText, 500, 600, true);
   100:     dgtBoard.setUnderlineCursorOn (true);
   101:     dgtBoard.setLineWrap (true);  //行を折り返す
   102:     dgtBoard.addDocumentListener (new DocumentListener () {
   103:       @Override public void changedUpdate (DocumentEvent de) {
   104:       }
   105:       @Override public void insertUpdate (DocumentEvent de) {
   106:         if (de.getOffset () < dgtOutputEnd) {
   107:           dgtOutputEnd += de.getLength ();  //出力された文字列の末尾を調整する
   108:         }
   109:       }
   110:       @Override public void removeUpdate (DocumentEvent de) {
   111:         if (de.getOffset () < dgtOutputEnd) {
   112:           dgtOutputEnd -= Math.min (de.getLength (), dgtOutputEnd - de.getOffset ());  //出力された文字列の末尾を調整する
   113:         }
   114:       }
   115:     });
   116:     dgtBoard.addKeyListener (new KeyAdapter () {
   117:       @Override public void keyPressed (KeyEvent ke) {
   118:         int code = ke.getKeyCode ();
   119:         int modifiersEx = ke.getModifiersEx ();
   120:         if (code == KeyEvent.VK_ENTER &&  //Enterキーが押された
   121:             (modifiersEx & (InputEvent.ALT_DOWN_MASK |
   122:                             InputEvent.CTRL_DOWN_MASK |
   123:                             InputEvent.META_DOWN_MASK)) == 0) {  //Altキー,Ctrlキー,Metaキーが押されていない
   124:           if ((modifiersEx & InputEvent.SHIFT_DOWN_MASK) == 0) {  //Shiftキーが押されていない
   125:             ke.consume ();  //Enterキーをキャンセルする
   126:             //Enterキーを処理する
   127:             dgtEnter ();
   128:           } else {  //Shiftキーが押されている
   129:             ke.consume ();  //Enterキーをキャンセルする。デフォルトのShift+Enterの機能を無効化する
   130:             //改行を挿入する
   131:             dgtBoard.replaceRange ("\n", dgtBoard.getSelectionStart (), dgtBoard.getSelectionEnd ());
   132:           }
   133:         }
   134:       }
   135:     });
   136: 
   137:     //ポップアップメニュー
   138:     ActionListener popupActionListener = new ActionListener () {
   139:       @Override public void actionPerformed (ActionEvent ae) {
   140:         switch (ae.getActionCommand ()) {
   141:         case "Cut":
   142:           dgtCut ();
   143:           break;
   144:         case "Copy":
   145:           dgtCopy ();
   146:           break;
   147:         case "Paste":
   148:           dgtPaste ();
   149:           break;
   150:         case "Select All":
   151:           dgtSelectAll ();
   152:           break;
   153:         }
   154:       }
   155:     };
   156:     dgtPopupMenu = ComponentFactory.createPopupMenu (
   157:       dgtPopupCutMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Cut", 'T', popupActionListener), "ja", "切り取り"),
   158:       dgtPopupCopyMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Copy", 'C', popupActionListener), "ja", "コピー"),
   159:       dgtPopupPasteMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Paste", 'P', popupActionListener), "ja", "貼り付け"),
   160:       ComponentFactory.createHorizontalSeparator (),
   161:       dgtPopupSelectAllMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Select All", 'A', popupActionListener), "ja", "すべて選択")
   162:       );
   163:     dgtBoard.addMouseListener (new MouseAdapter () {
   164:       @Override public void mousePressed (MouseEvent me) {
   165:         dgtShowPopup (me);
   166:       }
   167:       @Override public void mouseReleased (MouseEvent me) {
   168:         dgtShowPopup (me);
   169:       }
   170:     });
   171: 
   172:     //ウインドウ
   173:     dgtFrame = Multilingual.mlnTitle (
   174:       ComponentFactory.createRestorableSubFrame (
   175:         Settings.SGS_DGT_FRAME_KEY,
   176:         "Console",
   177:         null,
   178:         dgtBoard
   179:         ),
   180:       "ja", "コンソール");
   181: 
   182:     dgtBoard.setCaretPosition (dgtOutputEnd);
   183: 
   184:   }  //dgtMake()
   185: 
   186:   //dgtShowPopup (me)
   187:   //  ポップアップメニューを表示する
   188:   //  テキストエリアのマウスリスナーが呼び出す
   189:   public static void dgtShowPopup (MouseEvent me) {
   190:     if (me.isPopupTrigger ()) {
   191:       //選択範囲があれば切り取りとコピーが有効
   192:       boolean enableCutAndCopy = XEiJ.clpClipboard != null && dgtBoard.getSelectionStart () != dgtBoard.getSelectionEnd ();
   193:       ComponentFactory.setEnabled (dgtPopupCutMenuItem, enableCutAndCopy);
   194:       ComponentFactory.setEnabled (dgtPopupCopyMenuItem, enableCutAndCopy);
   195:       //クリップボードに文字列があれば貼り付けが有効
   196:       ComponentFactory.setEnabled (dgtPopupPasteMenuItem, XEiJ.clpClipboard != null && XEiJ.clpClipboard.isDataFlavorAvailable (DataFlavor.stringFlavor));
   197:       //クリップボードがあればすべて選択が有効
   198:       ComponentFactory.setEnabled (dgtPopupSelectAllMenuItem, XEiJ.clpClipboard != null);
   199:       //ポップアップメニューを表示する
   200:       dgtPopupMenu.show (me.getComponent (), me.getX (), me.getY ());
   201:     }
   202:   }  //dgtShowPopup(MouseEvent)
   203: 
   204:   //dgtCut ()
   205:   //  切り取り
   206:   public static void dgtCut () {
   207:     if (XEiJ.clpClipboard != null) {
   208:       //選択範囲の文字列をコピーする
   209:       XEiJ.clpClipboardString = dgtBoard.getSelectedText ();
   210:       try {
   211:         XEiJ.clpClipboard.setContents (XEiJ.clpStringContents, XEiJ.clpClipboardOwner);
   212:         XEiJ.clpIsClipboardOwner = true;  //自分がコピーした
   213:       } catch (Exception e) {
   214:         return;
   215:       }
   216:       //選択範囲の文字列を削除する
   217:       dgtBoard.replaceRange ("", dgtBoard.getSelectionStart (), dgtBoard.getSelectionEnd ());
   218:     }
   219:   }  //dgtCut()
   220: 
   221:   //dgtCopy ()
   222:   //  コピー
   223:   public static void dgtCopy () {
   224:     if (XEiJ.clpClipboard != null) {
   225:       //選択範囲の文字列をコピーする
   226:       String selectedText = dgtBoard.getSelectedText ();
   227:       if (selectedText != null) {
   228:         XEiJ.clpClipboardString = selectedText;
   229:         try {
   230:           XEiJ.clpClipboard.setContents (XEiJ.clpStringContents, XEiJ.clpClipboardOwner);
   231:           XEiJ.clpIsClipboardOwner = true;  //自分がコピーした
   232:         } catch (Exception e) {
   233:           return;
   234:         }
   235:       }
   236:     }
   237:   }  //dgtCopy()
   238: 
   239:   //dgtPaste ()
   240:   //  貼り付け
   241:   public static void dgtPaste () {
   242:     if (XEiJ.clpClipboard != null) {
   243:       //クリップボードから文字列を取り出す
   244:       String string = null;
   245:       try {
   246:         string = (String) XEiJ.clpClipboard.getData (DataFlavor.stringFlavor);
   247:       } catch (Exception e) {
   248:         return;
   249:       }
   250:       //選択範囲の文字列を置換する
   251:       dgtBoard.replaceRange (string, dgtBoard.getSelectionStart (), dgtBoard.getSelectionEnd ());
   252:     }
   253:   }  //dgtPaste()
   254: 
   255:   //dgtSelectAll ()
   256:   //  すべて選択
   257:   public static void dgtSelectAll () {
   258:     if (XEiJ.clpClipboard != null) {
   259:       //すべて選択する
   260:       dgtBoard.selectAll ();
   261:     }
   262:   }  //dgtSelectAll()
   263: 
   264:   //dgtStart ()
   265:   public static void dgtStart () {
   266:     if (RestorableFrame.rfmGetOpened (Settings.SGS_DGT_FRAME_KEY)) {
   267:       dgtOpen ();
   268:     }
   269:   }  //dgtStart()
   270: 
   271:   //dgtOpen ()
   272:   //  デバッグコンソールを開く
   273:   public static void dgtOpen () {
   274:     if (dgtFrame == null) {
   275:       dgtMake ();
   276:     }
   277:     dgtFrame.setVisible (true);
   278:   }  //dgtOpen()
   279: 
   280:   //dgtPrintChar (c)
   281:   //  末尾に1文字追加する
   282:   public static void dgtPrintChar (int c) {
   283:     if (c == 0x08) {  //バックスペース
   284:       if (0 < dgtOutputEnd) {
   285:         if (dgtBoard != null) {
   286:           dgtBoard.replaceRange ("", dgtOutputEnd - 1, dgtOutputEnd);  //1文字削除
   287:           dgtOutputEnd--;
   288:           dgtBoard.setCaretPosition (dgtOutputEnd);
   289:         }
   290:       }
   291:     } else if (0x20 <= c && c != 0x7f || c == 0x09 || c == 0x0a) {  //タブと改行以外の制御コードを除く
   292:       if (dgtBoard != null) {
   293:         dgtBoard.insert (String.valueOf ((char) c), dgtOutputEnd);  //1文字追加
   294:         dgtOutputEnd++;
   295:         if (DGT_CUT_OUTPUT_LENGTH <= dgtOutputEnd) {
   296:           dgtBoard.replaceRange ("", 0, dgtOutputEnd - DGT_MAX_OUTPUT_LENGTH);  //先頭を削って短くする
   297:           dgtOutputEnd = DGT_MAX_OUTPUT_LENGTH;
   298:         }
   299:         dgtBoard.setCaretPosition (dgtOutputEnd);
   300:       }
   301:     }
   302:   }  //dgtPrintChar(int)
   303: 
   304:   //dgtPrint (s)
   305:   //  末尾に文字列を追加する
   306:   //  制御コードを処理しないのでタブと改行以外の制御コードを含めないこと
   307:   public static void dgtPrint (String s) {
   308:     if (s == null) {
   309:       return;
   310:     }
   311:     if (dgtFrame != null) {
   312:       dgtBoard.insert (s, dgtOutputEnd);  //文字列追加
   313:       dgtOutputEnd += s.length ();
   314:       if (DGT_CUT_OUTPUT_LENGTH <= dgtOutputEnd) {
   315:         dgtBoard.replaceRange ("", 0, dgtOutputEnd - DGT_MAX_OUTPUT_LENGTH);  //先頭を削って短くする
   316:         dgtOutputEnd = DGT_MAX_OUTPUT_LENGTH;
   317:       }
   318:       dgtBoard.setCaretPosition (dgtOutputEnd);
   319:     }
   320:   }  //dgtPrint(String)
   321: 
   322:   //dgtPrintln (s)
   323:   //  末尾に文字列と改行を追加する
   324:   //  制御コードを処理しないのでタブと改行以外の制御コードを含めないこと
   325:   public static void dgtPrintln (String s) {
   326:     dgtPrint (s);
   327:     dgtPrintChar ('\n');
   328:   }  //dgtPrintln(String)
   329: 
   330:   //dgtEnter ()
   331:   //  Enterキーを処理する
   332:   public static void dgtEnter () {
   333:     String text = dgtBoard.getText ();  //テキスト全体
   334:     int length = text.length ();  //テキスト全体の長さ
   335:     int outputLineStart = text.lastIndexOf ('\n', dgtOutputEnd - 1) + 1;  //出力の末尾の行の先頭。プロンプトの先頭
   336:     int caretLineStart = text.lastIndexOf ('\n', dgtBoard.getCaretPosition () - 1) + 1;  //キャレットがある行の先頭
   337:     if (outputLineStart <= caretLineStart) {  //出力の末尾の行の先頭以降でEnterキーが押された
   338:       dgtBoard.replaceRange ("", dgtOutputEnd, length);  //入力された文字列を一旦削除する
   339:       dgtSend (text.substring (dgtOutputEnd, length));  //入力された文字列を送信する
   340:     } else if (outputLineStart < dgtOutputEnd) {  //出力の末尾の行の先頭よりも手前でEnterキーが押されて、出力の末尾の行にプロンプトがあるとき
   341:       String prompt = text.substring (outputLineStart, dgtOutputEnd);  //出力の末尾の行のプロンプト
   342:       int caretLineEnd = text.indexOf ('\n', caretLineStart);  //キャレットがある行の末尾
   343:       if (caretLineEnd == -1) {
   344:         caretLineEnd = length;
   345:       }
   346:       String line = text.substring (caretLineStart, caretLineEnd);  //キャレットがある行
   347:       int start = line.indexOf (prompt);  //キャレットがある行のプロンプトの先頭
   348:       if (0 <= start) {  //キャレットがある行にプロンプトがあるとき
   349:         dgtOutputEnd = length;  //入力された文字列を無効化する
   350:         if (text.charAt (dgtOutputEnd - 1) != '\n' && !text.endsWith ("\n" + prompt)) {  //改行または改行+プロンプトで終わっていないとき
   351:           dgtBoard.insert ("\n", dgtOutputEnd);  //末尾に改行を追加する
   352:           dgtOutputEnd++;
   353:           if (DGT_CUT_OUTPUT_LENGTH <= dgtOutputEnd) {
   354:             dgtBoard.replaceRange ("", 0, dgtOutputEnd - DGT_MAX_OUTPUT_LENGTH);  //先頭を削って短くする
   355:             dgtOutputEnd = DGT_MAX_OUTPUT_LENGTH;
   356:           }
   357:         }
   358:         dgtBoard.setCaretPosition (dgtOutputEnd);
   359:         dgtSend (line.substring (start + prompt.length ()));  //プロンプトの後ろから行の末尾までを送信する
   360:       }
   361:     }
   362:   }  //dgtEnter()
   363: 
   364:   //dgtSend (s)
   365:   //  入力された文字列を処理する
   366:   public static void dgtSend (String s) {
   367:     dgtPrintln (s);
   368:     if (dgtInputMode == DGT_INPUT_MODE_COMMAND) {  //コマンドモード
   369:       ExpressionEvaluator.ExpressionElement nodeTree = XEiJ.fpuBox.evxParse (s, ExpressionEvaluator.EVM_COMMAND);
   370:       if (nodeTree != null) {
   371:         nodeTree.exlEval (ExpressionEvaluator.EVM_COMMAND);
   372:         if (nodeTree.exlValueType == ExpressionEvaluator.ElementType.ETY_FLOAT) {
   373:           dgtPrintln (nodeTree.exlFloatValue.toString ());
   374:         } else if (nodeTree.exlValueType == ExpressionEvaluator.ElementType.ETY_STRING) {
   375:           dgtPrintln (nodeTree.exlStringValue);
   376:         }
   377:       }
   378:     } else if (dgtInputMode == DGT_INPUT_MODE_PAGE) {  //ページモード
   379:       if (!(s.equals ("") ||
   380:             s.toLowerCase ().startsWith (" ") ||
   381:             s.toLowerCase ().startsWith ("y"))) {
   382:         dgtPageList = null;
   383:       }
   384:       dgtPrintPage ();
   385:     } else if (dgtInputMode == DGT_INPUT_MODE_ASSEMBLER) {  //アセンブラモード
   386:       if (s.equals (".")) {  //コマンドモードに戻る
   387:         dgtInputMode = DGT_INPUT_MODE_COMMAND;
   388:         dgtCurrentPrompt = DGT_COMMAND_PROMPT;
   389:       } else {  //アセンブルする
   390:         byte[] binary = Assembler.asmAssemble (dgtAssemblePC, s);
   391:         if (binary != null && 0 < binary.length) {  //バイナリがある
   392:           for (int i = 0; i < binary.length; i++) {
   393:             MC68060.mmuPokeByte (dgtAssemblePC + i, binary[i], dgtAssembleFC);
   394:           }
   395:           //逆アセンブルする
   396:           int itemAddress = dgtAssemblePC;
   397:           dgtAssemblePC += binary.length;
   398:           dgtMakeAssemblerPrompt ();
   399:           int supervisor = DebugConsole.dgtAssembleFC & 4;
   400:           StringBuilder sb = new StringBuilder ();
   401:           while (itemAddress < dgtAssemblePC) {
   402:             String code = Disassembler.disDisassemble (new StringBuilder (), itemAddress, supervisor).toString ();
   403:             int itemEndAddress = Disassembler.disPC;
   404:             if (dgtAssemblePC < itemEndAddress) {  //アセンブルした範囲からはみ出すときdc.wに置き換える
   405:               itemEndAddress = dgtAssemblePC;
   406:               StringBuilder sb2 = new StringBuilder ();
   407:               sb2.append ("dc.w    ");
   408:               for (int a = itemAddress; a < itemEndAddress; a += 2) {
   409:                 if (itemAddress < a) {
   410:                   sb2.append (',');
   411:                 }
   412:                 XEiJ.fmtHex4 (sb2.append ('$'), MC68060.mmuPeekWordZeroCode (a, supervisor));
   413:               }
   414:               code = sb2.toString ();
   415:             }
   416:             //1行目
   417:             int lineAddress = itemAddress;  //行の開始アドレス
   418:             int lineEndAddress = Math.min (lineAddress + 10, itemEndAddress);  //行の終了アドレス
   419:             //アドレス
   420:             XEiJ.fmtHex8 (sb, lineAddress).append ("  ");
   421:             //データ
   422:             for (int a = lineAddress; a < lineEndAddress; a += 2) {
   423:               XEiJ.fmtHex4 (sb, MC68060.mmuPeekWordZeroCode (a, supervisor));
   424:             }
   425:             sb.append (XEiJ.DBG_SPACES, 0, 2 * Math.max (0, lineAddress + 10 - lineEndAddress) + 2);
   426:             //逆アセンブル結果
   427:             sb.append (code).append ('\n');
   428:             //2行目以降
   429:             while (lineEndAddress < itemEndAddress) {
   430:               lineAddress = lineEndAddress;  //行の開始アドレス
   431:               lineEndAddress = Math.min (lineAddress + 10, itemEndAddress);  //行の終了アドレス
   432:               //アドレス
   433:               XEiJ.fmtHex8 (sb, lineAddress).append ("  ");
   434:               //データ
   435:               for (int a = lineAddress; a < lineEndAddress; a += 2) {
   436:                 XEiJ.fmtHex4 (sb, MC68060.mmuPeekWordZeroCode (a, supervisor));
   437:               }
   438:               sb.append ('\n');
   439:             }  //while
   440:             itemAddress = itemEndAddress;
   441:           }  //while itemAddress<dgtAssemblePC
   442:           dgtPrint (sb.toString ());
   443:         }  //if バイナリがある
   444:       }  //if コマンドモードに戻る/アセンブルする
   445:     }  //if コマンドモード/ページモード/アセンブラモード
   446:     if (!dgtRequestRegs) {
   447:       dgtPrintPrompt ();
   448:     }
   449:   }  //dgtSend(String)
   450: 
   451:   //dgtMakeAssemblerPrompt ()
   452:   //  アセンブラモードのプロンプトを作る
   453:   public static void dgtMakeAssemblerPrompt () {
   454:     StringBuilder sb = XEiJ.fmtHex8 (new StringBuilder (), dgtAssemblePC);
   455:     if (Model.MPU_MC68LC040 <= XEiJ.currentMPU) {
   456:       sb.append ('@').append (dgtAssembleFC);
   457:     }
   458:     dgtCurrentPrompt = sb.append ("  ").toString ();
   459:   }  //dgtMakeAssemblerPrompt()
   460: 
   461:   //dgtPrintPrompt (s)
   462:   //  プロンプトを表示する
   463:   //  既に表示されているときは何もしない
   464:   public static void dgtPrintPrompt () {
   465:     String text = dgtBoard.getText ();  //テキスト全体
   466:     if (!text.substring (text.lastIndexOf ('\n', dgtOutputEnd - 1) + 1, dgtOutputEnd).equals (dgtCurrentPrompt)) {  //プロンプトが表示されていない
   467:       dgtPrint (text.endsWith ("\n") ? dgtCurrentPrompt : "\n" + dgtCurrentPrompt);
   468:     }
   469:   }  //dgtPrintPrompt()
   470: 
   471:   //dgtPrintPage ()
   472:   //  ページを表示する
   473:   public static void dgtPrintPage () {
   474:     if (dgtPageList != null && !dgtPageList.isEmpty ()) {  //ページがある
   475:       dgtPrint (dgtPageList.pollFirst ());
   476:       if (!dgtPageList.isEmpty ()) {  //次のページがある
   477:         //ページモードに移行する
   478:         DebugConsole.dgtInputMode = DebugConsole.DGT_INPUT_MODE_PAGE;
   479:         dgtCurrentPrompt = DGT_PAGE_PROMPT;
   480:       }
   481:     }
   482:     if (dgtPageList == null || dgtPageList.isEmpty ()) {  //ページがない
   483:       dgtPageList = null;
   484:       //コマンドモードに戻る
   485:       dgtInputMode = DGT_INPUT_MODE_COMMAND;
   486:       dgtCurrentPrompt = DGT_COMMAND_PROMPT;
   487:     }
   488:     dgtPrintPrompt ();
   489:   }  //dgtPrintPage()
   490: 
   491: }  //class DebugConsole
   492: 
   493: 
   494: