Skip to content

Commit c898766

Browse files
committed
1.3
Added interrupt functionality.
1 parent dda70b3 commit c898766

File tree

6 files changed

+99
-25
lines changed

6 files changed

+99
-25
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ UNIMPLEMENTED FEATURES:
77
- LCD Memory (sorry, it's a character-level simulation)
88
- LCD Reads (always returns not busy)
99
- Every feature on the 65C22 that isn't writing to the LCD (will always read 0).
10-
- Interrupts (the opcodes and functions are all there, but irq() and nmi() are never called)
1110

1211
Some might ask, why write an emulator in Java? And I would respond: "Because no one else would." Sure, Java is terribly slow (more than 1000x slower than the original!), and the fact that Java's ```byte```s and ```short```s are a pain to work with because they're signed, but it's the language I'm best in so I don't care ;)
1312

@@ -22,6 +21,7 @@ Feel free to fork it, improve it, whatever, just link back to here. Enjoy!
2221
- K/L - Decrement/Increment ROM Page
2322
- R - Reset
2423
- S - Toggle Slow Clock
24+
- I - Trigger Interrupt (the CA1 pin on the VIA)
2525

2626
You can load ```.bin``` files into RAM or ROM using the File Pickers in the top right. It should be fully compatible with any binary compiled for the 6502 kit, except if it uses any unimplemented features. I might get to these sometime in the future. If I do, the repo will be updated.
2727

src/Bus.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public static byte read(short address) {
1111

1212
public static void write(short address, byte data) {
1313
if (Short.toUnsignedInt(address) >= 32768) {
14-
System.out.println("Can't write to ROM!");
14+
System.err.println("Can't write to ROM! ("+Integer.toHexString(Short.toUnsignedInt(address)).toUpperCase()+")");
1515
} else if (Short.toUnsignedInt(address) <= 24592 && Short.toUnsignedInt(address) >= 24576) {
1616
EaterEmulator.via.write(address, data);
1717
} else {

src/CPU.java

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public class CPU {
2323

2424
public int additionalCycles = 0;
2525

26+
public boolean interruptRequested = false;
27+
public boolean NMinterruptRequested = false;
28+
2629
public Instruction[] lookup = new Instruction[0x100];
2730

2831
public CPU() {
@@ -304,16 +307,23 @@ public static byte setBit(byte b, int bit, boolean value) {
304307

305308
void clock() {
306309
if (cycles == 0) {
307-
additionalCycles = 0;
308-
opcode = Bus.read(programCounter);
309-
programCounter++;
310-
311-
cycles = lookup[Byte.toUnsignedInt(opcode)].cycles;
310+
if (!interruptRequested) {
311+
additionalCycles = 0;
312+
opcode = Bus.read(programCounter);
313+
programCounter++;
314+
315+
cycles = lookup[Byte.toUnsignedInt(opcode)].cycles;
312316

313-
try {
314-
this.getClass().getMethod(lookup[Byte.toUnsignedInt(opcode)].addressMode).invoke(this);
315-
this.getClass().getMethod(lookup[Byte.toUnsignedInt(opcode)].opcode).invoke(this);
316-
} catch (Exception e) {e.printStackTrace();}
317+
try {
318+
this.getClass().getMethod(lookup[Byte.toUnsignedInt(opcode)].addressMode).invoke(this);
319+
this.getClass().getMethod(lookup[Byte.toUnsignedInt(opcode)].opcode).invoke(this);
320+
} catch (Exception e) {e.printStackTrace();}
321+
} else {
322+
if (interruptRequested)
323+
irq();
324+
if (NMinterruptRequested)
325+
nmi();
326+
}
317327

318328
if (debug) {
319329
System.out.print(Integer.toHexString(Short.toUnsignedInt(programCounter))+" "+lookup[Byte.toUnsignedInt(opcode)].opcode+" "+ROMLoader.byteToHexString(opcode)+" ");
@@ -375,46 +385,46 @@ void reset() {
375385

376386
void irq() {
377387
if (!getFlag('I')) {
378-
Bus.write((short)(0x0100+Byte.toUnsignedInt(stackPointer)), (byte)((programCounter>>8)&0x00FF));
388+
Bus.write((short)(0x0100+Byte.toUnsignedInt(stackPointer)), (byte)(programCounter>>8));
379389
stackPointer--;
380-
Bus.write((short)(0x0100+Byte.toUnsignedInt(stackPointer)), (byte)(programCounter&0x00FF));
390+
Bus.write((short)(0x0100+Byte.toUnsignedInt(stackPointer)), (byte)(programCounter));
381391
stackPointer--;
382392

383393
setFlag('B',false);
384394
setFlag('U',false);
385-
setFlag('I',true);
386-
387395
Bus.write((short)(0x0100+Byte.toUnsignedInt(stackPointer)), flags);
388396
stackPointer--;
397+
setFlag('I',true);
389398

390-
addressAbsolute = (short)0xFFFE;
399+
addressAbsolute = (short)(0xFFFE);
391400
byte lo = Bus.read(addressAbsolute);
392401
byte hi = Bus.read((short)(addressAbsolute+1));
393402
programCounter = (short)(Byte.toUnsignedInt(lo)+256*Byte.toUnsignedInt(hi));
394403

395404
cycles = 7;
405+
interruptRequested = false;
396406
}
397407
}
398408

399409
void nmi() {
400-
Bus.write((short)(0x0100+Byte.toUnsignedInt(stackPointer)), (byte)((programCounter>>8)&0x00FF));
410+
Bus.write((short)(0x0100+Byte.toUnsignedInt(stackPointer)), (byte)(programCounter>>8));
401411
stackPointer--;
402-
Bus.write((short)(0x0100+Byte.toUnsignedInt(stackPointer)), (byte)(programCounter&0x00FF));
412+
Bus.write((short)(0x0100+Byte.toUnsignedInt(stackPointer)), (byte)(programCounter));
403413
stackPointer--;
404414

405415
setFlag('B',false);
406416
setFlag('U',false);
407-
setFlag('I',true);
408-
409417
Bus.write((short)(0x0100+Byte.toUnsignedInt(stackPointer)), flags);
410418
stackPointer--;
419+
setFlag('I',true);
411420

412-
addressAbsolute = (short)0xFFFA;
421+
addressAbsolute = (short)(0xFFFA);
413422
byte lo = Bus.read(addressAbsolute);
414423
byte hi = Bus.read((short)(addressAbsolute+1));
415424
programCounter = (short)(Byte.toUnsignedInt(lo)+256*Byte.toUnsignedInt(hi));
416425

417426
cycles = 7;
427+
NMinterruptRequested = false;
418428
}
419429

420430
//Data Getter
@@ -653,7 +663,6 @@ public void BRK() {
653663
setFlag('U',true);
654664
Bus.write((short)(0x0100+Byte.toUnsignedInt(stackPointer)), flags);
655665
stackPointer--;
656-
//setFlag('B',false);
657666
setFlag('I',true);
658667

659668
addressAbsolute = (short)0xFFFE;
@@ -895,7 +904,7 @@ public void ROR() {
895904

896905
public void RTI() {
897906
stackPointer++;
898-
flags = Bus.read((short)(0x0100+Byte.toUnsignedInt(stackPointer)));
907+
flags = Bus.read((short)(0x100+Byte.toUnsignedInt(stackPointer)));
899908
flags = (byte)(flags & (getFlag('B') ? 0b11101111 : 0));
900909
flags = (byte)(flags & (getFlag('U') ? 0b11011111 : 0));
901910

@@ -987,6 +996,6 @@ public void TYA() {
987996
}
988997

989998
public void XXX() {
990-
System.out.println("Illegal Opcode! (" + ROMLoader.byteToHexString(opcode) +") - "+lookup[Byte.toUnsignedInt(opcode)].opcode);
999+
System.out.println("Illegal Opcode at $"+Integer.toHexString(Short.toUnsignedInt(programCounter)).toUpperCase()+" (" + ROMLoader.byteToHexString(opcode) +") - "+lookup[Byte.toUnsignedInt(opcode)].opcode);
9911000
}
9921001
}

src/DisplayPanel.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,17 @@ public void paintComponent(Graphics g) {
102102
g.drawString("PORT B: "+ROMLoader.padStringWithZeroes(Integer.toBinaryString(Byte.toUnsignedInt(EaterEmulator.via.PORTB)), 8)+" ("+ROMLoader.byteToHexString(EaterEmulator.via.PORTB)+")", 35, 550);
103103
g.drawString("DDR A: "+ROMLoader.padStringWithZeroes(Integer.toBinaryString(Byte.toUnsignedInt(EaterEmulator.via.DDRA)), 8)+" ("+ROMLoader.byteToHexString(EaterEmulator.via.DDRA)+")", 35, 580);
104104
g.drawString("DDR B: "+ROMLoader.padStringWithZeroes(Integer.toBinaryString(Byte.toUnsignedInt(EaterEmulator.via.DDRB)), 8)+" ("+ROMLoader.byteToHexString(EaterEmulator.via.DDRB)+")", 35, 610);
105+
g.drawString(" PCR: "+ROMLoader.padStringWithZeroes(Integer.toBinaryString(Byte.toUnsignedInt(EaterEmulator.via.PCR)), 8)+" ("+ROMLoader.byteToHexString(EaterEmulator.via.PCR)+")", 35, 640);
106+
g.drawString(" IFR: "+ROMLoader.padStringWithZeroes(Integer.toBinaryString(Byte.toUnsignedInt(EaterEmulator.via.IFR)), 8)+" ("+ROMLoader.byteToHexString(EaterEmulator.via.IFR)+")", 35, 670);
107+
g.drawString(" IER: "+ROMLoader.padStringWithZeroes(Integer.toBinaryString(Byte.toUnsignedInt(EaterEmulator.via.IER)), 8)+" ("+ROMLoader.byteToHexString(EaterEmulator.via.IER)+")", 35, 700);
105108

106109
//Controls
107110
g.drawString("Controls:", 50, 750);
108111
g.drawString("C - Toggle Clock", 35, 780);
109112
g.drawString("Space - Pulse Clock", 35, 810);
110113
g.drawString("R - Reset", 35, 840);
111114
g.drawString("S - Toggle Slower Clock", 35, 870);
115+
g.drawString("I - Trigger VIA CA1", 35, 900);
112116
}
113117

114118
public static void drawString(Graphics g, String text, int x, int y) {
@@ -180,6 +184,9 @@ public void keyTyped(KeyEvent arg0) {
180184
case 's':
181185
EaterEmulator.slowerClock = !EaterEmulator.slowerClock;
182186
break;
187+
case 'i':
188+
EaterEmulator.via.CA1();
189+
break;
183190
}
184191
}
185192
}

src/EaterEmulator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
public class EaterEmulator extends JFrame implements ActionListener {
1111
public static EaterEmulator emu;
12-
public static String versionString = "1.2";
12+
public static String versionString = "1.3";
1313

1414
//Swing Things
1515
JPanel p = new JPanel();

src/VIA.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,29 @@ public class VIA {
33
byte PORTB = 0x00;
44
byte DDRA = 0x00;
55
byte DDRB = 0x00;
6+
byte PCR = 0x00;
7+
byte IFR = 0x00;
8+
byte IER = 0x00;
69

710
public byte read(short address) {
11+
switch (Short.toUnsignedInt(address)) {
12+
case 0x6000:
13+
IFR &= (byte)(0b01100111);
14+
return 0;
15+
case 0x6001:
16+
IFR &= (byte)(0b01111100);
17+
return 0;
18+
case 0x6002:
19+
return 0;
20+
case 0x6003:
21+
return 0;
22+
case 0x600C:
23+
return PCR;
24+
case 0x600D:
25+
return IFR;
26+
case 0x600E:
27+
return IER;
28+
}
829
return 0;
930
}
1031

@@ -25,6 +46,43 @@ public void write(short address, byte data) {
2546
case 0x6003:
2647
DDRA = data;
2748
break;
49+
case 0x600C:
50+
PCR = data;
51+
break;
52+
case 0x600D:
53+
IFR = data;
54+
break;
55+
case 0x600E:
56+
IER = data;
57+
break;
58+
}
59+
}
60+
61+
public void CA1() {
62+
if ((IER &= (byte)(0b00000010)) == 0b00000010) {
63+
IFR |= (byte)(0b10000010);
64+
EaterEmulator.cpu.interruptRequested = true;
65+
}
66+
}
67+
68+
public void CA2() {
69+
if ((IER &= (byte)(0b00000010)) == 0b00000001) {
70+
IFR |= (byte)(0b10000001);
71+
EaterEmulator.cpu.interruptRequested = true;
72+
}
73+
}
74+
75+
public void CB1() {
76+
if ((IER &= (byte)(0b00000010)) == 0b00010000) {
77+
IFR |= (byte)(0b10010000);
78+
EaterEmulator.cpu.interruptRequested = true;
79+
}
80+
}
81+
82+
public void CB2() {
83+
if ((IER &= (byte)(0b00000010)) == 0b00001000) {
84+
IFR |= (byte)(0b10001000);
85+
EaterEmulator.cpu.interruptRequested = true;
2886
}
2987
}
3088
}

0 commit comments

Comments
 (0)