-
Notifications
You must be signed in to change notification settings - Fork 2
/
DebuggerWindow.java
335 lines (270 loc) · 12.7 KB
/
DebuggerWindow.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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
package com.rox.emu.processor.mos6502.dbg.ui;
import com.rox.emu.UnknownOpCodeException;
import com.rox.emu.env.RoxByte;
import com.rox.emu.env.RoxWord;
import com.rox.emu.mem.Memory;
import com.rox.emu.mem.SimpleMemory;
import com.rox.emu.processor.mos6502.Mos6502;
import com.rox.emu.processor.mos6502.Registers;
import com.rox.emu.processor.mos6502.dbg.ui.component.MemoryPanel;
import com.rox.emu.processor.mos6502.dbg.ui.component.Registers6502;
import com.rox.emu.processor.mos6502.op.Mos6502AddressingMode;
import com.rox.emu.processor.mos6502.op.Mos6502OpCode;
import com.rox.emu.processor.mos6502.util.Mos6502Compiler;
import com.rox.emu.processor.mos6502.util.Program;
import com.rox.emu.rom.InesRom;
import javax.swing.*;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import java.awt.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* A DebuggerWindow for debugging 6502 CPU code
*
* @author Ross Drew
*/
final class DebuggerWindow extends JFrame {
private Mos6502 processor;
private Memory memory;
private Registers registers;
private Registers6502 newRegisterPanel;
private String instructionName = "...";
private final JLabel instruction = new JLabel(instructionName);
private final DefaultListModel<String> listModel;
private DebuggerWindow() {
super("6502 Debugger");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
init();
listModel = new DefaultListModel<>();
instruction.setHorizontalAlignment(JLabel.CENTER);
setLayout(new BorderLayout());
add(instruction, BorderLayout.NORTH);
add(getInstructionScroller(), BorderLayout.EAST);
add(getControlPanel(), BorderLayout.SOUTH);
add(getMemoryPanel(), BorderLayout.WEST);
add(getCenterPanel(), BorderLayout.CENTER);
loadProgram(getProgram());
setVisible(true);
pack();
}
private JComponent getCenterPanel(){
JTabbedPane centerPane = new JTabbedPane();
centerPane.add("Registers", newRegisterPanel);
centerPane.add("Code", getCodeInput());
return centerPane;
}
private JComponent getCodeInput(){
final JTextPane codeArea = getCodeArea();
final JScrollPane codeScroller = new JScrollPane(codeArea);
final JButton compilerButton = new JButton("Compile");
compilerButton.addActionListener(e -> compile(codeArea.getText()));
final JPanel codePanel = new JPanel();
codePanel.setLayout(new BorderLayout());
codePanel.add(codeScroller, BorderLayout.CENTER);
codePanel.add(compilerButton, BorderLayout.SOUTH);
return codePanel;
}
private JTextPane getCodeArea(){
final StyleContext sc = new StyleContext();
final DefaultStyledDocument doc = new DefaultStyledDocument(sc);
final JTextPane codeArea = new JTextPane(doc);
codeArea.setBackground(new Color(0x25401C));
codeArea.setCaretColor(new Color(0xD1E8CE));
final Style bodyStyle = sc.addStyle("body", null);
bodyStyle.addAttribute(StyleConstants.Foreground, new Color(0x789C6C));
bodyStyle.addAttribute(StyleConstants.FontSize, 13);
bodyStyle.addAttribute(StyleConstants.FontFamily, "monospaced");
bodyStyle.addAttribute(StyleConstants.Bold, true);
doc.setLogicalStyle(0, bodyStyle);
return codeArea;
}
private JComponent getMemoryPanel(){
// JPanel memoryPanel = new JPanel();
// memoryPanel.setLayout(new BorderLayout());
//
// final Map<String, Component> memoryComponents = getMemoryComponents();
//
// final Object[] objects = memoryComponents.keySet().toArray();
// final String[] memoryStrings = new String[objects.length];
// for (int i=0; i<objects.length; i++){
// memoryStrings[i] = (String)objects[i];
// }
// JComboBox petList = new JComboBox(memoryStrings);
//
// memoryPanel.add(petList, BorderLayout.NORTH);
// memoryPanel.add(memoryComponents.get("1"));
//
// return memoryPanel;
JTabbedPane memoryTabs = new JTabbedPane();
final Map<String, Component> memoryComponentBlocks = getMemoryComponents();
for (String memoryKey : memoryComponentBlocks.keySet()) {
memoryTabs.addTab(memoryKey, memoryComponentBlocks.get(memoryKey));
}
return memoryTabs;
}
private Map<String, Component> getMemoryComponents(){
final Map<String, Component> memoryBlocks = new LinkedHashMap<>();
final String[] blocks2 = new String[260];
for (int i=0; i<260; i++){
int start = i * 256;
blocks2[i] = ""+ i;//(i + " (" + start + "-" + (start + 255) + ")");
}
for (int i=0; i<7; i++)
// for (int i=0; i<blocks2.length; i++)
memoryBlocks.put(blocks2[i], getMemoryComponent(i * 256));
return memoryBlocks;
}
private Component getMemoryComponent(int fromMemoryAddress){
final MemoryPanel memoryPanel = new MemoryPanel();
final JScrollPane scrollPane = new JScrollPane();
memoryPanel.setMemory(memory, fromMemoryAddress);
memoryPanel.linkTo(processor.getRegisters());
scrollPane.setViewportView(memoryPanel);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
return scrollPane;
}
private JComponent getInstructionScroller(){
final JList<String> instructionList = new JList<>(listModel);
final JScrollPane scrollPane = new JScrollPane(instructionList);
scrollPane.setPreferredSize(new Dimension(300, 200));
return scrollPane;
}
private JPanel getControlPanel() {
JButton stepButton = new JButton("Step >>");
stepButton.addActionListener(e -> step());
JButton resetButton = new JButton("Reset!");
resetButton.addActionListener(e -> loadProgram(getProgramFromFile()));
JPanel controls = new JPanel();
controls.setLayout(new FlowLayout());
controls.add(resetButton);
controls.add(stepButton);
return controls;
}
private RoxByte[] getProgramFromFile() {
final File file = new File( "src" + File.separator + "main" + File.separator + "resources" + File.separator + "rom" + File.separator + "SMB1.NES");
System.out.println("Loading '" + file.getAbsolutePath() + "'...");
final FileInputStream fis;
byte fileContent[] = {};
try {
fis = new FileInputStream(file);
fileContent= new byte[(int)file.length()];
fis.read(fileContent);
} catch (IOException e ) {
e.printStackTrace();
}
final InesRom rom = InesRom.from(fileContent);
Memory prgRom = rom.getProgramRom();
return prgRom.getBlock(RoxWord.ZERO, RoxWord.fromLiteral(prgRom.getSize()-1));
}
private RoxByte[] getProgram(){
int data_offset = 0x32;
int MPD = data_offset + 0x10;
int MPR = data_offset + 0x11;
int TMP = data_offset + 0x20;
int RESAD_0 = data_offset + 0x30;
int RESAD_1 = data_offset + 0x31;
int valMPD = 7;
int valMPR = 4;
// Program countToTenProgram = new Program().with( OpCode.LDX_I, 10,
// OpCode.LDA_I, 0,
// OpCode.CLC,
// OpCode.ADC_I, 0x01,
// OpCode.DEX,
// OpCode.CPX_I, 0,
// OpCode.BNE, 0b11110111);
Program multiplicationProgram = new Program().with( Mos6502OpCode.LDA_I, valMPD,
Mos6502OpCode.STA_Z, MPD,
Mos6502OpCode.LDA_I, valMPR,
Mos6502OpCode.STA_Z, MPR,
Mos6502OpCode.LDA_I, 0, //<---- start
Mos6502OpCode.STA_Z, TMP, //Clear
Mos6502OpCode.STA_Z, RESAD_0, //...
Mos6502OpCode.STA_Z, RESAD_1, //...
Mos6502OpCode.LDX_I, 8, //X counts each bit
//:MULT(18)
Mos6502OpCode.LSR_Z, MPR, //LSR(MPR)
Mos6502OpCode.BCC, 13, //Test carry and jump (forward 13) to NOADD
Mos6502OpCode.LDA_Z, RESAD_0, //RESAD -> A
Mos6502OpCode.CLC, //Prepare to add
Mos6502OpCode.ADC_Z, MPD, //+MPD
Mos6502OpCode.STA_Z, RESAD_0, //Save result
Mos6502OpCode.LDA_Z, RESAD_1, //RESAD+1 -> A
Mos6502OpCode.ADC_Z, TMP, //+TMP
Mos6502OpCode.STA_Z, RESAD_1, //RESAD+1 <- A
//:NOADD(35)
Mos6502OpCode.ASL_Z, MPD, //ASL(MPD)
Mos6502OpCode.ROL_Z, TMP, //Save bit from MPD
Mos6502OpCode.DEX, //--X
Mos6502OpCode.BNE, 0b11100111 //Test equal and jump (back 24) to MULT
);
return multiplicationProgram.getProgramAsByteArray();
}
private void init(){
registers = new Registers();
memory = new SimpleMemory();
processor = new Mos6502(memory, registers);
newRegisterPanel = new Registers6502(registers);
}
public void loadProgram(RoxByte[] program){
reset();
memory.setBlock(RoxWord.ZERO, program);
}
public void reset(){
processor.reset();
memory.reset();
listModel.clear();
invalidate();
revalidate();
repaint();
}
public void step(){
upDateWithNextInstruction();
processor.step();
invalidate();
repaint();
}
public void compile(String programText){
final Mos6502Compiler compiler = new Mos6502Compiler(programText);
try {
final Program program = compiler.compileProgram();
final RoxByte[] programAsByteArray = program.getProgramAsByteArray();
loadProgram(programAsByteArray);
}catch (UnknownOpCodeException e){
JOptionPane.showMessageDialog(this, e.getMessage());
}
}
private void upDateWithNextInstruction() {
final Registers registers = processor.getRegisters();
final RoxWord pointer = registers.getPC();
final RoxByte instr = memory.getByte(pointer);
StringBuilder arguments = new StringBuilder();
for (int i=0; i<getArgumentCount(instr.getRawValue()); i++ ){
RoxWord n = RoxWord.fromLiteral(pointer.getRawValue() + (i+1));
arguments.append(" " + MemoryPanel.asHex(memory.getByte(n).getRawValue()));
}
instructionName = Mos6502OpCode.from(instr.getRawValue()).toString();
final String instructionLocation = MemoryPanel.asHex(pointer.getRawValue());
final String instructionCode = MemoryPanel.asHex(instr.getRawValue());
final String completeInstructionInfo = "[" + instructionLocation + "] (" + instructionCode + arguments.toString() + ") :" + instructionName;
instruction.setText(completeInstructionInfo);
listModel.add(0, completeInstructionInfo);
}
private int getArgumentCount(int instr) {
final Mos6502OpCode opCode = Mos6502OpCode.from(instr);
final Mos6502AddressingMode addressingMode = opCode.getAddressingMode();
return addressingMode.getInstructionBytes() - 1;
}
public static void main(String[] args){
new DebuggerWindow();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(1200, 500);
}
}