diff --git a/COPYING b/COPYING index 7b38a42..400850c 100644 --- a/COPYING +++ b/COPYING @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2008,2009 Seth J. Morabito +Copyright (c) 2008-2010 Seth J. Morabito Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README b/README index a4984a2..3b0f058 100644 --- a/README +++ b/README @@ -11,8 +11,8 @@ deemed ready for testing, it will be given a version number of "0.1". ==================================================================== Version: PRERELEASE -Last Updated: 07 January, 2009 -Copyright (c) 2008,2009 Seth J. Morabito +Last Updated: 10 January, 2010 +Copyright (c) 2008-2010 Seth J. Morabito See the file COPYING for license. @@ -36,7 +36,7 @@ ACIAs. More functionality may be considered as time goes on. - Java 1.5 or higher - Maven 2.0.x or higher (for building from source) - - JUnit 3.0 or higher (for testing) + - JUnit 4 or higher (for testing) (More to come!) @@ -44,25 +44,8 @@ ACIAs. More functionality may be considered as time goes on. --------- - Finish core functionality. -- Implement remaining addressing modes. - - COMPLETED ADDRESSING MODES: - o Implied - o Immediate - o Zero Page - o Accumulator - o Absolute - o Indirect [used only by JMP] - o Zero Page, X-indexed - o Zero Page, Y-indexed - o Absolute, X-indexed - o Absolute, Y-indexed - o Relative - - INCOMPLETE ADDRESSING MODES: - o Indexed Indirect [ (Indirect ,X) ] - o Indirect Indexed [ (Indirect),Y ] - +- Finish command monitor. +- Refactor address decoding (second refactor to DRY up more). - Clean up JavaDoc. - Implement CMOS 65C02 instructions and NMOS / CMOS mode flag. diff --git a/pom.xml b/pom.xml index b31dc1a..ca4acba 100644 --- a/pom.xml +++ b/pom.xml @@ -11,21 +11,21 @@ junit junit - 3.8.1 + 4.7 test - + org.apache.maven.plugins maven-compiler-plugin - 5 - 5 + 1.5 + 1.5 diff --git a/src/main/java/com/loomcom/symon/CommandParser.java b/src/main/java/com/loomcom/symon/CommandParser.java index 75030c9..1b3d927 100644 --- a/src/main/java/com/loomcom/symon/CommandParser.java +++ b/src/main/java/com/loomcom/symon/CommandParser.java @@ -29,11 +29,11 @@ public class CommandParser { System.exit(1); } } - + public void setSimulator(Simulator sim) { this.simulator = sim; } - + public Simulator getSimulator() { return this.simulator; } diff --git a/src/main/java/com/loomcom/symon/Cpu.java b/src/main/java/com/loomcom/symon/Cpu.java index af30fb1..d35a0b4 100644 --- a/src/main/java/com/loomcom/symon/Cpu.java +++ b/src/main/java/com/loomcom/symon/Cpu.java @@ -192,8 +192,8 @@ public class Cpu implements InstructionTable { case 1: switch(irAddressMode) { case 0: // (Zero Page,X) - // TODO: UNIT TESTS - effectiveAddress = bus.read(zpxAddress(args[0])); + tmp = args[0] + getXRegister(); + effectiveAddress = address(bus.read(tmp), bus.read(tmp + 1)); effectiveData = bus.read(effectiveAddress); break; case 1: // Zero Page @@ -209,11 +209,12 @@ public class Cpu implements InstructionTable { effectiveData = bus.read(effectiveAddress); break; case 4: // (Zero Page),Y - // TODO: UNIT TESTS - effectiveAddress = yAddress(bus.read(args[0]), getYRegister()); + tmp = address(bus.read(args[0]), + bus.read((args[0]+1)&0xff)); + effectiveAddress = (tmp + getYRegister())&0xffff; effectiveData = bus.read(effectiveAddress); break; - case 5: // Zero Page, X + case 5: // Zero Page,X effectiveAddress = zpxAddress(args[0]); effectiveData = bus.read(effectiveAddress); break; @@ -418,14 +419,14 @@ public class Cpu implements InstructionTable { /** ASL - Arithmetic Shift Left *****************************************/ - case 0x0a: // ASL - Accumulator + case 0x0a: // Accumulator a = asl(a); setArithmeticFlags(a); break; - case 0x06: // ASL - Zero Page - case 0x0e: // ASL - Absolute - case 0x16: // ASL - Zero Page,X - case 0x1e: // ASL - Absolute,X + case 0x06: // Zero Page + case 0x0e: // Absolute + case 0x16: // Zero Page,X + case 0x1e: // Absolute,X tmp = asl(effectiveData); bus.write(effectiveAddress, tmp); setArithmeticFlags(tmp); @@ -457,14 +458,14 @@ public class Cpu implements InstructionTable { /** ROL - Rotate Left ***************************************************/ - case 0x2a: // ROL - Accumulator + case 0x2a: // Accumulator a = rol(a); setArithmeticFlags(a); break; - case 0x26: // ROL - Zero Page - case 0x2e: // ROL - Absolute - case 0x36: // ROL - Zero Page,X - case 0x3e: // ROL - Absolute,X + case 0x26: // Zero Page + case 0x2e: // Absolute + case 0x36: // Zero Page,X + case 0x3e: // Absolute,X tmp = rol(effectiveData); bus.write(effectiveAddress, tmp); setArithmeticFlags(tmp); @@ -472,28 +473,28 @@ public class Cpu implements InstructionTable { /** EOR - Exclusive OR **************************************************/ - case 0x41: // EOR - (Zero Page, X) - case 0x45: // EOR - Zero Page - case 0x49: // EOR - Immediate - case 0x4d: // EOR - Absolute - case 0x51: // EOR - (Zero Page,Y) - case 0x55: // EOR - Zero Page,X - case 0x59: // EOR - Absolute,Y - case 0x5d: // EOR - Absolute,X + case 0x41: // (Zero Page,X) + case 0x45: // Zero Page + case 0x49: // Immediate + case 0x4d: // Absolute + case 0x51: // (Zero Page,Y) + case 0x55: // Zero Page,X + case 0x59: // Absolute,Y + case 0x5d: // Absolute,X a ^= effectiveData; setArithmeticFlags(a); break; /** LSR - Logical Shift Right *******************************************/ - case 0x4a: // LSR - Accumulator + case 0x4a: // Accumulator a = lsr(a); setArithmeticFlags(a); break; - case 0x46: // LSR - Zero Page - case 0x4e: // LSR - Absolute - case 0x56: // LSR - Zero Page,X - case 0x5e: // LSR - Absolute,X + case 0x46: // Zero Page + case 0x4e: // Absolute + case 0x56: // Zero Page,X + case 0x5e: // Absolute,X tmp = lsr(effectiveData); bus.write(effectiveAddress, tmp); setArithmeticFlags(tmp); @@ -533,7 +534,7 @@ public class Cpu implements InstructionTable { /** STA - Store Accumulator *********************************************/ - case 0x81: // (Zero Page, X) + case 0x81: // (Zero Page,X) case 0x85: // Zero Page case 0x8d: // Absolute case 0x91: // (Zero Page),Y @@ -564,11 +565,11 @@ public class Cpu implements InstructionTable { /** LDY - Load Y Register ***********************************************/ - case 0xa0: // LDY - Immediate - case 0xa4: // LDY - Zero Page - case 0xac: // LDY - Absolute - case 0xb4: // LDY - Zero Page,X - case 0xbc: // LDY - Absolute,X + case 0xa0: // Immediate + case 0xa4: // Zero Page + case 0xac: // Absolute + case 0xb4: // Zero Page,X + case 0xbc: // Absolute,X y = effectiveData; setArithmeticFlags(y); break; @@ -586,7 +587,7 @@ public class Cpu implements InstructionTable { /** LDA - Load Accumulator **********************************************/ - case 0xa1: // Zero Page, X) + case 0xa1: // (Zero Page,X) case 0xa5: // Zero Page case 0xa9: // Immediate case 0xad: // Absolute @@ -608,11 +609,11 @@ public class Cpu implements InstructionTable { /** CMP - Compare Accumulator *******************************************/ - case 0xc1: // (Zero Page, X) + case 0xc1: // (Zero Page,X) case 0xc5: // Zero Page case 0xc9: // #Immediate case 0xcd: // Absolute - case 0xd1: // (Zero Page), Y + case 0xd1: // (Zero Page),Y case 0xd5: // Zero Page,X case 0xd9: // Absolute,Y case 0xdd: // Absolute,X @@ -623,7 +624,7 @@ public class Cpu implements InstructionTable { /** DEC - Decrement Memory **********************************************/ case 0xc6: // Zero Page case 0xce: // Absolute - case 0xd6: // Zero Page, X + case 0xd6: // Zero Page,X case 0xde: // Absolute,X tmp = --effectiveData & 0xff; bus.write(effectiveAddress, tmp); @@ -640,11 +641,11 @@ public class Cpu implements InstructionTable { /** SBC - Subtract with Carry (Borrow) **********************************/ - case 0xe1: // (Zero Page, X) + case 0xe1: // (Zero Page,X) case 0xe5: // Zero Page case 0xe9: // Immediate case 0xed: // Absolute - case 0xf1: // (Zero Page), Y + case 0xf1: // (Zero Page),Y case 0xf5: // Zero Page,X case 0xf9: // Absolute,Y case 0xfd: // Absolute,X @@ -1255,7 +1256,7 @@ public class Cpu implements InstructionTable { * Given two bytes, return an address. */ int address(int lowByte, int hiByte) { - return ((hiByte<<8)|lowByte); + return ((hiByte<<8)|lowByte) & 0xffff; } /** @@ -1313,8 +1314,34 @@ public class Cpu implements InstructionTable { case ABS: sb.append(String.format(" $%04X", address(op1, op2))); break; + case ABX: + sb.append(String.format(" $%04X,X", address(op1, op2))); + break; + case ABY: + sb.append(String.format(" $%04X,Y", address(op1, op2))); + break; case IMM: sb.append(String.format(" #$%02X", op1)); + break; + case IND: + sb.append(String.format(" ($%04X)", address(op1, op2))); + break; + case XIN: + sb.append(String.format(" ($%02X),X", op1)); + break; + case INY: + sb.append(String.format(" ($%02X,Y)", op1)); + break; + case REL: + case ZPG: + sb.append(String.format(" $%02X", op1)); + break; + case ZPX: + sb.append(String.format(" $%02X,X", op1)); + break; + case ZPY: + sb.append(String.format(" $%02X,Y", op1)); + break; } return sb.toString(); diff --git a/src/test/java/com/loomcom/symon/CpuIndexedIndirectModeTest.java b/src/test/java/com/loomcom/symon/CpuIndexedIndirectModeTest.java new file mode 100644 index 0000000..72eaa76 --- /dev/null +++ b/src/test/java/com/loomcom/symon/CpuIndexedIndirectModeTest.java @@ -0,0 +1,82 @@ +package com.loomcom.symon; + +import com.loomcom.symon.devices.Memory; +import com.loomcom.symon.exceptions.MemoryAccessException; + +import org.junit.*; +import static org.junit.Assert.*; + +public class CpuIndexedIndirectModeTest { + + protected Cpu cpu; + protected Bus bus; + protected Memory mem; + + @Before + public void runBeforeEveryTest() throws Exception { + this.cpu = new Cpu(); + this.bus = new Bus(0x0000, 0xffff); + this.mem = new Memory(0x0000, 0x10000); + bus.addCpu(cpu); + bus.addDevice(mem); + + // Load the reset vector. + bus.write(0xfffc, Cpu.DEFAULT_BASE_ADDRESS & 0x00ff); + bus.write(0xfffd, (Cpu.DEFAULT_BASE_ADDRESS & 0xff00)>>>8); + + cpu.reset(); + // Assert initial state + assertEquals(0, cpu.getAccumulator()); + assertEquals(0, cpu.getXRegister()); + assertEquals(0, cpu.getYRegister()); + assertEquals(0x200, cpu.getProgramCounter()); + assertEquals(0xff, cpu.getStackPointer()); + assertEquals(0x20, cpu.getProcessorStatus()); + } + + @Test + public void test_LDA() throws Exception { + bus.write(0x008c, 0x3f); + bus.write(0x008d, 0xc4); + bus.write(0xc43f, 0x45); + + cpu.setXRegister(0x0c); + + bus.loadProgram(0xa1, 0x80); // LDA ($80,X) + cpu.step(1); + + assertEquals(0x45, cpu.getAccumulator()); + } + + @Test + public void test_ORA() throws Exception { + bus.write(0x0012, 0x1f); + bus.write(0x0013, 0xc5); + bus.write(0xc51f, 0x31); + + cpu.setXRegister(0x02); + cpu.setAccumulator(0x15); + + bus.loadProgram(0x01, 0x10); // ORA ($10,X) + cpu.step(1); + + assertEquals(0x35, cpu.getAccumulator()); + assertEquals(0x31, bus.read(0xc51f)); + } + + @Test + public void test_AND() throws Exception { + bus.write(0x0012, 0x1f); + bus.write(0x0013, 0xc5); + bus.write(0xc51f, 0x31); + + cpu.setXRegister(0x02); + cpu.setAccumulator(0x15); + + bus.loadProgram(0x21, 0x10); // AND ($10,X) + cpu.step(1); + + assertEquals(0x11, cpu.getAccumulator()); + assertEquals(0x31, bus.read(0xc51f)); + } +} \ No newline at end of file diff --git a/src/test/java/com/loomcom/symon/CpuIndirectIndexedModeTest.java b/src/test/java/com/loomcom/symon/CpuIndirectIndexedModeTest.java new file mode 100644 index 0000000..3ec80f0 --- /dev/null +++ b/src/test/java/com/loomcom/symon/CpuIndirectIndexedModeTest.java @@ -0,0 +1,84 @@ +package com.loomcom.symon; + +import com.loomcom.symon.devices.Memory; +import com.loomcom.symon.exceptions.MemoryAccessException; + +import org.junit.*; +import static org.junit.Assert.*; + +public class CpuIndirectIndexedModeTest { + + protected Cpu cpu; + protected Bus bus; + protected Memory mem; + + @Before + public void runBeforeEveryTest() throws Exception { + this.cpu = new Cpu(); + this.bus = new Bus(0x0000, 0xffff); + this.mem = new Memory(0x0000, 0x10000); + bus.addCpu(cpu); + bus.addDevice(mem); + + // Load the reset vector. + bus.write(0xfffc, Cpu.DEFAULT_BASE_ADDRESS & 0x00ff); + bus.write(0xfffd, (Cpu.DEFAULT_BASE_ADDRESS & 0xff00)>>>8); + + cpu.reset(); + // Assert initial state + assertEquals(0, cpu.getAccumulator()); + assertEquals(0, cpu.getXRegister()); + assertEquals(0, cpu.getYRegister()); + assertEquals(0x200, cpu.getProgramCounter()); + assertEquals(0xff, cpu.getStackPointer()); + assertEquals(0x20, cpu.getProcessorStatus()); + } + + @Test + public void test_LDA() throws Exception { + assertEquals(cpu.toString(), 0x00, cpu.getAccumulator()); + bus.write(0x0014, 0x00); + bus.write(0x0015, 0xd8); + bus.write(0xd828, 0x03); + + cpu.setYRegister(0x28); + + bus.loadProgram(0xb1, 0x14); // LDA ($14),Y + cpu.step(1); + + assertEquals(0x03, cpu.getAccumulator()); + } + + @Test + public void test_ORA() throws Exception { + bus.write(0x0014, 0x00); + bus.write(0x0015, 0xd8); + bus.write(0xd828, 0xe3); + + cpu.setYRegister(0x28); + cpu.setAccumulator(0x32); + + bus.loadProgram(0x11, 0x14); // ORA ($14),Y + cpu.step(1); + + assertEquals(0xf3, cpu.getAccumulator()); + assertEquals(0xe3, bus.read(0xd828)); + } + + @Test + public void test_AND() throws Exception { + bus.write(0x0014, 0x00); + bus.write(0x0015, 0xd8); + bus.write(0xd828, 0xe3); + + cpu.setYRegister(0x28); + cpu.setAccumulator(0x32); + + bus.loadProgram(0x31, 0x14); // AND ($14),Y + cpu.step(1); + + assertEquals(0x22, cpu.getAccumulator()); + assertEquals(0xe3, bus.read(0xd828)); + } + +} \ No newline at end of file