Skip to content

Commit

Permalink
v2.1
Browse files Browse the repository at this point in the history
Added bitmap VGA mode
File choosers now use system defaults
Bug Fixes
  • Loading branch information
DylanSpeiser committed Oct 20, 2022
1 parent 0a31e29 commit 2569df1
Show file tree
Hide file tree
Showing 10 changed files with 207 additions and 88 deletions.
7 changes: 7 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Launch LCD",
"request": "launch",
"mainClass": "LCD",
"projectName": "Java-6502-Emulator_cdf032ed"
},
{
"type": "java",
"name": "Launch GPU",
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
# Java 6502 Emulator


## Update: v2.0 is here!
Whoa! Almost a year after the last update it's back and better than ever! The emulator now includes a character-driven GPU (bitmap modes in development) and SO MUCH customizability!
## Update: v2.1 is here!
Whoa! Almost a year after the last update it's back and better than ever! The emulator now includes a GPU (with Ben's bitmap and a custom character mode) and SO MUCH customizability!
You can now hide and show the LCD and GPU windows with the buttons at the top right!
You can now customize the address ranges of the VIA and GPU!
The GPU's resolution and array size is _whatever you want it to be_!
The fonts actually work now!
The file choosers aren't the old Java ones!
And **COLORS!!**

Store the configs in our fancy new .pref files!
These configuration settings are stored in your AppData or Application Support folder on Windows/Mac respectively. It generates a defaults.pref file on startup every time if you want to go back to the default settings. (options.pref is loaded on startup.)

