Initial Commit
commit
a0ff1cf91a
|
|
@ -0,0 +1,125 @@
|
||||||
|
!SESSION 2020-12-23 07:02:50.204 -----------------------------------------------
|
||||||
|
eclipse.buildId=4.13.0.I20190916-1045
|
||||||
|
java.version=1.8.0_91
|
||||||
|
java.vendor=Oracle Corporation
|
||||||
|
BootLoader constants: OS=win32, ARCH=x86_64, WS=win32, NL=en_GB
|
||||||
|
Framework arguments: -product org.eclipse.epp.package.java.product
|
||||||
|
Command-line arguments: -os win32 -ws win32 -arch x86_64 -product org.eclipse.epp.package.java.product
|
||||||
|
|
||||||
|
!ENTRY org.eclipse.jface 2 0 2020-12-23 07:03:40.945
|
||||||
|
!MESSAGE Keybinding conflicts occurred. They may interfere with normal accelerator operation.
|
||||||
|
!SUBENTRY 1 org.eclipse.jface 2 0 2020-12-23 07:03:40.946
|
||||||
|
!MESSAGE A conflict occurred for ALT+T:
|
||||||
|
Binding(ALT+T,
|
||||||
|
ParameterizedCommand(Command(org.synthclipse.ide.command.TimelineShowView,Timeline / Show View,
|
||||||
|
,
|
||||||
|
Category(org.synthclipse.category,Synthclipse,null,true),
|
||||||
|
org.eclipse.ui.internal.WorkbenchHandlerServiceHandler@4b4228cf,
|
||||||
|
,,true),null),
|
||||||
|
org.eclipse.ui.defaultAcceleratorConfiguration,
|
||||||
|
org.eclipse.ui.contexts.window,,,system)
|
||||||
|
Binding(ALT+T,
|
||||||
|
ParameterizedCommand(Command(org.synthclipse.ide.command.GraphShowView,Graph / Show View,
|
||||||
|
,
|
||||||
|
Category(org.synthclipse.category,Synthclipse,null,true),
|
||||||
|
org.eclipse.ui.internal.WorkbenchHandlerServiceHandler@7d216ee8,
|
||||||
|
,,true),null),
|
||||||
|
org.eclipse.ui.defaultAcceleratorConfiguration,
|
||||||
|
org.eclipse.ui.contexts.window,,,system)
|
||||||
|
|
||||||
|
!ENTRY org.eclipse.equinox.p2.metadata.repository 4 1000 2020-12-23 07:39:51.272
|
||||||
|
!MESSAGE No repository found at jar:file:/E:/pdf/jd-eclipse-2.0.0.zip!/.
|
||||||
|
|
||||||
|
!ENTRY org.synthclipse.ide 4 0 2020-12-23 18:07:12.040
|
||||||
|
!MESSAGE java.lang.UnsatisfiedLinkError: no JSyphon in java.library.path
|
||||||
|
!STACK 0
|
||||||
|
java.lang.UnsatisfiedLinkError: no JSyphon in java.library.path
|
||||||
|
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
|
||||||
|
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
|
||||||
|
at java.lang.System.loadLibrary(System.java:1122)
|
||||||
|
at jsyphon.JSyphonServer.<clinit>(JSyphonServer.java:40)
|
||||||
|
at org.synthclipse.ide.controllers.SharingController.<init>(SharingController.java:54)
|
||||||
|
at org.synthclipse.ide.controllers.SynthclipseController.<init>(SynthclipseController.java:125)
|
||||||
|
at org.synthclipse.ide.controllers.SynthclipseController.<init>(SynthclipseController.java:153)
|
||||||
|
at org.synthclipse.ide.controllers.SynthclipseController$SingletonHolder.<clinit>(SynthclipseController.java:157)
|
||||||
|
at org.synthclipse.ide.controllers.SynthclipseController.getInstance(SynthclipseController.java:161)
|
||||||
|
at org.synthclipse.ide.Activator.start(Activator.java:87)
|
||||||
|
at org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:842)
|
||||||
|
at org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:1)
|
||||||
|
at java.security.AccessController.doPrivileged(Native Method)
|
||||||
|
at org.eclipse.osgi.internal.framework.BundleContextImpl.startActivator(BundleContextImpl.java:834)
|
||||||
|
at org.eclipse.osgi.internal.framework.BundleContextImpl.start(BundleContextImpl.java:791)
|
||||||
|
at org.eclipse.osgi.internal.framework.EquinoxBundle.startWorker0(EquinoxBundle.java:1015)
|
||||||
|
at org.eclipse.osgi.internal.framework.EquinoxBundle$EquinoxModule.startWorker(EquinoxBundle.java:365)
|
||||||
|
at org.eclipse.osgi.container.Module.doStart(Module.java:603)
|
||||||
|
at org.eclipse.osgi.container.Module.start(Module.java:467)
|
||||||
|
at org.eclipse.osgi.framework.util.SecureAction$23.run(SecureAction.java:500)
|
||||||
|
at org.eclipse.osgi.framework.util.SecureAction$23.run(SecureAction.java:1)
|
||||||
|
at java.security.AccessController.doPrivileged(Native Method)
|
||||||
|
at org.eclipse.osgi.framework.util.SecureAction.start(SecureAction.java:497)
|
||||||
|
at org.eclipse.osgi.internal.hooks.EclipseLazyStarter.postFindLocalClass(EclipseLazyStarter.java:117)
|
||||||
|
at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findLocalClass(ClasspathManager.java:571)
|
||||||
|
at org.eclipse.osgi.internal.loader.ModuleClassLoader.findLocalClass(ModuleClassLoader.java:330)
|
||||||
|
at org.eclipse.osgi.internal.loader.BundleLoader.findLocalClass(BundleLoader.java:398)
|
||||||
|
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:476)
|
||||||
|
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:425)
|
||||||
|
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:417)
|
||||||
|
at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:155)
|
||||||
|
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
|
||||||
|
at org.eclipse.osgi.internal.framework.EquinoxBundle.loadClass(EquinoxBundle.java:620)
|
||||||
|
at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.createExecutableExtension(RegistryStrategyOSGI.java:196)
|
||||||
|
at org.eclipse.core.internal.registry.ExtensionRegistry.createExecutableExtension(ExtensionRegistry.java:934)
|
||||||
|
at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:246)
|
||||||
|
at org.eclipse.core.internal.registry.ConfigurationElementHandle.createExecutableExtension(ConfigurationElementHandle.java:63)
|
||||||
|
at org.eclipse.ui.internal.handlers.HandlerProxy.loadHandler(HandlerProxy.java:342)
|
||||||
|
at org.eclipse.ui.internal.handlers.HandlerProxy.execute(HandlerProxy.java:277)
|
||||||
|
at org.eclipse.ui.internal.handlers.E4HandlerProxy.execute(E4HandlerProxy.java:95)
|
||||||
|
at sun.reflect.GeneratedMethodAccessor54.invoke(Unknown Source)
|
||||||
|
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||||
|
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||||
|
at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:58)
|
||||||
|
at org.eclipse.e4.core.internal.di.InjectorImpl.invokeUsingClass(InjectorImpl.java:318)
|
||||||
|
at org.eclipse.e4.core.internal.di.InjectorImpl.invoke(InjectorImpl.java:252)
|
||||||
|
at org.eclipse.e4.core.contexts.ContextInjectionFactory.invoke(ContextInjectionFactory.java:173)
|
||||||
|
at org.eclipse.e4.core.commands.internal.HandlerServiceHandler.execute(HandlerServiceHandler.java:156)
|
||||||
|
at org.eclipse.core.commands.Command.executeWithChecks(Command.java:498)
|
||||||
|
at org.eclipse.core.commands.ParameterizedCommand.executeWithChecks(ParameterizedCommand.java:487)
|
||||||
|
at org.eclipse.e4.core.commands.internal.HandlerServiceImpl.executeHandler(HandlerServiceImpl.java:213)
|
||||||
|
at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.executeCommand(KeyBindingDispatcher.java:308)
|
||||||
|
at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.press(KeyBindingDispatcher.java:584)
|
||||||
|
at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.processKeyEvent(KeyBindingDispatcher.java:653)
|
||||||
|
at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.filterKeySequenceBindings(KeyBindingDispatcher.java:443)
|
||||||
|
at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher.access$2(KeyBindingDispatcher.java:386)
|
||||||
|
at org.eclipse.e4.ui.bindings.keys.KeyBindingDispatcher$KeyDownFilter.handleEvent(KeyBindingDispatcher.java:96)
|
||||||
|
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:89)
|
||||||
|
at org.eclipse.swt.widgets.Display.filterEvent(Display.java:1199)
|
||||||
|
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1056)
|
||||||
|
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1081)
|
||||||
|
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1066)
|
||||||
|
at org.eclipse.swt.widgets.Control.traverse(Control.java:4270)
|
||||||
|
at org.eclipse.swt.widgets.Control.translateTraversal(Control.java:4252)
|
||||||
|
at org.eclipse.swt.widgets.Composite.translateTraversal(Composite.java:1299)
|
||||||
|
at org.eclipse.swt.widgets.Display.translateTraversal(Display.java:4729)
|
||||||
|
at org.eclipse.swt.widgets.Display.filterMessage(Display.java:1217)
|
||||||
|
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3581)
|
||||||
|
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1160)
|
||||||
|
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:338)
|
||||||
|
at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1049)
|
||||||
|
at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:155)
|
||||||
|
at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:633)
|
||||||
|
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:338)
|
||||||
|
at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:557)
|
||||||
|
at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:150)
|
||||||
|
at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:150)
|
||||||
|
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:203)
|
||||||
|
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:137)
|
||||||
|
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:107)
|
||||||
|
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:400)
|
||||||
|
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:255)
|
||||||
|
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||||
|
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||||
|
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||||
|
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||||
|
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:660)
|
||||||
|
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:597)
|
||||||
|
at org.eclipse.equinox.launcher.Main.run(Main.java:1468)
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1 @@
|
||||||
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21:
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31:
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF:
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Registers {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
case 0x31:
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
public CPU() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clock() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package playingcoffee.core.cpu;
|
||||||
|
|
||||||
|
public class MicroOps {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
public class MMU {
|
||||||
|
|
||||||
|
private int ram[];
|
||||||
|
|
||||||
|
public void loadBootRom() {
|
||||||
|
byte[] data;
|
||||||
|
try {
|
||||||
|
data = Files.readAllBytes(Paths.get("DMG_ROM.bin"));
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
ram[i] = Byte.toUnsignedInt(data[i]);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MMU() {
|
||||||
|
ram = new int[0x10000];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(int value, int address) {
|
||||||
|
ram[address] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read(int address) {
|
||||||
|
return ram[address];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// Is subject to change.
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
new JOptionPane(String.format("Unknown opcode: 0x%2x", opcode), JOptionPane.OK_OPTION).show();;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
package playingcoffee.ui;
|
||||||
|
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.GroupLayout;
|
||||||
|
import javax.swing.GroupLayout.Alignment;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.LayoutStyle.ComponentPlacement;
|
||||||
|
|
||||||
|
import playingcoffee.core.CPU;
|
||||||
|
import playingcoffee.core.MMU;
|
||||||
|
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.UnsupportedLookAndFeelException;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
|
||||||
|
public class CPUDebugger {
|
||||||
|
|
||||||
|
private JFrame frame;
|
||||||
|
private JTable memoryViewTable;
|
||||||
|
|
||||||
|
private CPU cpu;
|
||||||
|
private MMU mmu;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
EventQueue.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
CPUDebugger window = new CPUDebugger();
|
||||||
|
window.frame.setVisible(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public CPUDebugger() {
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
cpu = new CPU();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
try {
|
||||||
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||||
|
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
|
||||||
|
| UnsupportedLookAndFeelException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = new JFrame();
|
||||||
|
frame.setBounds(100, 100, 750, 500);
|
||||||
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
|
||||||
|
JButton btnStep = new JButton("Step");
|
||||||
|
|
||||||
|
JButton btnReset = new JButton("Reset");
|
||||||
|
|
||||||
|
JLabel lblRegisters = new JLabel("Registers:");
|
||||||
|
|
||||||
|
JList<String> registerList = new JList<String>();
|
||||||
|
|
||||||
|
memoryViewTable = new JTable();
|
||||||
|
|
||||||
|
JLabel lblMemoryView = new JLabel("Memory View:");
|
||||||
|
GroupLayout groupLayout = new GroupLayout(frame.getContentPane());
|
||||||
|
groupLayout.setHorizontalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addComponent(btnStep)
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addComponent(btnReset))
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addGap(18))
|
||||||
|
.addComponent(registerList, GroupLayout.PREFERRED_SIZE, 122, GroupLayout.PREFERRED_SIZE))
|
||||||
|
.addGap(18)
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addComponent(lblMemoryView)
|
||||||
|
.addComponent(memoryViewTable, GroupLayout.DEFAULT_SIZE, 574, Short.MAX_VALUE))
|
||||||
|
.addContainerGap())
|
||||||
|
);
|
||||||
|
groupLayout.setVerticalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.TRAILING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addComponent(lblMemoryView))
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addGap(8)
|
||||||
|
.addComponent(memoryViewTable, GroupLayout.DEFAULT_SIZE, 382, Short.MAX_VALUE))
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addComponent(registerList, GroupLayout.PREFERRED_SIZE, 195, GroupLayout.PREFERRED_SIZE)))
|
||||||
|
.addGap(18)
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
|
||||||
|
.addComponent(btnStep)
|
||||||
|
.addComponent(btnReset))
|
||||||
|
.addGap(5))
|
||||||
|
);
|
||||||
|
frame.getContentPane().setLayout(groupLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
private int cycles = 0;
|
||||||
|
|
||||||
|
public static final int[] INSTRUCTION_CYCLE_COUNT = {
|
||||||
|
4, 12, 8, 8, 4, 4, 8, 4, 20, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
4, 12, 8, 8, 4, 4, 8, 4, 12, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
8, 12, 8, 8, 12, 12, 12, 4, 8, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
8, 12, 8, 8, 12, 12, 12, 4, 8, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
8, 12, 12, 16, 12, 16, 8, 16, 8, 16, 12, 4, 12, 24, 8, 16,
|
||||||
|
8, 12, 12, -1, 12, 16, 8, 16, 8, 16, 12, -1, 12, -1, 8, 16,
|
||||||
|
12, 12, 8, -1, -1, 16, 8, 16, 16, 4, 16, -1, -1, -1, 8, 16,
|
||||||
|
12, 12, 8, 4, -1, 16, 8, 16, 12, 8, 16, 4, -1, -1, 8, 16
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final int[] PREFIXED_CYCLE_COUNT = {
|
||||||
|
8, 8, 8, 8, 8, 8, 16, 8, 8, 8, 8, 8, 8, 8, 16, 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
if (cycles == 0) {
|
||||||
|
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
decodeOpcode(opcode);
|
||||||
|
}
|
||||||
|
cycles--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeOpcode(int opcode) {
|
||||||
|
// Apply cycle count
|
||||||
|
cycles += INSTRUCTION_CYCLE_COUNT[opcode];
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
registers.writeHL(registers.readHL() - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
registers.setFlag(Registers.FLAG_Z, registers.readA() == 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xCB: // CB - prefix
|
||||||
|
decodePrefixedOpcode(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0x%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodePrefixedOpcode(int opcode) {
|
||||||
|
cycles += INSTRUCTION_CYCLE_COUNT[opcode & 0xF];
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x7C:
|
||||||
|
registers.setFlag(Registers.FLAG_Z, (registers.readH() & (1 << 7)) == 0);
|
||||||
|
registers.setFlag(Registers.FLAG_N, false);
|
||||||
|
registers.setFlag(Registers.FLAG_H, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0xcb%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final Memory memory;
|
||||||
|
|
||||||
|
public CPU() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clock() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Registers {
|
||||||
|
|
||||||
|
private int af;
|
||||||
|
private int bc;
|
||||||
|
private int de;
|
||||||
|
private int hl;
|
||||||
|
|
||||||
|
public int pc;
|
||||||
|
public int sp;
|
||||||
|
|
||||||
|
public int readAF() {
|
||||||
|
return af;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readBC() {
|
||||||
|
return bc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readDE() {
|
||||||
|
return de;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readHL() {
|
||||||
|
return hl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readA() {
|
||||||
|
return af & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeA(int a) {
|
||||||
|
this.af = a & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readF() {
|
||||||
|
return (af >> 8) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeF(int f) {
|
||||||
|
this.f = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readB() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeB(int b) {
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readC() {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeC(int c) {
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readD() {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeD(int d) {
|
||||||
|
this.d = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readE() {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeE(int e) {
|
||||||
|
this.e = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readH() {
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeH(int h) {
|
||||||
|
this.h = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readL() {
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeL(int l) {
|
||||||
|
this.l = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Memory {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Registers {
|
||||||
|
|
||||||
|
private int a, f;
|
||||||
|
private int b, c;
|
||||||
|
private int d, e;
|
||||||
|
private int h, l;
|
||||||
|
|
||||||
|
public int pc;
|
||||||
|
public int sp;
|
||||||
|
|
||||||
|
public static final int FLAG_Z = 1 << 7;
|
||||||
|
public static final int FLAG_N = 1 << 6;
|
||||||
|
public static final int FLAG_H = 1 << 5;
|
||||||
|
public static final int FLAG_C = 1 << 4;
|
||||||
|
|
||||||
|
public void setFlag(int flag, boolean value) {
|
||||||
|
if (value)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readAF() {
|
||||||
|
return a << 8 | f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readBC() {
|
||||||
|
return b << 8 | c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readDE() {
|
||||||
|
return d << 8 | e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readHL() {
|
||||||
|
return h << 8 | l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeAF(int af) {
|
||||||
|
a = (af >> 8) & 0xFF;
|
||||||
|
f = af & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeBC(int bc) {
|
||||||
|
b = (bc >> 8) & 0xFF;
|
||||||
|
c = bc & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeDE(int de) {
|
||||||
|
d = (de >> 8) & 0xFF;
|
||||||
|
e = de & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeHL(int hl) {
|
||||||
|
h = (hl >> 8) & 0xFF;
|
||||||
|
l = hl & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readA() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeA(int a) {
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readF() {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeF(int f) {
|
||||||
|
this.f = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readB() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeB(int b) {
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readC() {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeC(int c) {
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readD() {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeD(int d) {
|
||||||
|
this.d = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readE() {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeE(int e) {
|
||||||
|
this.e = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readH() {
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeH(int h) {
|
||||||
|
this.h = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readL() {
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeL(int l) {
|
||||||
|
this.l = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
decodeOpcode(opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
registers.writeHL(registers.readHL() - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
registers.setFlag(Registers.FLAG_Z, registers.readA() != 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xCB: // CB - prefix
|
||||||
|
decodePrefixedOpcode(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0x%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodePrefixedOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0xcb%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package playingcoffee.core.cpu;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import playingcoffee.core.cpu.microop.MicroOp;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
List<MicroOp> microOps;
|
||||||
|
|
||||||
|
public Opcode(MicroOp... ops) {
|
||||||
|
microOps = new ArrayList<MicroOp>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
private int cycles = 0;
|
||||||
|
|
||||||
|
public static int[] instructionCycle = {
|
||||||
|
4, 12, 8, 8, 4, 4, 8, 4, 20, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
4, 12, 8, 8, 4, 4, 8, 4, 12, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
8, 12, 8, 8, 12, 12, 12, 4, 8, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
8, 12, 8, 8, 12, 12, 12, 4, 8, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
8, 12, 12, 16, 12, 16, 8, 16, 8, 16, 12, 4, 12, 24, 8, 16,
|
||||||
|
8, 12, 12, -1, 12, 16, 8, 16, 8, 16, 12, -1, 12, -1, 8, 16,
|
||||||
|
12, 12, 8, -1, -1, 16, 8, 16, 16, 4, 16, -1, -1, -1, 8, 16,
|
||||||
|
12, 12, 8, 4, -1, 16, 8, 16, 12, 8, 16, 4, -1, -1, 8, 16
|
||||||
|
};
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
if (cycles == 0) {
|
||||||
|
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
decodeOpcode(opcode);
|
||||||
|
}
|
||||||
|
cycles--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeOpcode(int opcode) {
|
||||||
|
// Apply cycle count
|
||||||
|
cycles += instructionCycle[opcode];
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
registers.writeHL(registers.readHL() - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
registers.setFlag(Registers.FLAG_Z, registers.readA() == 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xCB: // CB - prefix
|
||||||
|
decodePrefixedOpcode(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0x%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodePrefixedOpcode(int opcode) {
|
||||||
|
cycles += instructionCycle[opcode];
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x7C:
|
||||||
|
registers.setFlag(Registers.FLAG_Z, (registers.readH() & (1 << 7)) == 0);
|
||||||
|
registers.setFlag(Registers.FLAG_N, false);
|
||||||
|
registers.setFlag(Registers.FLAG_H, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0xcb%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class MMU {
|
||||||
|
|
||||||
|
private int ram[];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void write(int value, int address) {
|
||||||
|
ram[address] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read(int address) {
|
||||||
|
return ram[address];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
package playingcoffee.ui;
|
||||||
|
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.GroupLayout;
|
||||||
|
import javax.swing.GroupLayout.Alignment;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.LayoutStyle.ComponentPlacement;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.UnsupportedLookAndFeelException;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
|
||||||
|
public class CPUDebugger {
|
||||||
|
|
||||||
|
private JFrame frame;
|
||||||
|
private JTable table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launch the application.
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) {
|
||||||
|
EventQueue.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
CPUDebugger window = new CPUDebugger();
|
||||||
|
window.frame.setVisible(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the application.
|
||||||
|
*/
|
||||||
|
public CPUDebugger() {
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the contents of the frame.
|
||||||
|
*/
|
||||||
|
private void initialize() {
|
||||||
|
try {
|
||||||
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||||
|
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
|
||||||
|
| UnsupportedLookAndFeelException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = new JFrame();
|
||||||
|
frame.setBounds(100, 100, 750, 500);
|
||||||
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
|
||||||
|
JButton btnStep = new JButton("Step");
|
||||||
|
|
||||||
|
JButton btnReset = new JButton("Reset");
|
||||||
|
|
||||||
|
JLabel lblRegisters = new JLabel("Registers:");
|
||||||
|
|
||||||
|
JList<String> list = new JList<String>();
|
||||||
|
|
||||||
|
table = new JTable();
|
||||||
|
|
||||||
|
JLabel lblMemoryView = new JLabel("Memory View:");
|
||||||
|
GroupLayout groupLayout = new GroupLayout(frame.getContentPane());
|
||||||
|
groupLayout.setHorizontalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING, false)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addComponent(btnStep)
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addComponent(btnReset))
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addGap(18))
|
||||||
|
.addComponent(list, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||||
|
.addGap(18)
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addComponent(table, GroupLayout.DEFAULT_SIZE, 574, Short.MAX_VALUE)
|
||||||
|
.addComponent(lblMemoryView))
|
||||||
|
.addContainerGap())
|
||||||
|
);
|
||||||
|
groupLayout.setVerticalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.TRAILING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addComponent(lblMemoryView))
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
|
||||||
|
.addComponent(list, GroupLayout.DEFAULT_SIZE, 396, Short.MAX_VALUE)
|
||||||
|
.addComponent(table, GroupLayout.DEFAULT_SIZE, 396, Short.MAX_VALUE))
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
|
||||||
|
.addComponent(btnStep)
|
||||||
|
.addComponent(btnReset))
|
||||||
|
.addGap(5))
|
||||||
|
);
|
||||||
|
frame.getContentPane().setLayout(groupLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
|
||||||
|
System.out.println(registers.readL());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
private int cycles = 0;
|
||||||
|
|
||||||
|
public static int[] instructionCycle = {
|
||||||
|
4, 12, 8, 8, 4, 4, 8, 4, 20, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
4, 12, 8, 8, 4, 4, 8, 4, 12, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
8, 12, 8, 8, 12, 12, 12, 4, 8, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
8, 12, 8, 8, 12, 12, 12, 4, 8, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
8, 12, 12, 16, 12, 16, 8, 16, 8, 16, 12, 4, 12, 24, 8, 16,
|
||||||
|
8, 12, 12, -1, 12, 16, 8, 16, 8, 16, 12, -1, 12, -1, 8, 16,
|
||||||
|
12, 12, 8, -1, -1, 16, 8, 16, 16, 4, 16, -1, -1, -1, 8, 16,
|
||||||
|
12, 12, 8, 4, -1, 16, 8, 16, 12, 8, 16, 4, -1, -1, 8, 16
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
if (cycles == 0) {
|
||||||
|
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
decodeOpcode(opcode);
|
||||||
|
}
|
||||||
|
cycles--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeOpcode(int opcode) {
|
||||||
|
// Apply cycle count
|
||||||
|
cycles += instructionCycle[opcode];
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
registers.writeHL(registers.readHL() - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
registers.setFlag(Registers.FLAG_Z, registers.readA() == 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xCB: // CB - prefix
|
||||||
|
decodePrefixedOpcode(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0x%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodePrefixedOpcode(int opcode) {
|
||||||
|
cycles += instructionCycle[opcode];
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x7C:
|
||||||
|
registers.setFlag(Registers.FLAG_Z, (registers.readH() & (1 << 7)) == 0);
|
||||||
|
registers.setFlag(Registers.FLAG_N, false);
|
||||||
|
registers.setFlag(Registers.FLAG_H, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0xcb%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package playingcoffee.core.cpu;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
public Opcode(MicroOp ops...) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package playingcoffee.core.cpu;
|
||||||
|
|
||||||
|
public abstract class MicroOp {
|
||||||
|
|
||||||
|
private int cycles;
|
||||||
|
|
||||||
|
public int getLength() {
|
||||||
|
return cycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void execute();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
private int cycles = 0;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
if (cycles == 0) {
|
||||||
|
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
decodeOpcode(opcode);
|
||||||
|
}
|
||||||
|
cycles--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
registers.writeHL(registers.readHL() - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
registers.setFlag(Registers.FLAG_Z, registers.readA() == 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xCB: // CB - prefix
|
||||||
|
decodePrefixedOpcode(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0x%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodePrefixedOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x7C:
|
||||||
|
registers.setFlag(Registers.FLAG_Z, (registers.readH() & (1 << 7)) == 0);
|
||||||
|
registers.setFlag(Registers.FLAG_N, false);
|
||||||
|
registers.setFlag(Registers.FLAG_H, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0xcb%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package playingcoffee.core.cpu;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Registers {
|
||||||
|
|
||||||
|
private int a, f;
|
||||||
|
private int b, c;
|
||||||
|
private int d, e;
|
||||||
|
private int h, l;
|
||||||
|
|
||||||
|
private int pc;
|
||||||
|
private int sp;
|
||||||
|
|
||||||
|
public int readA() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeA(int a) {
|
||||||
|
verify(a);
|
||||||
|
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readF() {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeF(int f) {
|
||||||
|
verify(a);
|
||||||
|
|
||||||
|
this.f = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readB() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeB(int b) {
|
||||||
|
verify(a);
|
||||||
|
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readC() {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeC(int c) {
|
||||||
|
verify(a);
|
||||||
|
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readD() {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeD(int d) {
|
||||||
|
verify(a);
|
||||||
|
|
||||||
|
this.d = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readE() {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeE(int e) {
|
||||||
|
verify(a);
|
||||||
|
|
||||||
|
this.e = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readH() {
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeH(int h) {
|
||||||
|
verify(a);
|
||||||
|
|
||||||
|
this.h = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readL() {
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeL(int l) {
|
||||||
|
verify(a);
|
||||||
|
|
||||||
|
this.l = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readPC() {
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writePC(int pc) {
|
||||||
|
verify(a);
|
||||||
|
|
||||||
|
this.pc = pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readSP() {
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeSP(int sp) {
|
||||||
|
verify(a);
|
||||||
|
|
||||||
|
this.sp = sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
registers.writeHL(registers.readHL() - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
package playingcoffee.ui;
|
||||||
|
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
import javax.swing.DefaultListModel;
|
||||||
|
import javax.swing.GroupLayout;
|
||||||
|
import javax.swing.GroupLayout.Alignment;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.LayoutStyle.ComponentPlacement;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.UnsupportedLookAndFeelException;
|
||||||
|
|
||||||
|
import playingcoffee.core.CPU;
|
||||||
|
import playingcoffee.core.MMU;
|
||||||
|
|
||||||
|
public class CPUDebugger {
|
||||||
|
|
||||||
|
private JFrame frmCpuDebugger;
|
||||||
|
private JList<String> registerList;
|
||||||
|
|
||||||
|
private MMU mmu;
|
||||||
|
private CPU cpu;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
EventQueue.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
CPUDebugger window = new CPUDebugger();
|
||||||
|
window.frmCpuDebugger.setVisible(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public CPUDebugger() {
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
mmu = new MMU();
|
||||||
|
cpu = new CPU(mmu);
|
||||||
|
|
||||||
|
updateValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateValues() {
|
||||||
|
DefaultListModel<String> model = new DefaultListModel<String>();
|
||||||
|
model.addElement("AF: 0x" + Integer.toHexString(cpu.getRegisters().readAF()));
|
||||||
|
model.addElement("BC: 0x" + Integer.toHexString(cpu.getRegisters().readBC()));
|
||||||
|
model.addElement("DE: 0x" + Integer.toHexString(cpu.getRegisters().readDE()));
|
||||||
|
model.addElement("HL: 0x" + Integer.toHexString(cpu.getRegisters().readHL()));
|
||||||
|
model.addElement("PC: 0x" + Integer.toHexString(cpu.getRegisters().readPC()));
|
||||||
|
model.addElement("SP: 0x" + Integer.toHexString(cpu.getRegisters().readSP()));
|
||||||
|
|
||||||
|
registerList.setModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
try {
|
||||||
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||||
|
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
|
||||||
|
| UnsupportedLookAndFeelException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
frmCpuDebugger = new JFrame();
|
||||||
|
frmCpuDebugger.setTitle("CPU Debugger");
|
||||||
|
frmCpuDebugger.setBounds(100, 100, 350, 350);
|
||||||
|
frmCpuDebugger.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
|
||||||
|
JButton btnStep = new JButton("Step");
|
||||||
|
btnStep.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
cpu.cycle();
|
||||||
|
updateValues();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
JButton btnReset = new JButton("Reset");
|
||||||
|
|
||||||
|
JLabel lblRegisters = new JLabel("Registers:");
|
||||||
|
|
||||||
|
registerList = new JList<String>();
|
||||||
|
GroupLayout groupLayout = new GroupLayout(frmCpuDebugger.getContentPane());
|
||||||
|
groupLayout.setHorizontalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addComponent(registerList, GroupLayout.DEFAULT_SIZE, 314, Short.MAX_VALUE)
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addGroup(Alignment.TRAILING, groupLayout.createSequentialGroup()
|
||||||
|
.addComponent(btnStep)
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED, 198, Short.MAX_VALUE)
|
||||||
|
.addComponent(btnReset)))
|
||||||
|
.addContainerGap())
|
||||||
|
);
|
||||||
|
groupLayout.setVerticalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.TRAILING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addComponent(registerList, GroupLayout.PREFERRED_SIZE, 195, GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addGap(51)
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
|
||||||
|
.addComponent(btnReset)
|
||||||
|
.addComponent(btnStep))
|
||||||
|
.addContainerGap())
|
||||||
|
);
|
||||||
|
frmCpuDebugger.getContentPane().setLayout(groupLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,120 @@
|
||||||
|
package playingcoffee.ui;
|
||||||
|
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
|
||||||
|
import javax.swing.DefaultListModel;
|
||||||
|
import javax.swing.GroupLayout;
|
||||||
|
import javax.swing.GroupLayout.Alignment;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.ListModel;
|
||||||
|
import javax.swing.LayoutStyle.ComponentPlacement;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.UnsupportedLookAndFeelException;
|
||||||
|
|
||||||
|
import playingcoffee.core.CPU;
|
||||||
|
import playingcoffee.core.MMU;
|
||||||
|
|
||||||
|
public class CPUDebugger {
|
||||||
|
|
||||||
|
private JFrame frame;
|
||||||
|
private JTable memoryViewTable;
|
||||||
|
private JList<String> registerList;
|
||||||
|
|
||||||
|
private MMU mmu;
|
||||||
|
private CPU cpu;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
EventQueue.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
CPUDebugger window = new CPUDebugger();
|
||||||
|
window.frame.setVisible(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public CPUDebugger() {
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
mmu = new MMU();
|
||||||
|
cpu = new CPU();
|
||||||
|
|
||||||
|
updateValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateValues() {
|
||||||
|
DefaultListModel<String> model = new DefaultListModel<String>();
|
||||||
|
model.
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
try {
|
||||||
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||||
|
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
|
||||||
|
| UnsupportedLookAndFeelException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = new JFrame();
|
||||||
|
frame.setBounds(100, 100, 750, 500);
|
||||||
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
|
||||||
|
JButton btnStep = new JButton("Step");
|
||||||
|
|
||||||
|
JButton btnReset = new JButton("Reset");
|
||||||
|
|
||||||
|
JLabel lblRegisters = new JLabel("Registers:");
|
||||||
|
|
||||||
|
registerList = new JList<String>();
|
||||||
|
|
||||||
|
memoryViewTable = new JTable();
|
||||||
|
|
||||||
|
JLabel lblMemoryView = new JLabel("Memory View:");
|
||||||
|
GroupLayout groupLayout = new GroupLayout(frame.getContentPane());
|
||||||
|
groupLayout.setHorizontalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addComponent(btnStep)
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addComponent(btnReset))
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addComponent(registerList, GroupLayout.PREFERRED_SIZE, 122, GroupLayout.PREFERRED_SIZE))
|
||||||
|
.addGap(18)
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addComponent(lblMemoryView)
|
||||||
|
.addComponent(memoryViewTable, GroupLayout.DEFAULT_SIZE, 574, Short.MAX_VALUE))
|
||||||
|
.addContainerGap())
|
||||||
|
);
|
||||||
|
groupLayout.setVerticalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.TRAILING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addComponent(lblMemoryView))
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addGap(8)
|
||||||
|
.addComponent(memoryViewTable, GroupLayout.DEFAULT_SIZE, 382, Short.MAX_VALUE))
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addComponent(registerList, GroupLayout.PREFERRED_SIZE, 195, GroupLayout.PREFERRED_SIZE)))
|
||||||
|
.addGap(18)
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
|
||||||
|
.addComponent(btnStep)
|
||||||
|
.addComponent(btnReset))
|
||||||
|
.addGap(5))
|
||||||
|
);
|
||||||
|
frame.getContentPane().setLayout(groupLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Registers {
|
||||||
|
|
||||||
|
private int a, f;
|
||||||
|
private int b, c;
|
||||||
|
private int d, e;
|
||||||
|
private int h, l;
|
||||||
|
|
||||||
|
private int pc;
|
||||||
|
private int sp;
|
||||||
|
|
||||||
|
public int readA() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeA(int a) {
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readF() {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeF(int f) {
|
||||||
|
this.f = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readB() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeB(int b) {
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readC() {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeC(int c) {
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readD() {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeD(int d) {
|
||||||
|
this.d = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readE() {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeE(int e) {
|
||||||
|
this.e = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readH() {
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeH(int h) {
|
||||||
|
this.h = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readL() {
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeL(int l) {
|
||||||
|
this.l = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readPC() {
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writePC(int pc) {
|
||||||
|
this.pc = pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readSP() {
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeSP(int sp) {
|
||||||
|
this.sp = sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Gameboy {
|
||||||
|
|
||||||
|
private CPU m_CPU;
|
||||||
|
|
||||||
|
public Gameboy() {
|
||||||
|
m_CPU = new CPU();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
private int cycles = 0;
|
||||||
|
|
||||||
|
public static int[] instructionCycle = {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
if (cycles == 0) {
|
||||||
|
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
decodeOpcode(opcode);
|
||||||
|
}
|
||||||
|
cycles--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeOpcode(int opcode) {
|
||||||
|
// Apply cycle count
|
||||||
|
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
registers.writeHL(registers.readHL() - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
registers.setFlag(Registers.FLAG_Z, registers.readA() == 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xCB: // CB - prefix
|
||||||
|
decodePrefixedOpcode(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0x%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodePrefixedOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x7C:
|
||||||
|
registers.setFlag(Registers.FLAG_Z, (registers.readH() & (1 << 7)) == 0);
|
||||||
|
registers.setFlag(Registers.FLAG_N, false);
|
||||||
|
registers.setFlag(Registers.FLAG_H, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0xcb%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Registers {
|
||||||
|
|
||||||
|
private int a, f;
|
||||||
|
private int b, c;
|
||||||
|
private int d, e;
|
||||||
|
private int h, l;
|
||||||
|
|
||||||
|
private int pc;
|
||||||
|
private int sp;
|
||||||
|
|
||||||
|
public int readA() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeA(int a) {
|
||||||
|
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readF() {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeF(int f) {
|
||||||
|
this.f = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readB() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeB(int b) {
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readC() {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeC(int c) {
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readD() {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeD(int d) {
|
||||||
|
this.d = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readE() {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeE(int e) {
|
||||||
|
this.e = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readH() {
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeH(int h) {
|
||||||
|
this.h = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readL() {
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeL(int l) {
|
||||||
|
this.l = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readPC() {
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writePC(int pc) {
|
||||||
|
this.pc = pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readSP() {
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeSP(int sp) {
|
||||||
|
this.sp = sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package playingcoffee.core.cpu;
|
||||||
|
|
||||||
|
import playingcoffee.core.cpu.microop.MicroOp;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
MicroOp microOps[];
|
||||||
|
|
||||||
|
public Opcode(MicroOp... ops) {
|
||||||
|
microOps = ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute() {
|
||||||
|
for(MicroOp op : microOps)
|
||||||
|
op.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.readPC());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
private Op[] ops;
|
||||||
|
|
||||||
|
public Opcode(Op... ops) {
|
||||||
|
this.ops = ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(Registers regs, MMU mmu) {
|
||||||
|
for (Op op : ops)
|
||||||
|
op.execute(regs, mmu);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Op {
|
||||||
|
|
||||||
|
public void execute(Registers regs, MMU mmu);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Read16BitOperand implements Op {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package playingcoffee.core.cpu;
|
||||||
|
|
||||||
|
import playingcoffee.core.Memory;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final Memory memory;
|
||||||
|
|
||||||
|
public CPU(Memory memory) {
|
||||||
|
this.memory = memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerOpcodes() {
|
||||||
|
// Example: instructions[0x01] = new OpcodeBuilder().read(OpcodeArgument.C, OpcodeArgument.PC_INC).read(OpcodeArgument.B, OpcodeArgument.PC_INC);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clock() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
private Op[] ops;
|
||||||
|
|
||||||
|
public Opcode(Op... ops) {
|
||||||
|
this.ops = ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute() {
|
||||||
|
for (Op op : ops)
|
||||||
|
op.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Op {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package playingcoffee.core.cpu;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import playingcoffee.core.cpu.microop.MicroOp;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
List<MicroOp> microOps;
|
||||||
|
|
||||||
|
public Opcode(MicroOp... ops) {
|
||||||
|
microOps = new ArrayList<MicroOp>();
|
||||||
|
microOps.add(ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
package playingcoffee.ui;
|
||||||
|
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
|
||||||
|
import javax.swing.DefaultListModel;
|
||||||
|
import javax.swing.GroupLayout;
|
||||||
|
import javax.swing.GroupLayout.Alignment;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.LayoutStyle.ComponentPlacement;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.UnsupportedLookAndFeelException;
|
||||||
|
|
||||||
|
import playingcoffee.core.CPU;
|
||||||
|
import playingcoffee.core.MMU;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
|
||||||
|
public class CPUDebugger {
|
||||||
|
|
||||||
|
private JFrame frmCpuDebugger;
|
||||||
|
private JList<String> registerList;
|
||||||
|
|
||||||
|
private MMU mmu;
|
||||||
|
private CPU cpu;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
EventQueue.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
CPUDebugger window = new CPUDebugger();
|
||||||
|
window.frmCpuDebugger.setVisible(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public CPUDebugger() {
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
mmu = new MMU();
|
||||||
|
cpu = new CPU(mmu);
|
||||||
|
|
||||||
|
updateValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateValues() {
|
||||||
|
DefaultListModel<String> model = new DefaultListModel<String>();
|
||||||
|
model.addElement("AF: 0x" + Integer.toHexString(cpu.getRegisters().readAF()));
|
||||||
|
model.addElement("BC: 0x" + Integer.toHexString(cpu.getRegisters().readBC()));
|
||||||
|
model.addElement("DE: 0x" + Integer.toHexString(cpu.getRegisters().readDE()));
|
||||||
|
model.addElement("HL: 0x" + Integer.toHexString(cpu.getRegisters().readHL()));
|
||||||
|
model.addElement("PC: 0x" + Integer.toHexString(cpu.getRegisters().readPC()));
|
||||||
|
model.addElement("SP: 0x" + Integer.toHexString(cpu.getRegisters().readSP()));
|
||||||
|
|
||||||
|
registerList.setModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
try {
|
||||||
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||||
|
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
|
||||||
|
| UnsupportedLookAndFeelException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
frmCpuDebugger = new JFrame();
|
||||||
|
frmCpuDebugger.setTitle("CPU Debugger");
|
||||||
|
frmCpuDebugger.setBounds(100, 100, 350, 350);
|
||||||
|
frmCpuDebugger.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
|
||||||
|
JButton btnStep = new JButton("Step");
|
||||||
|
btnStep.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
JButton btnReset = new JButton("Reset");
|
||||||
|
|
||||||
|
JLabel lblRegisters = new JLabel("Registers:");
|
||||||
|
|
||||||
|
registerList = new JList<String>();
|
||||||
|
GroupLayout groupLayout = new GroupLayout(frmCpuDebugger.getContentPane());
|
||||||
|
groupLayout.setHorizontalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addComponent(registerList, GroupLayout.DEFAULT_SIZE, 314, Short.MAX_VALUE)
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addGroup(Alignment.TRAILING, groupLayout.createSequentialGroup()
|
||||||
|
.addComponent(btnStep)
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED, 198, Short.MAX_VALUE)
|
||||||
|
.addComponent(btnReset)))
|
||||||
|
.addContainerGap())
|
||||||
|
);
|
||||||
|
groupLayout.setVerticalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.TRAILING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addComponent(registerList, GroupLayout.PREFERRED_SIZE, 195, GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addGap(51)
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
|
||||||
|
.addComponent(btnReset)
|
||||||
|
.addComponent(btnStep))
|
||||||
|
.addContainerGap())
|
||||||
|
);
|
||||||
|
frmCpuDebugger.getContentPane().setLayout(groupLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
package playingcoffee.ui;
|
||||||
|
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.GroupLayout;
|
||||||
|
import javax.swing.GroupLayout.Alignment;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.LayoutStyle.ComponentPlacement;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.UnsupportedLookAndFeelException;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
|
||||||
|
public class CPUDebugger {
|
||||||
|
|
||||||
|
private JFrame frame;
|
||||||
|
private JTable table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launch the application.
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) {
|
||||||
|
EventQueue.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
CPUDebugger window = new CPUDebugger();
|
||||||
|
window.frame.setVisible(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public CPUDebugger() {
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
try {
|
||||||
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||||
|
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
|
||||||
|
| UnsupportedLookAndFeelException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = new JFrame();
|
||||||
|
frame.setBounds(100, 100, 750, 500);
|
||||||
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
|
||||||
|
JButton btnStep = new JButton("Step");
|
||||||
|
|
||||||
|
JButton btnReset = new JButton("Reset");
|
||||||
|
|
||||||
|
JLabel lblRegisters = new JLabel("Registers:");
|
||||||
|
|
||||||
|
JList<String> list = new JList<String>();
|
||||||
|
|
||||||
|
table = new JTable();
|
||||||
|
|
||||||
|
JLabel lblMemoryView = new JLabel("Memory View:");
|
||||||
|
GroupLayout groupLayout = new GroupLayout(frame.getContentPane());
|
||||||
|
groupLayout.setHorizontalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addComponent(btnStep)
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addComponent(btnReset))
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addGap(18))
|
||||||
|
.addComponent(list, GroupLayout.PREFERRED_SIZE, 122, GroupLayout.PREFERRED_SIZE))
|
||||||
|
.addGap(18)
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addComponent(lblMemoryView)
|
||||||
|
.addComponent(table, GroupLayout.DEFAULT_SIZE, 574, Short.MAX_VALUE))
|
||||||
|
.addContainerGap())
|
||||||
|
);
|
||||||
|
groupLayout.setVerticalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.TRAILING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addComponent(lblMemoryView))
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addGap(8)
|
||||||
|
.addComponent(table, GroupLayout.DEFAULT_SIZE, 382, Short.MAX_VALUE))
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addComponent(list, GroupLayout.PREFERRED_SIZE, 195, GroupLayout.PREFERRED_SIZE)))
|
||||||
|
.addGap(18)
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
|
||||||
|
.addComponent(btnStep)
|
||||||
|
.addComponent(btnReset))
|
||||||
|
.addGap(5))
|
||||||
|
);
|
||||||
|
frame.getContentPane().setLayout(groupLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// Is subject to change.
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
JOptionPane.showMessageDialog(null, String.format("Unknown opcode: 0x%2x", opcode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
decodeOpcode(opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
registers.writeHL(registers.readHL() - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
registers.setFlag(Registers.FLAG_Z, registers.readA() == 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xCB: // CB - prefix
|
||||||
|
decodePrefixedOpcode(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0x%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodePrefixedOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0xcb%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Registers {
|
||||||
|
|
||||||
|
private int a, f;
|
||||||
|
private int b, c;
|
||||||
|
private int d, e;
|
||||||
|
private int h, l;
|
||||||
|
|
||||||
|
public int pc;
|
||||||
|
public int sp;
|
||||||
|
|
||||||
|
public static final int FLAG_Z = 1 << 7;
|
||||||
|
|
||||||
|
public void setFlag(int flag, boolean value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readAF() {
|
||||||
|
return a << 8 | f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readBC() {
|
||||||
|
return b << 8 | c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readDE() {
|
||||||
|
return d << 8 | e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readHL() {
|
||||||
|
return h << 8 | l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeAF(int af) {
|
||||||
|
a = (af >> 8) & 0xFF;
|
||||||
|
f = af & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeBC(int bc) {
|
||||||
|
b = (bc >> 8) & 0xFF;
|
||||||
|
c = bc & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeDE(int de) {
|
||||||
|
d = (de >> 8) & 0xFF;
|
||||||
|
e = de & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeHL(int hl) {
|
||||||
|
h = (hl >> 8) & 0xFF;
|
||||||
|
l = hl & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readA() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeA(int a) {
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readF() {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeF(int f) {
|
||||||
|
this.f = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readB() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeB(int b) {
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readC() {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeC(int c) {
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readD() {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeD(int d) {
|
||||||
|
this.d = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readE() {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeE(int e) {
|
||||||
|
this.e = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readH() {
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeH(int h) {
|
||||||
|
this.h = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readL() {
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeL(int l) {
|
||||||
|
this.l = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
private Op[] ops;
|
||||||
|
|
||||||
|
private final Registers registers;
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private int stored;
|
||||||
|
|
||||||
|
public Opcode(Registers registers, MMU mmu, Op... ops) {
|
||||||
|
this.registers = registers;
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
this.ops = ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(Registers regs, MMU mmu) {
|
||||||
|
for (Op op : ops)
|
||||||
|
op.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Op {
|
||||||
|
|
||||||
|
public void execute();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Read16BitOperand implements Op {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
stored = (mmu.read(registers.pc++) << 8) | mmu.read(registers.pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package playingcoffee.core.cpu;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import playingcoffee.core.cpu.microop.MicroOp;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
List<MicroOp> microOps;
|
||||||
|
|
||||||
|
public Opcode(MicroOp... ops) {
|
||||||
|
microOps = new ArrayList<MicroOp>(ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Registers {
|
||||||
|
|
||||||
|
private int a, f;
|
||||||
|
private int b, c;
|
||||||
|
private int d, e;
|
||||||
|
private int h, l;
|
||||||
|
|
||||||
|
public int pc;
|
||||||
|
public int sp;
|
||||||
|
|
||||||
|
public static final int FLAG_Z = 1 << 7;
|
||||||
|
public static final int FLAG_N = 1 << 6;
|
||||||
|
public static final int FLAG_H = 1 << 5;
|
||||||
|
public static final int FLAG_C = 1 << 4;
|
||||||
|
|
||||||
|
public void setFlag(int flag, boolean value) {
|
||||||
|
if (value)
|
||||||
|
f |= flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readAF() {
|
||||||
|
return a << 8 | f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readBC() {
|
||||||
|
return b << 8 | c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readDE() {
|
||||||
|
return d << 8 | e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readHL() {
|
||||||
|
return h << 8 | l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeAF(int af) {
|
||||||
|
a = (af >> 8) & 0xFF;
|
||||||
|
f = af & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeBC(int bc) {
|
||||||
|
b = (bc >> 8) & 0xFF;
|
||||||
|
c = bc & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeDE(int de) {
|
||||||
|
d = (de >> 8) & 0xFF;
|
||||||
|
e = de & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeHL(int hl) {
|
||||||
|
h = (hl >> 8) & 0xFF;
|
||||||
|
l = hl & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readA() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeA(int a) {
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readF() {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeF(int f) {
|
||||||
|
this.f = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readB() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeB(int b) {
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readC() {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeC(int c) {
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readD() {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeD(int d) {
|
||||||
|
this.d = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readE() {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeE(int e) {
|
||||||
|
this.e = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readH() {
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeH(int h) {
|
||||||
|
this.h = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readL() {
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeL(int l) {
|
||||||
|
this.l = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Op {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
decodeOpcode(opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
registers.writeHL(registers.readHL() - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
registers.setFlag(Registers.FLAG_Z, registers.readA() == 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xCB: // CB - prefix
|
||||||
|
decodePrefixedOpcode(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0x%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodePrefixedOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x7C:
|
||||||
|
registers.setFlag(Registers.FLAG_Z, (registers.readH() & (1 << 7)) == 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0xcb%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
decodeOpcode(opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
registers.writeHL(registers.readHL() - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0x%fx\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodePrefixedOpcode(int opcode) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package playingcoffee.core.cpu;
|
||||||
|
|
||||||
|
import playingcoffee.core.Memory;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final Memory memory;
|
||||||
|
|
||||||
|
public CPU(Memory memory) {
|
||||||
|
this.memory = memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerOpcodes() {
|
||||||
|
// Example: instructions[0x01] = new OpcodeBuilder().read(OpcodeArgument.C, OpcodeArgument.PC_INC).read(OpcodeArgument.B, OpcodeArgument.PC_INC);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clock() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
private Op[] ops;
|
||||||
|
|
||||||
|
public Opcode(Op... ops) {
|
||||||
|
this.ops = ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(Registers regs, MMU mmu) {
|
||||||
|
for (Op op : ops)
|
||||||
|
op.execute(regs, mmu);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Op {
|
||||||
|
|
||||||
|
public void execute(Registers regs, MMU mmu);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Read16BitOperand implements Op {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Registers regs, MMU mmu) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
private Op[] ops;
|
||||||
|
|
||||||
|
public Opcode(Op... ops) {
|
||||||
|
this.ops = ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(Registers regs, MMU mmu) {
|
||||||
|
for (Op op : ops)
|
||||||
|
op.execute(regs, mmu);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Op {
|
||||||
|
|
||||||
|
public void execute(Registers regs, MMU mmu);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Read16BitOp implements {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Gameboy {
|
||||||
|
|
||||||
|
private CPU m_CPU;
|
||||||
|
|
||||||
|
public Gameboy() {
|
||||||
|
m_CPU = new CPU();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// Is subject to change.
|
||||||
|
switch (opcode) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
private int cycles = 0;
|
||||||
|
|
||||||
|
public static int[] instructionCycle = {
|
||||||
|
4, 12, 8, 8, 4, 4, 8, 4, 20, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
4, 12, 8, 8, 4, 4, 8, 4, 12, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
8, 12, 8, 8, 12, 12, 12, 4, 8, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
8, 12, 8, 8, 12, 12, 12, 4, 8, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
8, 12, 12, 16, 12, 16, 8, 16, 8, 16, 12, 4, 12, 24, 8, 16,
|
||||||
|
8, 12, 12, -1, 12, 16, 8, 16, 8, 16, 12, -1, 12, -1, 8, 16
|
||||||
|
};
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
if (cycles == 0) {
|
||||||
|
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
decodeOpcode(opcode);
|
||||||
|
}
|
||||||
|
cycles--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeOpcode(int opcode) {
|
||||||
|
// Apply cycle count
|
||||||
|
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
registers.writeHL(registers.readHL() - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
registers.setFlag(Registers.FLAG_Z, registers.readA() == 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xCB: // CB - prefix
|
||||||
|
decodePrefixedOpcode(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0x%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodePrefixedOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x7C:
|
||||||
|
registers.setFlag(Registers.FLAG_Z, (registers.readH() & (1 << 7)) == 0);
|
||||||
|
registers.setFlag(Registers.FLAG_N, false);
|
||||||
|
registers.setFlag(Registers.FLAG_H, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0xcb%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Gameboy {
|
||||||
|
|
||||||
|
private CPU m_CPU;
|
||||||
|
|
||||||
|
public Gameboy() {
|
||||||
|
m_CPU = new CPU();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
m_CPU.clock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package playingcoffee.core.cpu;
|
||||||
|
|
||||||
|
public abstract class MicroOp {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
decodeOpcode(opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
registers.writeHL(registers.readHL() - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xCB: // CB - prefix
|
||||||
|
decodePrefixedOpcode(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0x%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodePrefixedOpcode(int opcode) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,120 @@
|
||||||
|
package playingcoffee.ui;
|
||||||
|
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
|
||||||
|
import javax.swing.DefaultListModel;
|
||||||
|
import javax.swing.GroupLayout;
|
||||||
|
import javax.swing.GroupLayout.Alignment;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.ListModel;
|
||||||
|
import javax.swing.LayoutStyle.ComponentPlacement;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.UnsupportedLookAndFeelException;
|
||||||
|
|
||||||
|
import playingcoffee.core.CPU;
|
||||||
|
import playingcoffee.core.MMU;
|
||||||
|
|
||||||
|
public class CPUDebugger {
|
||||||
|
|
||||||
|
private JFrame frame;
|
||||||
|
private JTable memoryViewTable;
|
||||||
|
private JList<String> registerList;
|
||||||
|
|
||||||
|
private MMU mmu;
|
||||||
|
private CPU cpu;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
EventQueue.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
CPUDebugger window = new CPUDebugger();
|
||||||
|
window.frame.setVisible(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public CPUDebugger() {
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
mmu = new MMU();
|
||||||
|
cpu = new CPU();
|
||||||
|
|
||||||
|
updateValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateValues() {
|
||||||
|
DefaultListModel<String> model = new DefaultListModel<String>();
|
||||||
|
model.addElement("");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
try {
|
||||||
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||||
|
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
|
||||||
|
| UnsupportedLookAndFeelException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = new JFrame();
|
||||||
|
frame.setBounds(100, 100, 750, 500);
|
||||||
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
|
||||||
|
JButton btnStep = new JButton("Step");
|
||||||
|
|
||||||
|
JButton btnReset = new JButton("Reset");
|
||||||
|
|
||||||
|
JLabel lblRegisters = new JLabel("Registers:");
|
||||||
|
|
||||||
|
registerList = new JList<String>();
|
||||||
|
|
||||||
|
memoryViewTable = new JTable();
|
||||||
|
|
||||||
|
JLabel lblMemoryView = new JLabel("Memory View:");
|
||||||
|
GroupLayout groupLayout = new GroupLayout(frame.getContentPane());
|
||||||
|
groupLayout.setHorizontalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addComponent(btnStep)
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addComponent(btnReset))
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addComponent(registerList, GroupLayout.PREFERRED_SIZE, 122, GroupLayout.PREFERRED_SIZE))
|
||||||
|
.addGap(18)
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addComponent(lblMemoryView)
|
||||||
|
.addComponent(memoryViewTable, GroupLayout.DEFAULT_SIZE, 574, Short.MAX_VALUE))
|
||||||
|
.addContainerGap())
|
||||||
|
);
|
||||||
|
groupLayout.setVerticalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.TRAILING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addComponent(lblMemoryView))
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addGap(8)
|
||||||
|
.addComponent(memoryViewTable, GroupLayout.DEFAULT_SIZE, 382, Short.MAX_VALUE))
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addComponent(registerList, GroupLayout.PREFERRED_SIZE, 195, GroupLayout.PREFERRED_SIZE)))
|
||||||
|
.addGap(18)
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
|
||||||
|
.addComponent(btnStep)
|
||||||
|
.addComponent(btnReset))
|
||||||
|
.addGap(5))
|
||||||
|
);
|
||||||
|
frame.getContentPane().setLayout(groupLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
import playingcoffee.core.Memory;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final Memory memory;
|
||||||
|
|
||||||
|
public CPU(Memory memory) {
|
||||||
|
this.memory = memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clock() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// Is subject to change.
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
new JOptionPane(String.format("Unknown opcode: 0x%2x", opcode), JOptionPane.OK_OPTION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.readPC());
|
||||||
|
registers.writePC(registers.readPC() + 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
private Op[] ops;
|
||||||
|
|
||||||
|
private final Registers registers;
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private int stored;
|
||||||
|
|
||||||
|
public Opcode(Registers registers, MMU mmu, Op... ops) {
|
||||||
|
this.registers = registers;
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
this.ops = ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(Registers regs, MMU mmu) {
|
||||||
|
for (Op op : ops)
|
||||||
|
op.execute(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Op {
|
||||||
|
|
||||||
|
public void execute(Opcode opcode);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Read16BitOperand implements Op {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Opcode opcode) {
|
||||||
|
opcode.stored =
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
private Op[] ops;
|
||||||
|
|
||||||
|
private final Registers registers;
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
public Opcode(Registers registers, MMU mmu, Op... ops) {
|
||||||
|
this.registers = registers;
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
this.ops = ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(Registers regs, MMU mmu) {
|
||||||
|
for (Op op : ops)
|
||||||
|
op.execute(regs, mmu);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Op {
|
||||||
|
|
||||||
|
public void execute(Opcode opcode);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Read16BitOperand implements Op {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Opcode opcode) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
private Op[] ops;
|
||||||
|
|
||||||
|
public Opcode(Op... ops) {
|
||||||
|
this.ops = ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(Registers regs, MMU mmu) {
|
||||||
|
for (Op op : ops)
|
||||||
|
op.execute(regs, mmu);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Op {
|
||||||
|
|
||||||
|
public void execute(Registers regs, MMU mmu);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Read16BitOperand implements Op {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Registers regs, MMU mmu) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Registers {
|
||||||
|
|
||||||
|
private int a, f;
|
||||||
|
private int b, c;
|
||||||
|
private int d, e;
|
||||||
|
private int h, l;
|
||||||
|
|
||||||
|
private int pc;
|
||||||
|
private int sp;
|
||||||
|
|
||||||
|
public int readA() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeA(int a) {
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readF() {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeF(int f) {
|
||||||
|
this.f = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readB() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeB(int b) {
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readC() {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeC(int c) {
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readD() {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeD(int d) {
|
||||||
|
this.d = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readE() {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeE(int e) {
|
||||||
|
this.e = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readH() {
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeH(int h) {
|
||||||
|
this.h = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readL() {
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeL(int l) {
|
||||||
|
this.l = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readPC() {
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writePC(int pc) {
|
||||||
|
this.pc = pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readSP() {
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeSP(int sp) {
|
||||||
|
this.sp = sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Registers {
|
||||||
|
|
||||||
|
private int a, f;
|
||||||
|
private int b, c;
|
||||||
|
private int d, e;
|
||||||
|
private int h, l;
|
||||||
|
|
||||||
|
private int pc;
|
||||||
|
private int sp;
|
||||||
|
|
||||||
|
public int readAF() {
|
||||||
|
return a << 8 | F;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readA() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeA(int a) {
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readF() {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeF(int f) {
|
||||||
|
this.f = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readB() {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeB(int b) {
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readC() {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeC(int c) {
|
||||||
|
this.c = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readD() {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeD(int d) {
|
||||||
|
this.d = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readE() {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeE(int e) {
|
||||||
|
this.e = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readH() {
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeH(int h) {
|
||||||
|
this.h = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readL() {
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeL(int l) {
|
||||||
|
this.l = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readPC() {
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writePC(int pc) {
|
||||||
|
this.pc = pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readSP() {
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeSP(int sp) {
|
||||||
|
this.sp = sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
decodeOpcode(opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
registers.writeHL(registers.readHL() - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
registers.setFlag(Registers.FLAG_Z, registers.readA() == 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xCB: // CB - prefix
|
||||||
|
decodePrefixedOpcode(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0x%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodePrefixedOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x7C:
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0xcb%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
private Op[] ops;
|
||||||
|
|
||||||
|
private final Registers registers;
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
public Opcode(Registers registers, MMU mmu, Op... ops) {
|
||||||
|
this.registers = registers;
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
this.ops = ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(Registers regs, MMU mmu) {
|
||||||
|
for (Op op : ops)
|
||||||
|
op.execute(regs, mmu);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Op {
|
||||||
|
|
||||||
|
public void execute(Registers regs, MMU mmu);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Read16BitOperand implements Op {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Registers regs, MMU mmu) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final Memory memory;
|
||||||
|
|
||||||
|
public CPU(Memory memory) {
|
||||||
|
this.memory = memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clock() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
private Op[] ops;
|
||||||
|
|
||||||
|
private final Registers registers;
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private int stored;
|
||||||
|
|
||||||
|
public Opcode(Registers registers, MMU mmu, Op... ops) {
|
||||||
|
this.registers = registers;
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
this.ops = ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(Registers regs, MMU mmu) {
|
||||||
|
for (Op op : ops)
|
||||||
|
op.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Op {
|
||||||
|
|
||||||
|
public void execute();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Read16BitOperand implements Op {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
stored = (mmu.read(registers.pc++) << 8) | mmu.read(registers.pc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32:
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
private int cycles = 0;
|
||||||
|
|
||||||
|
public static int[] instructionCycle = {
|
||||||
|
4, 12, 8, 8, 4, 4, 8, 4, 20, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
4, 12, 8, 8, 4, 4, 8, 4, 12, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
8, 12, 8, 8, 12, 12, 12, 4, 8, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
8, 12, 8, 8, 12, 12, 12, 4, 8, 8, 8, 8, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 8, 4,
|
||||||
|
8, 12, 12, 16, 12, 16, 8, 16, 8, 16, 12, 4, 12, 24, 8, 16,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
if (cycles == 0) {
|
||||||
|
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
decodeOpcode(opcode);
|
||||||
|
}
|
||||||
|
cycles--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeOpcode(int opcode) {
|
||||||
|
// Apply cycle count
|
||||||
|
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
registers.writeHL(registers.readHL() - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
registers.setFlag(Registers.FLAG_Z, registers.readA() == 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xCB: // CB - prefix
|
||||||
|
decodePrefixedOpcode(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0x%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodePrefixedOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x7C:
|
||||||
|
registers.setFlag(Registers.FLAG_Z, (registers.readH() & (1 << 7)) == 0);
|
||||||
|
registers.setFlag(Registers.FLAG_N, false);
|
||||||
|
registers.setFlag(Registers.FLAG_H, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0xcb%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class MMU {
|
||||||
|
|
||||||
|
private int ram[];
|
||||||
|
|
||||||
|
public void write(int value, int address) {
|
||||||
|
ram[address] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read(int address) {
|
||||||
|
return ram[address];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package playingcoffee.ui;
|
||||||
|
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
|
||||||
|
public class CPUDebugger {
|
||||||
|
|
||||||
|
private JFrame frame;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launch the application.
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) {
|
||||||
|
EventQueue.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
CPUDebugger window = new CPUDebugger();
|
||||||
|
window.frame.setVisible(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the application.
|
||||||
|
*/
|
||||||
|
public CPUDebugger() {
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the contents of the frame.
|
||||||
|
*/
|
||||||
|
private void initialize() {
|
||||||
|
frame = new JFrame();
|
||||||
|
frame.setBounds(100, 100, 450, 300);
|
||||||
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
package playingcoffee.ui;
|
||||||
|
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.GroupLayout;
|
||||||
|
import javax.swing.GroupLayout.Alignment;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.LayoutStyle.ComponentPlacement;
|
||||||
|
|
||||||
|
import playingcoffee.core.CPU;
|
||||||
|
import playingcoffee.core.MMU;
|
||||||
|
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.UnsupportedLookAndFeelException;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
|
||||||
|
public class CPUDebugger {
|
||||||
|
|
||||||
|
private JFrame frame;
|
||||||
|
private JTable memoryViewTable;
|
||||||
|
|
||||||
|
private CPU cpu;
|
||||||
|
private MMU mmu;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
EventQueue.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
CPUDebugger window = new CPUDebugger();
|
||||||
|
window.frame.setVisible(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public CPUDebugger() {
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
try {
|
||||||
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||||
|
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
|
||||||
|
| UnsupportedLookAndFeelException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = new JFrame();
|
||||||
|
frame.setBounds(100, 100, 750, 500);
|
||||||
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
|
||||||
|
JButton btnStep = new JButton("Step");
|
||||||
|
|
||||||
|
JButton btnReset = new JButton("Reset");
|
||||||
|
|
||||||
|
JLabel lblRegisters = new JLabel("Registers:");
|
||||||
|
|
||||||
|
JList<String> registerList = new JList<String>();
|
||||||
|
|
||||||
|
memoryViewTable = new JTable();
|
||||||
|
|
||||||
|
JLabel lblMemoryView = new JLabel("Memory View:");
|
||||||
|
GroupLayout groupLayout = new GroupLayout(frame.getContentPane());
|
||||||
|
groupLayout.setHorizontalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addComponent(btnStep)
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addComponent(btnReset))
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addGap(18))
|
||||||
|
.addComponent(registerList, GroupLayout.PREFERRED_SIZE, 122, GroupLayout.PREFERRED_SIZE))
|
||||||
|
.addGap(18)
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addComponent(lblMemoryView)
|
||||||
|
.addComponent(memoryViewTable, GroupLayout.DEFAULT_SIZE, 574, Short.MAX_VALUE))
|
||||||
|
.addContainerGap())
|
||||||
|
);
|
||||||
|
groupLayout.setVerticalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.TRAILING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addComponent(lblMemoryView))
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addGap(8)
|
||||||
|
.addComponent(memoryViewTable, GroupLayout.DEFAULT_SIZE, 382, Short.MAX_VALUE))
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addComponent(registerList, GroupLayout.PREFERRED_SIZE, 195, GroupLayout.PREFERRED_SIZE)))
|
||||||
|
.addGap(18)
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
|
||||||
|
.addComponent(btnStep)
|
||||||
|
.addComponent(btnReset))
|
||||||
|
.addGap(5))
|
||||||
|
);
|
||||||
|
frame.getContentPane().setLayout(groupLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
case 0x31:
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
private Op[] ops;
|
||||||
|
|
||||||
|
private final Registers registers;
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
public Opcode(Registers registers, MMU mmu, Op... ops) {
|
||||||
|
this.registers = registers;
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
this.ops = ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(Registers regs, MMU mmu) {
|
||||||
|
for (Op op : ops)
|
||||||
|
op.execute(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Op {
|
||||||
|
|
||||||
|
public void execute(Opcode opcode);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Read16BitOperand implements Op {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Opcode opcode) {
|
||||||
|
opcode.registers.pc = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
decodeOpcode(opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
registers.writeHL(registers.readHL() - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
registers.setFlag(Registers.FLAG_Z, registers.readA() == 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xCB: // CB - prefix
|
||||||
|
decodePrefixedOpcode(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0x%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodePrefixedOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x7C:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0xcb%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class Opcode {
|
||||||
|
|
||||||
|
private Op[] ops;
|
||||||
|
|
||||||
|
private final Registers registers;
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private int operand;
|
||||||
|
|
||||||
|
public Opcode(Registers registers, MMU mmu, Op... ops) {
|
||||||
|
this.registers = registers;
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
this.ops = ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(Registers regs, MMU mmu) {
|
||||||
|
for (Op op : ops)
|
||||||
|
op.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Op {
|
||||||
|
|
||||||
|
public void execute();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Read16BitOperand implements Op {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
operand = (mmu.read(registers.pc++) << 8) | mmu.read(registers.pc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
// Basic CPU implementation.
|
||||||
|
// This will be changed in the future.
|
||||||
|
|
||||||
|
package playingcoffee.core;
|
||||||
|
|
||||||
|
public class CPU {
|
||||||
|
|
||||||
|
private final MMU mmu;
|
||||||
|
|
||||||
|
private Registers registers;
|
||||||
|
|
||||||
|
private int cycles = 0;
|
||||||
|
|
||||||
|
public CPU(final MMU mmu) {
|
||||||
|
this.mmu = mmu;
|
||||||
|
|
||||||
|
registers = new Registers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Registers getRegisters() {
|
||||||
|
return registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cycle() {
|
||||||
|
if (cycles == 0) {
|
||||||
|
|
||||||
|
int opcode = mmu.read(registers.pc++);
|
||||||
|
System.out.printf("Fetched opcode: 0x%02x\n", opcode);
|
||||||
|
|
||||||
|
decodeOpcode(opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodeOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x00: // NOP
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21: // LD HL, d16
|
||||||
|
registers.writeL(mmu.read(registers.pc++));
|
||||||
|
registers.writeH(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31: // LD SP, d16
|
||||||
|
registers.sp = mmu.read(registers.pc++) | (mmu.read(registers.pc++) << 8);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x32: // LD (HL-), A
|
||||||
|
mmu.write(registers.readA(), registers.readHL());
|
||||||
|
registers.writeHL(registers.readHL() - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xAF: // XOR A
|
||||||
|
registers.writeA(registers.readA() ^ registers.readA());
|
||||||
|
registers.setFlag(Registers.FLAG_Z, registers.readA() == 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xCB: // CB - prefix
|
||||||
|
decodePrefixedOpcode(mmu.read(registers.pc++));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0x%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decodePrefixedOpcode(int opcode) {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x7C:
|
||||||
|
registers.setFlag(Registers.FLAG_Z, (registers.readH() & (1 << 7)) == 0);
|
||||||
|
registers.setFlag(Registers.FLAG_N, false);
|
||||||
|
registers.setFlag(Registers.FLAG_H, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
System.err.printf("Unknown opcode: 0xcb%2x\n", opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
package playingcoffee.ui;
|
||||||
|
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
|
||||||
|
import javax.swing.DefaultListModel;
|
||||||
|
import javax.swing.GroupLayout;
|
||||||
|
import javax.swing.GroupLayout.Alignment;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.LayoutStyle.ComponentPlacement;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.UnsupportedLookAndFeelException;
|
||||||
|
|
||||||
|
import playingcoffee.core.CPU;
|
||||||
|
import playingcoffee.core.MMU;
|
||||||
|
|
||||||
|
public class CPUDebugger {
|
||||||
|
|
||||||
|
private JFrame frmCpuDebugger;
|
||||||
|
private JList<String> registerList;
|
||||||
|
|
||||||
|
private MMU mmu;
|
||||||
|
private CPU cpu;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
EventQueue.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
CPUDebugger window = new CPUDebugger();
|
||||||
|
window.frmCpuDebugger.setVisible(true);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public CPUDebugger() {
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
mmu = new MMU();
|
||||||
|
cpu = new CPU();
|
||||||
|
|
||||||
|
updateValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateValues() {
|
||||||
|
DefaultListModel<String> model = new DefaultListModel<String>();
|
||||||
|
model.addElement("AF: 0x" + Integer.toHexString(cpu.getRegisters().readAF()));
|
||||||
|
model.addElement("BC: 0x" + Integer.toHexString(cpu.getRegisters().readBC()));
|
||||||
|
model.addElement("DE: 0x" + Integer.toHexString(cpu.getRegisters().readDE()));
|
||||||
|
model.addElement("HL: 0x" + Integer.toHexString(cpu.getRegisters().readHL()));
|
||||||
|
|
||||||
|
registerList.setModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
try {
|
||||||
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||||
|
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
|
||||||
|
| UnsupportedLookAndFeelException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
frmCpuDebugger = new JFrame();
|
||||||
|
frmCpuDebugger.setTitle("CPU Debugger");
|
||||||
|
frmCpuDebugger.setBounds(100, 100, 350, 350);
|
||||||
|
frmCpuDebugger.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
|
||||||
|
JButton btnStep = new JButton("Step");
|
||||||
|
|
||||||
|
JButton btnReset = new JButton("Reset");
|
||||||
|
|
||||||
|
JLabel lblRegisters = new JLabel("Registers:");
|
||||||
|
|
||||||
|
registerList = new JList<String>();
|
||||||
|
GroupLayout groupLayout = new GroupLayout(frmCpuDebugger.getContentPane());
|
||||||
|
groupLayout.setHorizontalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
|
||||||
|
.addComponent(registerList, GroupLayout.DEFAULT_SIZE, 314, Short.MAX_VALUE)
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addGroup(Alignment.TRAILING, groupLayout.createSequentialGroup()
|
||||||
|
.addComponent(btnStep)
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED, 198, Short.MAX_VALUE)
|
||||||
|
.addComponent(btnReset)))
|
||||||
|
.addContainerGap())
|
||||||
|
);
|
||||||
|
groupLayout.setVerticalGroup(
|
||||||
|
groupLayout.createParallelGroup(Alignment.TRAILING)
|
||||||
|
.addGroup(groupLayout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addComponent(lblRegisters)
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addComponent(registerList, GroupLayout.PREFERRED_SIZE, 195, GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addGap(51)
|
||||||
|
.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
|
||||||
|
.addComponent(btnReset)
|
||||||
|
.addComponent(btnStep))
|
||||||
|
.addContainerGap())
|
||||||
|
);
|
||||||
|
frmCpuDebugger.getContentPane().setLayout(groupLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue