MemoryDumpList.java
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13: package xeij;
14:
15: import java.awt.*;
16: import java.awt.event.*;
17: import java.lang.*;
18: import java.util.*;
19: import javax.swing.*;
20: import javax.swing.event.*;
21: import javax.swing.text.*;
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:
33:
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: };
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: };
48:
49: public static int dmpItemCount;
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];
54: public static final int[] dmpCaretArray = new int[DMP_MAX_ITEMS];
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 dmpFunctionCode;
62: public static DecimalSpinner dmpFCSpinner;
63:
64: public static boolean dmpSecondBridge;
65: public static Color dmpCellophaneColor;
66:
67:
68:
69: public static void dmpInit () {
70:
71: dmpItemCount = 0;
72: dmpItemIndex = 0;
73: dmpPageAddress = 0;
74:
75: dmpFunctionCode = 5;
76:
77:
78:
79:
80:
81: dmpFrame = null;
82:
83: }
84:
85:
86: public static void dmpStart () {
87: if (RestorableFrame.rfmGetOpened (Settings.SGS_DMP_FRAME_KEY)) {
88: dmpOpen (-1, -1, true);
89: }
90: }
91:
92:
93:
94:
95: public static void dmpOpen (int address, int functionCode, boolean forceUpdate) {
96: if (dmpFrame == null) {
97: dmpMake ();
98: }
99: dmpUpdate (address, functionCode, forceUpdate);
100: XEiJ.pnlExitFullScreen (false);
101: dmpFrame.setVisible (true);
102: XEiJ.dbgVisibleMask |= XEiJ.DBG_DMP_VISIBLE_MASK;
103: }
104:
105: static class MemoryDumpTextArea extends ScrollTextArea {
106: @Override public void paintAfterText (JTextArea textArea, Graphics2D g2) {
107: if (MemoryDumpList.dmpSecondBridge) {
108: try {
109: g2.setPaint (MemoryDumpList.dmpCellophaneColor);
110: Rectangle r0 = textArea.modelToView2D (61).getBounds ();
111: Rectangle r1 = textArea.modelToView2D (62).getBounds ();
112: g2.fillRect (r0.x - (r1.x - r0.x), r0.y,
113: r1.x - r0.x, r0.height * DMP_MAX_ITEMS);
114: g2.fillRect (r0.x + (r1.x - r0.x) * 16, r0.y,
115: r1.x - r0.x, r0.height * DMP_MAX_ITEMS);
116: } catch (BadLocationException ble) {
117: }
118: }
119: }
120: }
121:
122:
123:
124: public static void dmpMake () {
125:
126:
127: dmpBoard = ComponentFactory.setPreferredSize (
128: ComponentFactory.setFont (new MemoryDumpTextArea (), LnF.lnfMonospacedFont),
129: 500, 400);
130: dmpBoard.setMargin (new Insets (2, 4, 2, 4));
131: dmpBoard.setHighlightCursorOn (true);
132: dmpTextArea = dmpBoard.getTextArea ();
133: dmpTextArea.setEditable (false);
134: dmpTextArea.addMouseWheelListener ((mwe) -> {
135: int n = mwe.getWheelRotation ();
136: JViewport v = dmpBoard.getViewport ();
137: Point p = v.getViewPosition ();
138: v.setViewPosition (new Point (p.x,
139: Math.max (0,
140: Math.min (dmpTextArea.getSize ().height - v.getExtentSize ().height,
141: p.y + n * dmpTextArea.getFont ().getSize () * 5))));
142: });
143:
144:
145: dmpSpinner = new Hex8Spinner (dmpPageAddress, DMP_ITEM_MASK, true);
146:
147:
148:
149:
150:
151: dmpSpinner.addChangeListener (new ChangeListener () {
152: @Override public void stateChanged (ChangeEvent ce) {
153: if (XEiJ.dbgEventMask == 0) {
154: dmpUpdate (dmpSpinner.getIntValue (), dmpFunctionCode, false);
155: }
156: }
157: });
158:
159:
160:
161:
162:
163:
164: ComponentFactory.addListener (
165: dmpTextArea,
166: new CaretListener () {
167: @Override public void caretUpdate (CaretEvent ce) {
168: if (XEiJ.dbgEventMask == 0) {
169: int p = ce.getDot ();
170: if (p == ce.getMark ()) {
171: int i = Arrays.binarySearch (dmpSplitArray, 1, dmpItemCount, p + 1);
172: i = (i >> 31 ^ i) - 1;
173: dmpSpinner.setHintIndex (i);
174: }
175: }
176: }
177: });
178:
179:
180: ComponentFactory.addListener (
181: dmpTextArea,
182: new MouseAdapter () {
183: @Override public void mousePressed (MouseEvent me) {
184: if (XEiJ.mpuTask == null && me.isPopupTrigger ()) {
185: XEiJ.dbgShowPopup (me, dmpTextArea, false);
186: }
187: }
188: @Override public void mouseReleased (MouseEvent me) {
189: if (XEiJ.mpuTask == null && me.isPopupTrigger ()) {
190: XEiJ.dbgShowPopup (me, dmpTextArea, false);
191: }
192: }
193: });
194:
195:
196: ComponentFactory.addListener (
197: dmpBoard,
198: new FocusAdapter () {
199: @Override public void focusGained (FocusEvent fe) {
200: dmpBoard.setCaretVisible (true);
201: }
202: @Override public void focusLost (FocusEvent fe) {
203: dmpBoard.setCaretVisible (false);
204: }
205: });
206:
207:
208: ComponentFactory.addListener (
209: dmpBoard,
210: new KeyAdapter () {
211: @Override public void keyTyped (KeyEvent ke) {
212: if (XEiJ.dbgEventMask == 0) {
213: int x = Character.digit (ke.getKeyChar (), 16);
214: if (x >= 0) {
215: int p = dmpTextArea.getCaretPosition ();
216: int i = Arrays.binarySearch (dmpSplitArray, 1, dmpItemCount, p + 1);
217: i = (i >> 31 ^ i) - 1;
218: int t = p - dmpCaretArray[i] - DMP_DATA_START;
219: if (t >= 0 && t < DMP_DATA_ADDRESS.length) {
220: t = DMP_DATA_ADDRESS[t];
221: if (t >= 0) {
222: int a = dmpAddressArray[i] + (t >> 1);
223: XEiJ.dbgEventMask++;
224: if ((t & 1) == 0) {
225: try {
226: MC68060.mmuPokeByte (a, x << 4 | Character.digit (dmpTextArea.getText (p + 1, 1).charAt (0), 16), dmpFunctionCode);
227: } catch (BadLocationException ble) {
228: }
229: dmpTextArea.replaceRange (XEiJ.fmtHex2 (MC68060.mmuPeekByteZero (a, dmpFunctionCode)), p, p + 2);
230: dmpTextArea.setCaretPosition (p + 1);
231: } else {
232: try {
233: MC68060.mmuPokeByte (a, Character.digit (dmpTextArea.getText (p - 1, 1).charAt (0), 16) << 4 | x, dmpFunctionCode);
234: } catch (BadLocationException ble) {
235: }
236: dmpTextArea.replaceRange (XEiJ.fmtHex2 (MC68060.mmuPeekByteZero (a, dmpFunctionCode)), p - 1, p + 1);
237: if (t < 31) {
238: dmpTextArea.setCaretPosition (dmpCaretArray[i] + DMP_DATA_START + DMP_DATA_OFFSET[t + 1]);
239: }
240: }
241: XEiJ.dbgEventMask--;
242: }
243: }
244: }
245: }
246: }
247: });
248:
249:
250: ActionListener listener = new ActionListener () {
251: @Override public void actionPerformed (ActionEvent ae) {
252: Object source = ae.getSource ();
253: switch (ae.getActionCommand ()) {
254: case "Reload":
255: dmpItemCount = 0;
256: dmpUpdate (dmpAddressArray[dmpItemIndex], dmpFunctionCode, true);
257: break;
258: case "Second bridge":
259: dmpSecondBridge = ((JCheckBox) ae.getSource ()).isSelected ();
260: dmpItemCount = 0;
261: dmpUpdate (dmpAddressArray[dmpItemIndex], dmpFunctionCode, true);
262: break;
263: }
264: }
265: };
266:
267:
268: JButton reloadButton =
269: Multilingual.mlnToolTipText (
270: ComponentFactory.createImageButton (
271: XEiJ.createImage (
272: 20, 14,
273: "11111111111111111111" +
274: "1..................1" +
275: "1.......1111.......1" +
276: "1......111111.1....1" +
277: "1.....11....111....1" +
278: "1....11.....111....1" +
279: "1....11....1111....1" +
280: "1....11............1" +
281: "1....11............1" +
282: "1.....11....11.....1" +
283: "1......111111......1" +
284: "1.......1111.......1" +
285: "1..................1" +
286: "11111111111111111111",
287: LnF.lnfRGB[0],
288: LnF.lnfRGB[12]),
289: "Reload", listener),
290: "ja", "再読み込み");
291:
292:
293: dmpFCSpinner = ComponentFactory.createDecimalSpinner (
294: dmpFunctionCode,
295: 0,
296: 7,
297: 1,
298: 0,
299: new ChangeListener () {
300: @Override public void stateChanged (ChangeEvent ce) {
301: if (XEiJ.dbgEventMask == 0) {
302: dmpUpdate (dmpPageAddress, dmpFCSpinner.getIntValue (), false);
303: }
304: }
305: });
306:
307:
308: dmpSecondBridge = false;
309: dmpCellophaneColor = new Color ((LnF.lnfRGB[5] & 0x00ffffff) | 0xcc000000, true);
310: JCheckBox secondBridgeCheckBox =
311: Multilingual.mlnToolTipText (
312: ComponentFactory.createIconCheckBox (
313: dmpSecondBridge,
314: XEiJ.createImage (
315: 20, 14,
316: "22222222222222222222" +
317: "2..................2" +
318: "2...........11111..2" +
319: "2...........11111..2" +
320: "2....111111111111..2" +
321: "2...........11111..2" +
322: "2...........11111..2" +
323: "2..................2" +
324: "2..................2" +
325: "2....1111111111....2" +
326: "2..................2" +
327: "2..................2" +
328: "2..................2" +
329: "22222222222222222222",
330: LnF.lnfRGB[0],
331: LnF.lnfRGB[12],
332: LnF.lnfRGB[12]),
333: XEiJ.createImage (
334: 20, 14,
335: "22222222222222222222" +
336: "2..................2" +
337: "2...........11111..2" +
338: "2...........11111..2" +
339: "2....111111111111..2" +
340: "2...........11111..2" +
341: "2...........11111..2" +
342: "2..11111...........2" +
343: "2..11111...........2" +
344: "2..111111111111....2" +
345: "2..11111...........2" +
346: "2..11111...........2" +
347: "2..................2" +
348: "22222222222222222222",
349: LnF.lnfRGB[0],
350: LnF.lnfRGB[12],
351: LnF.lnfRGB[12]),
352: "Second bridge", listener),
353: "ja", "セカンドブリッジ");
354:
355:
356: dmpFrame = Multilingual.mlnTitle (
357: ComponentFactory.createRestorableSubFrame (
358: Settings.SGS_DMP_FRAME_KEY,
359: "Memory dump list",
360: null,
361: ComponentFactory.createBorderPanel (
362: dmpBoard,
363: ComponentFactory.createHorizontalBox (
364:
365: dmpFCSpinner,
366:
367: dmpSpinner,
368: reloadButton,
369: secondBridgeCheckBox,
370: Box.createHorizontalGlue ()
371: )
372: )
373: ),
374: "ja", "メモリダンプリスト");
375: ComponentFactory.addListener (
376: dmpFrame,
377: new WindowAdapter () {
378: @Override public void windowClosing (WindowEvent we) {
379: XEiJ.dbgVisibleMask &= ~XEiJ.DBG_DMP_VISIBLE_MASK;
380: }
381: });
382:
383: }
384:
385:
386:
387: public static void dmpUpdate (int address, int functionCode, boolean forceUpdate) {
388:
389: XEiJ.dbgEventMask++;
390:
391: if (address == -1) {
392: address = XEiJ.regRn[15];
393: forceUpdate = true;
394: }
395:
396: if (functionCode == -1) {
397: functionCode = XEiJ.regSRS != 0 ? 5 : 1;
398: forceUpdate = true;
399: }
400:
401: if (dmpFunctionCode != functionCode) {
402: dmpFunctionCode = functionCode;
403: forceUpdate = true;
404: dmpFCSpinner.setIntValue (functionCode);
405: }
406:
407: if (forceUpdate) {
408: dmpItemCount = 0;
409: }
410:
411: if (dmpItemCount != 0) {
412: int i = Arrays.binarySearch (dmpAddressArray, 1, dmpItemCount, address + 1);
413: i = (i >> 31 ^ i) - 1;
414: if (0 < i && i < dmpItemCount - 1 &&
415: dmpAddressArray[i] == address) {
416:
417:
418:
419: if (dmpItemIndex != i) {
420: dmpItemIndex = i;
421: dmpTextArea.setCaretPosition (dmpCaretArray[i]);
422: }
423:
424: XEiJ.dbgEventMask--;
425:
426: return;
427: }
428: }
429:
430:
431:
432:
433:
434: address &= DMP_ITEM_MASK;
435: dmpPageAddress = address & DMP_PAGE_MASK;
436: int pageEndAddress = dmpPageAddress + DMP_PAGE_SIZE;
437:
438:
439: dmpAddressArray[0] = dmpPageAddress - DMP_ITEM_SIZE;
440: dmpSplitArray[0] = 0;
441: dmpCaretArray[0] = 0;
442: StringBuilder sb = new StringBuilder (
443:
444:
445:
446: "▲ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F 0123456789ABCDEF\n");
447: int itemCount = 1;
448: int itemAddress = dmpPageAddress;
449: boolean bridge = false;
450: for (int k = 1; k <= 200; k++) {
451: int h = MC68060.mmuPeekByteZero (itemAddress - k, functionCode);
452: if ((0x81 <= h && h <= 0x9f) ||
453: (0xe0 <= h && h <= 0xef)) {
454: bridge = !bridge;
455: } else {
456: break;
457: }
458: }
459:
460: do {
461: int itemEndAddress = itemAddress + DMP_ITEM_SIZE;
462:
463: if (itemAddress == address) {
464: dmpItemIndex = itemCount;
465: }
466: dmpAddressArray[itemCount] = itemAddress;
467: dmpSplitArray[itemCount] = sb.length ();
468: dmpCaretArray[itemCount] = sb.length ();
469:
470: XEiJ.fmtHex8 (DMP_BASE, 0, itemAddress);
471:
472: XEiJ.fmtHex2 (DMP_BASE, 10, MC68060.mmuPeekByteZero (itemAddress , functionCode));
473: XEiJ.fmtHex2 (DMP_BASE, 13, MC68060.mmuPeekByteZero (itemAddress + 1, functionCode));
474: XEiJ.fmtHex2 (DMP_BASE, 16, MC68060.mmuPeekByteZero (itemAddress + 2, functionCode));
475: XEiJ.fmtHex2 (DMP_BASE, 19, MC68060.mmuPeekByteZero (itemAddress + 3, functionCode));
476: XEiJ.fmtHex2 (DMP_BASE, 23, MC68060.mmuPeekByteZero (itemAddress + 4, functionCode));
477: XEiJ.fmtHex2 (DMP_BASE, 26, MC68060.mmuPeekByteZero (itemAddress + 5, functionCode));
478: XEiJ.fmtHex2 (DMP_BASE, 29, MC68060.mmuPeekByteZero (itemAddress + 6, functionCode));
479: XEiJ.fmtHex2 (DMP_BASE, 32, MC68060.mmuPeekByteZero (itemAddress + 7, functionCode));
480: XEiJ.fmtHex2 (DMP_BASE, 36, MC68060.mmuPeekByteZero (itemAddress + 8, functionCode));
481: XEiJ.fmtHex2 (DMP_BASE, 39, MC68060.mmuPeekByteZero (itemAddress + 9, functionCode));
482: XEiJ.fmtHex2 (DMP_BASE, 42, MC68060.mmuPeekByteZero (itemAddress + 10, functionCode));
483: XEiJ.fmtHex2 (DMP_BASE, 45, MC68060.mmuPeekByteZero (itemAddress + 11, functionCode));
484: XEiJ.fmtHex2 (DMP_BASE, 49, MC68060.mmuPeekByteZero (itemAddress + 12, functionCode));
485: XEiJ.fmtHex2 (DMP_BASE, 52, MC68060.mmuPeekByteZero (itemAddress + 13, functionCode));
486: XEiJ.fmtHex2 (DMP_BASE, 55, MC68060.mmuPeekByteZero (itemAddress + 14, functionCode));
487: XEiJ.fmtHex2 (DMP_BASE, 58, MC68060.mmuPeekByteZero (itemAddress + 15, functionCode));
488: sb.append (DMP_BASE);
489:
490: boolean nextBridge = false;
491: int a;
492: if (!bridge) {
493: sb.append (' ');
494: a = itemAddress;
495: } else if (itemAddress == dmpPageAddress ||
496: dmpSecondBridge) {
497: a = itemAddress - 1;
498: } else {
499: sb.append (" ");
500: a = itemAddress + 1;
501: }
502: for (; a < itemEndAddress; a++) {
503: int h = MC68060.mmuPeekByteZero (a, functionCode);
504: int c;
505: if ((0x81 <= h && h <= 0x9f) ||
506: (0xe0 <= h && h <= 0xef)) {
507: int l = MC68060.mmuPeekByteZero (a + 1, functionCode);
508: if (0x40 <= l && l <= 0xfc && l != 0x7f) {
509: c = CharacterCode.chrSJISToChar[h << 8 | l];
510: if (c == 0) {
511: c = '※';
512: } else if (c == 0x3000) {
513: c = '\u2b1a';
514: }
515: a++;
516: if (a == itemEndAddress) {
517: nextBridge = true;
518: }
519: } else {
520: c = '.';
521: }
522: } else {
523: c = CharacterCode.chrSJISToChar[h];
524: if (c < 0x20 || c == 0x7f) {
525: c = '.';
526: }
527: }
528: sb.append ((char) c);
529: }
530: sb.append ('\n');
531:
532: itemCount++;
533: itemAddress = itemEndAddress;
534: bridge = nextBridge;
535: } while (itemAddress < pageEndAddress);
536:
537:
538: dmpAddressArray[itemCount] = itemAddress;
539: dmpSplitArray[itemCount] = sb.length ();
540: dmpCaretArray[itemCount] = sb.length ();
541: sb.append (
542:
543:
544: "▼ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F 0123456789ABCDEF");
545: itemCount++;
546: dmpItemCount = itemCount;
547:
548:
549: dmpTextArea.setText (sb.toString ());
550: dmpTextArea.setCaretPosition (dmpCaretArray[dmpItemIndex]);
551:
552:
553: dmpSpinner.setHintArray (dmpAddressArray, itemCount);
554: dmpSpinner.setHintIndex (dmpItemIndex);
555:
556: XEiJ.dbgEventMask--;
557:
558: }
559:
560: }
561:
562:
563: