xeij/Malfunction.java
//========================================================================================
// Malfunction.java
// en:Malfunction screen
// ja:故障画面
// Copyright (C) 2003-2026 Makoto Kamada
//
// This file is part of the XEiJ (X68000 Emulator in Java).
// You can use, modify and redistribute the XEiJ if the conditions are met.
// Read the XEiJ License for more details.
// https://stdkmd.net/xeij/
//========================================================================================
package xeij;
import java.awt.*; //FlowLayout
import java.awt.event.*; //ActionListener
import javax.swing.*;
class Malfunction {
public static final boolean MLF_ON = true;
/*
//警告
private static final String[] CAUTION_EN = {
"Due to insufficient information, the noise may not be displayed in the",
"correct position. If you notice any screen errors, please report them.",
};
private static final String[] CAUTION_JA = {
"情報不足のためノイズが正しい位置に表示されない可能性があります。",
"表示が間違っていることに気づいた方はご報告をお願いいたします。",
};
*/
//機種
private static final String[] MODEL_NAME = {
"First gen",
"XVI",
"Compact",
"X68030",
"030 Compact",
};
private static int modelNumber;
//チップ
public static int mlfChipMask;
private static int[] nthChip; //mask==1のチップに0~3の番号を振る
//アドレス
private static int addressZero;
private static int addressOne;
private static int addressMask; //zero|one
//データ
private static int dataLow; //15-12:1st,11-8:2nd,7-4:3rd,3-0:4th
private static int dataHigh;
private static int dataFrozen;
private static int dataDynamic;
private static int dataMask; //low|high|frozen|dynamic
private static byte[] noiseArray;
//IC
private static final String[][] IC_NAME = {
//1st gen
{
"IC1", "IC2", "IC3", "IC4", "IC5", "IC6", "IC7", "IC8",
"IC9", "IC10", "IC11", "IC12", "IC13", "IC14", "IC15", "IC16",
"IC17", "IC19", "IC18", "IC20", "IC21", "IC23", "IC22", "IC24",
"IC25", "IC27", "IC26", "IC28", "IC29", "IC31", "IC30", "IC32",
},
//XVI
{
"IC53", "IC54", "IC55", "IC56", "IC57", "IC58", "IC59", "IC60",
"IC61", "IC62", "IC63", "IC64", "IC65", "IC66", "IC67", "IC68",
"IC69", "IC70", "IC71", "IC72", "IC73", "IC74", "IC75", "IC76",
"IC77", "IC78", "IC79", "IC80", "IC81", "IC82", "IC83", "IC84",
},
//Compact
{
"IC20", "IC24", "IC53", "IC57", "IC21", "IC25", "IC54", "IC58",
"IC22", "IC26", "IC55", "IC59", "IC23", "IC27", "IC56", "IC60",
"IC12", "IC14", "IC13", "IC15", "IC16", "IC18", "IC17", "IC19",
"IC45", "IC47", "IC46", "IC48", "IC49", "IC51", "IC50", "IC52",
},
//X68030
{
"IC59", "IC61", "IC63", "IC65", "IC60", "IC62", "IC64", "IC66",
"IC67", "IC69", "IC71", "IC73", "IC68", "IC70", "IC72", "IC74",
"IC87", "IC89", "IC88", "IC90", "IC91", "IC93", "IC92", "IC94",
"IC95", "IC97", "IC96", "IC98", "IC99", "IC101", "IC100", "IC102",
},
//030Compact
{
"IC19", "IC23", "IC47", "IC51", "IC20", "IC24", "IC48", "IC52",
"IC21", "IC25", "IC49", "IC53", "IC22", "IC26", "IC50", "IC54",
"IC11", "IC13", "IC12", "IC14", "IC15", "IC17", "IC16", "IC18",
"IC39", "IC41", "IC40", "IC42", "IC43", "IC45", "IC44", "IC46",
},
};
//コンポーネント
private static JFrame frame; //ウインドウ
private static JRadioButton[] modelButton; //モデルラジオボタン
private static JCheckBox[] chipCheckBox; //チップチェックボックス
// button[0]が右上でmaskのbit0
// button[15]が左上でmaskのbit15
private static JRadioButton[] addressButton; //アドレスラジオボタン
private static JRadioButton[] dataButton; //データラジオボタン
//mlfInit ()
public static void mlfInit () {
//機種
modelNumber = 0;
{
String s = Settings.sgsGetString ("mlfmodel", "").replace ("%20", " ");
for (int m = 0; m < MODEL_NAME.length; m++) {
if (s.equals (MODEL_NAME[m])) {
modelNumber = m;
break;
}
}
}
//チップ
mlfChipMask = Settings.sgsGetInt ("mlfchip", 0);
nthChip = new int[32];
updateNthChip ();
//アドレス
addressZero = Settings.sgsGetInt ("mlfzero", 0, 0, 65535);
addressOne = Settings.sgsGetInt ("mlfone", 0, 0, 65535);
addressMask = addressZero | addressOne;
//データ
dataLow = Settings.sgsGetInt ("mlflow", 0, 0, 65535);
dataHigh = Settings.sgsGetInt ("mlfhigh", 0, 0, 65535);
dataFrozen = Settings.sgsGetInt ("mlffrozen", 0, 0, 65535);
dataDynamic = Settings.sgsGetInt ("mlfdynamic", 0, 0, 65535);
dataMask = dataLow | dataHigh | dataFrozen | dataDynamic;
noiseArray = new byte[65536 * 32];
for (int i = 0; i < 65536 * 32; i++) {
noiseArray[i] = (byte) (random () >>> 28);
}
//コンポーネント
frame = null;
chipCheckBox = null;
} //mlfInit
//mlfTini ()
public static void mlfTini () {
Settings.sgsPutString ("mlfmodel",
MODEL_NAME[modelNumber].replace (" ", "%20"));
Settings.sgsPutInt ("mlfchip", mlfChipMask);
Settings.sgsPutInt ("mlfzero", addressZero);
Settings.sgsPutInt ("mlfone", addressOne);
Settings.sgsPutInt ("mlflow", dataLow);
Settings.sgsPutInt ("mlfhigh", dataHigh);
Settings.sgsPutInt ("mlffrozen", dataFrozen);
Settings.sgsPutInt ("mlfdynamic", dataDynamic);
} //mlfTini
//mlfMake ()
public static void mlfMake () {
//アクションリスナー
ActionListener listener = new ActionListener () {
@Override public void actionPerformed (ActionEvent ae) {
Object source = ae.getSource ();
String command = ae.getActionCommand ();
if (command.equals ("Reset to initial settings")) {
//チップ
modelNumber = 0;
mlfChipMask = 0;
for (int m = 0; m < MODEL_NAME.length; m++) {
modelButton[m].setSelected (m == 0);
}
for (int i = 0; i < 32; i++) {
chipCheckBox[i].setText (IC_NAME[0][i]);
chipCheckBox[i].setSelected (false);
}
//アドレス
addressZero = 0;
addressOne = 0;
addressMask = addressZero | addressOne;
for (int i = 0; i < 16 * 3; i++) {
addressButton[i].setSelected (i < 16);
}
//データ
dataLow = 0;
dataHigh = 0;
dataFrozen = 0;
dataDynamic = 0;
dataMask = dataLow | dataHigh | dataFrozen | dataDynamic;
for (int i = 0; i < 16 * 5; i++) {
dataButton[i].setSelected (i < 16);
}
updateNthChip ();
return;
}
for (int m = 0; m < MODEL_NAME.length; m++) {
if (command.equals (MODEL_NAME[m])) {
modelNumber = m;
for (int i = 0; i < 32; i++) {
chipCheckBox[i].setText (IC_NAME[m][i]);
}
updateNthChip ();
return;
}
}
int c = command.charAt (0);
if (c == 'i') { //チップ
int m = 1 << Integer.parseInt (command.substring (1));
if (((JCheckBox) source).isSelected ()) {
mlfChipMask |= m;
} else {
mlfChipMask &= ~m;
}
updateNthChip ();
} else if (c == 'e') { //アドレス Either 0 or 1
int m = 1 << Integer.parseInt (command.substring (1));
addressZero &= ~m;
addressOne &= ~m;
addressMask = addressZero | addressOne;
} else if (c == 'z') { //アドレス 0
int m = 1 << Integer.parseInt (command.substring (1));
addressZero |= m;
addressOne &= ~m;
addressMask = addressZero | addressOne;
} else if (c == 'o') { //アドレス 1
int m = 1 << Integer.parseInt (command.substring (1));
addressZero &= ~m;
addressOne |= m;
addressMask = addressZero | addressOne;
} else if (c == 'n') { //データ Normal
int m = 1 << Integer.parseInt (command.substring (1));
dataLow &= ~m;
dataHigh &= ~m;
dataFrozen &= ~m;
dataDynamic &= ~m;
dataMask = dataLow | dataHigh | dataFrozen | dataDynamic;
} else if (c == 'l') { //データ Stuck at low
int m = 1 << Integer.parseInt (command.substring (1));
dataLow |= m;
dataHigh &= ~m;
dataFrozen &= ~m;
dataDynamic &= ~m;
dataMask = dataLow | dataHigh | dataFrozen | dataDynamic;
} else if (c == 'h') { //データ Stuck at high
int m = 1 << Integer.parseInt (command.substring (1));
dataLow &= ~m;
dataHigh |= m;
dataFrozen &= ~m;
dataDynamic &= ~m;
dataMask = dataLow | dataHigh | dataFrozen | dataDynamic;
} else if (c == 'f') { //データ Frozen noise
int m = 1 << Integer.parseInt (command.substring (1));
dataLow &= ~m;
dataHigh &= ~m;
dataFrozen |= m;
dataDynamic &= ~m;
dataMask = dataLow | dataHigh | dataFrozen | dataDynamic;
} else if (c == 'd') { //データ Dynamic noise
int m = 1 << Integer.parseInt (command.substring (1));
dataLow &= ~m;
dataHigh &= ~m;
dataFrozen &= ~m;
dataDynamic |= m;
dataMask = dataLow | dataHigh | dataFrozen | dataDynamic;
} else {
System.out.println ("unknown action command " + command);
} //switch command
} //actionPerformed
}; //listener
/*
//警告パネル
// 0 1 2
// 0 0:--------------
// 1 1: 2:caution0 3:
// 2 |: 4:caution1 |
// 3 5:--------------
//オブジェクト
Object[] cautionObject = new Object[6];
for (int i = 0; i < 6; i++) {
cautionObject[i] = (
//横線
i == 0 || i == 5 ?
ComponentFactory.createHorizontalSeparator () :
//縦線(隙間)
i == 1 || i == 3 ?
Box.createHorizontalStrut (10) :
//ラベル
i == 2 ? Multilingual.mlnText (
ComponentFactory.createLabel (CAUTION_EN[0]),
"ja", CAUTION_JA[0]) :
Multilingual.mlnText (
ComponentFactory.createLabel (CAUTION_EN[1]),
"ja", CAUTION_JA[1]));
}
//パネル
JPanel cautionPanel =
ComponentFactory.createGridPanel (
//colCount
3,
//rowCount
4,
//gridStyles
"paddingLeft=3,paddingRight=3,center",
//colStyles
"",
//rowStyles
"colSpan=3,widen;;;" + //row=0 横線
"colSpan=3,widen", //row=3 横線
//cellStyles
";" +
"rowSpan=2,lengthen;;" + //1: 縦線(隙間)
"rowSpan=2,lengthen", //3: 縦線(隙間)
cautionObject);
*/
//チップパネル
// 0 1 2 3-10 11
// 0 0:-----------------------------
// 1 1: 2:Model 3: 4:model 5:
// 2 6:-----------------------------
// 3 7: 8:TVRAM 9: 10-17:[]... 18:
// 4 | | | 19:----- |
// 5 | | | 20-27:[]... |
// 6 28:-----------------------------
// 7 29: 30:GVRAM 31: 32-39:[]... 40:
// 8 | | | 41:----- |
// 9 | | | 42-49:[]... |
// 10 50:-----------------------------
//modelパネル
ButtonGroup modelGroup = new ButtonGroup ();
modelButton = new JRadioButton[MODEL_NAME.length];
JPanel modelPanel = ComponentFactory.createFlowPanel (
FlowLayout.CENTER, 10, 0);
for (int m = 0; m < MODEL_NAME.length; m++) {
modelButton[m] = ComponentFactory.createRadioButton (
modelGroup,
m == modelNumber,
MODEL_NAME[m],
listener);
if (m == 0) {
Multilingual.mlnText (modelButton[m],
"ja", "初代");
}
modelPanel.add (modelButton[m]);
}
//チェックボックス
chipCheckBox = new JCheckBox[32];
for (int i = 0; i < 32; i++) {
chipCheckBox[i] =
ComponentFactory.setText (
ComponentFactory.createCheckBox (
(mlfChipMask & (1 << i)) != 0,
"i" + i,
listener),
IC_NAME[modelNumber][i]);
} //for i
//オブジェクト
Object[] chipObject = new Object[51];
for (int i = 0; i < 51; i++) {
chipObject[i] = (
//横線
i == 0 || i == 6 || i == 19 || i == 28 || i == 41 || i == 50 ?
ComponentFactory.createHorizontalSeparator () :
//縦線(隙間)
i == 1 || i == 3 || i == 5 ||
i == 7 || i == 9 || i == 18 ||
i == 29 || i == 31 || i == 40 ?
Box.createHorizontalStrut (10) :
//ラベル
i == 2 ? Multilingual.mlnText (
ComponentFactory.createLabel ("Model"),
"ja", "機種") :
i == 8 ? ComponentFactory.createLabel ("TVRAM") :
i == 30 ? ComponentFactory.createLabel ("GVRAM") :
//機種パネル
i == 4 ? modelPanel :
//チェックボックス
i <= 17 ? chipCheckBox[i - 10] :
i <= 27 ? chipCheckBox[i - 20 + 8] :
i <= 39 ? chipCheckBox[i - 32 + 16] :
chipCheckBox[i - 42 + 24]);
} //for i
//パネル
JPanel chipPanel =
ComponentFactory.createGridPanel (
//colCount
12,
//rowCount
11,
//gridStyles
"paddingLeft=3,paddingRight=3,center",
//colStyles
";" +
"italic", //col=1 ラベル
//rowStyles
"colSpan=12,widen;;" + //row=0 横線
"colSpan=12,widen;;" + //row=2 横線
"colSpan=8,widen;;" + //row=4 横線
"colSpan=12,widen;;" + //row=6 横線
"colSpan=8,widen;;" + //row=8 横線
"colSpan=12,widen", //row=10 横線
//cellStyles
";" +
"lengthen;;" + //1: 縦線(隙間)
"lengthen;" + //3: 縦線(隙間)
"colSpan=8;" + //4: model
"lengthen;;" + //5: 縦線(隙間)
"rowSpan=3,lengthen;" + //7: 縦線(隙間)
"rowSpan=3;" + //8: TVRAM
"rowSpan=3,lengthen;;;;;;;;;" + //9: 縦線(隙間)
"rowSpan=3,lengthen;;;;;;;;;;;" + //18: 縦線(隙間)
"rowSpan=3,lengthen;" + //29: 縦線(隙間)
"rowSpan=3;" + //30: GVRAM
"rowSpan=3,lengthen;;;;;;;;;" + //31: 縦線(隙間)
"rowSpan=3,lengthen", //40: 縦線(隙間)
chipObject);
//アドレスパネル
// 0 1 2 3-10 11 12-19 20
// 0 0:-------------------------------------------------------
// 1 1: 2: 3: 4-11:15-8 12: 13-20:7-0 21:
// 2 22:-------------------------------------------------------
// 3 23: 24:Either 0 or 1 25: 26-33:[]... 34: 35-42:[]... 43:
// mask bit/button 15-8 7-0
// 4 | 44:0 | 45-52:[]... | 53-60:[]... |
// button 31-24 23-16
// 5 | 61:1 | 62-69:[]... | 70-77:[]... |
// button 47-40 39-32
// 6 78:-------------------------------------------------------
//ボタン
ButtonGroup[] addressGroup = new ButtonGroup[16];
addressButton = new JRadioButton[16 * 3];
//Either 0 or 1
for (int i = 0; i < 16; i++) {
addressGroup[i] = new ButtonGroup ();
addressButton[16 * 0 + i] =
ComponentFactory.setText (
ComponentFactory.createRadioButton (
addressGroup[i],
(addressMask & (1 << i)) == 0,
"e" + i,
listener),
"");
} //for i
//0
for (int i = 0; i < 16; i++) {
addressButton[16 * 1 + i] =
ComponentFactory.setText (
ComponentFactory.createRadioButton (
addressGroup[i],
(addressZero & (1 << i)) != 0,
"z" + i,
listener),
"");
} //for i
//1
for (int i = 0; i < 16; i++) {
addressButton[16 * 2 + i] =
ComponentFactory.setText (
ComponentFactory.createRadioButton (
addressGroup[i],
(addressOne & (1 << i)) != 0,
"o" + i,
listener),
"");
} //for i
//オブジェクト
Object[] addressObject = new Object[79];
for (int i = 0; i < 79; i++) {
addressObject[i] = (
//横線
i == 0 || i == 22 || i == 78 ?
ComponentFactory.createHorizontalSeparator () :
//縦線(隙間)
i == 1 || i == 3 || i == 12 || i == 21 ||
i == 23 || i == 25 || i == 34 || i == 43 ?
Box.createHorizontalStrut (10) :
//ラベル
i == 2 ? ComponentFactory.createLabel ("") :
i == 24 ? Multilingual.mlnText (
ComponentFactory.createLabel ("Either 0 or 1"),
"ja", "0または1") :
i == 44 ? ComponentFactory.createLabel ("0") :
i == 61 ? ComponentFactory.createLabel ("1") :
i <= 11 ? ComponentFactory.createLabel (String.valueOf (8 + 11 - i)) :
i <= 20 ? ComponentFactory.createLabel (String.valueOf (20 - i)) :
//ボタン
addressButton[i <= 33 ? 8 + 33 - i : //15-8
i <= 42 ? 42 - i : //7-0
i <= 60 ? 16 + 60 - i : //31-16
32 + 77 - i]); //47-32
} //for i
//パネル
JPanel addressPanel =
ComponentFactory.createGridPanel (
//colCount
21,
//rowCount
7,
//gridStyles
"paddingLeft=3,paddingRight=3,center",
//colStyles
";" +
"italic;", //col=1 ラベル
//rowStyles
"colSpan=21,widen;" + //row=0 横線
"italic;" + //row=1 ラベル
"colSpan=21,widen;;;;" + //row=2 横線
"colSpan=21,widen", //row=6 横線
//cellStyles
";" +
"lengthen;;" + //1: 縦線(隙間)
"lengthen;;;;;;;;;" + //3: 縦線(隙間)
"lengthen;;;;;;;;;" + //12: 縦線(隙間)
"lengthen;;" + //21: 縦線(隙間)
"rowSpan=3,lengthen;;" + //23: 縦線(隙間)
"rowSpan=3,lengthen;;;;;;;;;" + //25: 縦線(隙間)
"rowSpan=3,lengthen;;;;;;;;;" + //34: 縦線(隙間)
"rowSpan=3,lengthen", //43: 縦線(隙間)
addressObject);
//データパネル
// 0 1 2 3-6 7 8-11 12 13-16 17 18-21 22
// 0 0:-------------------------------------------------------------------------------------
// 1 1: 2: 3: 4:1st 5: 6:2nd 7: 8:3rd 9: 10:4th 11:
// 2 | | | 12-15:3-0 | 16-19:3-0 | 20-23:3-0 | 24-27:3-0 |
// 3 28:-------------------------------------------------------------------------------------
// 4 29: 30:Normal 31: 32-35:[]... 36: 37-40:[]... 41: 42-45:[]... 46: 47-50:[]... 51:
// mask bit/button 15-12 11-8 7-4 3-0
// 5 |: 52:Stuck at low | 53-56:[]... | 57-60:[]... | 61-64:[]... | 65-68:[]... |
// button 31-28 27-24 23-20 19-16
// 6 |: 69:Stuck at high | 70-73:[]... | 74-77:[]... | 78-81:[]... | 82-85:[]... |
// button 47-44 43-40 39-36 35-32
// 7 |: 86:Frozen noise | 87-90:[]... | 91-94:[]... | 95-98:[]... | 99-102:[]... |
// button 63-60 59-56 55-52 51-48
// 8 |: 103:Dynamic noise |104-107:[]... |108-111:[]... |112-115:[]... |116-119:[]... |
// button 79-76 75-72 71-68 67-64
// 9 120:-------------------------------------------------------------------------------------
// dataGroup 0-3 4-7 8-11 12-15
//ボタン
ButtonGroup[] dataGroup = new ButtonGroup[16];
dataButton = new JRadioButton[16 * 5];
//Normal
for (int i = 0; i < 16; i++) {
dataGroup[i] = new ButtonGroup ();
dataButton[16 * 0 + i] =
ComponentFactory.setText (
ComponentFactory.createRadioButton (
dataGroup[i],
(dataMask & (1 << i)) == 0,
"n" + i,
listener),
"");
} //for i
//Stuck at low
for (int i = 0; i < 16; i++) {
dataButton[16 * 1 + i] =
ComponentFactory.setText (
ComponentFactory.createRadioButton (
dataGroup[i],
(dataLow & (1 << i)) != 0,
"l" + i,
listener),
"");
} //for i
//Stuck at high
for (int i = 0; i < 16; i++) {
dataButton[16 * 2 + i] =
ComponentFactory.setText (
ComponentFactory.createRadioButton (
dataGroup[i],
(dataHigh & (1 << i)) != 0,
"h" + i,
listener),
"");
} //for i
//Frozen noise
for (int i = 0; i < 16; i++) {
dataButton[16 * 3 + i] =
ComponentFactory.setText (
ComponentFactory.createRadioButton (
dataGroup[i],
(dataFrozen & (1 << i)) != 0,
"f" + i,
listener),
"");
} //for i
//Dynamic noise
for (int i = 0; i < 16; i++) {
dataButton[16 * 4 + i] =
ComponentFactory.setText (
ComponentFactory.createRadioButton (
dataGroup[i],
(dataDynamic & (1 << i)) != 0,
"d" + i,
listener),
"");
} //for i
//オブジェクト
Object[] dataObject = new Object[121];
for (int i = 0; i < 121; i++) {
dataObject[i] = (
//横線
i == 0 || i == 28 || i == 120 ?
ComponentFactory.createHorizontalSeparator () :
//縦線(隙間)
i == 1 || i == 3 || i == 5 || i == 7 || i == 9 || i == 11 ||
i == 29 || i == 31 | i == 36 || i == 41 || i == 46 || i == 51 ?
Box.createHorizontalStrut (10) :
//ラベル
i == 2 ? ComponentFactory.createLabel ("") :
i == 4 ? ComponentFactory.createLabel ("1st") :
i == 6 ? ComponentFactory.createLabel ("2nd") :
i == 8 ? ComponentFactory.createLabel ("3rd") :
i == 10 ? ComponentFactory.createLabel ("4th") :
i == 30 ? Multilingual.mlnText (
ComponentFactory.createLabel ("Normal"),
"ja", "正常") :
i == 52 ? Multilingual.mlnText (
ComponentFactory.createLabel ("Stuck at low"),
"ja", "常に0") :
i == 69 ? Multilingual.mlnText (
ComponentFactory.createLabel ("Stuck at high"),
"ja", "常に1") :
i == 86 ? Multilingual.mlnText (
ComponentFactory.createLabel ("Frozen noise"),
"ja", "静的ノイズ") :
i == 103 ? Multilingual.mlnText (
ComponentFactory.createLabel ("Dynamic noise"),
"ja", "動的ノイズ") :
i <= 15 ? ComponentFactory.createLabel (String.valueOf (15 - i)) : //3-0
i <= 19 ? ComponentFactory.createLabel (String.valueOf (19 - i)) : //3-0
i <= 23 ? ComponentFactory.createLabel (String.valueOf (23 - i)) : //3-0
i <= 27 ? ComponentFactory.createLabel (String.valueOf (27 - i)) : //3-0
//ボタン
dataButton[i <= 35 ? 16 * 0 + 12 + 35 - i : //15-12
i <= 40 ? 16 * 0 + 8 + 40 - i : //11-8
i <= 45 ? 16 * 0 + 4 + 45 - i : //7-4
i <= 50 ? 16 * 0 + 0 + 50 - i : //3-0
i <= 68 ? 16 * 1 + 68 - i : //16*1+(15-0)
i <= 85 ? 16 * 2 + 85 - i : //16*2+(15-0)
i <= 102 ? 16 * 3 + 102 - i : //16*3+(15-0)
16 * 4 + 119 - i]); //16*4+(15-0)
} //for i
//パネル
JPanel dataPanel =
ComponentFactory.createGridPanel (
//colCount
23,
//rowCount
10,
//gridStyles
"paddingLeft=3,paddingRight=3,center",
//colStyles
";" +
"italic;", //col=1 ラベル
//rowStyles
"colSpan=23,widen;" + //row=0 横線
"italic;" + //row=1 ラベル
"italic;" + //row=2 ラベル
"colSpan=23,widen;;;;;;" + //row=3 横線
"colSpan=23,widen", //row=9 横線
//cellStyles
";" +
"rowSpan=2,lengthen;" + //1: 縦線(隙間)
"rowSpan=2;" + //2: -
"rowSpan=2,lengthen;" + //3: 縦線(隙間)
"colSpan=4;" + //4: 1st
"rowSpan=2,lengthen;" + //5: 縦線(隙間)
"colSpan=4;" + //6: 2nd
"rowSpan=2,lengthen;" + //7: 縦線(隙間)
"colSpan=4;" + //8: 3rd
"rowSpan=2,lengthen;" + //9: 縦線(隙間)
"colSpan=4;" + //10: 4th
"rowSpan=2,lengthen;;;;;;;;;;;;;;;;;;" + //11: 縦線(隙間)
"rowSpan=5,lengthen;;" + //29: 縦線(隙間)
"rowSpan=5,lengthen;;;;;" + //31: 縦線(隙間)
"rowSpan=5,lengthen;;;;;" + //36: 縦線(隙間)
"rowSpan=5,lengthen;;;;;" + //41: 縦線(隙間)
"rowSpan=5,lengthen;;;;;" + //46: 縦線(隙間)
"rowSpan=5,lengthen", //51: 縦線(隙間)
dataObject);
updateNthChip ();
//ウインドウ
frame = Multilingual.mlnTitle (
ComponentFactory.createRestorableSubFrame (
Settings.SGS_MLF_FRAME_KEY,
"Malfunction screen (experimental)",
null,
ComponentFactory.createVerticalBox (
ComponentFactory.setPreferredSize (
ComponentFactory.setEmptyBorder (
ComponentFactory.createScrollPane (
ComponentFactory.setEmptyBorder (
ComponentFactory.createVerticalBox (
/*
ComponentFactory.createFlowPanel (
FlowLayout.CENTER, 0, 0,
Multilingual.mlnText (
ComponentFactory.createLabel ("Caution"),
"ja", "警告")),
ComponentFactory.createFlowPanel (
FlowLayout.CENTER, 0, 0,
cautionPanel),
Box.createVerticalStrut (10),
*/
ComponentFactory.createFlowPanel (
FlowLayout.CENTER, 0, 0,
Multilingual.mlnText (
ComponentFactory.createLabel ("VRAM chip"),
"ja", "VRAMチップ")),
ComponentFactory.createFlowPanel (
FlowLayout.CENTER, 0, 0,
chipPanel),
Box.createVerticalStrut (10),
ComponentFactory.createFlowPanel (
FlowLayout.CENTER, 0, 0,
Multilingual.mlnText (
ComponentFactory.createLabel ("Address within chip"),
"ja", "チップ内アドレス")),
ComponentFactory.createFlowPanel (
FlowLayout.CENTER, 0, 0,
addressPanel),
Box.createVerticalStrut (10),
ComponentFactory.createFlowPanel (
FlowLayout.CENTER, 0, 0,
Multilingual.mlnText (
ComponentFactory.createLabel ("Data corruption"),
"ja", "データ破壊")),
ComponentFactory.createFlowPanel (
FlowLayout.CENTER, 0, 0,
dataPanel),
Box.createVerticalStrut (10),
ComponentFactory.createFlowPanel (
FlowLayout.CENTER, 0, 0,
Multilingual.mlnText (
ComponentFactory.createButton (
"Reset to initial settings",
listener),
"ja", "初期設定に戻す")
)
), //createVerticalBox
10, 10, 10, 10) //setEmptyBorder
), //createScrollPane
0, 0, 0, 0), //setEmptyBorder
600, 500), //setPreferredSize
Box.createVerticalGlue ()
) //createVerticalBox
), //createRestorableSubFrame
"ja", "故障画面 (実験中)"); //mlnTitle
} //mlfMake
//mlfStart ()
public static void mlfStart () {
if (RestorableFrame.rfmGetOpened (Settings.SGS_MLF_FRAME_KEY)) {
mlfOpen ();
}
} //mlfStart
//mlfOpen ()
public static void mlfOpen () {
if (frame == null) {
mlfMake ();
}
XEiJ.pnlExitFullScreen (false);
frame.setVisible (true);
} //mlfOpen
private static void updateNthChip () {
int n = 0; //ONのチップの数
for (int i = 0; i < 32; i++) {
if ((mlfChipMask & (1 << i)) != 0) {
nthChip[i] = (n & 3);
n++;
} else {
nthChip[i] = -1;
}
}
if (addressButton != null) {
for (int i = 0; i < 16 * 3; i++) {
addressButton[i].setEnabled (0 < n);
}
}
if (dataButton != null) {
for (int i = 0; i < 16 * 5; i++) {
// (i&15)>>2 左から3,2,1,0
// 3-((i&15)>>2) 左から0,1,2,3
dataButton[i].setEnabled ((3 - ((i & 15) >> 2)) < n);
}
}
} //updateNthChip
//!!! 以下は推測のため誤りが含まれる可能性がある
/*
(SPECULATION)
CHIP ORDER IN SCHEMATICS
<-------P0--------> <-------P1-------->
A [ 0] [ 1] [ 2] [ 3] [ 4] [ 5] [ 6] [ 7]
TVRAM | LL LH HL HH LL LH HL HH
V [ 8] [ 9] [10] [11] [12] [13] [14] [15]
<-------P2--------> <-------P3-------->
<-------P0--------> <-------P1-------->
A [16] [17] [18] [19] [20] [21] [22] [23]
GVRAM | NW NE SW SE NW NE SW SE
V [24] [25] [26] [27] [28] [29] [30] [31]
<-------P2--------> <-------P3-------->
TVRAM
+0 +1 +7E +7F
E00000 [ 3] [ 2] [ 1] [ 0] ... [ 3] [ 2] [ 1] [ 0]
0000 0000 0000 0000 ... 003F 003F 003F 003F
E00080 [ 3] [ 2] [ 1] [ 0] ... [ 3] [ 2] [ 1] [ 0]
0040 0040 0040 0040 ... 007F 007F 007F 007F
:
E1FF80 [ 3] [ 2] [ 1] [ 0] ... [ 3] [ 2] [ 1] [ 0]
FFC0 FFC0 FFC0 FFC0 ... FFFF FFFF FFFF FFFF
E20000 [ 7] [ 6] [ 5] [ 4] ... [ 7] [ 6] [ 5] [ 4]
0000 0000 0000 0000 ... 003F 003F 003F 003F
:
E7FF80 [15] [14] [13] [12] ... [15] [14] [13] [12]
FFC0 FFC0 FFC0 FFC0 ... FFFF FFFF FFFF FFFF
GVRAM (512 DOTS 16 COLORS)
+0 +2 +4 +6 +3F8 +3FA +3FC +3FE
C00000 [16] [17] [16] [17] ... [16] [17] [16] [17]
0000 0000 0001 0001 ... 00FE 00FE 00FF 00FF
C00400 [16] [17] [16] [17] ... [16] [17] [16] [17]
0100 0100 0101 0101 ... 01FE 01FE 01FF 01FF
:
C3FC00 [16] [17] [16] [17] ... [16] [17] [16] [17]
FF00 FF00 FF01 FF01 ... FFFE FFFE FFFF FFFF
C40000 [18] [19] [18] [19] ... [18] [19] [18] [19]
0000 0000 0001 0001 ... 00FE 00FE 00FF 00FF
:
DFFC00 [30] [31] [30] [31] ... [30] [31] [30] [31]
FF00 FF00 FF01 FF01 ... FFFE FFFE FFFF FFFF
*/
//VRAMのデータを一時的に退避させる場所
// 1ラスタのハーフワード数だけ必要
private static final int[] tempTArray = new int[2 * 1024];
private static final int[] tempGArray = new int[2 * 1024];
private static int tempTIndex;
private static int tempGIndex;
//mlfRaster (dataY)
// 一時的にVRAMを書き換えて描画する
public static void mlfRaster (int src, int dst, boolean rh) {
//TVRAMを書き換える
tempTIndex = 0;
if ((mlfChipMask & 0x0000ffff) != 0 &&
(VideoController.vcnReg3Curr & 0x0060) != 0) {
int r8c2 = (CRTC.crtR11TxYZero + src) & 1023; //ドットY座標
for (int c6 = 0; c6 < 64; c6++) { //ワードX座標
int r8c8 = r8c2 << 6 | c6; //チップ内アドレス
if ((r8c8 & addressZero) != 0 ||
(~r8c8 & addressOne) != 0) {
continue;
}
for (int i5 = 0; i5 < 16; i5++) { //チップ番号
if ((mlfChipMask & (1 << i5)) == 0) {
continue;
}
int p2 = i5 >> 2; //プレーン
int a = (0x00e00000 | //メモリアドレス
p2 << 17 | //プレーン
r8c8 << 1 | //ワード
((~i5 >> 1) & 1)); //バイト。チップ番号が若い方が下位
int d = MainMemory.mmrM8[a];
tempTArray[tempTIndex] = a;
tempTArray[tempTIndex + 1] = d;
tempTIndex += 2;
// nthChip[i5] 左から0,1,2,3
// 3-nthChip[i5] 左から3,2,1,0
int b = ((3 - nthChip[i5]) << 2);
if ((i5 & 1) == 0) { //ハーフバイト下位
d &= ~((dataMask >> b) & 15);
d |= ((dataHigh >> b) & 15);
if (((dataFrozen >> b) & 15) != 0) {
d |= (((dataFrozen >> b) & 15) & noiseArray[0 << 18 | p2 << 16 | r8c8]);
}
if (((dataDynamic >> b) & 15) != 0) {
d |= (((dataDynamic >> b) & 15) & (random () >>> 28));
}
MainMemory.mmrM8[a] = (byte) d;
} else { //ハーフバイト上位
d &= ~(((dataMask >> b) & 15) << 4);
d |= ((dataHigh >> b) & 15) << 4;
if (((dataFrozen >> b) & 15) != 0) {
d |= (((dataFrozen >> b) & 15) & noiseArray[0 << 18 | p2 << 16 | r8c8]) << 4;
}
if (((dataDynamic >> b) & 15) != 0) {
d |= (((dataDynamic >> b) & 15) & (random () >>> 28)) << 4;
}
MainMemory.mmrM8[a] = (byte) d;
}
}
}
}
//GVRAMを書き換える
tempGIndex = 0;
if ((mlfChipMask & 0xffff0000) != 0 &&
(VideoController.vcnReg3Curr & 0x001f) != 0) {
for (int p2 = 0; p2 < 4; p2++) { //ページ
int y9; //ドットY座標
if ((VideoController.vcnReg1Curr & 7) < 4) { //512x512
y9 = (CRTC.crtR13GrYZero[p2] + src) & 511;
} else { //1024x1024
int y10 = (CRTC.crtR13GrYZero[0] + src) & 1023;
if ((y10 >> 9) != (p2 >> 1)) { //上半分は0,1、下半分は2,3
continue;
}
y9 = y10 & 511;
}
//int r8 = y9 >> 1; //NSはLSB
//int ns = y9 & 1;
int r8 = y9 & 255; //NSはMSB
int ns = y9 >> 8;
for (int x9 = 0; x9 < 512; x9++) { //ドットX座標
int c8 = x9 >> 1;
int we = x9 & 1;
int r8c8 = r8 << 8 | c8; //チップ内アドレス
if ((r8c8 & addressZero) != 0 ||
(~r8c8 & addressOne) != 0) {
continue;
}
int i5 = 16 | p2 << 2 | ns << 1 | we; //チップ番号
if ((mlfChipMask & (1 << i5)) == 0) {
continue;
}
int a = p2 << 18 | y9 << 9 | x9; //アドレス
int d = GraphicScreen.graM4[a];
tempGArray[tempGIndex] = a;
tempGArray[tempGIndex + 1] = d;
tempGIndex += 2;
// nthChip[i5] 左から0,1,2,3
// 3-nthChip[i5] 左から3,2,1,0
int b = ((3 - nthChip[i5]) << 2);
d &= ~((dataMask >> b) & 15);
d |= ((dataHigh >> b) & 15);
if (((dataFrozen >> b) & 15) != 0) {
d |= (((dataFrozen >> b) & 15) & noiseArray[1 << 18 | p2 << 16 | r8c8]);
}
if (((dataDynamic >> b) & 15) != 0) {
d |= (((dataDynamic >> b) & 15) & (random () >>> 28));
}
GraphicScreen.graM4[a] = (byte) d;
}
}
}
//描画する
VideoController.vcnMode.drawRaster (src, dst, rh);
//TVRAMを元に戻す
while (0 < tempTIndex) {
tempTIndex -= 2;
MainMemory.mmrM8[tempTArray[tempTIndex]] = (byte) tempTArray[tempTIndex + 1];
}
//GVRAMを元に戻す
while (0 < tempGIndex) {
tempGIndex -= 2;
GraphicScreen.graM4[tempGArray[tempGIndex]] = (byte) tempGArray[tempGIndex + 1];
}
} //mlfRaster
private static int x = 123456789;
private static int y = 362436069;
private static int z = 521288629;
private static int w = 88675123;
//w = random ()
// 疑似乱数
private static int random () {
int t = x ^ (x << 11);
x = y;
y = z;
z = w;
return w = (w ^ (w >>> 19)) ^ (t ^ (t >>> 8));
} //random
} //class Malfunction