(The GPU Mode setting doesn't do anything yet, but that will allow me to implement more fun modes in the future.)

Enjoy the new features!
-Dylan

Expand Down Expand Up @@ -48,3 +47,4 @@ You can load ```.bin``` files into RAM or ROM using the File Pickers in the top
![Screenshot 0](screenshots/screenshot0.png?raw=true)
![Screenshot 1](screenshots/screenshot1.png?raw=true)
![Screenshot 2](screenshots/screenshot2.png?raw=true)
![Screenshot 3](screenshots/screenshot3.png?raw=true)
Binary file added screenshots/screenshot3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/CPU.java
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ void clock() {
ClocksPerSecond = EaterEmulator.clocks/((System.currentTimeMillis()-startTime)/1000);

EaterEmulator.clocks++;

cycles--;
}

Expand Down
7 changes: 5 additions & 2 deletions src/DisplayPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ public void paintComponent(Graphics g) {

//Title
g.setFont(new Font("Calibri Bold", 50, 50));
g.drawString("Ben Eater 6502 Emulator", 40, 50);
g.drawString("BE6502 Emulator", 40, 50);

//Version
g.setFont(courierNewBold);
g.drawString("v"+EaterEmulator.versionString, 7, 1033);
g.drawString("v"+EaterEmulator.versionString+" (c) Dylan Speiser", 7, 1033);

//Clocks
g.drawString("Clocks: "+EaterEmulator.clocks, 40, 80);
Expand Down Expand Up @@ -146,6 +146,9 @@ public void resetGraphics() {
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(t)) {
EaterEmulator.running = true;

EaterEmulator.cpu.cycles = 0;


ramPageString = EaterEmulator.ram.RAMString.substring(ramPage*960,(ramPage+1)*960);
EaterEmulator.ROMopenButton.setBounds(rightAlignHelper-150, 15, 125, 25);
Expand Down
45 changes: 24 additions & 21 deletions src/EaterEmulator.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
import javax.swing.*;

public class EaterEmulator extends JFrame implements ActionListener {
public static EaterEmulator emu;
public static String versionString = "2.0";
public static String versionString = "2.1";
public static boolean debug = false;

//Swing Things
JPanel p = new JPanel();
JPanel header = new JPanel();
public static JFileChooser fc = new JFileChooser();
public static FileDialog fc = new java.awt.FileDialog((java.awt.Frame) null);
public static JButton ROMopenButton = new JButton("Open ROM File");
public static JButton RAMopenButton = new JButton("Open RAM File");

Expand All @@ -30,27 +29,29 @@ public class EaterEmulator extends JFrame implements ActionListener {
public static int clocks = 0;
public static boolean haltFlag = true;
public static boolean slowerClock = false;
public static boolean running = false;

//Emulator Things
public static EaterEmulator emu;
public static RAM ram = new RAM();
public static ROM rom = new ROM();
public static LCD lcd = new LCD();
public static VIA via = new VIA();
public static Bus bus = new Bus();
public static CPU cpu = new CPU();
public static GPU gpu = new GPU(ram);

public static GPU gpu = new GPU(ram,false);
public static DisplayPanel GraphicsPanel = new DisplayPanel();

//Options
public static OptionsPane options = new OptionsPane();

public static boolean running = false;

public EaterEmulator() {
//Swing Stuff:
System.setProperty("sun.java2d.opengl", "true");
this.setSize(1920,1080);
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}catch(Exception ex) {
ex.printStackTrace();
}

//Open .bin file button
ROMopenButton.setVisible(true);
Expand Down Expand Up @@ -86,8 +87,8 @@ public EaterEmulator() {
GraphicsPanel.add(optionsButton);

//file chooser
fc.setVisible(true);
fc.setCurrentDirectory(new File(options.data.defaultFileChooserDirectory));
fc.setDirectory(options.data.defaultFileChooserDirectory);
fc.setVisible(false);

//Clock thread setup
clockThread = new Thread(() -> {
Expand Down Expand Up @@ -121,22 +122,24 @@ public EaterEmulator() {
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(ROMopenButton)) {
fc.setSelectedFile(new File(""));
int returnVal = fc.showOpenDialog(this);
fc.setFile("");
fc.setMode(FileDialog.LOAD);
fc.setVisible(true);

if (returnVal == JFileChooser.APPROVE_OPTION) {
rom.setROMArray(ROMLoader.readROM(fc.getSelectedFile()));
}
if (fc.getFile() != null)
rom.setROMArray(ROMLoader.readROM(new File(fc.getDirectory()+fc.getFile())));

GraphicsPanel.requestFocus();
GraphicsPanel.romPageString = EaterEmulator.rom.ROMString.substring(GraphicsPanel.romPage*960,(GraphicsPanel.romPage+1)*960);
cpu.reset();
} else if (e.getSource().equals(RAMopenButton)) {
fc.setSelectedFile(new File(""));
int returnVal = fc.showOpenDialog(this);
fc.setFile("");
fc.setMode(FileDialog.LOAD);
fc.setVisible(true);

if (fc.getFile() != null)
ram.setRAMArray(ROMLoader.readROM(new File(fc.getDirectory()+fc.getFile())));

if (returnVal == JFileChooser.APPROVE_OPTION) {
ram.setRAMArray(ROMLoader.readROM(fc.getSelectedFile()));
}
GraphicsPanel.requestFocus();
GraphicsPanel.ramPageString = EaterEmulator.ram.RAMString.substring(GraphicsPanel.ramPage*960,(GraphicsPanel.ramPage+1)*960);
cpu.reset();
Expand Down
104 changes: 78 additions & 26 deletions src/GPU.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import java.io.File;
import java.io.InputStream;
import java.net.URISyntaxException;

import javax.imageio.ImageIO;
import java.nio.file.*;
import java.util.Scanner;
Expand All @@ -15,16 +14,22 @@

public class GPU extends JFrame implements ActionListener {
GPUPanel p = new GPUPanel();

Timer t;
Scanner s;

boolean scanned = false;

public static int VRAM_START_ADDRESS = 0x6000;

public static int n_cols = 80;
public static int n_rows = 60;

public static int width = 640;
public static int height = 480;
public static int width = 100;
public static int height = 75;

public static int gpuMode = 1;
public static int GPUPixelScale = 8;

int charWidth;
int charHeight;
Expand All @@ -39,8 +44,9 @@ public class GPU extends JFrame implements ActionListener {

RAM vram;

public GPU(RAM vram) {
this.setSize(width,height);
public GPU(RAM vram,boolean isVisible) {
this.setSize(GPUPixelScale*width,GPUPixelScale*height);

t = new Timer(16,this);
t.start();

Expand Down Expand Up @@ -107,18 +113,18 @@ public GPU(RAM vram) {
this.setTitle("GPU");
this.setContentPane(p);
this.setAlwaysOnTop(true);
this.setVisible(false);
this.setVisible(isVisible);
this.setDefaultCloseOperation(HIDE_ON_CLOSE);
this.setResizable(false);
}

public GPU() {
this(new RAM());
public GPU(boolean isVisible) {
this(new RAM(),isVisible);
}

@SuppressWarnings("unused")
public static void main(String[] args) {
GPU gpu = new GPU();
GPU gpu = new GPU(true);
gpu.setVisible(true);

@SuppressWarnings("resource")
Expand All @@ -144,11 +150,13 @@ public static void main(String[] args) {

System.out.println("Read "+newData.length+" bytes.");

System.arraycopy(newData, 0, newRAMArray, GPU.VRAM_START_ADDRESS, Math.min(newData.length,newRAMArray.length));
System.arraycopy(newData, 0, newRAMArray, (gpuMode == 1 | gpuMode == 2) ? 0 : (GPU.VRAM_START_ADDRESS), Math.min(newData.length,newRAMArray.length));

gpu.vram.setRAMArray(newRAMArray);

//System.out.println(ROMLoader.ROMString(gpu.vram.getRAMArray(),40,false));
gpu.scanned = true;
// System.out.println(ROMLoader.ROMString(gpu.vram.getRAMArray(),40,false));
// System.exit(0);
}
}

Expand All @@ -162,22 +170,66 @@ public GPUPanel() {
}

public void paintComponent(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, p.getWidth(), p.getHeight());

g.setColor(Color.white);

for (int i = 0; i<n_rows; i++) {
for (int j = 0; j<n_cols; j++) {
int index = i*n_cols + j;
int character = Byte.toUnsignedInt(vram.read((short)(VRAM_START_ADDRESS+index)));

g.drawImage(charImages[character],j*effectiveCharWidth,i*effectiveCharHeight,effectiveCharWidth,effectiveCharHeight,this);
if (debug) {
System.out.println("Painted Char #"+character+" @ index "+index+" ("+j*charWidth+","+i*charHeight+")");
if (this.isVisible()) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, p.getWidth(), p.getHeight());

g.setColor(Color.white);

if (gpuMode == 0) {
//Speiser Character Mode
for (int i = 0; i<n_rows; i++) {
for (int j = 0; j<n_cols; j++) {
int index = i*n_cols + j;
int character = Byte.toUnsignedInt(vram.read((short)(VRAM_START_ADDRESS+index)));

g.drawImage(charImages[character],j*effectiveCharWidth,i*effectiveCharHeight,effectiveCharWidth,effectiveCharHeight,this);
if (debug) {
System.out.println("Painted Char #"+character+" @ index "+index+" ("+j*charWidth+","+i*charHeight+")");
}
}
}
} else if (gpuMode == 1 || gpuMode == 2) {
//Eater Bitmap Mode
int nextPowerOf2 = (int)Math.pow(2,((int)Math.ceil(Math.log(width)/Math.log(2))));
for (int i = 0; i<height; i++) {
for (int j = 0; j<width; j++) {
int index = j+nextPowerOf2*i;

/*
System.out.println(" i: "+Integer.toBinaryString(i)+
" j: "+Integer.toBinaryString(j)+
" i (shifted): "+Integer.toBinaryString((i >> 3))+
" j (shifted): "+Integer.toBinaryString((j >> 1))+
" index: "+Integer.toBinaryString(index));
*/

byte pixelData = vram.read( (short) Math.min((((gpuMode == 1 || gpuMode == 2) && debug == true) ? 0 : VRAM_START_ADDRESS)+index,vram.getRAMArray().length-1) );
//pixelData = 0b001010;

byte red = (byte)((pixelData & 0b00110000) >> 4);
byte green = (byte)((pixelData & 0b00001100) >> 2);
byte blue = (byte)((pixelData & 0b00000011) >> 0);

Color c = Color.decode("#"+
Integer.toHexString(red*5)+Integer.toHexString(red*5)+
Integer.toHexString(green*5)+Integer.toHexString(green*5)+
Integer.toHexString(blue*5)+Integer.toHexString(blue*5)
);

if (scanned) {
System.out.println("PixelData: "+ROMLoader.byteToHexString(pixelData)+" Color "+c.toString()+" @ ("+i+","+j+"), Index "+Integer.toHexString(index));
System.out.println("PixelData "+Integer.toBinaryString(pixelData)+" R:"+Integer.toBinaryString(red)+" G:"+Integer.toBinaryString(green)+" B:"+Integer.toBinaryString(blue));
System.out.println("NextPowerOf2: "+nextPowerOf2);
}

g.setColor(c);

g.fillRect(GPUPixelScale*j, GPUPixelScale*i, GPUPixelScale, GPUPixelScale);
}
}
}
}
}
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/LCD.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ public LCD() {
this.setTitle("LCD");
this.setContentPane(p);
this.setAlwaysOnTop(true);
this.setVisible(true);
this.setVisible(false);
this.setDefaultCloseOperation(HIDE_ON_CLOSE);
}

public static void main(String[] args) {
LCD lcd = new LCD();
lcd.setVisible(true);

@SuppressWarnings("resource")
Scanner scan = new Scanner(System.in);
Expand Down
6 changes: 4 additions & 2 deletions src/OptionsData.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ public class OptionsData implements Serializable {
int GPUHeight = GPU.height;
int GPUCols = GPU.n_cols;
int GPURows = GPU.n_rows;
int GPUBufferBegin = 0x4000;
int GPUMode = 0; //GPU Modes (planned): 0=Character, 1=Bitmap Mono, 2=Character w/ Color, 3=Bitmap w/ Color
int GPUBufferBegin = 0x2000;
int GPUMode = GPU.gpuMode;
int GPUBitmapPixelScale = GPU.GPUPixelScale;
Color bgColor = Color.blue;
Color fgColor = Color.white;

Expand All @@ -27,6 +28,7 @@ public String toString() {
"GPU Buffer Address: 0x"+Integer.toHexString(GPUBufferBegin)+"\n"+
"GPU Character Dimentsions: "+GPUCols+"x"+GPURows+"\n"+
"GPU Mode: "+GPUMode+"\n"+
"GPU Bitmap Pixel Scale: "+GPUBitmapPixelScale+"\n"+
"Background Color: "+bgColor.toString()+"\n"+
"Foreground Color: "+fgColor.toString()+"\n";
}
Expand Down
Loading

0 comments on commit 2569df1

Please sign in to comment.