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 addressZero;
private static int addressOne;
private static int addressMask; //zero|one
//データ
private static int dataLow;
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; //チップチェックボックス
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);
//アドレス
addressZero = Settings.sgsGetInt ("mlfzero", 0, 0, 65535);
addressOne = Settings.sgsGetInt ("mlfone", 0, 0, 65535);
addressMask = addressZero | addressOne;
//データ
dataLow = Settings.sgsGetInt ("mlflow", 0, 0, 15);
dataHigh = Settings.sgsGetInt ("mlfhigh", 0, 0, 15);
dataFrozen = Settings.sgsGetInt ("mlffrozen", 0, 0, 15);
dataDynamic = Settings.sgsGetInt ("mlfdynamic", 0, 0, 15);
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 < 48; i++) {
addressButton[i].setSelected (i < 16);
}
//データ
dataLow = 0;
dataHigh = 0;
dataFrozen = 0;
dataDynamic = 0;
dataMask = dataLow | dataHigh | dataFrozen | dataDynamic;
for (int i = 0; i < 20; i++) {
dataButton[i].setSelected (i < 4);
}
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]);
}
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;
}
} 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:
// 4 | 44:0 | 45-52:[]... | 53-60:[]... |
// 5 | 61:1 | 62-69:[]... | 70-77:[]... |
// 6 78:-------------------------------------------------------
//ボタン
ButtonGroup[] addressGroup = new ButtonGroup[16];
addressButton = new JRadioButton[48];
//Either 0 or 1
for (int i = 0; i < 16; i++) {
addressGroup[i] = new ButtonGroup ();
addressButton[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 + 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[32 + 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
// 0 0:------------------------------------
// 1 1: 2: 3: 4-7:3-0 8:
// 2 9:------------------------------------
// 3 10: 11:Normal 12: 13-16:[]... 17:
// 4 |: 18:Stuck at low | 19-22:[]... |
// 5 |: 23:Stuck at high | 24-27:[]... |
// 6 |: 28:Frozen noise | 29-32:[]... |
// 7 |: 33:Dynamic noise | 34-37:[]... |
// 8 38:------------------------------------
//ボタン
ButtonGroup[] dataGroup = new ButtonGroup[4];
dataButton = new JRadioButton[20];
//Normal
for (int i = 0; i < 4; i++) {
dataGroup[i] = new ButtonGroup ();
dataButton[i] =
ComponentFactory.setText (
ComponentFactory.createRadioButton (
dataGroup[i],
(dataMask & (1 << i)) == 0,
"n" + i,
listener),
"");
} //for i
//Stuck at low
for (int i = 0; i < 4; i++) {
dataButton[4 + i] =
ComponentFactory.setText (
ComponentFactory.createRadioButton (
dataGroup[i],
(dataLow & (1 << i)) != 0,
"l" + i,
listener),
"");
} //for i
//Stuck at high
for (int i = 0; i < 4; i++) {
dataButton[8 + i] =
ComponentFactory.setText (
ComponentFactory.createRadioButton (
dataGroup[i],
(dataHigh & (1 << i)) != 0,
"h" + i,
listener),
"");
} //for i
//Frozen noise
for (int i = 0; i < 4; i++) {
dataButton[12 + i] =
ComponentFactory.setText (
ComponentFactory.createRadioButton (
dataGroup[i],
(dataFrozen & (1 << i)) != 0,
"f" + i,
listener),
"");
} //for i
//Dynamic noise
for (int i = 0; i < 4; i++) {
dataButton[16 + i] =
ComponentFactory.setText (
ComponentFactory.createRadioButton (
dataGroup[i],
(dataDynamic & (1 << i)) != 0,
"d" + i,
listener),
"");
} //for i
//オブジェクト
Object[] dataObject = new Object[39];
for (int i = 0; i < 39; i++) {
dataObject[i] = (
//横線
i == 0 || i == 9 || i == 38 ?
ComponentFactory.createHorizontalSeparator () :
//縦線(隙間)
i == 1 || i == 3 || i == 8 ||
i == 10 || i == 12 | i == 17 ?
Box.createHorizontalStrut (10) :
//ラベル
i == 2 ? ComponentFactory.createLabel ("") :
i == 11 ? Multilingual.mlnText (
ComponentFactory.createLabel ("Normal"),
"ja", "正常") :
i == 18 ? Multilingual.mlnText (
ComponentFactory.createLabel ("Stuck at low"),
"ja", "常に0") :
i == 23 ? Multilingual.mlnText (
ComponentFactory.createLabel ("Stuck at high"),
"ja", "常に1") :
i == 28 ? Multilingual.mlnText (
ComponentFactory.createLabel ("Frozen noise"),
"ja", "静的ノイズ") :
i == 33 ? Multilingual.mlnText (
ComponentFactory.createLabel ("Dynamic noise"),
"ja", "動的ノイズ") :
i <= 7 ? ComponentFactory.createLabel (String.valueOf (7 - i)) :
//ボタン
dataButton[i <= 16 ? 16 - i : //3-0
i <= 22 ? 4 + 22 - i : //7-4
i <= 27 ? 8 + 27 - i : //11-8
i <= 32 ? 12 + 32 - i : //15-12
16 + 37 - i]); //19-16
} //for i
//パネル
JPanel dataPanel =
ComponentFactory.createGridPanel (
//colCount
8,
//rowCount
9,
//gridStyles
"paddingLeft=3,paddingRight=3,center",
//colStyles
";" +
"italic;", //col=1 ラベル
//rowStyles
"colSpan=8,widen;" + //row=0 横線
"italic;" + //row=1 ラベル
"colSpan=8,widen;;;;;;" + //row=2 横線
"colSpan=8,widen", //row=8 横線
//cellStyles
";" +
"lengthen;;" + //1: 縦線(隙間)
"lengthen;;;;;" + //3: 縦線(隙間)
"lengthen;;" + //8: 縦線(隙間)
"rowSpan=5,lengthen;;" + //10: 縦線(隙間)
"rowSpan=5,lengthen;;;;;" + //12: 縦線(隙間)
"rowSpan=5,lengthen", //17: 縦線(隙間)
dataObject);
//ウインドウ
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 ("Multiport RAM chip"),
"ja", "マルチポートRAMチップ")),
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
580, 520), //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()
//!!! 以下は推測のため誤りが含まれる可能性がある
//
// 回路図位置→チップ番号→TVRAM/GVRAM範囲(推測)
// P0 P1
// ┌──────┴───────┐┌──────┴───────┐
// ┌┏━━┓┏━━┓┏━━┓┏━━┓┏━━┓┏━━┓┏━━┓┏━━┓
// │┃ #0 ┃┃ #1 ┃┃ #2 ┃┃ #3 ┃┃ #4 ┃┃ #5 ┃┃ #6 ┃┃ #7 ┃
// │┗━━┛┗━━┛┗━━┛┗━━┛┗━━┛┗━━┛┗━━┛┗━━┛
// TVRAM ┤ LL LH HL HH LL LH HL HH
// │┏━━┓┏━━┓┏━━┓┏━━┓┏━━┓┏━━┓┏━━┓┏━━┓
// │┃ #8 ┃┃ #9 ┃┃#10 ┃┃#11 ┃┃#12 ┃┃#13 ┃┃#14 ┃┃#15 ┃
// └┗━━┛┗━━┛┗━━┛┗━━┛┗━━┛┗━━┛┗━━┛┗━━┛
// └──────┬───────┘└──────┬───────┘
// P2 P3
// P0-3はプレーン
// HH,HL,LH,LLは水平16bitの上位から4bitずつ
// P0 P1
// ┌──────┴───────┐┌──────┴───────┐
// ┌┏━━┓┏━━┓┏━━┓┏━━┓┏━━┓┏━━┓┏━━┓┏━━┓
// │┃#16 ┃┃#17 ┃┃#18 ┃┃#19 ┃┃#20 ┃┃#21 ┃┃#22 ┃┃#23 ┃
// │┗━━┛┗━━┛┗━━┛┗━━┛┗━━┛┗━━┛┗━━┛┗━━┛
// GVRAM ┤ NW NE SW SE NW NE SW SE
// │┏━━┓┏━━┓┏━━┓┏━━┓┏━━┓┏━━┓┏━━┓┏━━┓
// │┃#24 ┃┃#25 ┃┃#26 ┃┃#27 ┃┃#28 ┃┃#29 ┃┃#30 ┃┃#31 ┃
// └┗━━┛┗━━┛┗━━┛┗━━┛┗━━┛┗━━┛┗━━┛┗━━┛
// └──────┬───────┘└──────┬───────┘
// P2 P3
// P0-3はページ
// W-EはX座標のLSB
// W:X={0,2,4,…,510},E:X={1,3,5,…,511}
// N-SはY座標のLSBまたはMSB
// N:Y={0,2,4,…,510},S:Y={1,3,5,…,511}
// N:Y={0,1,2,…,255},S:Y={256,257,258,…,511}
//
// TVRAM範囲→チップ番号とチップ内アドレス(推測)
// +00 +01 +7E +7F
// 00E00000 #3-0000 #2-0000 #1-0000 #0-0000 .. #3-003F #2-003F #1-003F #0-003F
// 80 #3-0040 #2-0040 #1-0040 #0-0040 .. #3-007F #2-007F #1-007F #0-007F
// 100 #3-0080 #2-0080 #1-0080 #0-0080 .. #3-00BF #2-00BF #1-00BF #0-00BF
// 180 #3-00C0 #2-00C0 #1-00C0 #0-00C0 .. #3-00FF #2-00FF #1-00FF #0-00FF
// 200 #3-0100 #2-0100 #1-0100 #0-0100 .. #3-0100 #2-0100 #1-0100 #0-0100
// :
// 1FF80 #3-FFC0 #2-FFC0 #1-FFC0 #0-FFC0 .. #3-FFFF #2-FFFF #1-FFFF #0-FFFF
// 00E20000 #7-0000 #6-0000 #5-0000 #4-0000 .. #7-003F #6-003F #5-003F #4-003F
// :
// #7-FFC0 #6-FFC0 #5-FFC0 #4-FFC0 .. #7-FFFF #6-FFFF #5-FFFF #4-FFFF
// 00E40000 #11-0000 #10-0000 #9-0000 #8-0000 .. #11-003F #10-003F #9-003F #8-003F
// :
// #11-FFC0 #10-FFC0 #9-FFC0 #8-FFC0 .. #11-FFFF #10-FFFF #9-FFFF #8-FFFF
// 00E60000 #15-0000 #14-0000 #13-0000 #12-0000 .. #15-003F #14-003F #13-003F #12-003F
// :
// #15-FFC0 #14-FFC0 #13-FFC0 #12-FFC0 .. #15-FFFF #14-FFFF #13-FFFF #12-FFFF
//
// GVRAM範囲(16色4ページ)→チップ番号とチップ内アドレス(推測)
// +000 +002 +004 +006 +3F8 +3FA +3FC +3FE
// 00C00000 #16-0000 #17-0000 #16-0001 #17-0001 .. #16-00FE #17-00FE #16-00FF #17-00FF
// 400 #18-0000 #19-0000 #18-0001 #19-0001 .. #18-00FE #19-00FE #18-00FF #19-00FF
// 800 #16-0100 #17-0100 #16-0101 #17-0101 .. #16-01FE #17-01FE #16-01FF #17-01FF
// C00 #18-0100 #19-0100 #18-0101 #19-0101 .. #18-01FE #19-01FE #18-01FF #19-01FF
// :
// 7F800 #16-FF00 #17-FF00 #16-FF01 #17-FF01 .. #16-FFFE #17-FFFE #16-FFFF #17-FFFF
// 7FC00 #18-FF00 #19-FF00 #18-FF01 #19-FF01 .. #18-FFFE #19-FFFE #18-FFFF #19-FFFF
// 00C80000 #20-0000 #21-0000 #20-0001 #21-0001 .. #20-00FE #21-00FE #20-00FF #21-00FF
// 400 #22-0000 #23-0000 #22-0001 #23-0001 .. #22-00FE #23-00FE #22-00FF #23-00FF
// :
// FF800 #20-FF00 #21-FF00 #20-FF01 #21-FF01 .. #20-FFFE #21-FFFE #20-FFFF #21-FFFF
// FFC00 #22-FF00 #23-FF00 #22-FF01 #23-FF01 .. #22-FFFE #23-FFFE #22-FFFF #23-FFFF
// 00D00000 #24-0000 #25-0000 #24-0001 #25-0001 .. #24-00FE #25-00FE #24-00FF #25-00FF
// 400 #26-0000 #27-0000 #26-0001 #27-0001 .. #26-00FE #27-00FE #26-00FF #27-00FF
// :
// 7F800 #24-FF00 #25-FF00 #24-FF01 #25-FF01 .. #24-FFFE #25-FFFE #24-FFFF #25-FFFF
// 7FC00 #26-FF00 #27-FF00 #26-FF01 #27-FF01 .. #26-FFFE #27-FFFE #26-FFFF #27-FFFF
// 00D80000 #28-0000 #29-0000 #28-0001 #29-0001 .. #28-00FE #29-00FE #28-00FF #29-00FF
// 400 #30-0000 #31-0000 #30-0001 #31-0001 .. #30-00FE #31-00FE #30-00FF #31-00FF
// :
// FF800 #28-FF00 #29-FF00 #28-FF01 #29-FF01 .. #28-FFFE #29-FFFE #28-FFFF #29-FFFF
// FFC00 #30-FF00 #31-FF00 #30-FF01 #31-FF01 .. #30-FFFE #31-FFFE #30-FFFF #31-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 i4 = 0; i4 < 16; i4++) { //チップ番号
if ((mlfChipMask & (1 << i4)) == 0) {
continue;
}
int p2 = i4 >> 2; //プレーン
int a = (0x00e00000 | //メモリアドレス
p2 << 17 | //プレーン
r8c8 << 1 | //ワード
((~i4 >> 1) & 1)); //バイト。チップ番号が若い方が下位
int d = MainMemory.mmrM8[a];
tempTArray[tempTIndex] = a;
tempTArray[tempTIndex + 1] = d;
tempTIndex += 2;
if ((i4 & 1) == 0) { //ハーフバイト下位
d &= ~dataMask;
d |= dataHigh;
if (dataFrozen != 0) {
d |= (dataFrozen & noiseArray[0 << 18 | p2 << 16 | r8c8]);
}
if (dataDynamic != 0) {
d |= (dataDynamic & (random () >>> 28));
}
MainMemory.mmrM8[a] = (byte) d;
} else { //ハーフバイト上位
d &= ~(dataMask << 4);
d |= dataHigh << 4;
if (dataFrozen != 0) {
d |= (dataFrozen & noiseArray[0 << 18 | p2 << 16 | r8c8]) << 4;
}
if (dataDynamic != 0) {
d |= (dataDynamic & (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;
int ns = y9 & 1;
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 i4 = 16 | p2 << 2 | ns << 1 | we; //チップ番号
if ((mlfChipMask & (1 << i4)) == 0) {
continue;
}
int a = p2 << 18 | y9 << 9 | x9; //アドレス
int d = GraphicScreen.graM4[a];
tempGArray[tempGIndex] = a;
tempGArray[tempGIndex + 1] = d;
tempGIndex += 2;
d &= ~dataMask;
d |= dataHigh;
if (dataFrozen != 0) {
d |= (dataFrozen & noiseArray[1 << 18 | p2 << 16 | r8c8]);
}
if (dataDynamic != 0) {
d |= (dataDynamic & (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