├── .gitignore ├── .travis.yml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ ├── kotlin │ │ └── android │ │ │ └── emu6502 │ │ │ ├── Assembler.kt │ │ │ ├── CPU.kt │ │ │ ├── Display.kt │ │ │ ├── Emu6502Application.kt │ │ │ ├── Emulator.kt │ │ │ ├── ExtensionFunctions.kt │ │ │ ├── Labels.kt │ │ │ ├── Memory.kt │ │ │ ├── Utils.kt │ │ │ ├── app │ │ │ └── MainActivity.kt │ │ │ └── instructions │ │ │ ├── AddressingMode.kt │ │ │ ├── BaseInstruction.kt │ │ │ ├── Instruction.kt │ │ │ ├── InstructionMode.kt │ │ │ ├── InstructionTarget.kt │ │ │ ├── Opcodes.kt │ │ │ ├── Symbols.kt │ │ │ └── impl │ │ │ ├── ADC.kt │ │ │ ├── AND.kt │ │ │ ├── ASL.kt │ │ │ ├── BCC.kt │ │ │ ├── BCS.kt │ │ │ ├── BEQ.kt │ │ │ ├── BIT.kt │ │ │ ├── BNE.kt │ │ │ ├── BPL.kt │ │ │ ├── BRK.kt │ │ │ ├── CLC.kt │ │ │ ├── CMP.kt │ │ │ ├── CPX.kt │ │ │ ├── DEC.kt │ │ │ ├── DEX.kt │ │ │ ├── DEY.kt │ │ │ ├── INC.kt │ │ │ ├── INX.kt │ │ │ ├── JMP.kt │ │ │ ├── JSR.kt │ │ │ ├── LDA.kt │ │ │ ├── LDX.kt │ │ │ ├── LDY.kt │ │ │ ├── LSR.kt │ │ │ ├── NOP.kt │ │ │ ├── ORA.kt │ │ │ ├── RTS.kt │ │ │ ├── SBC.kt │ │ │ ├── SEC.kt │ │ │ ├── SEI.kt │ │ │ ├── STA.kt │ │ │ ├── STX.kt │ │ │ ├── TAX.kt │ │ │ └── TXA.kt │ └── res │ │ ├── drawable-xxxhdpi │ │ └── ic_play_arrow_white_48dp.png │ │ ├── layout │ │ ├── activity_main.xml │ │ └── toolbar.xml │ │ ├── menu │ │ └── menu_main.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_play_arrow_white_48dp.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_play_arrow_white_48dp.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_play_arrow_white_48dp.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ ├── kotlin │ └── android │ │ └── emu6502 │ │ ├── AssemblerTest.kt │ │ ├── CPUTest.kt │ │ ├── LabelsTest.kt │ │ └── nes │ │ └── INESFileParserTest.kt │ └── resources │ └── roms │ └── testrom.nes ├── build.gradle ├── demo.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # ant 2 | bin 3 | build 4 | gen 5 | out 6 | lib 7 | 8 | # intellij 9 | .idea 10 | *.iml 11 | 12 | # eclipse 13 | .classpath 14 | .project 15 | .settings 16 | .DS_Store 17 | local.properties 18 | .gradle -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | 3 | android: 4 | components: 5 | - tools 6 | - platform-tools 7 | - build-tools-25.0.2 8 | - extra-android-m2repository 9 | - android-25 10 | licenses: 11 | - 'android-sdk-license-.+' 12 | 13 | jdk: 14 | - oraclejdk8 15 | 16 | branches: 17 | except: 18 | - gh-pages 19 | 20 | notifications: 21 | email: false 22 | 23 | sudo: false 24 | 25 | before_cache: 26 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 27 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ 28 | 29 | cache: 30 | directories: 31 | - $HOME/.gradle/caches/ 32 | - $HOME/.gradle/wrapper/ 33 | - $HOME/.android/build-cache -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 6502 Android 2 | 3 | Ported from the awesome Javascript implementation [Easy 6502 by Nick Morgan](http://skilldrick.github.io/easy6502/). 4 | 5 | This project is my first stab at learning Kotlin and doing Emulator programmimg. This emulator was 6 | based on the project mentioned above but not ported verbatim. A Kotlin and Android optimized 7 | solution was implemented. As of now, it is able to assemble and run simple programs, including 8 | the [snake6502](https://gist.github.com/wkjagt/9043907) implementation by Willem van der Jagt, which 9 | was also used in the Easy 6502 "ebook". 10 | 11 | ## Demo 12 | 13 | ![](https://raw.githubusercontent.com/felipecsl/6502Android/master/demo.gif) 14 | 15 | ## Status 16 | 17 | There are still some instructions not implemented yet. I will update the CPU class soon with the 18 | implementation for the remaining ones 19 | 20 | ## License 21 | 22 | ``` 23 | Copyright 2015 Felipe Lima 24 | 25 | Licensed under the Apache License, Version 2.0 (the "License"); 26 | you may not use this file except in compliance with the License. 27 | You may obtain a copy of the License at 28 | 29 | http://www.apache.org/licenses/LICENSE-2.0 30 | 31 | Unless required by applicable law or agreed to in writing, software 32 | distributed under the License is distributed on an "AS IS" BASIS, 33 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 34 | See the License for the specific language governing permissions and 35 | limitations under the License. 36 | ``` -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | 5 | android { 6 | compileSdkVersion 28 7 | buildToolsVersion '28.0.2' 8 | 9 | defaultConfig { 10 | applicationId "android.emu6502" 11 | minSdkVersion 16 12 | targetSdkVersion 28 13 | versionCode 1 14 | versionName "1.0" 15 | } 16 | sourceSets { 17 | main.java.srcDirs += 'src/main/kotlin' 18 | test.java.srcDirs += 'src/test/kotlin' 19 | } 20 | testOptions { 21 | unitTests.returnDefaultValues = true 22 | } 23 | } 24 | 25 | dependencies { 26 | implementation 'com.google.android.material:material:1.0.0-alpha1' 27 | implementation 'androidx.appcompat:appcompat:1.0.0-alpha1' 28 | implementation 'androidx.cardview:cardview:1.0.0-alpha1' 29 | implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.2.61' 30 | implementation "org.jetbrains.kotlin:kotlin-reflect:1.2.61" 31 | 32 | testImplementation 'junit:junit:4.12' 33 | testImplementation 'com.google.truth:truth:0.42' 34 | testImplementation 'org.mockito:mockito-core:1.10.19' 35 | } 36 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/felipe_lima/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/Assembler.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502 2 | 3 | import android.emu6502.instructions.Instruction 4 | import android.emu6502.instructions.Opcodes 5 | import android.emu6502.instructions.Symbols 6 | import java.util.regex.Pattern 7 | 8 | class Assembler(private var memory: Memory, private val symbols: Symbols) { 9 | var codeLen = 0 10 | var defaultCodePC = BOOTSTRAP_ADDRESS 11 | private var labels = Labels(this, symbols) 12 | 13 | fun assembleCode(lines: List) { 14 | val preprocessedLines = preprocess(lines) 15 | 16 | labels.indexLines(preprocessedLines) 17 | 18 | // Reset PC and code length since labels screwed it 19 | defaultCodePC = BOOTSTRAP_ADDRESS 20 | codeLen = 0 21 | 22 | preprocessedLines.forEachIndexed { i, line -> 23 | if (!assembleLine(line)) { 24 | throw RuntimeException("**Syntax error line " + (i + 1) + ": " + line + "**") 25 | } 26 | } 27 | // set a null byte at the end of the code 28 | memory.set(defaultCodePC, 0x00) 29 | } 30 | 31 | private fun preprocess(lines: List): List { 32 | val pattern = Pattern.compile("^define\\s+(\\w+)\\s+(\\S+)", Pattern.CASE_INSENSITIVE) 33 | val sanitizedLines = lines.map { sanitize(it) } 34 | sanitizedLines 35 | .map { pattern.matcher(it) } 36 | .filter { it.find() } 37 | .forEach { symbols[it.group(1)] = sanitize(it.group(2)) } 38 | 39 | return sanitizedLines.filterNot { pattern.matcher(it).find() } 40 | } 41 | 42 | private fun sanitize(line: String): String { 43 | return line.replace("^(.*?);.*".toRegex(), "$1").trim() 44 | } 45 | 46 | fun assembleLine(line: String): Boolean { 47 | var input = line 48 | var command: String 49 | var param: String 50 | val addr: Int 51 | 52 | // Find command or label 53 | if (input.matches("^\\w+:".toRegex())) { 54 | if (line.matches("^\\w+:[\\s]*\\w+.*$".toRegex())) { 55 | input = input.replace("^\\w+:[\\s]*(.*)$".toRegex(), "$1") 56 | command = input.replace("^(\\w+).*$".toRegex(), "$1") 57 | } else { 58 | command = "" 59 | } 60 | } else { 61 | command = input.replace("^(\\w+).*$".toRegex(), "$1") 62 | } 63 | 64 | // Nothing to do for blank lines 65 | if (command == "") { 66 | return true 67 | } 68 | 69 | command = command.toUpperCase() 70 | 71 | if (input.matches("^\\*\\s*=\\s*\\$?[0-9a-f]*$".toRegex())) { 72 | // equ spotted 73 | param = input.replace("^\\s*\\*\\s*=\\s*".toRegex(), "") 74 | if (param[0] == '$') { 75 | param = param.replace("^\\$".toRegex(), "") 76 | addr = Integer.parseInt(param, 16) 77 | } else { 78 | addr = Integer.parseInt(param, 10) 79 | } 80 | if (addr < 0 || addr > 0xffff) { 81 | throw IllegalStateException("Unable to relocate code outside 64k memory") 82 | } 83 | defaultCodePC = addr 84 | return true 85 | } 86 | 87 | param = if (input.matches("^\\w+\\s+.*?$".toRegex())) { 88 | input.replace("^\\w+\\s+(.*?)".toRegex(), "$1") 89 | } else if (input.matches("^\\w+$".toRegex())) { 90 | "" 91 | } else { 92 | return false 93 | } 94 | 95 | param = param.replace("[ ]".toRegex(), "") 96 | 97 | if (command == "DCB") { 98 | return DCB(param) 99 | } 100 | 101 | val opcode = Opcodes.MAP[Instruction.valueOf(command)] 102 | 103 | if (opcode != null) { 104 | if (checkImmediate(param, opcode[0].opcode)) { 105 | return true 106 | } 107 | if (checkZeroPage(param, opcode[1].opcode)) { 108 | return true 109 | } 110 | if (checkZeroPageX(param, opcode[2].opcode)) { 111 | return true 112 | } 113 | if (checkZeroPageY(param, opcode[3].opcode)) { 114 | return true 115 | } 116 | if (checkAbsolute(param, opcode[4].opcode)) { 117 | return true 118 | } 119 | if (checkAbsoluteX(param, opcode[5].opcode)) { 120 | return true 121 | } 122 | if (checkAbsoluteY(param, opcode[6].opcode)) { 123 | return true 124 | } 125 | if (checkIndirect(param, opcode[7].opcode)) { 126 | return true 127 | } 128 | if (checkIndirectX(param, opcode[8].opcode)) { 129 | return true 130 | } 131 | if (checkIndirectY(param, opcode[9].opcode)) { 132 | return true 133 | } 134 | if (checkSingle(param, opcode[10].opcode)) { 135 | return true 136 | } 137 | if (checkBranch(param, opcode[11].opcode)) { 138 | return true 139 | } 140 | } 141 | return false 142 | } 143 | 144 | fun hexdump(): String { 145 | return memory.format(0x600, codeLen) 146 | } 147 | 148 | private fun DCB(param: String): Boolean { 149 | throw UnsupportedOperationException( 150 | "not implemented") //To change body of created functions use File | Settings | File Templates. 151 | } 152 | 153 | /** Common branch function for all branches (BCC, BCS, BEQ, BNE..) */ 154 | private fun checkBranch(param: String, opcode: Int): Boolean { 155 | if (opcode == 0xff) { 156 | return false 157 | } 158 | 159 | var addr = -1 160 | if (param.matches("\\w+".toRegex())) { 161 | addr = labels.get(param) 162 | } 163 | if (addr == -1) { 164 | pushWord(0x00) 165 | return false 166 | } 167 | pushByte(opcode) 168 | if (addr < (defaultCodePC - 0x600)) { 169 | // Backwards? 170 | pushByte((0xff - ((defaultCodePC - 0x600) - addr)).and(0xff)) 171 | return true 172 | } 173 | pushByte((addr - (defaultCodePC - 0x600) - 1).and(0xff)) 174 | return true 175 | } 176 | 177 | private fun checkAbsolute(param: String, opcode: Int): Boolean { 178 | if (opcode == 0xff) { 179 | return false 180 | } 181 | 182 | if (checkWordOperand(param, opcode, "^([\\w\\$]+)$")) { 183 | return true 184 | } 185 | 186 | // it could be a label too.. 187 | return checkLabel(param, opcode, "^\\w+$".toRegex()) 188 | } 189 | 190 | private fun checkWordOperand(param: String, opcode: Int, regex: String): Boolean { 191 | val matcher = Pattern.compile(regex, Pattern.CASE_INSENSITIVE).matcher(param) 192 | if (!matcher.find()) { 193 | return false 194 | } 195 | return innerCheckWordOperand(matcher.group(1), opcode) 196 | } 197 | 198 | private fun innerCheckWordOperand(param: String, opcode: Int): Boolean { 199 | val operand = tryParseWordOperand(param) 200 | if (operand < 0) { 201 | return false 202 | } 203 | pushByte(opcode) 204 | pushWord(operand) 205 | return true 206 | } 207 | 208 | private fun checkByteOperand(param: String, opcode: Int, regex: String): Boolean { 209 | val matcher = Pattern.compile(regex, Pattern.CASE_INSENSITIVE).matcher(param) 210 | if (!matcher.find()) { 211 | return false 212 | } 213 | return innerCheckByteOperand(matcher.group(1), opcode) 214 | } 215 | 216 | private fun innerCheckByteOperand(param: String, opcode: Int): Boolean { 217 | val operand = tryParseByteOperand(param) 218 | if (operand < 0) { 219 | return false 220 | } 221 | pushByte(opcode) 222 | pushByte(operand) 223 | return true 224 | } 225 | 226 | private fun checkLabel(param: String, opcode: Int, regex: Regex): Boolean { 227 | if (param.matches(regex)) { 228 | val finalParam = param.replace(",Y", "", true).replace(",X", "", true) 229 | pushByte(opcode) 230 | val addr = labels[finalParam] 231 | if (addr != -1) { 232 | if (addr < 0 || addr > 0xffff) { 233 | return false 234 | } 235 | pushWord(addr) 236 | return true 237 | } else { 238 | pushWord(0xffff) // filler, only used while indexing labels 239 | return true 240 | } 241 | } 242 | return false 243 | } 244 | 245 | private fun checkIndirectY(param: String, opcode: Int): Boolean { 246 | if (opcode == 0xff) { 247 | return false 248 | } 249 | return checkByteOperand(param, opcode, "^\\(([\\w\\$]+)\\),Y$") 250 | } 251 | 252 | private fun checkIndirectX(param: String, opcode: Int): Boolean { 253 | if (opcode == 0xff) { 254 | return false 255 | } 256 | return checkByteOperand(param, opcode, "^\\(([\\w\\$]+),X\\)$") 257 | } 258 | 259 | private fun checkIndirect(param: String, opcode: Int): Boolean { 260 | if (opcode == 0xff) { 261 | return false 262 | } 263 | return checkWordOperand(param, opcode, "^\\(([\\w\\$]+)\\)$") 264 | } 265 | 266 | private fun checkAbsoluteY(param: String, opcode: Int): Boolean { 267 | if (opcode == 0xff) { 268 | return false 269 | } 270 | return checkWordOperand(param, opcode, "^([\\w\\$]+),Y$") || 271 | checkLabel(param, opcode, "^\\w+,Y$".toRegex()) 272 | } 273 | 274 | private fun checkAbsoluteX(param: String, opcode: Int): Boolean { 275 | if (opcode == 0xff) { 276 | return false 277 | } 278 | return checkWordOperand(param, opcode, "^([\\w\\$]+),X$") || 279 | checkLabel(param, opcode, "^\\w+,X$".toRegex()) 280 | } 281 | 282 | private fun checkZeroPageY(param: String, opcode: Int): Boolean { 283 | if (opcode == 0xff) { 284 | return false 285 | } 286 | return checkByteOperand(param, opcode, "^([\\w\\$]+),Y") 287 | } 288 | 289 | private fun checkZeroPageX(param: String, opcode: Int): Boolean { 290 | if (opcode == 0xff) { 291 | return false 292 | } 293 | return checkByteOperand(param, opcode, "^([\\w\\$]+),X") 294 | } 295 | 296 | private fun checkZeroPage(param: String, opcode: Int): Boolean { 297 | if (opcode == 0xff) { 298 | return false 299 | } 300 | return innerCheckByteOperand(param, opcode) 301 | } 302 | 303 | private fun checkImmediate(param: String, opcode: Int): Boolean { 304 | if (opcode == 0xff) { 305 | return false 306 | } 307 | if (checkByteOperand(param, opcode, "^#([\\w\\$]+)$")) { 308 | return true 309 | } 310 | 311 | // Label lo/hi 312 | if (param.matches("^#[<>]\\w+$".toRegex())) { 313 | val label = param.replace("^#[<>](\\w+)$".toRegex(), "$1") 314 | val hilo = param.replace("^#([<>]).*$".toRegex(), "$1") 315 | pushByte(opcode) 316 | val addr = labels[label] 317 | if (addr != -1) { 318 | when (hilo) { 319 | ">" -> { 320 | pushByte(addr.shr(8).and(0xFF)) 321 | } 322 | "<" -> { 323 | pushByte(addr.and(0xFF)) 324 | } 325 | else -> return false 326 | } 327 | } else { 328 | pushByte(0x00) 329 | return true 330 | } 331 | } 332 | 333 | return false 334 | } 335 | 336 | // Try to parse the given parameter as a byte operand. 337 | // Returns the (positive) value if successful, otherwise -1 338 | private fun tryParseByteOperand(param: String): Int { 339 | var value: Int = -1 340 | var parameter = param 341 | 342 | if (parameter.matches("^\\w+$".toRegex())) { 343 | val lookupVal = symbols[parameter] // Substitute symbol by actual value, then proceed 344 | if (lookupVal != null) { 345 | parameter = lookupVal 346 | } 347 | } 348 | 349 | // Is it a hexadecimal operand? 350 | var pattern = Pattern.compile("^\\$([0-9a-f]{1,2})$", Pattern.CASE_INSENSITIVE) 351 | var matcher = pattern.matcher(parameter) 352 | if (matcher.find()) { 353 | value = Integer.parseInt(matcher.group(1), 16) 354 | } else { 355 | // Is it a decimal operand? 356 | pattern = Pattern.compile("^([0-9]{1,3})$", Pattern.CASE_INSENSITIVE) 357 | matcher = pattern.matcher(parameter) 358 | if (matcher.find()) { 359 | value = Integer.parseInt(matcher.group(1), 10) 360 | } 361 | } 362 | 363 | // Validate range 364 | if (value in 0..0xff) { 365 | return value 366 | } 367 | return -1 368 | } 369 | 370 | private fun tryParseWordOperand(param: String): Int { 371 | var value: Int = -1 372 | var parameter = param 373 | 374 | if (parameter.matches("^\\w+$".toRegex())) { 375 | val lookupVal = symbols[parameter] // Substitute symbol by actual value, then proceed 376 | if (lookupVal != null) { 377 | parameter = lookupVal 378 | } 379 | } 380 | 381 | // Is it a hexadecimal operand? 382 | var pattern = Pattern.compile("^\\$([0-9a-f]{3,4})$", Pattern.CASE_INSENSITIVE) 383 | var matcher = pattern.matcher(parameter) 384 | if (matcher.find()) { 385 | value = Integer.parseInt(matcher.group(1), 16) 386 | } else { 387 | // Is it a decimal operand? 388 | pattern = Pattern.compile("^([0-9]{1,5})$", Pattern.CASE_INSENSITIVE) 389 | matcher = pattern.matcher(parameter) 390 | if (matcher.find()) { 391 | value = Integer.parseInt(matcher.group(1), 10) 392 | } 393 | } 394 | 395 | // Validate range 396 | if (value in 0..0xffff) { 397 | return value 398 | } 399 | return -1 400 | } 401 | 402 | private fun pushByte(value: Int) { 403 | memory.set(defaultCodePC, value.and(0xff)) 404 | defaultCodePC++ 405 | codeLen++ 406 | } 407 | 408 | private fun pushWord(value: Int) { 409 | pushByte(value.and(0xff)) 410 | pushByte(value.shr(8).and(0xff)) 411 | } 412 | 413 | private fun checkSingle(param: String, opcode: Int): Boolean { 414 | // Accumulator instructions are counted as single-byte opcodes 415 | if (param != "" && param != "A") { 416 | return false 417 | } 418 | pushByte(opcode) 419 | return true 420 | } 421 | 422 | companion object { 423 | const val BOOTSTRAP_ADDRESS = 0x600 424 | } 425 | } 426 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/CPU.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502 2 | 3 | import android.emu6502.instructions.BaseInstruction 4 | import android.emu6502.instructions.Instruction 5 | import android.emu6502.instructions.InstructionTarget 6 | import android.emu6502.instructions.Opcodes 7 | import android.emu6502.instructions.impl.* 8 | import android.os.Handler 9 | import android.os.HandlerThread 10 | import android.util.Log 11 | import java.util.* 12 | import java.util.concurrent.CountDownLatch 13 | 14 | class CPU(val memory: Memory) : Display.Callbacks { 15 | private val bgHandlerThread = HandlerThread("Screencast Thread") 16 | private val bgHandler: Handler 17 | private var executionLock: CountDownLatch? = null 18 | 19 | init { 20 | bgHandlerThread.start() 21 | bgHandler = Handler(bgHandlerThread.looper) 22 | } 23 | 24 | var A: Int = 0 // Accumulator 25 | var X: Int = 0 // Register X 26 | var Y: Int = 0 // Register Y 27 | var PC: Int = 0x600 // Program counter 28 | var SP: Int = 0xFF // Stack pointer 29 | var P: Int = 0x30 // Processor flags 30 | 31 | private var isRunning = false 32 | private var debug = false 33 | private var monitoring = false 34 | private var TAG = "CPU" 35 | private val instructionList: HashMap = HashMap() 36 | private val operationList: HashMap = hashMapOf( 37 | Pair(Instruction.ADC, ADC(this)), Pair(Instruction.AND, AND(this)), 38 | Pair(Instruction.ASL, ASL(this)), Pair(Instruction.BIT, BIT(this)), 39 | Pair(Instruction.LDA, LDA(this)), Pair(Instruction.LDX, LDX(this)), 40 | Pair(Instruction.LDY, LDY(this)), Pair(Instruction.STA, STA(memory, this)), 41 | Pair(Instruction.STX, STX(this)), Pair(Instruction.TAX, TAX(this)), 42 | Pair(Instruction.INX, INX(this)), Pair(Instruction.DEX, DEX(this)), 43 | Pair(Instruction.ORA, ORA(this)), Pair(Instruction.CPX, CPX(this)), 44 | Pair(Instruction.BRK, BRK(this)), Pair(Instruction.BNE, BNE(this)), 45 | Pair(Instruction.JMP, JMP(this)), Pair(Instruction.JSR, JSR(this)), 46 | Pair(Instruction.RTS, RTS(this)), Pair(Instruction.SEI, SEI(this)), 47 | Pair(Instruction.DEY, DEY(this)), Pair(Instruction.CLC, CLC(this)), 48 | Pair(Instruction.CMP, CMP(this)), Pair(Instruction.BEQ, BEQ(this)), 49 | Pair(Instruction.TXA, TXA(this)), Pair(Instruction.BPL, BPL(this)), 50 | Pair(Instruction.LSR, LSR(this)), Pair(Instruction.BCS, BCS(this)), 51 | Pair(Instruction.INC, INC(this)), Pair(Instruction.NOP, NOP(this)), 52 | Pair(Instruction.SEC, SEC(this)), Pair(Instruction.SBC, SBC(this)), 53 | Pair(Instruction.BCC, BCC(this)), Pair(Instruction.DEC, DEC(this)) 54 | //Pair(Instruction.BMI, BMI(this)), Pair(Instruction.BVC, BVC(this)), 55 | //Pair(Instruction.BVS, BVS(this)), Pair(Instruction.CPY, CPY(this)), 56 | //Pair(Instruction.EOR, EOR(this)), Pair(Instruction.CLI, CLI(this)), 57 | //Pair(Instruction.CLV, CLV(this)), Pair(Instruction.CLD, CLD(this)), 58 | //Pair(Instruction.SED, SED(this)), Pair(Instruction.TAY, TAY(this)), 59 | //Pair(Instruction.TYA, TYA(this)), Pair(Instruction.INY, INY(this)), 60 | //Pair(Instruction.ROR, ROR(this)), Pair(Instruction.ROL, ROL(this)), 61 | //Pair(Instruction.RTI, RTI(this)), Pair(Instruction.TXS, TXS(this)), 62 | //Pair(Instruction.TSX, TSX(this)), Pair(Instruction.PHA, PHA(this)), 63 | //Pair(Instruction.PLA, PLA(this)), Pair(Instruction.PHP, PHP(this)), 64 | //Pair(Instruction.PLP, PLP(this)), Pair(Instruction.STY, STY(this)) 65 | ) 66 | 67 | // for testing only 68 | fun testRun() { 69 | isRunning = true 70 | while (true) { 71 | setRandomByte() 72 | executeNextInstruction() 73 | if (PC == 0 || !isRunning) { 74 | break 75 | } 76 | } 77 | stop() 78 | } 79 | 80 | fun run() { 81 | isRunning = true 82 | bgHandler.post { innerRun() } 83 | } 84 | 85 | private fun innerRun() { 86 | (0..97).forEach { execute() } 87 | bgHandler.postDelayed({ innerRun() }, 10) 88 | } 89 | 90 | private fun execute() { 91 | if (!isRunning) { 92 | return 93 | } 94 | 95 | setRandomByte() 96 | executeNextInstruction() 97 | 98 | if (PC == 0 || !isRunning) { 99 | stop() 100 | Log.i(TAG, "Program end at PC=$" + (PC - 1).toHexString() + ", A=$" + A.toHexString() + 101 | ", X=$" + X.toHexString() + ", Y=$" + Y.toHexString()) 102 | } 103 | } 104 | 105 | private fun executeNextInstruction() { 106 | val instruction = popByte() 107 | val target = instructionList[instruction] 108 | if (target != null) { 109 | target.method.invoke() 110 | } else { 111 | val candidate = Opcodes.MAP.entries 112 | .first { e -> e.value.any { it.opcode == instruction } } 113 | throw Exception( 114 | "Address $${PC.toHexString()} - unknown opcode 0x${instruction.toHexString()} " + 115 | "(instruction ${candidate.key.name})") 116 | } 117 | } 118 | 119 | fun stop() { 120 | isRunning = false 121 | bgHandler.removeCallbacks(null) 122 | } 123 | 124 | fun reset() { 125 | var i = 0 126 | while (i < 0x600) { 127 | memory.set(i++, 0x00) 128 | } 129 | A = 0 130 | Y = 0 131 | X = 0 132 | PC = 0x600 133 | SP = 0xff 134 | P = 0x30 135 | } 136 | 137 | fun addInstruction(opcode: Int, target: InstructionTarget) { 138 | instructionList.put(opcode, target) 139 | } 140 | 141 | fun popByte(): Int { 142 | return memory.get(PC++).and(0xff) 143 | } 144 | 145 | private fun setRandomByte() { 146 | memory.set(0xfe, Math.floor(Math.random() * 256).toInt()) 147 | } 148 | 149 | fun setSZFlagsForRegA() { 150 | setSVFlagsForValue(A) 151 | } 152 | 153 | fun setSZflagsForRegX() { 154 | setSVFlagsForValue(X) 155 | } 156 | 157 | fun setSZflagsForRegY() { 158 | setSVFlagsForValue(Y) 159 | } 160 | 161 | fun setSVFlagsForValue(value: Int) { 162 | if (value != 0) { 163 | P = P.and(0xfd) 164 | } else { 165 | P = P.or(0x02) 166 | } 167 | if (value.and(0x80) != 0) { 168 | P = P.or(0x80) 169 | } else { 170 | P = P.and(0x7f) 171 | } 172 | } 173 | 174 | fun popWord(): Int { 175 | return popByte() + popByte().shl(8) 176 | } 177 | 178 | fun overflow(): Boolean { 179 | return P.and(0x40) != 0 180 | } 181 | 182 | fun decimalMode(): Boolean { 183 | return P.and(8) != 0 184 | } 185 | 186 | fun carry(): Boolean { 187 | return P.and(1) != 0 188 | } 189 | 190 | fun negative(): Boolean { 191 | return P.and(0x80) != 0 192 | } 193 | 194 | fun zero(): Boolean { 195 | return P.and(0x02) != 0 196 | } 197 | 198 | fun setCarryFlagFromBit0(value: Int) { 199 | P = P.and(0xfe).or(value.and(1)) 200 | } 201 | 202 | fun jumpBranch(offset: Int) { 203 | if (offset > 0x7f) { 204 | PC -= (0x100 - offset) 205 | } else { 206 | PC += offset 207 | } 208 | } 209 | 210 | fun doCompare(reg: Int, value: Int) { 211 | if (reg >= value) { 212 | SEC() 213 | } else { 214 | CLC() 215 | } 216 | setSVFlagsForValue(reg - value) 217 | } 218 | 219 | /** CLear Carry */ 220 | fun CLC() { 221 | P = P.and(0xfe) 222 | } 223 | 224 | /** SEt Carry */ 225 | fun SEC() { 226 | P = P.or(1) 227 | } 228 | 229 | /** CLear oVerflow */ 230 | fun CLV() { 231 | P = P.and(0xbf) 232 | } 233 | 234 | fun setOverflow() { 235 | P = P.or(0x40) 236 | } 237 | 238 | fun stackPush(value: Int) { 239 | memory.set(SP.and(0xff) + 0x100, value.and(0xff)) 240 | SP-- 241 | if (SP < 0) { 242 | SP = SP.and(0xff) 243 | Log.i(TAG, "6502 Stack filled! Wrapping...") 244 | } 245 | } 246 | 247 | fun stackPop(): Int { 248 | SP++ 249 | if (SP >= 0x100) { 250 | SP = SP.and(0xff) 251 | Log.i(TAG, "6502 Stack emptied! Wrapping...") 252 | } 253 | return memory.get(SP + 0x100) 254 | } 255 | 256 | /** 257 | * http://nesdev.com/6502.txt 258 | * Returns the processor flags in the format SV-BDIZC 259 | * Sign - this is set if the result of an operation is negative, cleared if positive. 260 | * Overflow - when an arithmetic operation produces a result too large to be represented in a byte 261 | * Unused - Supposed to be logical 1 at all times. 262 | * Break - this is set when a software interrupt (BRK instruction) is executed. 263 | * Decimal Mode - When set, and an Add with Carry or Subtract with Carry instruction is executed, 264 | * the source values are treated as valid BCD (Binary Coded Decimal, eg. 0x00-0x99 = 0-99) numbers. 265 | * The result generated is also a BCD number. 266 | * Interrupt - If it is set, interrupts are disabled. If it is cleared, interrupts are enabled. 267 | * Zero - this is set to 1 when any arithmetic or logical operation produces a zero result, and is 268 | * set to 0 if the result is non-zero. 269 | * Carry - this holds the carry out of the most significant bit in any arithmetic operation. 270 | * In subtraction operations however, this flag is cleared - set to 0 - if a borrow is required, 271 | * set to 1 - if no borrow is required. The carry flag is also used in shift and rotate logical 272 | * operations. 273 | * */ 274 | fun flags(): String { 275 | val flags = StringBuilder() 276 | for (i in 7 downTo 0) { 277 | flags.append(P.shr(i).and(1)) 278 | } 279 | return flags.toString() 280 | } 281 | 282 | override fun onUpdate() { 283 | executionLock = CountDownLatch(1) 284 | executionLock?.await() 285 | } 286 | 287 | override fun onDraw() { 288 | executionLock?.countDown() 289 | } 290 | 291 | fun triggerIRQ() { 292 | throw NotImplementedError() 293 | } 294 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/Display.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502 2 | 3 | import android.content.Context 4 | import android.graphics.Canvas 5 | import android.graphics.Color 6 | import android.graphics.Paint 7 | import android.util.AttributeSet 8 | import android.view.View 9 | 10 | open class Display(context: Context, attrs: AttributeSet) : View(context, attrs) { 11 | private val numX = 32 12 | private val numY = 32 13 | private val matrix = Array(numX) { IntArray(numY) } 14 | 15 | private val palette = arrayOf( 16 | "#000000", "#ffffff", "#880000", "#aaffee", 17 | "#cc44cc", "#00cc55", "#0000aa", "#eeee77", 18 | "#dd8855", "#664400", "#ff7777", "#333333", 19 | "#777777", "#aaff66", "#0088ff", "#bbbbbb") 20 | 21 | private val paint: Paint = Paint() 22 | private val bgPaint: Paint = Paint() 23 | private var listener: Callbacks? = null 24 | 25 | init { 26 | bgPaint.color = Color.BLACK 27 | } 28 | 29 | fun setOnDisplayCallback(callback: Callbacks) { 30 | listener = callback 31 | } 32 | 33 | open fun updatePixel(addr: Int, value: Int) { 34 | val offsetAddr = addr - 0x200 35 | val x = offsetAddr % numX 36 | val y = Math.floor((offsetAddr / numY).toDouble()).toInt() 37 | val color = palette[value] 38 | matrix[x][y] = Color.parseColor(color) 39 | postInvalidate() 40 | listener?.onUpdate() 41 | } 42 | 43 | override fun onDraw(canvas: Canvas) { 44 | val pixelSizeX = width / numX 45 | val pixelSizeY = height / numX 46 | 47 | matrix.forEachIndexed { i, _ -> 48 | matrix[i].forEachIndexed { j, _ -> 49 | val color = matrix[i][j] 50 | val right = (i * pixelSizeX).toFloat() 51 | val top = (j * pixelSizeY).toFloat() 52 | if (color != 0) { 53 | paint.color = color 54 | canvas.drawRect(right, top, right + pixelSizeX, top + pixelSizeY, paint) 55 | } else { 56 | canvas.drawRect(right, top, right + pixelSizeX, top + pixelSizeY, bgPaint) 57 | } 58 | } 59 | } 60 | listener?.onDraw() 61 | } 62 | 63 | interface Callbacks { 64 | fun onUpdate() 65 | fun onDraw() 66 | } 67 | 68 | fun reset() { 69 | matrix.forEachIndexed { i, _ -> 70 | matrix[i].forEachIndexed { j, _ -> 71 | matrix[i][j] = 0 72 | } 73 | } 74 | postInvalidate() 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/Emu6502Application.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502 2 | 3 | import android.app.Application 4 | 5 | class Emu6502Application : Application() { 6 | } 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/Emulator.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502 2 | 3 | import android.emu6502.instructions.Symbols 4 | 5 | class Emulator(val display: Display) { 6 | val memory = Memory(display) 7 | val cpu = CPU(memory) 8 | val assembler = Assembler(memory, Symbols()) 9 | 10 | init { 11 | display.setOnDisplayCallback(cpu) 12 | } 13 | 14 | fun reset() { 15 | display.reset() 16 | cpu.reset() 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/ExtensionFunctions.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502 2 | 3 | infix fun Byte.shr(other: Int): Byte { 4 | return this.toInt().shr(other).toByte() 5 | } 6 | 7 | infix fun Byte.shl(other: Int): Byte { 8 | return this.toInt().shr(other).toByte() 9 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/Labels.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502 2 | 3 | import android.emu6502.instructions.Symbols 4 | import java.util.* 5 | 6 | class Labels(private val assembler: Assembler, 7 | private val symbols: Symbols) : HashMap() { 8 | private val labelIndex: ArrayList = ArrayList() 9 | 10 | fun indexLines(lines: List) { 11 | lines.forEach { line -> 12 | indexLine(line) 13 | } 14 | } 15 | 16 | override fun get(label: String): Int { 17 | return super.get(label) ?: -1 18 | } 19 | 20 | // Extract label if line contains one and calculate position in memory. 21 | // Return false if label already exists. 22 | private fun indexLine(input: String) { 23 | // Figure out how many bytes this instruction takes 24 | val currentPC = assembler.defaultCodePC 25 | // TODO: find a better way for Labels to have access to assembler 26 | assembler.assembleLine(input); 27 | 28 | // Find command or label 29 | if (input.matches("^\\w+:".toRegex())) { 30 | val label = input.replace("(^\\w+):.*$".toRegex(), "$1") 31 | 32 | if (symbols.get(label) != null) { 33 | throw RuntimeException( 34 | "**Label ${label}is already used as a symbol; please rename one of them**") 35 | } 36 | 37 | put(label, currentPC) 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/Memory.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502 2 | 3 | class Memory(private val display: Display) { 4 | private val mem = IntArray(65536) 5 | 6 | fun get(addr: Int): Int { 7 | return mem[addr] 8 | } 9 | 10 | fun getWord(addr: Int): Int { 11 | return get(addr) + get(addr + 1).shl(8) 12 | } 13 | 14 | fun set(addr: Int, value: Int) { 15 | mem[addr] = value 16 | } 17 | 18 | fun storeByte(addr: Int, value: Int) { 19 | set(addr, value.and(0xff)) 20 | if (addr in 0x200..0x5ff) { 21 | display.updatePixel(addr, mem[addr].and(0x0f)) 22 | } 23 | } 24 | // Store keycode in ZP $ff 25 | fun storeKeypress(keyCode: Int) { 26 | storeByte(0xff, keyCode) 27 | } 28 | 29 | fun format(start: Int, length: Int): String { 30 | var i = 0 31 | var n: Int 32 | val dump = StringBuilder() 33 | while (i < length) { 34 | if (i.and(15) == 0) { 35 | if (i > 0) { 36 | dump.append("\n") 37 | } 38 | n = start + i 39 | dump.append(n.shr(8).and(0xff).toHexString()) 40 | dump.append(n.and(0xff).toHexString()) 41 | dump.append(": ") 42 | } 43 | dump.append(get(start + i).toHexString()) 44 | dump.append(" ") 45 | i++ 46 | } 47 | return dump.toString().trim() 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/Utils.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502 2 | 3 | fun Int.toHexString(): String { 4 | return java.lang.String.format("%02X", this) 5 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/app/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.app 2 | 3 | import android.emu6502.Emulator 4 | import android.emu6502.R 5 | import android.os.Bundle 6 | import android.view.Menu 7 | import android.view.MenuItem 8 | import android.view.View 9 | import androidx.appcompat.app.ActionBar 10 | import androidx.appcompat.app.AppCompatActivity 11 | import com.google.android.material.snackbar.Snackbar 12 | import kotlinx.android.synthetic.main.activity_main.* 13 | import kotlinx.android.synthetic.main.toolbar.* 14 | 15 | class MainActivity : AppCompatActivity() { 16 | private lateinit var emulator: Emulator 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | setContentView(R.layout.activity_main) 21 | setSupportActionBar(toolbar) 22 | val actionBar: ActionBar = supportActionBar!! 23 | actionBar.setDisplayHomeAsUpEnabled(true) 24 | fabRun.setOnClickListener { 25 | display_wrapper.visibility = View.VISIBLE 26 | emulator = Emulator(display) 27 | emulator.assembler.assembleCode(txtInstructions.text.toString().split("\n")) 28 | Snackbar.make(layout_content, 29 | "Code assembled successfully, ${emulator.assembler.codeLen} bytes.", 30 | Snackbar.LENGTH_SHORT).show() 31 | emulator.cpu.run() 32 | } 33 | 34 | btnReset.setOnClickListener { emulator.reset() } 35 | 36 | val onClickButton = { code: Int -> 37 | emulator.cpu.memory.storeKeypress(code) 38 | } 39 | arrowLeft.setOnClickListener { onClickButton(0x61) } 40 | arrowRight.setOnClickListener { onClickButton(0x64) } 41 | arrowUp.setOnClickListener { onClickButton(0x77) } 42 | arrowDown.setOnClickListener { onClickButton(0x73) } 43 | } 44 | 45 | override fun onCreateOptionsMenu(menu: Menu?): Boolean { 46 | // Inflate the menu; this adds items to the action bar if it is present. 47 | menuInflater.inflate(R.menu.menu_main, menu) 48 | return true 49 | } 50 | 51 | override fun onOptionsItemSelected(item: MenuItem?): Boolean { 52 | // Handle action bar item clicks here. The action bar will 53 | // automatically handle clicks on the Home/Up button, so long 54 | // as you specify a parent activity in AndroidManifest.xml. 55 | val id = item!!.itemId 56 | return if (id == R.id.action_settings) { 57 | true 58 | } else { 59 | super.onOptionsItemSelected(item) 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/AddressingMode.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions 2 | 3 | enum class AddressingMode { 4 | IMMEDIATE, ZERO_PAGE, ZERO_PAGE_X, ABSOLUTE, ABSOLUTE_X, ABSOLUTE_Y, INDIRECT_X, INDIRECT_Y 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/BaseInstruction.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions 2 | 3 | import android.emu6502.CPU 4 | 5 | open class BaseInstruction(val instruction: Instruction, private val cpu: CPU) { 6 | init { 7 | val opcodes = Opcodes.MAP[instruction] 8 | val methods = arrayOf( 9 | this::immediate, 10 | this::zeroPage, 11 | this::zeroPageX, 12 | this::zeroPageY, 13 | this::absolute, 14 | this::absoluteX, 15 | this::absoluteY, 16 | this::indirect, 17 | this::indirectX, 18 | this::indirectY, 19 | this::single, 20 | this::branch) 21 | 22 | opcodes!!.forEachIndexed { i, opcode -> 23 | if (opcode.opcode != 0xff) { 24 | cpu.addInstruction(opcodes[i].opcode, InstructionTarget(this, methods[i])) 25 | } 26 | } 27 | } 28 | 29 | open fun immediate() { 30 | throw IllegalStateException("Instruction " + javaClass.simpleName + " not implemented" + 31 | " with immediate addressing") 32 | } 33 | 34 | open fun zeroPage() { 35 | throw IllegalStateException("Instruction " + javaClass.simpleName + " not implemented" + 36 | " with zeroPage addressing") 37 | } 38 | 39 | open fun zeroPageX() { 40 | throw IllegalStateException("Instruction " + javaClass.simpleName + " not implemented" + 41 | " with zeroPageX addressing") 42 | } 43 | 44 | open fun zeroPageY() { 45 | throw IllegalStateException("Instruction " + javaClass.simpleName + " not implemented" + 46 | " with zeroPageY addressing") 47 | } 48 | 49 | open fun absolute() { 50 | throw IllegalStateException("Instruction " + javaClass.simpleName + " not implemented" + 51 | " with absolute addressing") 52 | } 53 | 54 | open fun absoluteX() { 55 | throw IllegalStateException("Instruction " + javaClass.simpleName + " not implemented" + 56 | " with absoluteX addressing") 57 | } 58 | 59 | open fun absoluteY() { 60 | throw IllegalStateException("Instruction " + javaClass.simpleName + " not implemented" + 61 | " with absoluteY addressing") 62 | } 63 | 64 | open fun indirect() { 65 | throw IllegalStateException("Instruction " + javaClass.simpleName + " not implemented" + 66 | " with indirect addressing") 67 | } 68 | 69 | open fun indirectX() { 70 | throw IllegalStateException("Instruction " + javaClass.simpleName + " not implemented" + 71 | " with indirectX addressing") 72 | } 73 | 74 | open fun indirectY() { 75 | throw IllegalStateException("Instruction " + javaClass.simpleName + " not implemented" + 76 | " with indirectY addressing") 77 | } 78 | 79 | open fun single() { 80 | throw IllegalStateException("Instruction " + javaClass.simpleName + " not implemented" + 81 | " with single addressing") 82 | } 83 | 84 | open fun branch() { 85 | throw IllegalStateException("Instruction " + javaClass.simpleName + " not implemented" + 86 | " with branch addressing") 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/Instruction.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions 2 | 3 | enum class Instruction { 4 | ADC, AND, ASL, BIT, BPL, BMI, BVC, BVS, BCC, BCS, BNE, BEQ, BRK, CMP, CPX, CPY, DEC, EOR, CLC, 5 | SEC, CLI, SEI, CLV, CLD, SED, INC, JMP, JSR, LDA, LDX, LDY, LSR, NOP, ORA, TAX, TXA, DEX, INX, 6 | TAY, TYA, DEY, INY, ROR, ROL, RTI, RTS, SBC, STA, TXS, TSX, PHA, PLA, PHP, PLP, STX, STY, XXX 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/InstructionMode.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions 2 | 3 | data class InstructionMode(val opcode: Int, val size: Int, val cycles: Int) -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/InstructionTarget.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions 2 | 3 | data class InstructionTarget(val operation: BaseInstruction, val method: () -> Unit) -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/Opcodes.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions 2 | 3 | // http://www.obelisk.me.uk/6502/reference.html 4 | class Opcodes { 5 | companion object { 6 | private fun im(opcode: Int, size: Int, cycles: Int) = InstructionMode(opcode, size, cycles) 7 | 8 | val MAP: Map> = hashMapOf( 9 | Instruction.ADC to arrayOf(im(0x69, 2, 2), im(0x65, 2, 3), im(0x75, 2, 4), im(0xff, 0, 0), 10 | im(0x6d, 3, 4), im(0x7d, 3, 4), im(0x79, 3, 4), im(0xff, 0, 0), im(0x61, 2, 6), 11 | im(0x71, 2, 5), im(0xff, 0, 0), im(0xff, 0, 0)), 12 | Instruction.AND to arrayOf(im(0x29, 2, 2), im(0x25, 2, 3), im(0x35, 2, 4), im(0xff, 0, 0), 13 | im(0x2d, 3, 4), im(0x3d, 3, 4), im(0x39, 3, 4), im(0xff, 0, 0), im(0x21, 2, 6), 14 | im(0x31, 2, 5), im(0xff, 0, 0), im(0xff, 0, 0)), 15 | Instruction.ASL to arrayOf(im(0xff, 0, 0), im(0x06, 2, 5), im(0x16, 2, 6), im(0xff, 0, 0), 16 | im(0x0e, 2, 5), im(0x1e, 3, 7), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 17 | im(0xff, 0, 0), im(0x0a, 1, 2), im(0xff, 0, 0)), 18 | Instruction.BIT to arrayOf(im(0xff, 0, 0), im(0x24, 2, 3), im(0xff, 0, 0), im(0xff, 0, 0), 19 | im(0x2c, 3, 4), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 20 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0)), 21 | Instruction.BPL to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 22 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 23 | im(0xff, 0, 0), im(0xff, 0, 0), im(0x10, 2, 2)), 24 | Instruction.BMI to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 25 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 26 | im(0xff, 0, 0), im(0xff, 0, 0), im(0x30, 2, 2)), 27 | Instruction.BVC to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 28 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 29 | im(0xff, 0, 0), im(0xff, 0, 0), im(0x50, 2, 2)), 30 | Instruction.BVS to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 31 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 32 | im(0xff, 0, 0), im(0xff, 0, 0), im(0x70, 2, 2)), 33 | Instruction.BCC to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 34 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 35 | im(0xff, 0, 0), im(0xff, 0, 0), im(0x90, 2, 2)), 36 | Instruction.BCS to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 37 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 38 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xb0, 2, 2)), 39 | Instruction.BNE to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 40 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 41 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xd0, 2, 2)), 42 | Instruction.BEQ to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 43 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 44 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xf0, 2, 2)), 45 | Instruction.BRK to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 46 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 47 | im(0xff, 0, 0), im(0x00, 1, 7), im(0xff, 0, 0)), 48 | Instruction.CMP to arrayOf(im(0xc9, 2, 2), im(0xc5, 2, 3), im(0xd5, 2, 4), im(0xff, 0, 0), 49 | im(0xcd, 3, 4), im(0xdd, 3, 4), im(0xd9, 3, 4), im(0xff, 0, 0), im(0xc1, 2, 6), 50 | im(0xd1, 2, 5), im(0xff, 0, 0), im(0xff, 0, 0)), 51 | Instruction.CPX to arrayOf(im(0xe0, 2, 2), im(0xe4, 2, 3), im(0xff, 0, 0), im(0xff, 0, 0), 52 | im(0xec, 3, 4), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 53 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0)), 54 | Instruction.CPY to arrayOf(im(0xc0, 2, 2), im(0xc4, 2, 3), im(0xff, 0, 0), im(0xff, 0, 0), 55 | im(0xcc, 3, 4), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 56 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0)), 57 | Instruction.DEC to arrayOf(im(0xff, 0, 0), im(0xc6, 2, 5), im(0xd6, 2, 6), im(0xff, 0, 0), 58 | im(0xce, 3, 6), im(0xde, 3, 7), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 59 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0)), 60 | Instruction.EOR to arrayOf(im(0x49, 2, 2), im(0x45, 2, 3), im(0x55, 2, 4), im(0xff, 0, 0), 61 | im(0x4d, 3, 4), im(0x5d, 3, 4), im(0x59, 3, 4), im(0xff, 0, 0), im(0x41, 2, 6), 62 | im(0x51, 2, 5), im(0xff, 0, 0), im(0xff, 0, 0)), 63 | Instruction.CLC to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 64 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 65 | im(0xff, 0, 0), im(0x18, 1, 2), im(0xff, 0, 0)), 66 | Instruction.SEC to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 67 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 68 | im(0xff, 0, 0), im(0x38, 1, 2), im(0xff, 0, 0)), 69 | Instruction.CLI to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 70 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 71 | im(0xff, 0, 0), im(0x58, 1, 2), im(0xff, 0, 0)), 72 | Instruction.SEI to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 73 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 74 | im(0xff, 0, 0), im(0x78, 1, 2), im(0xff, 0, 0)), 75 | Instruction.CLV to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 76 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 77 | im(0xff, 0, 0), im(0xb8, 1, 2), im(0xff, 0, 0)), 78 | Instruction.CLD to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 79 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 80 | im(0xff, 0, 0), im(0xd8, 1, 2), im(0xff, 0, 0)), 81 | Instruction.SED to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 82 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 83 | im(0xff, 0, 0), im(0xf8, 1, 2), im(0xff, 0, 0)), 84 | Instruction.INC to arrayOf(im(0xff, 0, 0), im(0xe6, 2, 5), im(0xf6, 2, 6), im(0xff, 0, 0), 85 | im(0xee, 3, 6), im(0xfe, 3, 7), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 86 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0)), 87 | Instruction.JMP to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 88 | im(0x4c, 3, 3), im(0xff, 0, 0), im(0xff, 0, 0), im(0x6c, 3, 5), im(0xff, 0, 0), 89 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0)), 90 | Instruction.JSR to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 91 | im(0x20, 3, 6), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 92 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0)), 93 | Instruction.LDA to arrayOf(im(0xa9, 2, 2), im(0xa5, 2, 3), im(0xb5, 2, 4), im(0xff, 0, 0), 94 | im(0xad, 3, 4), im(0xbd, 3, 4), im(0xb9, 3, 4), im(0xff, 0, 0), im(0xa1, 2, 6), 95 | im(0xb1, 2, 5), im(0xff, 0, 0), im(0xff, 0, 0)), 96 | Instruction.LDX to arrayOf(im(0xa2, 2, 2), im(0xa6, 2, 3), im(0xff, 0, 0), im(0xb6, 2, 4), 97 | im(0xae, 3, 4), im(0xff, 0, 0), im(0xbe, 3, 4), im(0xff, 0, 0), im(0xff, 0, 0), 98 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0)), 99 | Instruction.LDY to arrayOf(im(0xa0, 2, 2), im(0xa4, 2, 3), im(0xb4, 2, 4), im(0xff, 0, 0), 100 | im(0xac, 3, 4), im(0xbc, 3, 4), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 101 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0)), 102 | Instruction.LSR to arrayOf(im(0xff, 0, 0), im(0x46, 2, 5), im(0x56, 2, 6), im(0xff, 0, 0), 103 | im(0x4e, 3, 6), im(0x5e, 3, 7), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 104 | im(0xff, 0, 0), im(0x4a, 1, 2), im(0xff, 0, 0)), 105 | Instruction.NOP to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 106 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 107 | im(0xff, 0, 0), im(0xea, 1, 2), im(0xff, 0, 0)), 108 | Instruction.ORA to arrayOf(im(0x09, 2, 2), im(0x05, 2, 3), im(0x15, 2, 4), im(0xff, 0, 0), 109 | im(0x0d, 3, 4), im(0x1d, 3, 4), im(0x19, 3, 4), im(0xff, 0, 0), im(0x01, 2, 6), 110 | im(0x11, 2, 5), im(0xff, 0, 0), im(0xff, 0, 0)), 111 | Instruction.TAX to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 112 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 113 | im(0xff, 0, 0), im(0xaa, 1, 2), im(0xff, 0, 0)), 114 | Instruction.TXA to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 115 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 116 | im(0xff, 0, 0), im(0x8a, 1, 2), im(0xff, 0, 0)), 117 | Instruction.DEX to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 118 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 119 | im(0xff, 0, 0), im(0xca, 1, 2), im(0xff, 0, 0)), 120 | Instruction.INX to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 121 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 122 | im(0xff, 0, 0), im(0xe8, 1, 2), im(0xff, 0, 0)), 123 | Instruction.TAY to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 124 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 125 | im(0xff, 0, 0), im(0xa8, 1, 2), im(0xff, 0, 0)), 126 | Instruction.TYA to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 127 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 128 | im(0xff, 0, 0), im(0x98, 1, 2), im(0xff, 0, 0)), 129 | Instruction.DEY to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 130 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 131 | im(0xff, 0, 0), im(0x88, 1, 2), im(0xff, 0, 0)), 132 | Instruction.INY to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 133 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 134 | im(0xff, 0, 0), im(0xc8, 1, 2), im(0xff, 0, 0)), 135 | Instruction.ROR to arrayOf(im(0xff, 0, 0), im(0x66, 2, 5), im(0x76, 2, 6), im(0xff, 0, 0), 136 | im(0x6e, 3, 6), im(0x7e, 3, 7), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 137 | im(0xff, 0, 0), im(0x6a, 1, 2), im(0xff, 0, 0)), 138 | Instruction.ROL to arrayOf(im(0xff, 0, 0), im(0x26, 2, 5), im(0x36, 2, 6), im(0xff, 0, 0), 139 | im(0x2e, 3, 6), im(0x3e, 3, 7), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 140 | im(0xff, 0, 0), im(0x2a, 1, 2), im(0xff, 0, 0)), 141 | Instruction.RTI to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 142 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 143 | im(0xff, 0, 0), im(0x40, 1, 6), im(0xff, 0, 0)), 144 | Instruction.RTS to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 145 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 146 | im(0xff, 0, 0), im(0x60, 1, 6), im(0xff, 0, 0)), 147 | Instruction.SBC to arrayOf(im(0xe9, 2, 2), im(0xe5, 2, 3), im(0xf5, 2, 4), im(0xff, 0, 0), 148 | im(0xed, 3, 4), im(0xfd, 3, 4), im(0xf9, 3, 4), im(0xff, 0, 0), im(0xe1, 2, 6), 149 | im(0xf1, 2, 5), im(0xff, 0, 0), im(0xff, 0, 0)), 150 | Instruction.STA to arrayOf(im(0xff, 0, 0), im(0x85, 2, 3), im(0x95, 2, 4), im(0xff, 0, 0), 151 | im(0x8d, 3, 4), im(0x9d, 3, 5), im(0x99, 3, 5), im(0xff, 0, 0), im(0x81, 2, 6), 152 | im(0x91, 2, 6), im(0xff, 0, 0), im(0xff, 0, 0)), 153 | Instruction.TXS to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 154 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 155 | im(0xff, 0, 0), im(0x9a, 1, 2), im(0xff, 0, 0)), 156 | Instruction.TSX to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 157 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 158 | im(0xff, 0, 0), im(0xba, 1, 2), im(0xff, 0, 0)), 159 | Instruction.PHA to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 160 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 161 | im(0xff, 0, 0), im(0x48, 1, 3), im(0xff, 0, 0)), 162 | Instruction.PLA to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 163 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 164 | im(0xff, 0, 0), im(0x68, 1, 4), im(0xff, 0, 0)), 165 | Instruction.PHP to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 166 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 167 | im(0xff, 0, 0), im(0xff, 0, 0), im(0x08, 1, 3), im(0xff, 0, 0)), 168 | Instruction.PLP to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 169 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 170 | im(0xff, 0, 0), im(0xff, 0, 0), im(0x28, 1, 4), im(0xff, 0, 0)), 171 | Instruction.STX to arrayOf(im(0xff, 0, 0), im(0x86, 2, 3), im(0xff, 0, 0), im(0x96, 2, 4), 172 | im(0x8e, 3, 4), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 173 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0)), 174 | Instruction.STY to arrayOf(im(0xff, 0, 0), im(0x84, 2, 3), im(0x94, 2, 4), im(0xff, 0, 0), 175 | im(0x8c, 3, 4), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 176 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0)), 177 | Instruction.XXX to arrayOf(im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 178 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0), 179 | im(0xff, 0, 0), im(0xff, 0, 0), im(0xff, 0, 0))) 180 | } 181 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/Symbols.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions 2 | 3 | import java.util.* 4 | 5 | class Symbols : HashMap() -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/ADC.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** ADd with Carry */ 8 | class ADC(private val cpu: CPU) : BaseInstruction(Instruction.ADC, cpu) { 9 | override fun immediate() { 10 | testADC(cpu.popByte()) 11 | } 12 | 13 | private fun testADC(value: Int) { 14 | var tmp: Int 15 | if (cpu.A.xor(value).and(0x80) != 0) { 16 | cpu.CLV() 17 | } else { 18 | cpu.setOverflow() 19 | } 20 | 21 | if (cpu.decimalMode()) { 22 | tmp = cpu.A.and(0xf) + value.and(0xf) + cpu.P.and(1) 23 | if (tmp >= 10) { 24 | tmp = 0x10.or((tmp + 6).and(0xf)) 25 | } 26 | tmp += cpu.A.and(0xf0) + value.and(0xf0) 27 | if (tmp >= 160) { 28 | cpu.SEC() 29 | if (cpu.overflow() && tmp >= 0x180) { 30 | cpu.CLV() 31 | } 32 | tmp += 0x60 33 | } else { 34 | cpu.CLC() 35 | if (cpu.overflow() && tmp < 0x80) { 36 | cpu.CLV() 37 | } 38 | } 39 | } else { 40 | tmp = cpu.A + value + cpu.P.and(1) 41 | if (tmp >= 0x100) { 42 | cpu.SEC() 43 | if (cpu.overflow() && tmp >= 0x180) { 44 | cpu.CLV() 45 | } 46 | } else { 47 | cpu.CLC() 48 | if (cpu.overflow() && tmp < 0x80) { 49 | cpu.CLV() 50 | } 51 | } 52 | } 53 | cpu.A = tmp.and(0xff) 54 | cpu.setSZFlagsForRegA() 55 | } 56 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/AND.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** bitwise AND with accumulator */ 8 | class AND(private val cpu: CPU) : BaseInstruction(Instruction.AND, cpu) { 9 | override fun immediate() { 10 | cpu.A = cpu.A.and(cpu.popByte()) 11 | cpu.setSZFlagsForRegA() 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/ASL.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** Arithmetic Shift Left */ 8 | class ASL(private val cpu: CPU) : BaseInstruction(Instruction.ASL, cpu) 9 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/BCC.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** Branch on Carry Clear */ 8 | class BCC(private val cpu: CPU) : BaseInstruction(Instruction.BCC, cpu) { 9 | override fun branch() { 10 | val offset = cpu.popByte() 11 | if (!cpu.carry()) { 12 | cpu.jumpBranch(offset) 13 | } 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/BCS.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** Branch on Carry Set */ 8 | class BCS(private val cpu: CPU) : BaseInstruction(Instruction.BCS, cpu) { 9 | override fun branch() { 10 | val offset = cpu.popByte() 11 | if (cpu.carry()) { 12 | cpu.jumpBranch(offset) 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/BEQ.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** Branch on EQual */ 8 | class BEQ(private val cpu: CPU) : BaseInstruction(Instruction.BEQ, cpu) { 9 | override fun branch() { 10 | val offset = cpu.popByte() 11 | if (cpu.zero()) { 12 | cpu.jumpBranch(offset) 13 | } 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/BIT.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** test BITs */ 8 | class BIT(private val cpu: CPU) : BaseInstruction(Instruction.BIT, cpu) { 9 | override fun zeroPage() { 10 | val value = cpu.memory.get(cpu.popByte()) 11 | BIT(value) 12 | } 13 | 14 | private fun BIT(value: Int) { 15 | if (value.and(0x80) != 0) { 16 | cpu.P = cpu.P.or(0x80) 17 | } else { 18 | cpu.P = cpu.P.and(0x7f) 19 | } 20 | if (value.and(0x40) != 0) { 21 | cpu.P = cpu.P.or(0x40) 22 | } else { 23 | cpu.P = cpu.P.and(0x40.inv()) 24 | } 25 | if (cpu.A.and(value) != 0) { 26 | cpu.P = cpu.P.and(0xfd) 27 | } else { 28 | cpu.P = cpu.P.or(0x02) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/BNE.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** Branch on Not Equal */ 8 | class BNE(private val cpu: CPU) : BaseInstruction(Instruction.BNE, cpu) { 9 | override fun branch() { 10 | val offset = cpu.popByte() 11 | if (!cpu.zero()) { 12 | cpu.jumpBranch(offset) 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/BPL.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** Branch on PLus */ 8 | class BPL(private val cpu: CPU) : BaseInstruction(Instruction.BPL, cpu) { 9 | override fun branch() { 10 | val offset = cpu.popByte() 11 | if (!cpu.negative()) { 12 | cpu.jumpBranch(offset) 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/BRK.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** BRreaK */ 8 | class BRK(private val cpu: CPU) : BaseInstruction(Instruction.BRK, cpu) { 9 | override fun single() { 10 | cpu.stop() 11 | } 12 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/CLC.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** CLear Carry */ 8 | class CLC(private val cpu: CPU) : BaseInstruction(Instruction.CLC, cpu) { 9 | override fun single() { 10 | cpu.CLC() 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/CMP.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** CoMPare accumulator */ 8 | class CMP(private val cpu: CPU) : BaseInstruction(Instruction.CMP, cpu) { 9 | override fun immediate() { 10 | cpu.doCompare(cpu.A, cpu.popByte()) 11 | } 12 | 13 | override fun zeroPage() { 14 | val value = cpu.memory.get(cpu.popByte()) 15 | cpu.doCompare(cpu.A, value) 16 | } 17 | } 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/CPX.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** ComPare X register */ 8 | class CPX(private val cpu: CPU) : BaseInstruction(Instruction.CPX, cpu) { 9 | override fun immediate() { 10 | val value = cpu.popByte() 11 | cpu.doCompare(cpu.X, value) 12 | } 13 | 14 | override fun zeroPage() { 15 | val value = cpu.memory.get(cpu.popByte()) 16 | cpu.doCompare(cpu.X, value) 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/DEC.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** DECrement memory */ 8 | class DEC(private val cpu: CPU) : BaseInstruction(Instruction.DEC, cpu) { 9 | override fun zeroPage() { 10 | DEC(cpu.popByte()) 11 | } 12 | 13 | fun DEC(addr: Int) { 14 | var value = cpu.memory.get(addr) 15 | value = (value - 1).and(0xff) 16 | cpu.memory.storeByte(addr, value) 17 | cpu.setSVFlagsForValue(value) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/DEX.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** DEcrement X */ 8 | class DEX(private val cpu: CPU) : BaseInstruction(Instruction.DEX, cpu) { 9 | override fun single() { 10 | cpu.X = (cpu.X - 1).and(0xff) 11 | cpu.setSZflagsForRegX() 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/DEY.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** DEcrement Y */ 8 | class DEY(private val cpu: CPU) : BaseInstruction(Instruction.DEY, cpu) { 9 | override fun single() { 10 | cpu.Y = (cpu.Y - 1).and(0xff) 11 | cpu.setSZflagsForRegY() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/INC.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** INCrement memory */ 8 | class INC(private val cpu: CPU) : BaseInstruction(Instruction.INC, cpu) { 9 | override fun zeroPage() { 10 | inc(cpu.popByte()) 11 | } 12 | 13 | private fun inc(addr: Int) { 14 | var value = cpu.memory.get(addr) 15 | value = (value + 1).and(0xff) 16 | cpu.memory.storeByte(addr, value) 17 | cpu.setSVFlagsForValue(value) 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/INX.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** INcrement X */ 8 | class INX(private val cpu: CPU) : BaseInstruction(Instruction.INX, cpu) { 9 | override fun single() { 10 | cpu.X = (cpu.X + 1).and(0xff) 11 | cpu.setSZflagsForRegX() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/JMP.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** JuMP */ 8 | class JMP(private val cpu: CPU) : BaseInstruction(Instruction.JMP, cpu) { 9 | override fun absolute() { 10 | cpu.PC = cpu.popWord() 11 | } 12 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/JSR.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** Jump to SubRoutine */ 8 | class JSR(private val cpu: CPU) : BaseInstruction(Instruction.JSR, cpu) { 9 | override fun absolute() { 10 | val addr = cpu.popWord() 11 | val currAddr = cpu.PC - 1 12 | cpu.stackPush(currAddr.shr(8).and(0xff)) 13 | cpu.stackPush(currAddr.and(0xff)) 14 | cpu.PC = addr 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/LDA.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** LoaD Accumulator */ 8 | class LDA(private val cpu: CPU) : BaseInstruction(Instruction.LDA, cpu) { 9 | override fun immediate() { 10 | cpu.A = cpu.popByte() 11 | cpu.setSZFlagsForRegA() 12 | } 13 | 14 | override fun zeroPage() { 15 | cpu.A = cpu.memory.get(cpu.popByte()) 16 | cpu.setSZFlagsForRegA() 17 | } 18 | 19 | override fun zeroPageX() { 20 | cpu.A = cpu.memory.get(cpu.popByte() + cpu.X).and(0xff) 21 | cpu.setSZFlagsForRegA() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/LDX.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** LoaD X register */ 8 | class LDX(private val cpu: CPU) : BaseInstruction(Instruction.LDX, cpu) { 9 | override fun immediate() { 10 | cpu.X = cpu.popByte() 11 | cpu.setSZflagsForRegX() 12 | } 13 | 14 | override fun zeroPage() { 15 | cpu.X = cpu.memory.get(cpu.popByte()) 16 | cpu.setSZflagsForRegX() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/LDY.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** LoaD Y register */ 8 | class LDY(private val cpu: CPU) : BaseInstruction(Instruction.LDY, cpu) { 9 | override fun immediate() { 10 | cpu.Y = cpu.popByte() 11 | cpu.setSZflagsForRegY() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/LSR.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** Logical Shift Right */ 8 | class LSR(private val cpu: CPU) : BaseInstruction(Instruction.LSR, cpu) { 9 | override fun single() { 10 | cpu.setCarryFlagFromBit0(cpu.A) 11 | cpu.A = cpu.A.shr(1) 12 | cpu.setSZFlagsForRegA() 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/NOP.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** No OPeration */ 8 | class NOP(private val cpu: CPU) : BaseInstruction(Instruction.NOP, cpu) { 9 | override fun single() { 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/ORA.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** bitwise OR with Accumulator */ 8 | class ORA(cpu: CPU) : BaseInstruction(Instruction.ORA, cpu) { 9 | } -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/RTS.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** ReTurn from Subroutine */ 8 | class RTS(private val cpu: CPU) : BaseInstruction(Instruction.RTS, cpu) { 9 | override fun single() { 10 | cpu.PC = cpu.stackPop().or(cpu.stackPop().shl(8)) + 1 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/SBC.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** SuBtract with Carry */ 8 | class SBC(private val cpu: CPU) : BaseInstruction(Instruction.SBC, cpu) { 9 | override fun immediate() { 10 | testSBC(cpu.popByte()) 11 | } 12 | 13 | private fun testSBC(value: Int) { 14 | if (cpu.A.xor(value).and(0x80) != 0) { 15 | cpu.setOverflow() 16 | } else { 17 | cpu.CLV() 18 | } 19 | 20 | var w: Int 21 | if (cpu.decimalMode()) { 22 | var tmp = 0xf + cpu.A.and(0xf) - value.and(0xf) + cpu.P.and(1) 23 | if (tmp < 0x10) { 24 | w = 0 25 | tmp -= 6 26 | } else { 27 | w = 0x10 28 | tmp -= 0x10 29 | } 30 | w += 0xf0 + cpu.A.and(0xf0) - value.and(0xf0) 31 | if (w < 0x100) { 32 | cpu.CLC() 33 | if (cpu.overflow() && w < 0x80) { 34 | cpu.CLV() 35 | } 36 | w -= 0x60 37 | } else { 38 | cpu.SEC() 39 | if (cpu.overflow() && w >= 0x180) { 40 | cpu.CLV() 41 | } 42 | } 43 | w += tmp 44 | } else { 45 | w = 0xff + cpu.A - value + cpu.P.and(1) 46 | if (w < 0x100) { 47 | cpu.CLC() 48 | if (cpu.overflow() && w < 0x80) { 49 | cpu.CLV() 50 | } 51 | } else { 52 | cpu.SEC() 53 | if (cpu.overflow() && w >= 0x180) { 54 | cpu.CLV() 55 | } 56 | } 57 | } 58 | cpu.A = w.and(0xff) 59 | cpu.setSZFlagsForRegA() 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/SEC.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** SEt Carry */ 8 | class SEC(private val cpu: CPU) : BaseInstruction(Instruction.SEC, cpu) { 9 | override fun single() { 10 | cpu.carry() 11 | } 12 | } 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/SEI.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** SEt Interrupt */ 8 | class SEI(private val cpu: CPU) : BaseInstruction(Instruction.SEI, cpu) { 9 | } 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/STA.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.Memory 5 | import android.emu6502.instructions.BaseInstruction 6 | import android.emu6502.instructions.Instruction 7 | 8 | /** STore Accumulator */ 9 | class STA(private val memory: Memory, private val cpu: CPU) 10 | : BaseInstruction(Instruction.STA, cpu) { 11 | 12 | override fun absolute() { 13 | memory.storeByte(cpu.popWord(), cpu.A) 14 | } 15 | 16 | override fun zeroPage() { 17 | memory.storeByte(cpu.popByte(), cpu.A) 18 | } 19 | 20 | override fun zeroPageX() { 21 | cpu.memory.storeByte((cpu.popByte() + cpu.X).and(0xff), cpu.A) 22 | } 23 | 24 | override fun indirectY() { 25 | val addr = memory.getWord(cpu.popByte()) + cpu.Y 26 | memory.storeByte(addr, cpu.A) 27 | } 28 | 29 | override fun indirectX() { 30 | val zp = (cpu.popByte() + cpu.X).and(0xff) 31 | val addr = memory.getWord(zp) 32 | memory.storeByte(addr, cpu.A) 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/STX.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** STore X register */ 8 | class STX(private val cpu: CPU) : BaseInstruction(Instruction.STX, cpu) { 9 | override fun zeroPage() { 10 | cpu.memory.storeByte(cpu.popByte(), cpu.X) 11 | } 12 | 13 | override fun absolute() { 14 | cpu.memory.storeByte(cpu.popWord(), cpu.X) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/TAX.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** Transfer A to X */ 8 | class TAX(private val cpu: CPU) : BaseInstruction(Instruction.TAX, cpu) { 9 | override fun single() { 10 | cpu.X = cpu.A.and(0xFF) 11 | cpu.setSZflagsForRegX() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/kotlin/android/emu6502/instructions/impl/TXA.kt: -------------------------------------------------------------------------------- 1 | package android.emu6502.instructions.impl 2 | 3 | import android.emu6502.CPU 4 | import android.emu6502.instructions.BaseInstruction 5 | import android.emu6502.instructions.Instruction 6 | 7 | /** Transfer X to A */ 8 | class TXA(private val cpu: CPU) : BaseInstruction(Instruction.TXA, cpu) { 9 | override fun single() { 10 | cpu.A = cpu.X.and(0xff) 11 | cpu.setSZFlagsForRegA() 12 | } 13 | } 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipecsl/6502Android/b928d84c4911db28cdd2973fd87d3d6ba4d18ea5/app/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 14 | 15 | 20 | 21 | 22 | 23 | 24 | 25 | 29 | 30 | 34 | 35 | 43 | 44 | 50 | 51 | 55 | 56 | 57 | 58 | 59 | 63 | 64 |