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