mirror of
https://github.com/felipecsl/6502Android.git
synced 2024-06-07 15:48:23 +00:00
Adds some instructions and assembler implementation
This commit is contained in:
parent
895292bc50
commit
54fa43a893
|
@ -3,6 +3,7 @@ package android.emu6502
|
|||
import android.emu6502.instructions.Instruction
|
||||
import android.emu6502.instructions.Opcodes
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.text.Regex
|
||||
|
||||
class Assembler(private var labels: Labels,
|
||||
private var memory: Memory,
|
||||
|
@ -131,60 +132,106 @@ class Assembler(private var labels: Labels,
|
|||
}
|
||||
|
||||
private fun checkAbsolute(param: String, opcode: Int): Boolean {
|
||||
throw UnsupportedOperationException(
|
||||
"not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
if (checkWordOperand("^([\\w\$]+)$")) {
|
||||
return true
|
||||
}
|
||||
|
||||
private fun checkIndirectY(param: String, opcode: Int): Boolean {
|
||||
throw UnsupportedOperationException(
|
||||
"not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
// it could be a label too..
|
||||
return checkLabel(param, opcode, "^\\w+$".toRegex())
|
||||
}
|
||||
|
||||
private fun checkIndirectX(param: String, opcode: Int): Boolean {
|
||||
throw UnsupportedOperationException(
|
||||
"not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
private fun checkWordOperand(param: String, opcode: Int, regex: String): Boolean {
|
||||
val matcher = Pattern.compile(regex, Pattern.CASE_INSENSITIVE).matcher(param)
|
||||
if (!matcher.find()) {
|
||||
return false
|
||||
}
|
||||
return innerCheckWordOperand(matcher.group(1), opcode)
|
||||
}
|
||||
|
||||
private fun checkIndirect(param: String, opcode: Int): Boolean {
|
||||
throw UnsupportedOperationException(
|
||||
"not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
private fun innerCheckWordOperand(param: String, opcode: Int): Boolean {
|
||||
var operand = tryParseWordOperand(param)
|
||||
if (operand < 0) {
|
||||
return false
|
||||
}
|
||||
pushByte(opcode)
|
||||
pushWord(operand)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun checkAbsoluteY(param: String, opcode: Int): Boolean {
|
||||
throw UnsupportedOperationException(
|
||||
"not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
private fun checkByteOperand(param: String, opcode: Int, regex: String): Boolean {
|
||||
val matcher = Pattern.compile(regex, Pattern.CASE_INSENSITIVE).matcher(param)
|
||||
if (!matcher.find()) {
|
||||
return false
|
||||
}
|
||||
return innerCheckByteOperand(matcher.group(1), opcode)
|
||||
}
|
||||
|
||||
private fun checkAbsoluteX(param: String, opcode: Int): Boolean {
|
||||
throw UnsupportedOperationException(
|
||||
"not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
private fun innerCheckByteOperand(param: String, opcode: Int): Boolean {
|
||||
var operand = tryParseByteOperand(param)
|
||||
if (operand < 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
private fun checkZeroPageY(param: String, opcode: Int): Boolean {
|
||||
throw UnsupportedOperationException(
|
||||
"not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
private fun checkZeroPageX(param: String, opcode: Int): Boolean {
|
||||
throw UnsupportedOperationException(
|
||||
"not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
private fun checkZeroPage(param: String, opcode: Int): Boolean {
|
||||
throw UnsupportedOperationException(
|
||||
"not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
private fun checkImmediate(param: String, opcode: Int): Boolean {
|
||||
val pattern = Pattern.compile("^#([\\w\$]+)$")
|
||||
val matcher = pattern.matcher(param)
|
||||
if (matcher.find()) {
|
||||
var operand = tryParseByteOperand(matcher.group(1))
|
||||
if (operand >= 0) {
|
||||
pushByte(opcode)
|
||||
pushByte(operand)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun checkLabel(param: String, opcode: Int, regex: Regex): Boolean {
|
||||
if (param.matches(regex)) {
|
||||
val finalParam = param.replace(",Y", "", true).replace(",X", "", true)
|
||||
pushByte(opcode)
|
||||
if (labels.find(finalParam)) {
|
||||
val addr = (labels.getPC(finalParam))
|
||||
if (addr < 0 || addr > 0xffff) {
|
||||
return false
|
||||
}
|
||||
pushWord(addr)
|
||||
return true
|
||||
} else {
|
||||
pushWord(0xffff) // filler, only used while indexing labels
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun checkIndirectY(param: String, opcode: Int): Boolean {
|
||||
return checkByteOperand(param, opcode, "^\\(([\\w\$]+)\\),Y$")
|
||||
}
|
||||
|
||||
private fun checkIndirectX(param: String, opcode: Int): Boolean {
|
||||
return checkByteOperand(param, opcode, "^\\(([\\w\$]+)\\),X$")
|
||||
}
|
||||
|
||||
private fun checkIndirect(param: String, opcode: Int): Boolean {
|
||||
return checkWordOperand(param, opcode, "^\\(([\\w\$]+)\\)$")
|
||||
}
|
||||
|
||||
private fun checkAbsoluteY(param: String, opcode: Int): Boolean {
|
||||
return checkWordOperand(param, opcode, "^([\\w\$]+),Y$") ||
|
||||
checkLabel(param, opcode, "^\\w+,Y$".toRegex())
|
||||
}
|
||||
|
||||
private fun checkAbsoluteX(param: String, opcode: Int): Boolean {
|
||||
return checkWordOperand(param, opcode, "^([\\w\$]+),X$") ||
|
||||
checkLabel(param, opcode, "^\\w+,X$".toRegex())
|
||||
}
|
||||
|
||||
private fun checkZeroPageY(param: String, opcode: Int): Boolean {
|
||||
return checkByteOperand(param, opcode, "^([\\w\$]+),Y")
|
||||
}
|
||||
|
||||
private fun checkZeroPageX(param: String, opcode: Int): Boolean {
|
||||
return checkByteOperand(param, opcode, "^([\\w\$]+),X")
|
||||
}
|
||||
|
||||
private fun checkZeroPage(param: String, opcode: Int): Boolean {
|
||||
return innerCheckByteOperand(param, opcode)
|
||||
}
|
||||
|
||||
private fun checkImmediate(param: String, opcode: Int): Boolean {
|
||||
if (checkByteOperand(param, opcode, "^#([\\w\$]+)$")) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Label lo/hi
|
||||
|
@ -216,7 +263,7 @@ class Assembler(private var labels: Labels,
|
|||
// Returns the (positive) value if successful, otherwise -1
|
||||
private fun tryParseByteOperand(param: String): Int {
|
||||
var value: Int = 0
|
||||
var parameter = param;
|
||||
var parameter = param
|
||||
|
||||
if (parameter.matches("^\\w+$".toRegex())) {
|
||||
var lookupVal = symbols.lookup(parameter) // Substitute symbol by actual value, then proceed
|
||||
|
@ -246,14 +293,55 @@ class Assembler(private var labels: Labels,
|
|||
return -1
|
||||
}
|
||||
|
||||
private fun tryParseWordOperand(param: String): Int {
|
||||
var value: Int = 0
|
||||
var parameter = param
|
||||
|
||||
if (parameter.matches("^\\w+$".toRegex())) {
|
||||
var lookupVal = symbols.lookup(parameter) // Substitute symbol by actual value, then proceed
|
||||
if (lookupVal != null) {
|
||||
parameter = lookupVal
|
||||
}
|
||||
}
|
||||
|
||||
// Is it a hexadecimal operand?
|
||||
var pattern = Pattern.compile("^\$([0-9a-f]{3,4})$")
|
||||
var matcher = pattern.matcher(parameter)
|
||||
if (matcher.find()) {
|
||||
value = Integer.parseInt(matcher.group(1), 16)
|
||||
} else {
|
||||
// Is it a decimal operand?
|
||||
pattern = Pattern.compile("^([0-9]{1,5})$")
|
||||
matcher = pattern.matcher(parameter)
|
||||
if (matcher.find()) {
|
||||
value = Integer.parseInt(matcher.group(1), 10)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate range
|
||||
if (value >= 0 && value <= 0xffff) {
|
||||
return value
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
private fun pushByte(value: Int) {
|
||||
memory.set(defaultCodePC, value.and(0xFF))
|
||||
memory.set(defaultCodePC, value.and(0xff))
|
||||
defaultCodePC++
|
||||
codeLen++
|
||||
}
|
||||
|
||||
private fun pushWord(value: Int) {
|
||||
pushByte(value.and(0xff))
|
||||
pushByte(value.shr(8).and(0xff))
|
||||
}
|
||||
|
||||
private fun checkSingle(param: String, opcode: Int): Boolean {
|
||||
throw UnsupportedOperationException(
|
||||
"not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
// Accumulator instructions are counted as single-byte opcodes
|
||||
if (!param.equals("") && !param.equals("A")) {
|
||||
return false
|
||||
}
|
||||
pushByte(opcode)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package android.emu6502
|
||||
|
||||
import android.emu6502.instructions.BaseInstruction
|
||||
import android.emu6502.instructions.ORA
|
||||
import android.emu6502.instructions.*
|
||||
import android.util.Log
|
||||
import java.util.HashMap
|
||||
import kotlin.reflect.KMemberFunction0
|
||||
|
||||
|
@ -19,8 +19,66 @@ class CPU(private val memory: Memory) {
|
|||
private var isRunning = false
|
||||
private var debug = false
|
||||
private var monitoring = false
|
||||
|
||||
private var TAG = "CPU"
|
||||
private val instructionList: HashMap<Int, KMemberFunction0<BaseInstruction, Unit>> = HashMap()
|
||||
private val operationList: HashMap<Instruction, BaseInstruction> = hashMapOf(
|
||||
Pair(Instruction.ADC, ADC(instructionList)),
|
||||
Pair(Instruction.AND, AND(instructionList)),
|
||||
Pair(Instruction.ASL, ASL(instructionList)),
|
||||
Pair(Instruction.BIT, BIT(instructionList)),
|
||||
Pair(Instruction.BPL, BPL(instructionList)),
|
||||
Pair(Instruction.BMI, BMI(instructionList)),
|
||||
Pair(Instruction.BVC, BVC(instructionList)),
|
||||
Pair(Instruction.BVS, BVS(instructionList)),
|
||||
Pair(Instruction.BCC, BCC(instructionList)),
|
||||
Pair(Instruction.BCS, BCS(instructionList)),
|
||||
Pair(Instruction.BNE, BNE(instructionList)),
|
||||
Pair(Instruction.BEQ, BEQ(instructionList)),
|
||||
Pair(Instruction.BRK, BRK(instructionList)),
|
||||
Pair(Instruction.CMP, CMP(instructionList)),
|
||||
Pair(Instruction.CPX, CPX(instructionList)),
|
||||
Pair(Instruction.CPY, CPY(instructionList)),
|
||||
Pair(Instruction.DEC, DEC(instructionList)),
|
||||
Pair(Instruction.EOR, EOR(instructionList)),
|
||||
Pair(Instruction.CLC, CLC(instructionList)),
|
||||
Pair(Instruction.SEC, SEC(instructionList)),
|
||||
Pair(Instruction.CLI, CLI(instructionList)),
|
||||
Pair(Instruction.SEI, SEI(instructionList)),
|
||||
Pair(Instruction.CLV, CLV(instructionList)),
|
||||
Pair(Instruction.CLD, CLD(instructionList)),
|
||||
Pair(Instruction.SED, SED(instructionList)),
|
||||
Pair(Instruction.INC, INC(instructionList)),
|
||||
Pair(Instruction.JMP, JMP(instructionList)),
|
||||
Pair(Instruction.JSR, JSR(instructionList)),
|
||||
Pair(Instruction.LDA, LDA(instructionList)),
|
||||
Pair(Instruction.LDX, LDX(instructionList)),
|
||||
Pair(Instruction.LDY, LDY(instructionList)),
|
||||
Pair(Instruction.LSR, LSR(instructionList)),
|
||||
Pair(Instruction.NOP, NOP(instructionList)),
|
||||
Pair(Instruction.ORA, ORA(instructionList)),
|
||||
Pair(Instruction.TAX, TAX(instructionList)),
|
||||
Pair(Instruction.TXA, TXA(instructionList)),
|
||||
Pair(Instruction.DEX, DEX(instructionList)),
|
||||
Pair(Instruction.INX, INX(instructionList)),
|
||||
Pair(Instruction.TAY, TAY(instructionList)),
|
||||
Pair(Instruction.TYA, TYA(instructionList)),
|
||||
Pair(Instruction.DEY, DEY(instructionList)),
|
||||
Pair(Instruction.INY, INY(instructionList)),
|
||||
Pair(Instruction.ROR, ROR(instructionList)),
|
||||
Pair(Instruction.ROL, ROL(instructionList)),
|
||||
Pair(Instruction.RTI, RTI(instructionList)),
|
||||
Pair(Instruction.RTS, RTS(instructionList)),
|
||||
Pair(Instruction.SBC, SBC(instructionList)),
|
||||
Pair(Instruction.STA, STA(instructionList)),
|
||||
Pair(Instruction.TXS, TXS(instructionList)),
|
||||
Pair(Instruction.TSX, TSX(instructionList)),
|
||||
Pair(Instruction.PHA, PHA(instructionList)),
|
||||
Pair(Instruction.PLA, PLA(instructionList)),
|
||||
Pair(Instruction.PHP, PHP(instructionList)),
|
||||
Pair(Instruction.PLP, PLP(instructionList)),
|
||||
Pair(Instruction.STX, STX(instructionList)),
|
||||
Pair(Instruction.STY, STY(instructionList))
|
||||
)
|
||||
|
||||
fun execute() {
|
||||
setRandomByte()
|
||||
|
@ -28,8 +86,7 @@ class CPU(private val memory: Memory) {
|
|||
|
||||
if (PC == 0 || !isRunning) {
|
||||
stop()
|
||||
// message("Program end at PC=$" + addr2hex(regPC - 1))
|
||||
// ui.stop()
|
||||
Log.i(TAG, "Program end at PC=$" + (PC - 1))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,10 +97,11 @@ class CPU(private val memory: Memory) {
|
|||
private fun executeNextInstruction() {
|
||||
val instruction = Integer.valueOf(popByte().toInt().toString(), 16)
|
||||
val function = instructionList.get(instruction)
|
||||
if (function != null) {
|
||||
ORA(instructionList).function()
|
||||
// else {
|
||||
// instructions.ierr()
|
||||
// }
|
||||
} else {
|
||||
Log.e(TAG, "Address $" + PC + " - unknown opcode")
|
||||
}
|
||||
}
|
||||
|
||||
private fun popByte(): Byte {
|
||||
|
|
9
app/src/main/kotlin/android/emu6502/instructions/ADC.kt
Normal file
9
app/src/main/kotlin/android/emu6502/instructions/ADC.kt
Normal file
|
@ -0,0 +1,9 @@
|
|||
package android.emu6502.instructions
|
||||
|
||||
import java.util.*
|
||||
import kotlin.reflect.KMemberFunction0
|
||||
|
||||
/** ADd with Carry */
|
||||
class ADC(instructionList: HashMap<Int, KMemberFunction0<BaseInstruction, Unit>>)
|
||||
: BaseInstruction(Instruction.ADC, instructionList) {
|
||||
}
|
9
app/src/main/kotlin/android/emu6502/instructions/AND.kt
Normal file
9
app/src/main/kotlin/android/emu6502/instructions/AND.kt
Normal file
|
@ -0,0 +1,9 @@
|
|||
package android.emu6502.instructions
|
||||
|
||||
import java.util.*
|
||||
import kotlin.reflect.KMemberFunction0
|
||||
|
||||
/** bitwise AND with accumulator */
|
||||
class AND(instructionList: HashMap<Int, KMemberFunction0<BaseInstruction, Unit>>)
|
||||
: BaseInstruction(Instruction.AND, instructionList) {
|
||||
}
|
9
app/src/main/kotlin/android/emu6502/instructions/ASL.kt
Normal file
9
app/src/main/kotlin/android/emu6502/instructions/ASL.kt
Normal file
|
@ -0,0 +1,9 @@
|
|||
package android.emu6502.instructions
|
||||
|
||||
import java.util.*
|
||||
import kotlin.reflect.KMemberFunction0
|
||||
|
||||
/** Arithmetic Shift Left */
|
||||
class ASL(instructionList: HashMap<Int, KMemberFunction0<BaseInstruction, Unit>>)
|
||||
: BaseInstruction(Instruction.ASL, instructionList) {
|
||||
}
|
9
app/src/main/kotlin/android/emu6502/instructions/LDX.kt
Normal file
9
app/src/main/kotlin/android/emu6502/instructions/LDX.kt
Normal file
|
@ -0,0 +1,9 @@
|
|||
package android.emu6502.instructions
|
||||
|
||||
import java.util.*
|
||||
import kotlin.reflect.KMemberFunction0
|
||||
|
||||
/** LoaD X register */
|
||||
class LDX(instructionList: HashMap<Int, KMemberFunction0<BaseInstruction, Unit>>)
|
||||
: BaseInstruction(Instruction.LDX, instructionList) {
|
||||
}
|
10
app/src/main/kotlin/android/emu6502/instructions/STX.kt
Normal file
10
app/src/main/kotlin/android/emu6502/instructions/STX.kt
Normal file
|
@ -0,0 +1,10 @@
|
|||
package android.emu6502.instructions
|
||||
|
||||
|
||||
import java.util.*
|
||||
import kotlin.reflect.KMemberFunction0
|
||||
|
||||
/** STore X register */
|
||||
class STX(instructionList: HashMap<Int, KMemberFunction0<BaseInstruction, Unit>>)
|
||||
: BaseInstruction(Instruction.STX, instructionList) {
|
||||
}
|
Loading…
Reference in New Issue
Block a user