RasterBreakPoint.java
     1: //========================================================================================
     2: //  RasterBreakPoint.java
     3: //    en:Raster break point -- It stops the MPU at the horizontal front porch just before the specified break raster or the IRQ raster.
     4: //    ja:ラスタブレークポイント -- 指定されたブレークラスタまたはIRQラスタの直前の水平フロントポーチでMPUを止めます。
     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.event.*;  //ActionEvent,ActionListener,ComponentAdapter,ComponentEvent,ComponentListener,FocusAdapter,FocusEvent,FocusListener,InputEvent,KeyAdapter,KeyEvent,KeyListener,MouseAdapter,MouseEvent,MouseListener,MouseMotionAdapter,MouseWheelEvent,WindowAdapter,WindowEvent,WindowListener,WindowStateListener
    16: 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
    17: import javax.swing.event.*;  //CaretListener,ChangeEvent,ChangeListener,DocumentEvent,DocumentListener,ListSelectionListener
    18: 
    19: public class RasterBreakPoint {
    20: 
    21:   public static final boolean RBP_ON = true;  //true=ラスタブレークポイント機能を有効にする
    22: 
    23:   //ラスタブレーク
    24:   public static boolean rbpBreakEnabled;  //true=指定されたブレークラスタでラスタブレークをかける
    25:   public static int rbpBreakRaster;  //ブレークラスタ。0~1023
    26:   public static int rbpActiveBreakRaster;  //使用中のブレークラスタ。rbpBreakEnabled?rbpBreakRaster:-1
    27:   public static boolean rbpIRQBreakEnabled;  //true=IRQラスタでラスタブレークをかける
    28:   public static int rbpCountValue;  //回数
    29:   public static int rbpThresholdValue;  //閾値
    30: 
    31:   //ウインドウ
    32:   public static JFrame rbpFrame;
    33:   public static JCheckBox rbpEnabledCheckBox;
    34:   public static JCheckBox rbpIRQEnabledCheckBox;
    35:   public static JLabel rbpStatusLabel;
    36:   public static JTextField rbpCurrentRasterTextField;
    37:   public static JTextField rbpIRQRasterTextField;
    38:   public static SpinnerNumberModel rbpBreakModel;
    39:   public static SpinnerNumberModel rbpCountModel;
    40:   public static SpinnerNumberModel rbpThresholdModel;
    41: 
    42:   //タイマー
    43:   public static final int RBP_INTERVAL = 10;
    44:   public static int rbpTimer;
    45: 
    46:   //rbpInit ()
    47:   //  初期化
    48:   public static void rbpInit () {
    49:     //ラスタブレーク
    50:     rbpBreakEnabled = false;
    51:     rbpBreakRaster = 0;
    52:     rbpActiveBreakRaster = -1;
    53:     rbpIRQBreakEnabled = false;
    54:     rbpCountValue = 0;
    55:     rbpThresholdValue = 0;
    56:     //ウインドウ
    57:     rbpFrame = null;
    58:     //タイマー
    59:     rbpTimer = 0;
    60:   }  //rbpInit()
    61: 
    62:   //rbpStart ()
    63:   public static void rbpStart () {
    64:     if (RestorableFrame.rfmGetOpened (Settings.SGS_RBP_FRAME_KEY)) {
    65:       rbpOpen ();
    66:     }
    67:   }  //rbpStart()
    68: 
    69:   //rbpOpen ()
    70:   //  ラスタブレークポイントウインドウを開く
    71:   public static void rbpOpen () {
    72:     if (rbpFrame == null) {
    73:       rbpMakeFrame ();
    74:     } else {
    75:       rbpUpdateFrame ();
    76:     }
    77:     XEiJ.dbgVisibleMask |= XEiJ.DBG_RBP_VISIBLE_MASK;
    78:     rbpFrame.setVisible (true);
    79:   }  //rbpOpen()
    80: 
    81:   //rbpMakeFrame ()
    82:   //  ラスタブレークポイントウインドウを作る
    83:   //  ここでは開かない
    84:   public static void rbpMakeFrame () {
    85:     //アクションリスナー
    86:     ActionListener listener = new ActionListener () {
    87:       @Override public void actionPerformed (ActionEvent ae) {
    88:         Object source = ae.getSource ();
    89:         switch (ae.getActionCommand ()) {
    90:         case "Fixed raster ":  //固定ラスタ
    91:           rbpSetBreakEnabled (((JCheckBox) source).isSelected ());  //指定されたブレークラスタでラスタブレークをかけるかどうか
    92:           break;
    93:         case "IRQ raster ":  //IRQ ラスタ
    94:           rbpSetIRQEnabled (((JCheckBox) source).isSelected ());  //IRQラスタでラスタブレークをかけるかどうか
    95:           break;
    96:         case "Run to next raster":  //次のラスタまで実行
    97:           if (XEiJ.mpuTask == null) {
    98:             //一旦無効にする
    99:             rbpSetBreakEnabled (false);
   100:             //ブレークラスタをインクリメントする
   101:             //  rbpSetBreakRaster()で指定してからrbpBreakModelを更新するとrbpSetBreakRaster()が2回呼び出されることになるが、
   102:             //  rbpBreakModel経由だけにするとrbpBreakRasterの更新が遅れる可能性がある
   103:             rbpSetBreakRaster (CRTC.crtRasterNumber < CRTC.crtR04VFrontEndCurr ? CRTC.crtRasterNumber + 1 : 0);
   104:             rbpBreakModel.setValue (Integer.valueOf (rbpBreakRaster));
   105:             //有効にする
   106:             rbpSetBreakEnabled (true);
   107:             rbpEnabledCheckBox.setSelected (true);
   108:             //現在の値を表示する
   109:             rbpUpdateFrame ();
   110:             //実行する
   111:             XEiJ.mpuStart ();
   112:           }
   113:           break;
   114:         case "Run":  //実行
   115:           if (XEiJ.mpuTask == null) {
   116:             //実行する
   117:             XEiJ.mpuStart ();
   118:             //if (!rbpBreakEnabled) {  //無効になっているときは閉じる
   119:             //  rbpFrame.setVisible (false);
   120:             //}
   121:           }
   122:           break;
   123:         }
   124:       }
   125:     };
   126:     //ウインドウ
   127:     rbpFrame = Multilingual.mlnTitle (
   128:       ComponentFactory.createRestorableSubFrame (
   129:         Settings.SGS_RBP_FRAME_KEY,
   130:         "Raster break point",
   131:         null,
   132:         ComponentFactory.createVerticalBox (
   133:           Box.createVerticalStrut (4),
   134:           ComponentFactory.createHorizontalBox (
   135:             Box.createHorizontalStrut (12),
   136:             Box.createHorizontalGlue (),
   137:             rbpStatusLabel = ComponentFactory.createLabel (rbpMakeStatusText ()),
   138:             Box.createHorizontalGlue (),
   139:             Box.createHorizontalStrut (12)
   140:             ),
   141:           Box.createVerticalStrut (4),
   142:           ComponentFactory.createHorizontalBox (
   143:             Box.createHorizontalStrut (12),
   144:             Box.createHorizontalGlue (),
   145:             Multilingual.mlnText (ComponentFactory.createLabel ("Current raster "), "ja", "現在のラスタ "),
   146:             rbpCurrentRasterTextField = ComponentFactory.setEditable (
   147:               ComponentFactory.createNumberField (String.valueOf (CRTC.crtRasterNumber), 5),
   148:               false),
   149:             Box.createHorizontalStrut (12),
   150:             Box.createHorizontalGlue (),
   151:             rbpEnabledCheckBox = Multilingual.mlnText (ComponentFactory.createCheckBox (rbpBreakEnabled, "Fixed raster ", listener), "ja", "固定ラスタ "),
   152:             ComponentFactory.createNumberSpinner (rbpBreakModel = new SpinnerNumberModel (rbpBreakRaster, 0, 1023, 1), 5, new ChangeListener () {
   153:               @Override public void stateChanged (ChangeEvent ce) {
   154:                 rbpSetBreakRaster (rbpBreakModel.getNumber ().intValue ());  //ブレークラスタ
   155:               }
   156:             }),
   157:             Box.createHorizontalStrut (12),
   158:             Box.createHorizontalGlue (),
   159:             rbpIRQEnabledCheckBox = Multilingual.mlnText (ComponentFactory.createCheckBox (rbpIRQBreakEnabled, "IRQ raster ", listener), "ja", "IRQ ラスタ "),
   160:             rbpIRQRasterTextField = ComponentFactory.setEditable (
   161:               ComponentFactory.createNumberField (String.valueOf (CRTC.crtR09IRQRasterCurr), 5),
   162:               false),
   163:             Box.createHorizontalGlue (),
   164:             Box.createHorizontalStrut (12)
   165:             ),
   166:           Box.createVerticalStrut (4),
   167:           ComponentFactory.createHorizontalBox (
   168:             Box.createHorizontalStrut (12),
   169:             Box.createHorizontalGlue (),
   170:             Multilingual.mlnText (ComponentFactory.createLabel ("Count "), "ja", "回数 "),
   171:             ComponentFactory.createNumberSpinner (rbpCountModel = new SpinnerNumberModel (rbpCountValue, 0, 99999999, 1), 8, new ChangeListener () {
   172:               @Override public void stateChanged (ChangeEvent ce) {
   173:                 rbpCountValue = rbpCountModel.getNumber ().intValue ();
   174:               }
   175:             }),
   176:             Box.createHorizontalStrut (12),
   177:             Multilingual.mlnText (ComponentFactory.createLabel ("Threshold "), "ja", "閾値 "),
   178:             ComponentFactory.createNumberSpinner (rbpThresholdModel = new SpinnerNumberModel (rbpThresholdValue, 0, 99999999, 1), 8, new ChangeListener () {
   179:               @Override public void stateChanged (ChangeEvent ce) {
   180:                 rbpThresholdValue = rbpThresholdModel.getNumber ().intValue ();
   181:               }
   182:             }),
   183:             Box.createHorizontalStrut (12),
   184:             Box.createHorizontalGlue (),
   185:             XEiJ.mpuAddButtonStopped (Multilingual.mlnText (ComponentFactory.createButton ("Run to next raster", listener), "ja", "次のラスタまで実行")),
   186:             Box.createHorizontalStrut (12),
   187:             XEiJ.mpuAddButtonStopped (Multilingual.mlnText (ComponentFactory.createButton ("Run", listener), "ja", "実行")),
   188:             Box.createHorizontalGlue (),
   189:             Box.createHorizontalStrut (12)
   190:             ),
   191:           Box.createVerticalStrut (4)
   192:           )
   193:         ),
   194:       "ja", "ラスタブレークポイント");
   195:     //  ウインドウリスナー
   196:     ComponentFactory.addListener (
   197:       rbpFrame,
   198:       new WindowAdapter () {
   199:         @Override public void windowClosing (WindowEvent we) {
   200:           XEiJ.dbgVisibleMask &= ~XEiJ.DBG_RBP_VISIBLE_MASK;
   201:         }
   202:       });
   203:   }  //rbpMakeFrame()
   204: 
   205:   //rbpMakeStatusText ()
   206:   public static String rbpMakeStatusText () {
   207:     StringBuilder sb = new StringBuilder ();
   208:     return (Multilingual.mlnJapanese ? sb.
   209:             append ("帰線期間 0-").append (CRTC.crtR05VSyncEndCurr).
   210:             append ("    バックポーチ ").append (CRTC.crtR05VSyncEndCurr + 1).append ("-").append (CRTC.crtR06VBackEndCurr).
   211:             append ("    映像期間 ").append (CRTC.crtR06VBackEndCurr + 1).append ("-").append (CRTC.crtR07VDispEndCurr).
   212:             append ("    フロントポーチ ").append (CRTC.crtR07VDispEndCurr + 1).append ("-").append (CRTC.crtR04VFrontEndCurr)
   213:             : sb.
   214:             append ("Blanking period 0-").append (CRTC.crtR05VSyncEndCurr).
   215:             append ("    Back porch ").append (CRTC.crtR05VSyncEndCurr + 1).append ("-").append (CRTC.crtR06VBackEndCurr).
   216:             append ("    Video period ").append (CRTC.crtR06VBackEndCurr + 1).append ("-").append (CRTC.crtR07VDispEndCurr).
   217:             append ("    Front porch ").append (CRTC.crtR07VDispEndCurr + 1).append ("-").append (CRTC.crtR04VFrontEndCurr)
   218:             ).toString ();
   219:   }  //rbpMakeStatusText ()
   220: 
   221:   //rbpUpdateFrame ()
   222:   //  ラスタブレークポイントウインドウを更新する
   223:   //  ウインドウが構築済みであることを確認してから呼び出すこと
   224:   public static void rbpUpdateFrame () {
   225:     rbpStatusLabel.setText (rbpMakeStatusText ());
   226:     rbpCurrentRasterTextField.setText (String.valueOf (CRTC.crtRasterNumber));
   227:     rbpIRQRasterTextField.setText (String.valueOf (CRTC.crtR09IRQRasterCurr));
   228:     rbpTimer = RBP_INTERVAL;
   229:   }  //rbpUpdateFrame()
   230: 
   231:   //rbpSetBreakEnabled (enabled)
   232:   //  指定されたブレークラスタでラスタブレークをかけるかどうかを設定する
   233:   public static void rbpSetBreakEnabled (boolean enabled) {
   234:     rbpBreakEnabled = enabled;
   235:     rbpActiveBreakRaster = rbpBreakEnabled ? rbpBreakRaster : -1;
   236:     if (CRTC.CRT_RASTER_HASH_ON) {
   237:       CRTC.crtUpdateRasterHash ();
   238:     }
   239:   }  //rbpSetBreakEnabled(boolean)
   240: 
   241:   //rbpSetBreakRaster (breakRaster)
   242:   //  ラスタブレークをかけるラスタ番号を設定する
   243:   public static void rbpSetBreakRaster (int raster) {
   244:     rbpBreakRaster = raster;
   245:     rbpActiveBreakRaster = rbpBreakEnabled ? rbpBreakRaster : -1;
   246:     if (CRTC.CRT_RASTER_HASH_ON) {
   247:       CRTC.crtUpdateRasterHash ();
   248:     }
   249:   }  //rbpSetBreakRaster(int)
   250: 
   251:   //rbpSetIRQEnabled (atInterrupt)
   252:   //  IRQラスタでラスタブレークをかけるかどうかを設定する
   253:   public static void rbpSetIRQEnabled (boolean enabled) {
   254:     rbpIRQBreakEnabled = enabled;
   255:   }  //rbpSetIRQEnabled(boolean)
   256: 
   257:   //rbpCheckIRQ ()
   258:   //  IRQを確認する
   259:   public static void rbpCheckIRQ () {
   260:     int irq = CRTC.crtRasterNumber == CRTC.crtR09IRQRasterCurr ? 0 : MC68901.MFP_GPIP_RINT_MASK;  //IRQ信号を更新
   261:     if (irq != MC68901.mfpGpipRint) {  //IRQ信号が変化したとき
   262:       if (irq == 0) {  //IRQ信号が0になったとき
   263:         if (RBP_ON) {
   264:           if (rbpIRQBreakEnabled) {  //IRQラスタでラスタブレークをかけるとき
   265:             rbpFire ();  //ラスタブレークをかける
   266:           }
   267:         }
   268:         MC68901.mfpRintFall ();  //IRQ開始
   269:       } else {  //IRQ信号が0でなくなったとき
   270:         MC68901.mfpRintRise ();  //IRQ終了
   271:       }
   272:     }
   273:   }  //rbpCheckIRQ()
   274: 
   275:   //rbpFire ()
   276:   //  ラスタブレークをかける
   277:   //  ブレークラスタの水平フロントポーチで呼び出す
   278:   public static void rbpFire () {
   279:     if (XEiJ.mpuTask == null) {  //既に停止している(ブレークラスタとIRQラスタが同じとき2回呼び出されることがある)
   280:       return;
   281:     }
   282:     //回数を数える
   283:     rbpCountValue++;
   284:     //ウインドウが表示されていたら更新する
   285:     if ((XEiJ.dbgVisibleMask & XEiJ.DBG_RBP_VISIBLE_MASK) != 0) {
   286:       rbpUpdateFrame ();
   287:       rbpCountModel.setValue (Integer.valueOf (rbpCountValue));
   288:     }
   289:     //回数が閾値に達していたらラスタブレークをかける
   290:     if (rbpThresholdValue <= rbpCountValue) {
   291:       //スクリーンを更新する
   292:       if (CRTC.crtDirtyY0 >= 0) {  //更新されたラスタがある
   293:         int dirtyY0 = CRTC.crtDirtyY0;
   294:         CRTC.crtUpdateScreen ();  //スクリーンを更新する
   295:         CRTC.crtDirtyY0 = dirtyY0;  //CRTC.crtDirtyY0を更新しない
   296:       }
   297:       //逆アセンブルリストウインドウが開いていなかったら開く
   298:       if ((XEiJ.dbgVisibleMask & XEiJ.DBG_DDP_VISIBLE_MASK) == 0) {
   299:         DisassembleList.ddpOpen (-1, -1, false);
   300:       }
   301:       //ラスタブレークをかける
   302:       XEiJ.mpuStop (null);
   303:     }
   304:   }  //rbpFire()
   305: 
   306:   public static void rbpTrace () {
   307:     System.out.println (new StringBuilder ().
   308:                         append ("backEnd=").append (CRTC.crtR06VBackEndCurr).append (",").
   309:                         append ("dispEnd=").append (CRTC.crtR07VDispEndCurr).append (",").
   310:                         append ("frontEnd=").append (CRTC.crtR04VFrontEndCurr).append (",").
   311:                         append ("IRQ=").append (CRTC.crtR09IRQRasterCurr).append (",").
   312:                         append ("break=").append (rbpBreakRaster).append (",").
   313:                         append ("raster=").append (CRTC.crtRasterNumber).toString ());
   314:   }  //rbpTrace()
   315: 
   316: }  //class RasterBreakPoint
   317: 
   318: 
   319: