mirror of
https://github.com/felipecsl/6502Android.git
synced 2024-06-07 15:48:23 +00:00
Adds more instructions
This commit is contained in:
parent
b793402c90
commit
908f42587b
|
@ -21,6 +21,9 @@ android {
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main.java.srcDirs += 'src/main/kotlin'
|
main.java.srcDirs += 'src/main/kotlin'
|
||||||
}
|
}
|
||||||
|
testOptions {
|
||||||
|
unitTests.returnDefaultValues = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
|
@ -35,6 +35,8 @@ class CPU(private val memory: Memory) {
|
||||||
Pair(Instruction.LDY, LDY(this)),
|
Pair(Instruction.LDY, LDY(this)),
|
||||||
Pair(Instruction.STA, STA(memory, this)),
|
Pair(Instruction.STA, STA(memory, this)),
|
||||||
Pair(Instruction.STX, STX(this)),
|
Pair(Instruction.STX, STX(this)),
|
||||||
|
Pair(Instruction.TAX, TAX(this)),
|
||||||
|
Pair(Instruction.INX, INX(this)),
|
||||||
Pair(Instruction.ORA, ORA(this))
|
Pair(Instruction.ORA, ORA(this))
|
||||||
// Pair(Instruction.BPL, BPL(this)),
|
// Pair(Instruction.BPL, BPL(this)),
|
||||||
// Pair(Instruction.BMI, BMI(this)),
|
// Pair(Instruction.BMI, BMI(this)),
|
||||||
|
@ -62,10 +64,8 @@ class CPU(private val memory: Memory) {
|
||||||
// Pair(Instruction.JSR, JSR(this)),
|
// Pair(Instruction.JSR, JSR(this)),
|
||||||
// Pair(Instruction.LSR, LSR(this)),
|
// Pair(Instruction.LSR, LSR(this)),
|
||||||
// Pair(Instruction.NOP, NOP(this)),
|
// Pair(Instruction.NOP, NOP(this)),
|
||||||
// Pair(Instruction.TAX, TAX(this)),
|
|
||||||
// Pair(Instruction.TXA, TXA(this)),
|
// Pair(Instruction.TXA, TXA(this)),
|
||||||
// Pair(Instruction.DEX, DEX(this)),
|
// Pair(Instruction.DEX, DEX(this)),
|
||||||
// Pair(Instruction.INX, INX(this)),
|
|
||||||
// Pair(Instruction.TAY, TAY(this)),
|
// Pair(Instruction.TAY, TAY(this)),
|
||||||
// Pair(Instruction.TYA, TYA(this)),
|
// Pair(Instruction.TYA, TYA(this)),
|
||||||
// Pair(Instruction.DEY, DEY(this)),
|
// Pair(Instruction.DEY, DEY(this)),
|
||||||
|
@ -94,7 +94,7 @@ class CPU(private val memory: Memory) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isRunning = false
|
stop()
|
||||||
Log.i(TAG, "Program end at PC=$" + (PC - 1).toHexString() + ", A=$" + A.toHexString() +
|
Log.i(TAG, "Program end at PC=$" + (PC - 1).toHexString() + ", A=$" + A.toHexString() +
|
||||||
", X=$" + X.toHexString() + ", Y=$" + Y.toHexString())
|
", X=$" + X.toHexString() + ", Y=$" + Y.toHexString())
|
||||||
}
|
}
|
||||||
|
@ -107,12 +107,16 @@ class CPU(private val memory: Memory) {
|
||||||
target.operation.function()
|
target.operation.function()
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "Address $" + PC.toHexString() + " - unknown opcode " + instruction.toHexString())
|
Log.e(TAG, "Address $" + PC.toHexString() + " - unknown opcode " + instruction.toHexString())
|
||||||
isRunning = false
|
stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun stop() {
|
||||||
|
isRunning = false
|
||||||
|
}
|
||||||
|
|
||||||
fun popByte(): Int {
|
fun popByte(): Int {
|
||||||
return memory.get(PC++).and(0xff);
|
return memory.get(PC++).and(0xff)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setRandomByte() {
|
private fun setRandomByte() {
|
||||||
|
@ -123,20 +127,107 @@ class CPU(private val memory: Memory) {
|
||||||
setSZFlagsForValue(A)
|
setSZFlagsForValue(A)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setSZflagsForRegX() {
|
||||||
|
setSZFlagsForValue(X)
|
||||||
|
}
|
||||||
|
|
||||||
private fun setSZFlagsForValue(value: Int) {
|
private fun setSZFlagsForValue(value: Int) {
|
||||||
if (value != 0) {
|
if (value != 0) {
|
||||||
P = P.and(0xfd);
|
P = P.and(0xfd)
|
||||||
} else {
|
} else {
|
||||||
P = P.or(0x02);
|
P = P.or(0x02)
|
||||||
}
|
}
|
||||||
if (value.and(0x80) != 0) {
|
if (value.and(0x80) != 0) {
|
||||||
P = P.or(0x80);
|
P = P.or(0x80)
|
||||||
} else {
|
} else {
|
||||||
P = P.and(0x7f);
|
P = P.and(0x7f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun popWord(): Int {
|
fun popWord(): Int {
|
||||||
return popByte() + popByte().shl(8)
|
return popByte() + popByte().shl(8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testADC(value: Int) {
|
||||||
|
var tmp: Int
|
||||||
|
if (A.xor(value).and(0x80) != 0) {
|
||||||
|
CLV()
|
||||||
|
} else {
|
||||||
|
setOverflow()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decimalMode().isSet()) {
|
||||||
|
tmp = A.and(0xf) + value.and(0xf) + carry()
|
||||||
|
if (tmp >= 10) {
|
||||||
|
tmp = 0x10.or((tmp + 6).and(0xf))
|
||||||
|
}
|
||||||
|
tmp += A.and(0xf0) + value.and(0xf0)
|
||||||
|
if (tmp >= 160) {
|
||||||
|
SEC()
|
||||||
|
if (overflow().isSet() && tmp >= 0x180) {
|
||||||
|
CLV()
|
||||||
|
}
|
||||||
|
tmp += 0x60
|
||||||
|
} else {
|
||||||
|
CLC()
|
||||||
|
if (overflow().isSet() && tmp < 0x80) {
|
||||||
|
CLV()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tmp = A + value + carry()
|
||||||
|
if (tmp >= 0x100) {
|
||||||
|
SEC()
|
||||||
|
if (overflow().isSet() && tmp >= 0x180) {
|
||||||
|
CLV()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CLC()
|
||||||
|
if (overflow().isSet() && tmp < 0x80) {
|
||||||
|
CLV()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
A = tmp.and(0xff)
|
||||||
|
setSZFlagsForRegA()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun overflow(): Int {
|
||||||
|
return P.and(0x40)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun decimalMode(): Int {
|
||||||
|
return P.and(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun carry(): Int {
|
||||||
|
return P.and(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun negative(): Int {
|
||||||
|
return P.and(0x80);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun zero(): Int {
|
||||||
|
return P.and(0x02);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** CLear Carry */
|
||||||
|
fun CLC() {
|
||||||
|
P = P.and(0xfe)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** SEt Carry */
|
||||||
|
fun SEC() {
|
||||||
|
P = P.or(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** CLear oVerflow */
|
||||||
|
fun CLV() {
|
||||||
|
P = P.and(0xbf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setOverflow() {
|
||||||
|
P = P.or(0x40)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -3,3 +3,7 @@ package android.emu6502
|
||||||
fun Int.toHexString(): String {
|
fun Int.toHexString(): String {
|
||||||
return java.lang.String.format("%02X", this);
|
return java.lang.String.format("%02X", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Int.isSet(): Boolean {
|
||||||
|
return this != 0
|
||||||
|
}
|
|
@ -5,6 +5,8 @@ import android.emu6502.instructions.BaseInstruction
|
||||||
import android.emu6502.instructions.Instruction
|
import android.emu6502.instructions.Instruction
|
||||||
|
|
||||||
/** ADd with Carry */
|
/** ADd with Carry */
|
||||||
class ADC(cpu: CPU)
|
class ADC(private val cpu: CPU) : BaseInstruction(Instruction.ADC, cpu.instructionList) {
|
||||||
: BaseInstruction(Instruction.ADC, cpu.instructionList) {
|
override fun immediate() {
|
||||||
|
cpu.testADC(cpu.popByte())
|
||||||
|
}
|
||||||
}
|
}
|
12
app/src/main/kotlin/android/emu6502/instructions/impl/BRK.kt
Normal file
12
app/src/main/kotlin/android/emu6502/instructions/impl/BRK.kt
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package android.emu6502.instructions.impl
|
||||||
|
|
||||||
|
import android.emu6502.CPU
|
||||||
|
import android.emu6502.instructions.BaseInstruction
|
||||||
|
import android.emu6502.instructions.Instruction
|
||||||
|
|
||||||
|
/** BRreaK */
|
||||||
|
final class BRK(private val cpu: CPU) : BaseInstruction(Instruction.INX, cpu.instructionList) {
|
||||||
|
override fun single() {
|
||||||
|
cpu.stop()
|
||||||
|
}
|
||||||
|
}
|
13
app/src/main/kotlin/android/emu6502/instructions/impl/INX.kt
Normal file
13
app/src/main/kotlin/android/emu6502/instructions/impl/INX.kt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package android.emu6502.instructions.impl
|
||||||
|
|
||||||
|
import android.emu6502.CPU
|
||||||
|
import android.emu6502.instructions.BaseInstruction
|
||||||
|
import android.emu6502.instructions.Instruction
|
||||||
|
|
||||||
|
/** INcrement X */
|
||||||
|
class INX(private val cpu: CPU) : BaseInstruction(Instruction.INX, cpu.instructionList) {
|
||||||
|
override fun single() {
|
||||||
|
cpu.X = (cpu.X + 1).and(0xff)
|
||||||
|
cpu.setSZflagsForRegX()
|
||||||
|
}
|
||||||
|
}
|
13
app/src/main/kotlin/android/emu6502/instructions/impl/TAX.kt
Normal file
13
app/src/main/kotlin/android/emu6502/instructions/impl/TAX.kt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package android.emu6502.instructions.impl
|
||||||
|
|
||||||
|
import android.emu6502.CPU
|
||||||
|
import android.emu6502.instructions.BaseInstruction
|
||||||
|
import android.emu6502.instructions.Instruction
|
||||||
|
|
||||||
|
/** Transfer A to X */
|
||||||
|
class TAX(private val cpu: CPU) : BaseInstruction(Instruction.TAX, cpu.instructionList) {
|
||||||
|
override fun single() {
|
||||||
|
cpu.X = cpu.A.and(0xFF)
|
||||||
|
cpu.setSZflagsForRegX()
|
||||||
|
}
|
||||||
|
}
|
76
app/src/test/java/android/emu6502/CPUTest.java
Normal file
76
app/src/test/java/android/emu6502/CPUTest.java
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
package android.emu6502;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
import android.emu6502.instructions.Symbols;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
public class CPUTest {
|
||||||
|
|
||||||
|
private CPU cpu;
|
||||||
|
private Assembler assembler;
|
||||||
|
|
||||||
|
@Before public void setUp() {
|
||||||
|
Memory memory = new Memory(new Display());
|
||||||
|
assembler = new Assembler(memory, new Symbols());
|
||||||
|
cpu = new CPU(memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testSimple() {
|
||||||
|
List<String> lines = ImmutableList.of(
|
||||||
|
"LDA #$01",
|
||||||
|
"STA $0200",
|
||||||
|
"LDA #$05",
|
||||||
|
"STA $0201",
|
||||||
|
"LDA #$08",
|
||||||
|
"STA $0202");
|
||||||
|
assembler.assembleCode(lines);
|
||||||
|
cpu.execute();
|
||||||
|
assertThat(cpu.getA(), equalTo(0x08));
|
||||||
|
assertThat(cpu.getX(), equalTo(0x00));
|
||||||
|
assertThat(cpu.getY(), equalTo(0x00));
|
||||||
|
assertThat(cpu.getSP(), equalTo(0xFF));
|
||||||
|
assertThat(cpu.getPC(), equalTo(0x0610));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testWithComments() {
|
||||||
|
List<String> lines = ImmutableList.of(
|
||||||
|
"LDA #$c0 ;Load the hex value $c0 into the A register",
|
||||||
|
"TAX ;Transfer the value in the A register to X",
|
||||||
|
"INX ;Increment the value in the X register",
|
||||||
|
"ADC #$c4 ;Add the hex value $c4 to the A register",
|
||||||
|
"BRK ;Break - we're done");
|
||||||
|
assembler.assembleCode(lines);
|
||||||
|
cpu.execute();
|
||||||
|
assertThat(cpu.getA(), equalTo(0x84));
|
||||||
|
assertThat(cpu.getX(), equalTo(0xC1));
|
||||||
|
assertThat(cpu.getY(), equalTo(0x00));
|
||||||
|
assertThat(cpu.getSP(), equalTo(0xFF));
|
||||||
|
assertThat(cpu.getPC(), equalTo(0x0607));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testBranchAndLabel() {
|
||||||
|
List<String> lines = ImmutableList.of(
|
||||||
|
"LDX #$08",
|
||||||
|
"decrement:",
|
||||||
|
"DEX",
|
||||||
|
"STX $0200",
|
||||||
|
"CPX #$03",
|
||||||
|
"BNE decrement",
|
||||||
|
"STX $0201",
|
||||||
|
"BRK");
|
||||||
|
assembler.assembleCode(lines);
|
||||||
|
assertThat(cpu.getA(), equalTo(0x00));
|
||||||
|
assertThat(cpu.getX(), equalTo(0x03));
|
||||||
|
assertThat(cpu.getY(), equalTo(0x00));
|
||||||
|
assertThat(cpu.getSP(), equalTo(0xFF));
|
||||||
|
assertThat(cpu.getPC(), equalTo(0x060e));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user