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