BranchLog.java
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42: package xeij;
43:
44: import java.awt.*;
45: import java.awt.event.*;
46: import java.lang.*;
47: import java.util.*;
48: import javax.swing.*;
49: import javax.swing.event.*;
50:
51: public class BranchLog {
52:
53: public static final boolean BLG_ON = true;
54:
55:
56:
57:
58: public static final int BLG_RECORD_SHIFT = 1;
59: public static final int[] blgArray = new int[65536 << BLG_RECORD_SHIFT];
60: public static long blgNewestRecord;
61: public static int blgPrevHeadSuper;
62: public static int blgPrevTailInt;
63: public static int blgHead;
64: public static int blgSuper;
65: public static int blgInt;
66:
67:
68: public static JFrame blgFrame;
69:
70:
71: public static SpinnerNumberModel blgModel;
72: public static JSpinner blgSpinner;
73:
74:
75: public static final int BLG_TEXT_AREA_WIDTH = 400;
76: public static final int BLG_TEXT_AREA_HEIGHT = 400;
77: public static ScrollTextArea blgScrollTextArea;
78: public static JTextArea blgTextArea;
79: public static boolean blgLock;
80:
81:
82: public static final long BLG_SELECT_OLDEST = -3L;
83: public static final long BLG_SELECT_NEWEST = -2L;
84: public static final long BLG_SELECT_NONE = -1L;
85: public static final int BLG_RECORDS_PER_PAGE = 1000;
86: public static int blgNumberOfRecords;
87: public static long blgFirstRecord;
88: public static long blgLastRecord;
89: public static long blgSelectedRecord;
90: public static int blgNumberOfItems;
91: public static int blgSelectedItem;
92: public static final long[] blgRecordArray = new long[BLG_RECORDS_PER_PAGE + 2];
93: public static final int[] blgPositionArray = new int[BLG_RECORDS_PER_PAGE + 3];
94:
95:
96: public static boolean blgShowUser;
97: public static boolean blgShowSupervisor;
98: public static boolean blgShowNormal;
99: public static boolean blgShowInterrupt;
100:
101:
102:
103: public static void blgInit () {
104:
105:
106:
107: blgNewestRecord = 0L;
108: blgPrevHeadSuper = 0;
109: blgPrevTailInt = 0;
110: blgHead = 0;
111: blgSuper = 0;
112: blgInt = 0;
113:
114:
115: blgFrame = null;
116:
117:
118:
119:
120: blgModel = null;
121: blgSpinner = null;
122:
123:
124: blgScrollTextArea = null;
125: blgTextArea = null;
126: blgLock = false;
127:
128:
129: blgNumberOfRecords = 0;
130: blgFirstRecord = -1L;
131: blgLastRecord = -1L;
132: blgSelectedRecord = -1L;
133: blgNumberOfItems = 0;
134: blgSelectedItem = -1;
135:
136:
137:
138:
139: blgShowUser = true;
140: blgShowSupervisor = true;
141: blgShowNormal = true;
142: blgShowInterrupt = true;
143:
144: }
145:
146:
147:
148:
149: public static void blgReset () {
150:
151: blgNewestRecord = 0L;
152: blgPrevHeadSuper = 0;
153: blgPrevTailInt = 0;
154: blgHead = XEiJ.regPC;
155: blgSuper = XEiJ.regSRS >>> 13;
156: blgInt = XEiJ.mpuISR == 0 ? 0 : 1;
157:
158: blgNumberOfRecords = 0;
159: blgFirstRecord = -1L;
160: blgLastRecord = -1L;
161: blgSelectedRecord = -1L;
162: blgNumberOfItems = 0;
163: blgSelectedItem = -1;
164:
165: DisassembleList.ddpBacktraceRecord = -1L;
166:
167: }
168:
169:
170:
171:
172:
173: public static void blgStop () {
174: int i = (char) blgNewestRecord << BLG_RECORD_SHIFT;
175: blgArray[i] = blgHead | blgSuper;
176: blgArray[i + 1] = XEiJ.regPC | blgInt;
177: }
178:
179:
180:
181: public static void blgJump (int a) {
182: if (blgPrevHeadSuper != (blgHead | blgSuper) ||
183: blgPrevTailInt != (XEiJ.regPC0 | blgInt)) {
184: int i = (char) blgNewestRecord++ << BLG_RECORD_SHIFT;
185: blgArray[i] = blgPrevHeadSuper = blgHead | blgSuper;
186: blgArray[i + 1] = blgPrevTailInt = XEiJ.regPC0 | blgInt;
187: }
188: blgHead = XEiJ.regPC = a;
189: blgSuper = XEiJ.regSRS >>> 13;
190: blgInt = XEiJ.mpuISR == 0 ? 0 : 1;
191: }
192:
193:
194:
195:
196: public static void blgMakeFrame () {
197:
198:
199: blgScrollTextArea = ComponentFactory.setPreferredSize (
200: ComponentFactory.setFont (new ScrollTextArea (), LnF.lnfMonospacedFont),
201: BLG_TEXT_AREA_WIDTH, BLG_TEXT_AREA_HEIGHT);
202: blgScrollTextArea.setMargin (new Insets (2, 4, 2, 4));
203: blgScrollTextArea.setHighlightCursorOn (true);
204: blgTextArea = blgScrollTextArea.getTextArea ();
205: blgTextArea.setEditable (false);
206: blgTextArea.setText (Multilingual.mlnJapanese ? "MPU が動作中です" : "MPU is running");
207: blgTextArea.setCaretPosition (0);
208: blgTextArea.addMouseWheelListener ((mwe) -> {
209: int n = mwe.getWheelRotation ();
210: JViewport v = blgScrollTextArea.getViewport ();
211: Point p = v.getViewPosition ();
212: v.setViewPosition (new Point (p.x,
213: Math.max (0,
214: Math.min (blgTextArea.getSize ().height - v.getExtentSize ().height,
215: p.y + n * blgTextArea.getFont ().getSize () * 5))));
216: });
217:
218:
219: ComponentFactory.addListener (
220: blgTextArea,
221: new MouseAdapter () {
222: @Override public void mousePressed (MouseEvent me) {
223: if (XEiJ.mpuTask == null && me.isPopupTrigger ()) {
224: XEiJ.dbgShowPopup (me, blgTextArea, false);
225: }
226: }
227: @Override public void mouseReleased (MouseEvent me) {
228: if (XEiJ.mpuTask == null && me.isPopupTrigger ()) {
229: XEiJ.dbgShowPopup (me, blgTextArea, false);
230: }
231: }
232: });
233:
234:
235:
236: ComponentFactory.addListener (
237: blgTextArea,
238: new CaretListener () {
239: @Override public void caretUpdate (CaretEvent ce) {
240: if (blgSelectedRecord >= 0 && !blgLock &&
241: XEiJ.dbgEventMask == 0) {
242: int p = ce.getDot ();
243: if (p == ce.getMark ()) {
244: int item = Arrays.binarySearch (blgPositionArray, 1, blgNumberOfItems, p + 1);
245: item = (item >> 31 ^ item) - 1;
246: if (blgSelectedItem != item) {
247: if (item == 0) {
248: blgUpdate (Math.max (0L, blgFirstRecord - 1L));
249: } else if (item <= blgNumberOfRecords) {
250: blgLock = true;
251: long record = blgRecordArray[item];
252: blgSelectedRecord = record;
253: blgSelectedItem = item;
254: if (blgModel.getNumber ().longValue () != record) {
255: blgModel.setValue (Long.valueOf (record));
256: }
257: blgLock = false;
258: } else {
259: blgUpdate (blgLastRecord + 1L);
260: }
261: }
262: }
263: }
264: }
265: });
266:
267:
268: blgModel = new ReverseLongModel (0L, 0L, Long.MAX_VALUE, 1L);
269: blgSpinner = ComponentFactory.createNumberSpinner (blgModel, 15, new ChangeListener () {
270: @Override public void stateChanged (ChangeEvent ce) {
271: if (!blgLock) {
272: blgUpdate (blgModel.getNumber ().longValue ());
273: }
274: }
275: });
276:
277:
278: ActionListener listener = new ActionListener () {
279: @Override public void actionPerformed (ActionEvent ae) {
280: Object source = ae.getSource ();
281: switch (ae.getActionCommand ()) {
282: case "Clear":
283: blgReset ();
284: blgArray[0] = XEiJ.regPC | XEiJ.regSRS >>> 13;
285: blgArray[1] = XEiJ.regPC | (XEiJ.mpuISR == 0 ? 0 : 1);
286: blgUpdate (BLG_SELECT_NEWEST);
287: break;
288: case "Oldest record":
289: if (blgSelectedRecord >= 0) {
290: blgUpdate (BLG_SELECT_OLDEST);
291: }
292: break;
293: case "Previous page":
294: if (blgSelectedRecord >= 0) {
295: blgUpdate (blgFirstRecord < blgSelectedRecord ? blgFirstRecord :
296: Math.max (0L, blgFirstRecord - BLG_RECORDS_PER_PAGE));
297: }
298: break;
299: case "Previous record":
300: if (blgSelectedRecord > 0) {
301: if (blgTextArea.getCaretPosition () != blgPositionArray[blgSelectedItem]) {
302: blgTextArea.setCaretPosition (blgPositionArray[blgSelectedItem]);
303: } else {
304: blgUpdate (blgSelectedRecord - 1);
305: }
306: }
307: break;
308: case "Next record":
309: if (blgSelectedRecord >= 0) {
310: blgUpdate (blgSelectedRecord + 1);
311: }
312: break;
313: case "Next page":
314: if (blgSelectedRecord >= 0) {
315: blgUpdate (blgSelectedRecord < blgLastRecord ? blgLastRecord :
316: blgLastRecord + BLG_RECORDS_PER_PAGE);
317: }
318: break;
319: case "Newest record":
320: if (blgSelectedRecord >= 0) {
321: blgUpdate (BLG_SELECT_NEWEST);
322: }
323: break;
324:
325: case "U":
326: blgShowUser = ((JCheckBox) source).isSelected ();
327: blgUpdate (BLG_SELECT_NONE);
328: break;
329: case "S":
330: blgShowSupervisor = ((JCheckBox) source).isSelected ();
331: blgUpdate (BLG_SELECT_NONE);
332: break;
333: case "N":
334: blgShowNormal = ((JCheckBox) source).isSelected ();
335: blgUpdate (BLG_SELECT_NONE);
336: break;
337: case "I":
338: blgShowInterrupt = ((JCheckBox) source).isSelected ();
339: blgUpdate (BLG_SELECT_NONE);
340: break;
341:
342: }
343: }
344: };
345:
346:
347: blgFrame = Multilingual.mlnTitle (
348: ComponentFactory.createRestorableSubFrame (
349: Settings.SGS_BLG_FRAME_KEY,
350: "Branch log",
351: null,
352: ComponentFactory.createBorderPanel (
353:
354: blgScrollTextArea,
355:
356: ComponentFactory.createHorizontalBox (
357: XEiJ.mpuAddButtonStopped (
358: Multilingual.mlnToolTipText (
359: ComponentFactory.createImageButton (
360: LnF.LNF_CLEAR_IMAGE,
361: LnF.LNF_CLEAR_DISABLED_IMAGE,
362: "Clear", listener),
363: "ja", "クリア")
364: ),
365: Box.createHorizontalStrut (12),
366: blgSpinner,
367: Box.createHorizontalStrut (12),
368: XEiJ.mpuAddButtonStopped (
369: Multilingual.mlnToolTipText (
370: ComponentFactory.createImageButton (
371: LnF.LNF_OLDEST_IMAGE,
372: LnF.LNF_OLDEST_DISABLED_IMAGE,
373: "Oldest record", listener),
374: "ja", "最古のレコード")
375: ),
376: XEiJ.mpuAddButtonStopped (
377: Multilingual.mlnToolTipText (
378: ComponentFactory.createImageButton (
379: LnF.LNF_OLDER_IMAGE,
380: LnF.LNF_OLDER_DISABLED_IMAGE,
381: "Previous page", listener),
382: "ja", "前のページ")
383: ),
384: XEiJ.mpuAddButtonStopped (
385: Multilingual.mlnToolTipText (
386: ComponentFactory.createImageButton (
387: LnF.LNF_PREVIOUS_IMAGE,
388: LnF.LNF_PREVIOUS_DISABLED_IMAGE,
389: "Previous record", listener),
390: "ja", "前のレコード")
391: ),
392: XEiJ.mpuAddButtonStopped (
393: Multilingual.mlnToolTipText (
394: ComponentFactory.createImageButton (
395: LnF.LNF_NEXT_IMAGE,
396: LnF.LNF_NEXT_DISABLED_IMAGE,
397: "Next record", listener),
398: "ja", "次のレコード")
399: ),
400: XEiJ.mpuAddButtonStopped (
401: Multilingual.mlnToolTipText (
402: ComponentFactory.createImageButton (
403: LnF.LNF_NEWER_IMAGE,
404: LnF.LNF_NEWER_DISABLED_IMAGE,
405: "Next page", listener),
406: "ja", "次のページ")
407: ),
408: XEiJ.mpuAddButtonStopped (
409: Multilingual.mlnToolTipText (
410: ComponentFactory.createImageButton (
411: LnF.LNF_NEWEST_IMAGE,
412: LnF.LNF_NEWEST_DISABLED_IMAGE,
413: "Newest record", listener),
414: "ja", "最新のレコード")
415: ),
416:
417: Box.createHorizontalStrut (12),
418: ComponentFactory.createCheckBox (blgShowUser, "U", listener),
419: Box.createHorizontalStrut (4),
420: ComponentFactory.createCheckBox (blgShowSupervisor, "S", listener),
421: Box.createHorizontalStrut (4),
422: ComponentFactory.createCheckBox (blgShowNormal, "N", listener),
423: Box.createHorizontalStrut (4),
424: ComponentFactory.createCheckBox (blgShowInterrupt, "I", listener),
425:
426: Box.createHorizontalGlue (),
427: Box.createHorizontalStrut (12),
428: XEiJ.mpuMakeOriIllegalCheckBox (),
429: XEiJ.mpuMakeStopOnErrorCheckBox (),
430: XEiJ.mpuMakeStopAtStartCheckBox (),
431: Box.createHorizontalStrut (12),
432: XEiJ.mpuMakeBreakButton (),
433: XEiJ.mpuMakeTraceButton (),
434: XEiJ.mpuMakeTrace10Button (),
435: XEiJ.mpuMakeTrace100Button (),
436: XEiJ.mpuMakeStepButton (),
437: XEiJ.mpuMakeStep10Button (),
438: XEiJ.mpuMakeStep100Button (),
439: XEiJ.mpuMakeReturnButton (),
440: XEiJ.mpuMakeRunButton ()
441: )
442: )
443: ),
444: "ja", "分岐ログ");
445:
446: ComponentFactory.addListener (
447: blgFrame,
448: new WindowAdapter () {
449: @Override public void windowClosing (WindowEvent we) {
450: XEiJ.dbgVisibleMask &= ~XEiJ.DBG_BLG_VISIBLE_MASK;
451: }
452: });
453:
454: }
455:
456:
457: public static void blgStart () {
458: if (RestorableFrame.rfmGetOpened (Settings.SGS_BLG_FRAME_KEY)) {
459: blgOpen (BLG_SELECT_NONE);
460: }
461: }
462:
463:
464:
465: public static void blgOpen (long selectedRecord) {
466: if (blgFrame == null) {
467: blgMakeFrame ();
468: }
469: XEiJ.dbgVisibleMask |= XEiJ.DBG_BLG_VISIBLE_MASK;
470: blgUpdate (selectedRecord);
471: XEiJ.pnlExitFullScreen (false);
472: blgFrame.setVisible (true);
473: }
474:
475:
476:
477:
478: public static void blgUpdate (long selectedRecord) {
479: if (XEiJ.mpuTask != null) {
480: blgLock = true;
481: blgTextArea.setText (Multilingual.mlnJapanese ? "MPU が動作中です" : "MPU is running");
482: blgTextArea.setCaretPosition (0);
483: blgLock = false;
484: return;
485: }
486: if (blgLock) {
487: return;
488: }
489: blgLock = true;
490: blgStop ();
491: long newestRecord = blgNewestRecord;
492: long oldestRecord = Math.max (0L, newestRecord - 65535);
493: if (selectedRecord < 0L) {
494: if (selectedRecord == BLG_SELECT_NONE) {
495: selectedRecord = blgSelectedRecord < 0L ? newestRecord : blgSelectedRecord;
496: } else if (selectedRecord == BLG_SELECT_NEWEST) {
497: selectedRecord = newestRecord;
498: } else if (selectedRecord == BLG_SELECT_OLDEST) {
499: selectedRecord = oldestRecord;
500: }
501: }
502: if (selectedRecord < oldestRecord) {
503: selectedRecord = oldestRecord;
504: } else if (selectedRecord > newestRecord) {
505: selectedRecord = newestRecord;
506: }
507: long firstRecord = selectedRecord / BLG_RECORDS_PER_PAGE * BLG_RECORDS_PER_PAGE;
508: long lastRecord = firstRecord + (long) (BLG_RECORDS_PER_PAGE - 1);
509: if (firstRecord < oldestRecord) {
510: firstRecord = oldestRecord;
511: }
512: if (lastRecord > newestRecord) {
513: lastRecord = newestRecord;
514: }
515:
516: if (blgFirstRecord != firstRecord || blgLastRecord != lastRecord ||
517: blgLastRecord == blgNewestRecord) {
518:
519:
520:
521:
522: blgFirstRecord = firstRecord;
523: blgLastRecord = lastRecord;
524: blgSelectedRecord = selectedRecord;
525:
526: int pcPosition = -1;
527:
528:
529:
530:
531:
532: blgRecordArray[0] = firstRecord - 1;
533: blgPositionArray[0] = 0;
534: StringBuilder sb = new StringBuilder (
535: firstRecord == oldestRecord ?
536: Multilingual.mlnJapanese ? "───── 分岐ログの先頭 ─────\n" : "───── Top of the branch log ─────\n" :
537: Multilingual.mlnJapanese ? "↑↑↑↑↑ 手前のページ ↑↑↑↑↑\n" : "↑↑↑↑↑ Previous page ↑↑↑↑↑\n");
538:
539:
540: int itemNumber = 1;
541: long itemRecord = firstRecord;
542: while (itemRecord <= lastRecord) {
543: int i = (char) itemRecord << BLG_RECORD_SHIFT;
544: int headAddress = blgArray[i] & ~1;
545: int supervisor = blgArray[i] & 1;
546: int tailAddress = blgArray[i + 1] & ~1;
547: int interrupt = blgArray[i + 1] & 1;
548:
549:
550: if (itemRecord == selectedRecord) {
551: blgSelectedItem = itemNumber;
552: }
553: blgRecordArray[itemNumber] = itemRecord;
554: blgPositionArray[itemNumber] = sb.length ();
555: sb.append (itemRecord);
556: sb.append (supervisor == 0 ? "[U" : "[S");
557: sb.append (interrupt == 0 ? "N] " : "I] ");
558: XEiJ.fmtHex8 (sb, headAddress);
559: LabeledAddress.lblSearch (sb, headAddress);
560: sb.append ('\n');
561:
562:
563: if ((supervisor == 0 ? blgShowUser : blgShowSupervisor) &&
564: (interrupt == 0 ? blgShowNormal : blgShowInterrupt)) {
565: for (Disassembler.disPC = headAddress; Disassembler.disPC <= tailAddress; ) {
566: if (itemRecord == selectedRecord &&
567: Disassembler.disPC == XEiJ.regPC) {
568: pcPosition = sb.length ();
569: }
570: Disassembler.disDisassemble (XEiJ.fmtHex8 (sb.append (" "),
571: Disassembler.disPC).
572: append (" "),
573: Disassembler.disPC, supervisor).
574: append ('\n');
575: if ((Disassembler.disStatus & Disassembler.DIS_ALWAYS_BRANCH) != 0) {
576: sb.append ('\n');
577: }
578: }
579: }
580:
581:
582: itemNumber++;
583: itemRecord++;
584:
585: }
586:
587:
588: blgRecordArray[itemNumber] = lastRecord + 1;
589: blgPositionArray[itemNumber] = sb.length ();
590: sb.append (
591: lastRecord == newestRecord ?
592: Multilingual.mlnJapanese ? "───── 分岐ログの末尾 ─────" : "───── Bottom of the branch log ─────" :
593: Multilingual.mlnJapanese ? "↓↓↓↓↓ 次のページ ↓↓↓↓↓" : "↓↓↓↓↓ Next page ↓↓↓↓↓");
594: itemNumber++;
595: blgPositionArray[itemNumber] = sb.length ();
596: blgNumberOfRecords = itemNumber - 2;
597: blgNumberOfItems = itemNumber;
598:
599:
600: blgTextArea.setText (sb.toString ());
601: blgTextArea.setCaretPosition (pcPosition >= 0 ? pcPosition :
602: blgPositionArray[blgSelectedItem]);
603:
604: } else if (blgSelectedRecord != selectedRecord) {
605:
606: blgSelectedRecord = selectedRecord;
607: blgSelectedItem = (int) (blgSelectedRecord - blgFirstRecord) + 1;
608: blgTextArea.setCaretPosition (blgPositionArray[blgSelectedItem]);
609:
610: }
611:
612:
613:
614:
615: if (blgModel.getNumber ().longValue () != selectedRecord) {
616: blgModel.setValue (Long.valueOf (selectedRecord));
617: }
618:
619: blgLock = false;
620: }
621:
622: }
623:
624:
625: