MemoryDumpList.java
     1: //========================================================================================
     2: //  MemoryDumpList.java
     3: //    en:Memory dump list
     4: //    ja:メモリダンプリスト
     5: //  Copyright (C) 2003-2017 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: //  http://stdkmd.com/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.event.*;  //ActionEvent,ActionListener,ComponentAdapter,ComponentEvent,ComponentListener,FocusAdapter,FocusEvent,FocusListener,InputEvent,KeyAdapter,KeyEvent,KeyListener,MouseAdapter,MouseEvent,MouseListener,MouseMotionAdapter,MouseWheelEvent,WindowAdapter,WindowEvent,WindowListener,WindowStateListener
    17: import java.lang.*;  //Boolean,Character,Class,Comparable,Double,Exception,Float,IllegalArgumentException,Integer,Long,Math,Number,Object,Runnable,SecurityException,String,StringBuilder,System
    18: import java.util.*;  //ArrayList,Arrays,Calendar,GregorianCalendar,HashMap,Map,Map.Entry,TimeZone,Timer,TimerTask,TreeMap
    19: import javax.swing.*;  //AbstractSpinnerModel,Box,ButtonGroup,DefaultListModel,ImageIcon,JApplet,JButton,JCheckBox,JCheckBoxMenuItem,JDialog,JFileChooser,JFrame,JLabel,JList,JMenu,JMenuBar,JMenuItem,JPanel,JRadioButton,JScrollPane,JSpinner,JTextArea,JTextField,JTextPane,JViewport,ScrollPaneConstants,SpinnerListModel,SpinnerNumberModel,SwingConstants,SwingUtilities,UIManager,UIDefaults,UnsupportedLookAndFeelException
    20: import javax.swing.event.*;  //CaretEvent,CaretListener,ChangeEvent,ChangeListener,DocumentEvent,DocumentListener,ListSelectionListener
    21: import javax.swing.text.*;  //AbstractDocument,BadLocationException,DefaultCaret,Document,DocumentFilter,JTextComponent,ParagraphView,Style,StyleConstants,StyleContext,StyledDocument
    22: 
    23: public class MemoryDumpList {
    24: 
    25:   public static final int DMP_ITEM_SIZE = 0x00000010;  //項目の最小サイズ
    26:   public static final int DMP_PAGE_SIZE = 0x00000400;  //ページのサイズ
    27:   public static final int DMP_ITEM_MASK = -DMP_ITEM_SIZE;
    28:   public static final int DMP_PAGE_MASK = -DMP_PAGE_SIZE;
    29:   public static final int DMP_MAX_ITEMS = DMP_PAGE_SIZE / DMP_ITEM_SIZE + 2;  //ページの最大項目数。先頭と末尾の番兵を含む
    30: 
    31:   public static final char[] DMP_BASE = (
    32:     //         11111111112222222222333333333344444444445555555555666666666677777777778
    33:     //12345678901234567890123456789012345678901234567890123456789012345678901234567890
    34:     "xxxxxxxx  xx xx xx xx  xx xx xx xx  xx xx xx xx  xx xx xx xx  ").toCharArray ();
    35:   public static final int DMP_DATA_START = 10;  //行頭からデータの開始位置までのオフセット
    36:   public static final int[] DMP_DATA_ADDRESS = {
    37:     0,   1, -1,  2,  3, -1,  4,  5, -1,  6,  7, -1, -1,
    38:     8,   9, -1, 10, 11, -1, 12, 13, -1, 14, 15, -1, -1,
    39:     16, 17, -1, 18, 19, -1, 20, 21, -1, 22, 23, -1, -1,
    40:     24, 25, -1, 26, 27, -1, 28, 29, -1, 30, 31,
    41:   };  //データの開始位置からのオフセット→データのアドレス*2+(0=上位,1=下位)。-1=空白
    42:   public static final int[] DMP_DATA_OFFSET = {
    43:     0,   1,  3,  4,  6,  7,  9, 10,
    44:     13, 14, 16, 17, 19, 20, 22, 23,
    45:     26, 27, 29, 30, 32, 33, 35, 36,
    46:     39, 40, 42, 43, 45, 46, 48, 49,
    47:   };  //データのアドレス*2+(0=上位,1=下位)→データの開始位置からのオフセット
    48: 
    49:   public static int dmpItemCount;  //ページに含まれる項目の数。先頭と末尾の番兵を含む。0=構築前または再構築要求
    50:   public static int dmpItemIndex;  //キャレットがある項目の番号
    51:   public static int dmpPageAddress;  //ページの先頭アドレス
    52:   public static final int[] dmpAddressArray = new int[DMP_MAX_ITEMS];  //項目の先頭アドレスの配列。先頭は前のページの末尾、末尾は次のページの先頭。スピナーのヒント
    53:   public static final int[] dmpSplitArray = new int[DMP_MAX_ITEMS];  //項目を区切る位置の配列。先頭は0
    54:   public static final int[] dmpCaretArray = new int[DMP_MAX_ITEMS];  //項目が選択されたときキャレットを移動させる位置の配列。行の手前にヘッダやラベルなどを挿入しないときはdmpSplitArrayと同じ
    55: 
    56:   public static JFrame dmpFrame;  //ウインドウ
    57:   public static ScrollTextArea dmpBoard;  //スクロールテキストエリア
    58:   public static JTextArea dmpTextArea;  //テキストエリア
    59:   public static Hex8Spinner dmpSpinner;  //スピナー
    60: 
    61:   public static int dmpSupervisorMode;  //0=ユーザモード,0以外=スーパーバイザモード
    62:   public static JCheckBox dmpSupervisorCheckBox;  //ユーザ/スーパーバイザチェックボックス
    63: 
    64:   //dmpInit ()
    65:   //  初期化
    66:   public static void dmpInit () {
    67: 
    68:     dmpItemCount = 0;  //構築前
    69:     dmpItemIndex = 0;
    70:     dmpPageAddress = 0;
    71:     dmpSupervisorMode = 1;
    72:     //dmpAddressArray = new int[DMP_MAX_ITEMS];
    73:     //dmpSplitArray = new int[DMP_MAX_ITEMS];
    74:     //dmpCaretArray = new int[DMP_MAX_ITEMS];
    75: 
    76:     dmpFrame = null;
    77: 
    78:   }  //dmpInit()
    79: 
    80:   //dmpStart ()
    81:   public static void dmpStart () {
    82:     if (RestorableFrame.rfmGetOpened (Settings.SGS_DMP_FRAME_KEY)) {
    83:       dmpOpen (-1, -1, true);
    84:     }
    85:   }  //dmpStart()
    86: 
    87:   //dmpOpen (address, supervisor, forceUpdate)
    88:   //  メモリダンプリストウインドウを開く
    89:   //  既に開いているときは手前に持ってくる
    90:   public static void dmpOpen (int address, int supervisor, boolean forceUpdate) {
    91:     if (dmpFrame == null) {
    92:       dmpMake ();
    93:     }
    94:     dmpUpdate (address, supervisor, forceUpdate);
    95:     dmpFrame.setVisible (true);
    96:     XEiJ.dbgVisibleMask |= XEiJ.DBG_DMP_VISIBLE_MASK;
    97:   }  //dmpOpen(int,int,boolean)
    98: 
    99:   //dmpMake ()
   100:   //  メモリダンプリストウインドウを作る
   101:   public static void dmpMake () {
   102: 
   103:     //スクロールテキストエリア
   104:     dmpBoard = ComponentFactory.setPreferredSize (
   105:       ComponentFactory.setFont (new ScrollTextArea (), new Font ("Monospaced", Font.PLAIN, 12)),
   106:       500, 400);
   107:     dmpBoard.setMargin (new Insets (2, 4, 2, 4));
   108:     dmpBoard.setHighlightCursorOn (true);
   109:     dmpTextArea = dmpBoard.getTextArea ();
   110:     dmpTextArea.setEditable (false);
   111: 
   112:     //スピナー
   113:     dmpSpinner = new Hex8Spinner (dmpPageAddress, DMP_ITEM_MASK, true);
   114: 
   115:     //スピナーのチェンジリスナー
   116:     //  スピナーが操作されたとき、そのアドレスの行にテキストエリアのキャレットを移動させる
   117:     //  ページの範囲外になったときはテキストエリアを再構築する
   118:     //  ページの構築中に呼び出されたときは何もしない
   119:     dmpSpinner.addChangeListener (new ChangeListener () {
   120:       @Override public void stateChanged (ChangeEvent ce) {
   121:         if (XEiJ.dbgEventMask == 0) {  //テキストは構築済みでsetTextの中ではない
   122:           dmpUpdate (dmpSpinner.getIntValue (), dmpSupervisorMode, false);
   123:         }
   124:       }
   125:     });
   126: 
   127:     //テキストエリアのキャレットリスナー
   128:     //  テキストエリアがクリックされてキャレットが動いたとき、その行のアドレスをスピナーに設定する
   129:     //  クリックでテキストエリアに移ってしまったフォーカスをスピナーに戻す
   130:     //  ページの構築中に呼び出されたときは何もしない
   131:     //    setText→キャレットリスナー→スピナーのチェンジリスナー→setTextとなるとsetTextの二重呼び出しでエラーが出る
   132:     ComponentFactory.addListener (
   133:       dmpTextArea,
   134:       new CaretListener () {
   135:         @Override public void caretUpdate (CaretEvent ce) {
   136:           if (XEiJ.dbgEventMask == 0) {  //テキストは構築済みでsetTextの中ではない
   137:             int p = ce.getDot ();  //キャレットの位置
   138:             if (p == ce.getMark ()) {  //選択範囲がない
   139:               int i = Arrays.binarySearch (dmpSplitArray, 1, dmpItemCount, p + 1);  //項目の先頭のときも次の項目を検索してから1つ戻る
   140:               i = (i >> 31 ^ i) - 1;  //キャレットがある位置を含む項目の番号
   141:               dmpSpinner.setHintIndex (i);
   142:             }
   143:           }
   144:         }
   145:       });
   146: 
   147:     //テキストエリアのマウスリスナー
   148:     ComponentFactory.addListener (
   149:       dmpTextArea,
   150:       new MouseAdapter () {
   151:         @Override public void mousePressed (MouseEvent me) {
   152:           if (XEiJ.mpuTask == null && me.isPopupTrigger ()) {
   153:             XEiJ.dbgShowPopup (me, dmpTextArea, false);
   154:           }
   155:         }
   156:         @Override public void mouseReleased (MouseEvent me) {
   157:           if (XEiJ.mpuTask == null && me.isPopupTrigger ()) {
   158:             XEiJ.dbgShowPopup (me, dmpTextArea, false);
   159:           }
   160:         }
   161:       });
   162: 
   163:     //テキストエリアのフォーカスリスナー
   164:     ComponentFactory.addListener (
   165:       dmpBoard,
   166:       new FocusAdapter () {
   167:         @Override public void focusGained (FocusEvent fe) {
   168:           dmpBoard.setCaretVisible (true);
   169:         }
   170:         @Override public void focusLost (FocusEvent fe) {
   171:           dmpBoard.setCaretVisible (false);
   172:         }
   173:       });
   174: 
   175:     //テキストエリアのキーリスナー
   176:     ComponentFactory.addListener (
   177:       dmpBoard,
   178:       new KeyAdapter () {
   179:         @Override public void keyTyped (KeyEvent ke) {
   180:           if (XEiJ.dbgEventMask == 0) {  //テキストは構築済みでsetTextの中ではない
   181:             int x = Character.digit (ke.getKeyChar (), 16);
   182:             if (x >= 0) {  //16進数のキーが押された
   183:               int p = dmpTextArea.getCaretPosition ();  //キャレットの位置
   184:               int i = Arrays.binarySearch (dmpSplitArray, 1, dmpItemCount, p + 1);
   185:               i = (i >> 31 ^ i) - 1;  //キャレットがある位置を含む項目の番号
   186:               int t = p - dmpCaretArray[i] - DMP_DATA_START;  //最初のデータの位置からのオフセット
   187:               if (t >= 0 && t < DMP_DATA_ADDRESS.length) {
   188:                 t = DMP_DATA_ADDRESS[t];
   189:                 if (t >= 0) {  //データがある
   190:                   int a = dmpAddressArray[i] + (t >> 1);  //アドレス
   191:                   XEiJ.dbgEventMask++;  //キャレットが動くがキャレットリスナーが反応しないようにする
   192:                   if ((t & 1) == 0) {  //上位
   193:                     try {
   194:                       MC68060.mmuPokeByteData (a, x << 4 | Character.digit (dmpTextArea.getText (p + 1, 1).charAt (0), 16), XEiJ.regSRS);  //書き込む
   195:                     } catch (BadLocationException ble) {
   196:                     }
   197:                     dmpTextArea.replaceRange (XEiJ.fmtHex2 (MC68060.mmuPeekByteZeroData (a, XEiJ.regSRS)), p, p + 2);  //読み出す
   198:                     dmpTextArea.setCaretPosition (p + 1);  //下位の位置
   199:                   } else {  //下位
   200:                     try {
   201:                       MC68060.mmuPokeByteData (a, Character.digit (dmpTextArea.getText (p - 1, 1).charAt (0), 16) << 4 | x, XEiJ.regSRS);  //書き込む
   202:                     } catch (BadLocationException ble) {
   203:                     }
   204:                     dmpTextArea.replaceRange (XEiJ.fmtHex2 (MC68060.mmuPeekByteZeroData (a, XEiJ.regSRS)), p - 1, p + 1);  //読み出す
   205:                     if (t < 31) {
   206:                       dmpTextArea.setCaretPosition (dmpCaretArray[i] + DMP_DATA_START + DMP_DATA_OFFSET[t + 1]);  //次のアドレスの上位の位置
   207:                     }
   208:                   }
   209:                   XEiJ.dbgEventMask--;
   210:                 }
   211:               }
   212:             }
   213:           }
   214:         }
   215:       });
   216: 
   217:     //ボタンのアクションリスナー
   218:     ActionListener listener = new ActionListener () {
   219:       @Override public void actionPerformed (ActionEvent ae) {
   220:         Object source = ae.getSource ();
   221:         switch (ae.getActionCommand ()) {
   222:         case "Reload":
   223:           dmpItemCount = 0;  //再構築要求
   224:           dmpUpdate (dmpAddressArray[dmpItemIndex], dmpSupervisorMode, true);
   225:           break;
   226:         case "User/Supervisor":  //ユーザ/スーパーバイザ
   227:           if (XEiJ.dbgEventMask == 0) {
   228:             dmpUpdate (dmpAddressArray[dmpItemIndex], ((JCheckBox) ae.getSource ()).isSelected () ? 1 : 0, true);
   229:           }
   230:           break;
   231:         }
   232:       }
   233:     };
   234: 
   235:     //スーパーバイザチェックボックス
   236:     dmpSupervisorCheckBox =
   237:       Multilingual.mlnToolTipText (
   238:         ComponentFactory.createIconCheckBox (
   239:           dmpSupervisorMode != 0,
   240:           XEiJ.createImage (
   241:             20, 14,
   242:             "22222222222222222222" +
   243:             "2..................2" +
   244:             "2..................2" +
   245:             "2.....11....11.....2" +
   246:             "2.....11....11.....2" +
   247:             "2.....11....11.....2" +
   248:             "2.....11....11.....2" +
   249:             "2.....11....11.....2" +
   250:             "2.....11....11.....2" +
   251:             "2.....11111111.....2" +
   252:             "2.....11111111.....2" +
   253:             "2..................2" +
   254:             "2..................2" +
   255:             "22222222222222222222",
   256:             LnF.LNF_RGB[0],
   257:             LnF.LNF_RGB[12],
   258:             LnF.LNF_RGB[12]),
   259:           XEiJ.createImage (
   260:             20, 14,
   261:             "22222222222222222222" +
   262:             "2..................2" +
   263:             "2..................2" +
   264:             "2.....11111111.....2" +
   265:             "2.....11111111.....2" +
   266:             "2.....11...........2" +
   267:             "2.....11111111.....2" +
   268:             "2.....11111111.....2" +
   269:             "2...........11.....2" +
   270:             "2.....11111111.....2" +
   271:             "2.....11111111.....2" +
   272:             "2..................2" +
   273:             "2..................2" +
   274:             "22222222222222222222",
   275:             LnF.LNF_RGB[0],
   276:             LnF.LNF_RGB[12],
   277:             LnF.LNF_RGB[12]),
   278:           "User/Supervisor", listener),
   279:         "ja", "ユーザ/スーパーバイザ");
   280: 
   281:     //ウインドウ
   282:     dmpFrame = Multilingual.mlnTitle (
   283:       ComponentFactory.createRestorableSubFrame (
   284:         Settings.SGS_DMP_FRAME_KEY,
   285:         "Memory Dump List",
   286:         null,
   287:         ComponentFactory.createBorderPanel (
   288:           dmpBoard,
   289:           ComponentFactory.createHorizontalBox (
   290:             dmpSpinner,
   291:             dmpSupervisorCheckBox,
   292:             Multilingual.mlnToolTipText (
   293:               ComponentFactory.createImageButton (
   294:                 XEiJ.createImage (
   295:                   20, 14,
   296:                   "11111111111111111111" +
   297:                   "1..................1" +
   298:                   "1.......1111.......1" +
   299:                   "1......111111.1....1" +
   300:                   "1.....11....111....1" +
   301:                   "1....11.....111....1" +
   302:                   "1....11....1111....1" +
   303:                   "1....11............1" +
   304:                   "1....11............1" +
   305:                   "1.....11....11.....1" +
   306:                   "1......111111......1" +
   307:                   "1.......1111.......1" +
   308:                   "1..................1" +
   309:                   "11111111111111111111",
   310:                   LnF.LNF_RGB[0],
   311:                   LnF.LNF_RGB[12]),
   312:                 "Reload", listener),
   313:               "ja", "再読み込み"),
   314:             Box.createHorizontalGlue ()
   315:             )
   316:           )
   317:         ),
   318:       "ja", "メモリダンプリスト");
   319:     ComponentFactory.addListener (
   320:       dmpFrame,
   321:       new WindowAdapter () {
   322:         @Override public void windowClosing (WindowEvent we) {
   323:           XEiJ.dbgVisibleMask &= ~XEiJ.DBG_DMP_VISIBLE_MASK;
   324:         }
   325:       });
   326: 
   327:   }  //dmpMake()
   328: 
   329:   //dmpUpdate (address, supervisor, forceUpdate)
   330:   //  メモリダンプリストウインドウを更新する
   331:   public static void dmpUpdate (int address, int supervisor, boolean forceUpdate) {
   332: 
   333:     XEiJ.dbgEventMask++;  //構築開始
   334: 
   335:     if (address == -1) {  //spを表示
   336:       address = XEiJ.regRn[15];
   337:       forceUpdate = true;
   338:     }
   339: 
   340:     if (supervisor == -1) {
   341:       supervisor = XEiJ.regSRS;
   342:       forceUpdate = true;
   343:     }
   344: 
   345:     if ((dmpSupervisorMode != 0) != (supervisor != 0)) {  //ユーザ/スーパーバイザが一致しない
   346:       dmpSupervisorMode = supervisor;
   347:       forceUpdate = true;
   348:       if (dmpSupervisorCheckBox.isSelected () != (supervisor != 0)) {
   349:         dmpSupervisorCheckBox.setSelected (supervisor != 0);
   350:       }
   351:     }
   352: 
   353:     if (forceUpdate) {  //再構築要求
   354:       dmpItemCount = 0;
   355:     }
   356: 
   357:     if (dmpItemCount != 0) {  //構築前または再構築要求のいずれでもない
   358:       int i = Arrays.binarySearch (dmpAddressArray, 1, dmpItemCount, address + 1);  //項目の先頭のときも次の項目を検索してから1つ戻る
   359:       i = (i >> 31 ^ i) - 1;  //目的のアドレスを含む項目の番号
   360:       if (0 < i && i < dmpItemCount - 1 &&  //ページの内側
   361:           dmpAddressArray[i] == address) {  //項目の先頭
   362: 
   363:         //再構築しない
   364: 
   365:         if (dmpItemIndex != i) {  //キャレットがある項目を変更する必要がある
   366:           dmpItemIndex = i;
   367:           dmpTextArea.setCaretPosition (dmpCaretArray[i]);
   368:         }
   369: 
   370:         XEiJ.dbgEventMask--;  //構築終了
   371: 
   372:         return;
   373:       }
   374:     }
   375: 
   376:     //再構築する
   377: 
   378:     //構築前または再構築要求または先頭または末尾の番兵が選択された
   379:     //  0x00000000の境界を跨ぐとき反対側を指すことがあるので先頭と末尾の番兵を区別しない
   380:     address &= DMP_ITEM_MASK;  //目的のアドレスを含む項目の先頭アドレス
   381:     dmpPageAddress = address & DMP_PAGE_MASK;  //ページの先頭アドレス
   382:     int pageEndAddress = dmpPageAddress + DMP_PAGE_SIZE;  //ページの末尾アドレス。0になることがある
   383: 
   384:     //先頭の番兵
   385:     dmpAddressArray[0] = dmpPageAddress - DMP_ITEM_SIZE;  //昇順を維持するためマスクしない
   386:     dmpSplitArray[0] = 0;
   387:     dmpCaretArray[0] = 0;
   388:     StringBuilder sb = new StringBuilder (
   389:       //         1111111111222222222233333333334444444444555555555566666666667777777777
   390:       //1234567890123456789012345678901234567890123456789012345678901234567890123456789
   391:       //xxxxxxx  xx xx xx xx  xx xx xx xx  xx xx xx xx  xx xx xx xx  ................
   392:       "          +0 +1 +2 +3  +4 +5 +6 +7  +8 +9 +A +B  +C +D +E +F                ▲\n");
   393:     int itemCount = 1;  //項目数
   394:     int itemAddress = dmpPageAddress;  //項目の先頭アドレス
   395: 
   396:     do {
   397:       int itemEndAddress = itemAddress + DMP_ITEM_SIZE;  //項目の末尾アドレス
   398:       //項目の開始
   399:       if (itemAddress == address) {
   400:         dmpItemIndex = itemCount;  //目的のアドレスを含む項目の番号
   401:       }
   402:       dmpAddressArray[itemCount] = itemAddress;  //項目の先頭アドレス
   403:       dmpSplitArray[itemCount] = sb.length ();  //項目を区切る位置
   404:       dmpCaretArray[itemCount] = sb.length ();  //項目が選択されたときキャレットを移動させる位置
   405:       //アドレス
   406:       XEiJ.fmtHex8 (DMP_BASE,  0, itemAddress);
   407:       //データ
   408:       XEiJ.fmtHex2 (DMP_BASE, 10, MC68060.mmuPeekByteZeroData (itemAddress     , supervisor));
   409:       XEiJ.fmtHex2 (DMP_BASE, 13, MC68060.mmuPeekByteZeroData (itemAddress +  1, supervisor));
   410:       XEiJ.fmtHex2 (DMP_BASE, 16, MC68060.mmuPeekByteZeroData (itemAddress +  2, supervisor));
   411:       XEiJ.fmtHex2 (DMP_BASE, 19, MC68060.mmuPeekByteZeroData (itemAddress +  3, supervisor));
   412:       XEiJ.fmtHex2 (DMP_BASE, 23, MC68060.mmuPeekByteZeroData (itemAddress +  4, supervisor));
   413:       XEiJ.fmtHex2 (DMP_BASE, 26, MC68060.mmuPeekByteZeroData (itemAddress +  5, supervisor));
   414:       XEiJ.fmtHex2 (DMP_BASE, 29, MC68060.mmuPeekByteZeroData (itemAddress +  6, supervisor));
   415:       XEiJ.fmtHex2 (DMP_BASE, 32, MC68060.mmuPeekByteZeroData (itemAddress +  7, supervisor));
   416:       XEiJ.fmtHex2 (DMP_BASE, 36, MC68060.mmuPeekByteZeroData (itemAddress +  8, supervisor));
   417:       XEiJ.fmtHex2 (DMP_BASE, 39, MC68060.mmuPeekByteZeroData (itemAddress +  9, supervisor));
   418:       XEiJ.fmtHex2 (DMP_BASE, 42, MC68060.mmuPeekByteZeroData (itemAddress + 10, supervisor));
   419:       XEiJ.fmtHex2 (DMP_BASE, 45, MC68060.mmuPeekByteZeroData (itemAddress + 11, supervisor));
   420:       XEiJ.fmtHex2 (DMP_BASE, 49, MC68060.mmuPeekByteZeroData (itemAddress + 12, supervisor));
   421:       XEiJ.fmtHex2 (DMP_BASE, 52, MC68060.mmuPeekByteZeroData (itemAddress + 13, supervisor));
   422:       XEiJ.fmtHex2 (DMP_BASE, 55, MC68060.mmuPeekByteZeroData (itemAddress + 14, supervisor));
   423:       XEiJ.fmtHex2 (DMP_BASE, 58, MC68060.mmuPeekByteZeroData (itemAddress + 15, supervisor));
   424:       sb.append (DMP_BASE);
   425:       //キャラクタ
   426:       for (int a = itemAddress; a < itemEndAddress; a++) {
   427:         int h = MC68060.mmuPeekByteZeroData (a, supervisor);
   428:         int c;
   429:         if (0x81 <= h && h <= 0x9f || 0xe0 <= h && h <= 0xef) {  //SJISの2バイトコードの1バイト目
   430:           int l = MC68060.mmuPeekByteZeroData (a + 1, supervisor);  //これは範囲外になる場合がある
   431:           if (0x40 <= l && l != 0x7f && l <= 0xfc) {  //SJISの2バイトコードの2バイト目
   432:             c = CharacterCode.chrSJISToChar[h << 8 | l];  //2バイトで変換する
   433:             if (c == 0) {  //対応する文字がない
   434:               c = '※';
   435:             }
   436:             a++;
   437:           } else {  //SJISの2バイトコードの2バイト目ではない
   438:             c = '.';  //SJISの2バイトコードの1バイト目ではなかった
   439:           }
   440:         } else {  //SJISの2バイトコードの1バイト目ではない
   441:           c = CharacterCode.chrSJISToChar[h];  //1バイトで変換する
   442:           if (c < 0x20 || c == 0x7f) {  //対応する文字がないまたは制御コード
   443:             c = '.';
   444:           }
   445:         }
   446:         sb.append ((char) c);
   447:       }  //for a
   448:       sb.append ('\n');
   449:       //項目の終了
   450:       itemCount++;
   451:       itemAddress = itemEndAddress;
   452:     } while (itemAddress < pageEndAddress);
   453: 
   454:     //末尾の番兵
   455:     dmpAddressArray[itemCount] = itemAddress;  //昇順を維持するためマスクしない
   456:     dmpSplitArray[itemCount] = sb.length ();
   457:     dmpCaretArray[itemCount] = sb.length ();
   458:     sb.append (
   459:       //         1111111111222222222233333333334444444444555555555566666666667777777777
   460:       //1234567890123456789012345678901234567890123456789012345678901234567890123456789
   461:       "          +0 +1 +2 +3  +4 +5 +6 +7  +8 +9 +A +B  +C +D +E +F                ▼");
   462:     itemCount++;
   463:     dmpItemCount = itemCount;
   464: 
   465:     //テキスト
   466:     dmpTextArea.setText (sb.toString ());
   467:     dmpTextArea.setCaretPosition (dmpCaretArray[dmpItemIndex]);
   468: 
   469:     //スピナー
   470:     dmpSpinner.setHintArray (dmpAddressArray, itemCount);
   471:     dmpSpinner.setHintIndex (dmpItemIndex);
   472: 
   473:     XEiJ.dbgEventMask--;  //構築終了
   474: 
   475:   }  //dmpUpdate(int,int,boolean)
   476: 
   477: }  //class MemoryDumpList
   478: 
   479: 
   480: