├── .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 | 
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 |
70 |
71 |
75 |
76 |
81 |
82 |
89 |
90 |
97 |
98 |
104 |
105 |
106 |
107 |
112 |
113 |
120 |
121 |
128 |
129 |
130 |
131 |
135 |
136 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
152 |
153 |
159 |
160 |
166 |
167 |
173 |
174 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
195 |
196 |
197 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/toolbar.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/felipecsl/6502Android/b928d84c4911db28cdd2973fd87d3d6ba4d18ea5/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_play_arrow_white_48dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/felipecsl/6502Android/b928d84c4911db28cdd2973fd87d3d6ba4d18ea5/app/src/main/res/mipmap-hdpi/ic_play_arrow_white_48dp.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/felipecsl/6502Android/b928d84c4911db28cdd2973fd87d3d6ba4d18ea5/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/felipecsl/6502Android/b928d84c4911db28cdd2973fd87d3d6ba4d18ea5/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_play_arrow_white_48dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/felipecsl/6502Android/b928d84c4911db28cdd2973fd87d3d6ba4d18ea5/app/src/main/res/mipmap-xhdpi/ic_play_arrow_white_48dp.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/felipecsl/6502Android/b928d84c4911db28cdd2973fd87d3d6ba4d18ea5/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_play_arrow_white_48dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/felipecsl/6502Android/b928d84c4911db28cdd2973fd87d3d6ba4d18ea5/app/src/main/res/mipmap-xxhdpi/ic_play_arrow_white_48dp.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #4A90E2
4 | #ff274b76
5 | #e395000a
6 | #cccccc
7 | #dddddd
8 | #20000000
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 | 16dp
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 6502 Android Emulator
3 | Settings
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/kotlin/android/emu6502/AssemblerTest.kt:
--------------------------------------------------------------------------------
1 | package android.emu6502
2 |
3 | import android.emu6502.instructions.Symbols
4 | import com.google.common.collect.ImmutableList
5 | import com.google.common.truth.Truth.assertThat
6 | import org.junit.Test
7 | import org.mockito.Mockito.mock
8 |
9 | class AssemblerTest {
10 | private val assembler = Assembler(Memory(mock(Display::class.java)), Symbols())
11 |
12 | @Test fun testSimple() {
13 | val lines = ImmutableList.of(
14 | "LDA #$01",
15 | "STA $0200",
16 | "LDA #$05",
17 | "STA $0201",
18 | "LDA #$08",
19 | "STA $0202")
20 | assembler.assembleCode(lines)
21 | assertThat(assembler.hexdump()).isEqualTo("0600: A9 01 8D 00 02 A9 05 8D 01 02 A9 08 8D 02 02")
22 | }
23 |
24 | @Test fun testWithComments() {
25 | val lines = ImmutableList.of(
26 | "LDA #\$c0 ;Load the hex value \$c0 into the A register",
27 | "TAX ;Transfer the value in the A register to X",
28 | "INX ;Increment the value in the X register",
29 | "ADC #\$c4 ;Add the hex value \$c4 to the A register",
30 | "BRK ;Break - we're done")
31 | assembler.assembleCode(lines)
32 | assertThat(assembler.hexdump()).isEqualTo("0600: A9 C0 AA E8 69 C4 00")
33 | }
34 |
35 | @Test fun testBranchAndLabel() {
36 | val lines = ImmutableList.of(
37 | "LDX #$08",
38 | "decrement:",
39 | "DEX",
40 | "STX $0200",
41 | "CPX #$03",
42 | "BNE decrement",
43 | "STX $0201",
44 | "BRK")
45 | assembler.assembleCode(lines)
46 | assertThat(assembler.hexdump()).isEqualTo("0600: A2 08 CA 8E 00 02 E0 03 D0 F8 8E 01 02 00")
47 | }
48 |
49 | @Test fun testRelative() {
50 | val lines = ImmutableList.of(
51 | "LDA #$01",
52 | "CMP #$02",
53 | "BNE notequal",
54 | "STA $22",
55 | "notequal:",
56 | "BRK")
57 |
58 | assembler.assembleCode(lines)
59 | assertThat(assembler.hexdump()).isEqualTo("0600: A9 01 C9 02 D0 02 85 22 00")
60 | }
61 |
62 | @Test fun testIndirect() {
63 | val lines = ImmutableList.of(
64 | "LDA #$01",
65 | "STA \$f0",
66 | "LDA #\$cc",
67 | "STA \$f1",
68 | "JMP ($00f0) ;dereferences to \$cc01")
69 |
70 | assembler.assembleCode(lines)
71 | assertThat(assembler.hexdump()).isEqualTo("0600: A9 01 85 F0 A9 CC 85 F1 6C F0 00")
72 | }
73 |
74 | @Test fun testIndirectX() {
75 | val lines = ImmutableList.of(
76 | "LDX #$01",
77 | "LDA #$05",
78 | "STA $01",
79 | "LDA #$06",
80 | "STA $02",
81 | "LDY #$0a",
82 | "STY $0605",
83 | "LDA ($00,X)")
84 |
85 | assembler.assembleCode(lines)
86 | assertThat(assembler.hexdump())
87 | .isEqualTo("0600: A2 01 A9 05 85 01 A9 06 85 02 A0 0A 8C 05 06 A1 \n0610: 00")
88 | }
89 |
90 | @Test fun testIndirectY() {
91 | val lines = ImmutableList.of(
92 | "LDY #$01",
93 | "LDA #$03",
94 | "STA $01",
95 | "LDA #$07",
96 | "STA $02",
97 | "LDX #$0a",
98 | "STX $0704",
99 | "LDA ($01),Y")
100 |
101 | assembler.assembleCode(lines)
102 | assertThat(assembler.hexdump())
103 | .isEqualTo("0600: A0 01 A9 03 85 01 A9 07 85 02 A2 0A 8E 04 07 B1 \n0610: 01")
104 | }
105 |
106 | @Test fun testJump() {
107 | val lines = ImmutableList.of(
108 | "LDA #$03",
109 | "JMP there",
110 | "BRK",
111 | "BRK",
112 | "BRK",
113 | "there:",
114 | "STA $0200")
115 |
116 | assembler.assembleCode(lines)
117 | assertThat(assembler.hexdump()).isEqualTo("0600: A9 03 4C 08 06 00 00 00 8D 00 02")
118 | }
119 |
120 | @Test fun testSymbols() {
121 | val lines = ImmutableList.of(
122 | "define sysRandom \$fe ; an adress",
123 | "define a_dozen $0c ; a constant",
124 | "LDA sysRandom ; equivalent to \"LDA \$fe\"",
125 | "LDX #a_dozen ; equivalent to \"LDX #$0c\"")
126 | assembler.assembleCode(lines)
127 | assertThat(assembler.hexdump()).isEqualTo("0600: A5 FE A2 0C")
128 | }
129 |
130 | @Test fun testSnake() {
131 | val lines = ImmutableList.of(
132 | "define appleL $00 ; screen location of apple, low byte",
133 | "define appleH $01 ; screen location of apple, high byte",
134 | "define snakeHeadL $10 ; screen location of snake head, low byte",
135 | "define snakeHeadH $11 ; screen location of snake head, high byte",
136 | "define snakeBodyStart $12 ; start of snake body byte pairs",
137 | "define snakeDirection $02 ; direction (possible values are below)",
138 | "define snakeLength $03 ; snake length, in bytes",
139 | "; Directions (each using a separate bit)",
140 | "define movingUp 1",
141 | "define movingRight 2",
142 | "define movingDown 4",
143 | "define movingLeft 8",
144 | "; ASCII values of keys controlling the snake",
145 | "define ASCII_w $77",
146 | "define ASCII_a $61",
147 | "define ASCII_s $73",
148 | "define ASCII_d $64",
149 | "; System variables",
150 | "define sysRandom \$fe",
151 | "define sysLastKey \$ff",
152 | " jsr init",
153 | " jsr loop",
154 | "init:",
155 | " jsr initSnake",
156 | " jsr generateApplePosition",
157 | " rts",
158 | "initSnake:",
159 | " lda #movingRight ;start direction",
160 | " sta snakeDirection",
161 | " lda #4 ;start length (2 segments)",
162 | " sta snakeLength",
163 | " ",
164 | " lda #$11",
165 | " sta snakeHeadL",
166 | " ",
167 | " lda #$10",
168 | " sta snakeBodyStart",
169 | " ",
170 | " lda #$0f",
171 | " sta $14 ; body segment 1",
172 | " ",
173 | " lda #$04",
174 | " sta snakeHeadH",
175 | " sta $13 ; body segment 1",
176 | " sta $15 ; body segment 2",
177 | " rts",
178 | "generateApplePosition:",
179 | " ;load a new random byte into $00",
180 | " lda sysRandom",
181 | " sta appleL",
182 | " ;load a new random number from 2 to 5 into $01",
183 | " lda sysRandom",
184 | " and #$03 ;mask out lowest 2 bits",
185 | " clc",
186 | " adc #2",
187 | " sta appleH",
188 | " rts",
189 | "loop:",
190 | " jsr readKeys",
191 | " jsr checkCollision",
192 | " jsr updateSnake",
193 | " jsr drawApple",
194 | " jsr drawSnake",
195 | " jsr spinWheels",
196 | " jmp loop",
197 | "readKeys:",
198 | " lda sysLastKey",
199 | " cmp #ASCII_w",
200 | " beq upKey",
201 | " cmp #ASCII_d",
202 | " beq rightKey",
203 | " cmp #ASCII_s",
204 | " beq downKey",
205 | " cmp #ASCII_a",
206 | " beq leftKey",
207 | " rts",
208 | "upKey:",
209 | " lda #movingDown",
210 | " bit snakeDirection",
211 | " bne illegalMove",
212 |
213 | " lda #movingUp",
214 | " sta snakeDirection",
215 | " rts",
216 | "rightKey:",
217 | " lda #movingLeft",
218 | " bit snakeDirection",
219 | " bne illegalMove",
220 | " lda #movingRight",
221 | " sta snakeDirection",
222 | " rts",
223 | "downKey:",
224 | " lda #movingUp",
225 | " bit snakeDirection",
226 | " bne illegalMove",
227 | " lda #movingDown",
228 | " sta snakeDirection",
229 | " rts",
230 | "leftKey:",
231 | " lda #movingRight",
232 | " bit snakeDirection",
233 | " bne illegalMove",
234 | " lda #movingLeft",
235 | " sta snakeDirection",
236 | " rts",
237 | "illegalMove:",
238 | " rts",
239 | "checkCollision:",
240 | " jsr checkAppleCollision",
241 | " jsr checkSnakeCollision",
242 | " rts",
243 | "checkAppleCollision:",
244 | " lda appleL",
245 | " cmp snakeHeadL",
246 | " bne doneCheckingAppleCollision",
247 | " lda appleH",
248 | " cmp snakeHeadH",
249 | " bne doneCheckingAppleCollision",
250 | " ;eat apple",
251 | " inc snakeLength",
252 | " inc snakeLength ;increase length",
253 | " jsr generateApplePosition",
254 | "doneCheckingAppleCollision:",
255 | " rts",
256 | "checkSnakeCollision:",
257 | " ldx #2 ;start with second segment",
258 | "snakeCollisionLoop:",
259 | " lda snakeHeadL,x",
260 | " cmp snakeHeadL",
261 | " bne continueCollisionLoop",
262 | "maybeCollided:",
263 | " lda snakeHeadH,x",
264 | " cmp snakeHeadH",
265 | " beq didCollide",
266 | "continueCollisionLoop:",
267 | " inx",
268 | " inx",
269 | " cpx snakeLength ;got to last section with no collision",
270 | " beq didntCollide",
271 | " jmp snakeCollisionLoop",
272 | "didCollide:",
273 | " jmp gameOver",
274 | "didntCollide:",
275 | " rts",
276 | "updateSnake:",
277 | " ldx snakeLength",
278 | " dex",
279 | " txa",
280 | "updateloop:",
281 | " lda snakeHeadL,x",
282 | " sta snakeBodyStart,x",
283 | " dex",
284 | " bpl updateloop",
285 | " lda snakeDirection",
286 | " lsr",
287 | " bcs up",
288 | " lsr",
289 | " bcs right",
290 | " lsr",
291 | " bcs down",
292 | " lsr",
293 | " bcs left",
294 | "up:",
295 | " lda snakeHeadL",
296 | " sec",
297 | " sbc #$20",
298 | " sta snakeHeadL",
299 | " bcc upup",
300 | " rts",
301 | "upup:",
302 | " dec snakeHeadH",
303 | " lda #$1",
304 | " cmp snakeHeadH",
305 | " beq collision",
306 | " rts",
307 | "right:",
308 | " inc snakeHeadL",
309 | " lda #$1f",
310 | " bit snakeHeadL",
311 | " beq collision",
312 | " rts",
313 | "down:",
314 | " lda snakeHeadL",
315 | " clc",
316 | " adc #$20",
317 | " sta snakeHeadL",
318 | " bcs downdown",
319 | " rts",
320 | "downdown:",
321 | " inc snakeHeadH",
322 | " lda #$6",
323 | " cmp snakeHeadH",
324 | " beq collision",
325 | " rts",
326 | "left:",
327 | " dec snakeHeadL",
328 | " lda snakeHeadL",
329 | " and #$1f",
330 | " cmp #$1f",
331 | " beq collision",
332 | " rts",
333 | "collision:",
334 | " jmp gameOver",
335 | "drawApple:",
336 | " ldy #0",
337 | " lda sysRandom",
338 | " sta (appleL),y",
339 | " rts",
340 | "drawSnake:",
341 | " ldx #0",
342 | " lda #1",
343 | " sta (snakeHeadL,x) ; paint head",
344 | " ",
345 | " ldx snakeLength",
346 | " lda #0",
347 | " sta (snakeHeadL,x) ; erase end of tail",
348 | " rts",
349 | "spinWheels:",
350 | " ldx #0",
351 | "spinloop:",
352 | " nop",
353 | " nop",
354 | " dex",
355 | " bne spinloop",
356 | " rts",
357 | "gameOver:", "\n")
358 | assembler.assembleCode(lines)
359 | assertThat(assembler.hexdump().toLowerCase()).isEqualTo(
360 | "0600: 20 06 06 20 38 06 20 0d 06 20 2a 06 60 a9 02 85 \n" +
361 | "0610: 02 a9 04 85 03 a9 11 85 10 a9 10 85 12 a9 0f 85 \n" +
362 | "0620: 14 a9 04 85 11 85 13 85 15 60 a5 fe 85 00 a5 fe \n" +
363 | "0630: 29 03 18 69 02 85 01 60 20 4d 06 20 8d 06 20 c3 \n" +
364 | "0640: 06 20 19 07 20 20 07 20 2d 07 4c 38 06 a5 ff c9 \n" +
365 | "0650: 77 f0 0d c9 64 f0 14 c9 73 f0 1b c9 61 f0 22 60 \n" +
366 | "0660: a9 04 24 02 d0 26 a9 01 85 02 60 a9 08 24 02 d0 \n" +
367 | "0670: 1b a9 02 85 02 60 a9 01 24 02 d0 10 a9 04 85 02 \n" +
368 | "0680: 60 a9 02 24 02 d0 05 a9 08 85 02 60 60 20 94 06 \n" +
369 | "0690: 20 a8 06 60 a5 00 c5 10 d0 0d a5 01 c5 11 d0 07 \n" +
370 | "06a0: e6 03 e6 03 20 2a 06 60 a2 02 b5 10 c5 10 d0 06 \n" +
371 | "06b0: b5 11 c5 11 f0 09 e8 e8 e4 03 f0 06 4c aa 06 4c \n" +
372 | "06c0: 35 07 60 a6 03 ca 8a b5 10 95 12 ca 10 f9 a5 02 \n" +
373 | "06d0: 4a b0 09 4a b0 19 4a b0 1f 4a b0 2f a5 10 38 e9 \n" +
374 | "06e0: 20 85 10 90 01 60 c6 11 a9 01 c5 11 f0 28 60 e6 \n" +
375 | "06f0: 10 a9 1f 24 10 f0 1f 60 a5 10 18 69 20 85 10 b0 \n" +
376 | "0700: 01 60 e6 11 a9 06 c5 11 f0 0c 60 c6 10 a5 10 29 \n" +
377 | "0710: 1f c9 1f f0 01 60 4c 35 07 a0 00 a5 fe 91 00 60 \n" +
378 | "0720: a2 00 a9 01 81 10 a6 03 a9 00 81 10 60 a2 00 ea \n" +
379 | "0730: ea ca d0 fb 60")
380 | }
381 | }
382 |
--------------------------------------------------------------------------------
/app/src/test/kotlin/android/emu6502/CPUTest.kt:
--------------------------------------------------------------------------------
1 | package android.emu6502
2 |
3 | import android.emu6502.instructions.Symbols
4 | import com.google.common.collect.ImmutableList
5 | import org.hamcrest.CoreMatchers.equalTo
6 | import org.junit.Assert.assertThat
7 | import org.junit.Test
8 | import org.mockito.Mockito.mock
9 |
10 | class CPUTest {
11 | private val memory = Memory(mock(Display::class.java))
12 | private val assembler = Assembler(memory, Symbols())
13 | private val cpu = CPU(memory)
14 |
15 | @Test fun testSimple() {
16 | val lines = ImmutableList.of(
17 | "LDA #$01",
18 | "STA $0200",
19 | "LDA #$05",
20 | "STA $0201",
21 | "LDA #$08",
22 | "STA $0202")
23 | assembler.assembleCode(lines)
24 | cpu.testRun()
25 | assertThat(cpu.A, equalTo(0x08))
26 | assertThat(cpu.X, equalTo(0x00))
27 | assertThat(cpu.Y, equalTo(0x00))
28 | assertThat(cpu.SP, equalTo(0xFF))
29 | assertThat(cpu.PC, equalTo(0x0610))
30 | assertThat(cpu.flags(), equalTo("00110000"))
31 | }
32 |
33 | @Test fun testWithComments() {
34 | val lines = ImmutableList.of(
35 | "LDA #\$c0 ;Load the hex value \$c0 into the A register",
36 | "TAX ;Transfer the value in the A register to X",
37 | "INX ;Increment the value in the X register",
38 | "ADC #\$c4 ;Add the hex value \$c4 to the A register",
39 | "BRK ;Break - we're done")
40 | assembler.assembleCode(lines)
41 | cpu.testRun()
42 | assertThat(cpu.A, equalTo(0x84))
43 | assertThat(cpu.X, equalTo(0xC1))
44 | assertThat(cpu.Y, equalTo(0x00))
45 | assertThat(cpu.SP, equalTo(0xFF))
46 | assertThat(cpu.PC, equalTo(0x0607))
47 | assertThat(cpu.flags(), equalTo("10110001"))
48 | }
49 |
50 | @Test fun testBranchAndLabel() {
51 | val lines = ImmutableList.of(
52 | "LDX #$08",
53 |
54 | "decrement:",
55 | "DEX",
56 | "STX $0200",
57 | "CPX #$03",
58 | "BNE decrement",
59 | "STX $0201",
60 | "BRK")
61 | assembler.assembleCode(lines)
62 | cpu.testRun()
63 | assertThat(cpu.A, equalTo(0x00))
64 | assertThat(cpu.X, equalTo(0x03))
65 | assertThat(cpu.Y, equalTo(0x00))
66 | assertThat(cpu.SP, equalTo(0xFF))
67 | assertThat(cpu.PC, equalTo(0x060e))
68 | assertThat(cpu.flags(), equalTo("00110011"))
69 | }
70 |
71 | @Test fun testJump() {
72 | val lines = ImmutableList.of(
73 | "LDA #$03",
74 | "JMP there",
75 | "BRK",
76 | "BRK",
77 | "BRK",
78 |
79 | "there:",
80 | "STA $0200")
81 | assembler.assembleCode(lines)
82 | cpu.testRun()
83 | assertThat(cpu.A, equalTo(0x03))
84 | assertThat(cpu.X, equalTo(0x00))
85 | assertThat(cpu.Y, equalTo(0x00))
86 | assertThat(cpu.SP, equalTo(0xFF))
87 | assertThat(cpu.PC, equalTo(0x060c))
88 | assertThat(cpu.flags(), equalTo("00110000"))
89 | }
90 |
91 | @Test fun testJumpToSubroutines() {
92 | val lines = ImmutableList.of(
93 | "JSR init",
94 | "JSR loop",
95 | "JSR end",
96 |
97 | "init:",
98 | "LDX #$00",
99 | "RTS",
100 |
101 | "loop:",
102 | "INX",
103 | "CPX #$05",
104 | "BNE loop",
105 | "RTS",
106 |
107 | "end:",
108 | "BRK")
109 | assembler.assembleCode(lines)
110 | cpu.testRun()
111 | assertThat(cpu.A, equalTo(0x00))
112 | assertThat(cpu.X, equalTo(0x05))
113 | assertThat(cpu.Y, equalTo(0x00))
114 | assertThat(cpu.SP, equalTo(0xFD))
115 | assertThat(cpu.PC, equalTo(0x0613))
116 | assertThat(cpu.flags(), equalTo("00110011"))
117 | }
118 |
119 | @Test fun testSymbols() {
120 | val lines = ImmutableList.of(
121 | "define a_dozen $0c ; a constant",
122 | "LDX #a_dozen ; equivalent to \"LDX #$0c\"")
123 | assembler.assembleCode(lines)
124 | cpu.testRun()
125 | assertThat(cpu.A, equalTo(0x00))
126 | assertThat(cpu.X, equalTo(0x0C))
127 | assertThat(cpu.Y, equalTo(0x00))
128 | assertThat(cpu.SP, equalTo(0xFF))
129 | assertThat(cpu.PC, equalTo(0x0603))
130 | assertThat(cpu.flags(), equalTo("00110000"))
131 | }
132 |
133 | @Test fun testSnake() {
134 | val lines = ImmutableList.of(
135 | "define appleL $00 ; screen location of apple, low byte",
136 | "define appleH $01 ; screen location of apple, high byte",
137 | "define snakeHeadL $10 ; screen location of snake head, low byte",
138 | "define snakeHeadH $11 ; screen location of snake head, high byte",
139 | "define snakeBodyStart $12 ; start of snake body byte pairs",
140 | "define snakeDirection $02 ; direction (possible values are below)",
141 | "define snakeLength $03 ; snake length, in bytes",
142 | "; Directions (each using a separate bit)",
143 | "define movingUp 1",
144 | "define movingRight 2",
145 | "define movingDown 4",
146 | "define movingLeft 8",
147 | "; ASCII values of keys controlling the snake",
148 | "define ASCII_w $77",
149 | "define ASCII_a $61",
150 | "define ASCII_s $73",
151 | "define ASCII_d $64",
152 | "; System variables",
153 | "define sysRandom \$fe",
154 | "define sysLastKey \$ff",
155 | " jsr init",
156 | " jsr loop",
157 | "init:",
158 | " jsr initSnake",
159 | " jsr generateApplePosition",
160 | " rts",
161 | "initSnake:",
162 | " lda #movingRight ;start direction",
163 | " sta snakeDirection",
164 | " lda #4 ;start length (2 segments)",
165 | " sta snakeLength",
166 | " ",
167 | " lda #$11",
168 | " sta snakeHeadL",
169 | " ",
170 | " lda #$10",
171 | " sta snakeBodyStart",
172 | " ",
173 | " lda #$0f",
174 | " sta $14 ; body segment 1",
175 | " ",
176 | " lda #$04",
177 | " sta snakeHeadH",
178 | " sta $13 ; body segment 1",
179 | " sta $15 ; body segment 2",
180 | " rts",
181 | "generateApplePosition:",
182 | " ;load a new random byte into $00",
183 | " lda sysRandom",
184 | " sta appleL",
185 | " ;load a new random number from 2 to 5 into $01",
186 | " lda sysRandom",
187 | " and #$03 ;mask out lowest 2 bits",
188 | " clc",
189 | " adc #2",
190 | " sta appleH",
191 | " rts",
192 | "loop:",
193 | " jsr readKeys",
194 | " jsr checkCollision",
195 | " jsr updateSnake",
196 | " jsr drawApple",
197 | " jsr drawSnake",
198 | " jsr spinWheels",
199 | " jmp loop",
200 | "readKeys:",
201 | " lda sysLastKey",
202 | " cmp #ASCII_w",
203 | " beq upKey",
204 | " cmp #ASCII_d",
205 | " beq rightKey",
206 | " cmp #ASCII_s",
207 | " beq downKey",
208 | " cmp #ASCII_a",
209 | " beq leftKey",
210 | " rts",
211 | "upKey:",
212 | " lda #movingDown",
213 | " bit snakeDirection",
214 | " bne illegalMove",
215 |
216 | " lda #movingUp",
217 | " sta snakeDirection",
218 | " rts",
219 | "rightKey:",
220 | " lda #movingLeft",
221 | " bit snakeDirection",
222 | " bne illegalMove",
223 | " lda #movingRight",
224 | " sta snakeDirection",
225 | " rts",
226 | "downKey:",
227 | " lda #movingUp",
228 | " bit snakeDirection",
229 | " bne illegalMove",
230 | " lda #movingDown",
231 | " sta snakeDirection",
232 | " rts",
233 | "leftKey:",
234 | " lda #movingRight",
235 | " bit snakeDirection",
236 | " bne illegalMove",
237 | " lda #movingLeft",
238 | " sta snakeDirection",
239 | " rts",
240 | "illegalMove:",
241 | " rts",
242 | "checkCollision:",
243 | " jsr checkAppleCollision",
244 | " jsr checkSnakeCollision",
245 | " rts",
246 | "checkAppleCollision:",
247 | " lda appleL",
248 | " cmp snakeHeadL",
249 | " bne doneCheckingAppleCollision",
250 | " lda appleH",
251 | " cmp snakeHeadH",
252 | " bne doneCheckingAppleCollision",
253 | " ;eat apple",
254 | " inc snakeLength",
255 | " inc snakeLength ;increase length",
256 | " jsr generateApplePosition",
257 | "doneCheckingAppleCollision:",
258 | " rts",
259 | "checkSnakeCollision:",
260 | " ldx #2 ;start with second segment",
261 | "snakeCollisionLoop:",
262 | " lda snakeHeadL,x",
263 | " cmp snakeHeadL",
264 | " bne continueCollisionLoop",
265 | "maybeCollided:",
266 | " lda snakeHeadH,x",
267 | " cmp snakeHeadH",
268 | " beq didCollide",
269 | "continueCollisionLoop:",
270 | " inx",
271 | " inx",
272 | " cpx snakeLength ;got to last section with no collision",
273 | " beq didntCollide",
274 | " jmp snakeCollisionLoop",
275 | "didCollide:",
276 | " jmp gameOver",
277 | "didntCollide:",
278 | " rts",
279 | "updateSnake:",
280 | " ldx snakeLength",
281 | " dex",
282 | " txa",
283 | "updateloop:",
284 | " lda snakeHeadL,x",
285 | " sta snakeBodyStart,x",
286 | " dex",
287 | " bpl updateloop",
288 | " lda snakeDirection",
289 | " lsr",
290 | " bcs up",
291 | " lsr",
292 | " bcs right",
293 | " lsr",
294 | " bcs down",
295 | " lsr",
296 | " bcs left",
297 | "up:",
298 | " lda snakeHeadL",
299 | " sec",
300 | " sbc #$20",
301 | " sta snakeHeadL",
302 | " bcc upup",
303 | " rts",
304 | "upup:",
305 | " dec snakeHeadH",
306 | " lda #$1",
307 | " cmp snakeHeadH",
308 | " beq collision",
309 | " rts",
310 | "right:",
311 | " inc snakeHeadL",
312 | " lda #$1f",
313 | " bit snakeHeadL",
314 | " beq collision",
315 | " rts",
316 | "down:",
317 | " lda snakeHeadL",
318 | " clc",
319 | " adc #$20",
320 | " sta snakeHeadL",
321 | " bcs downdown",
322 | " rts",
323 | "downdown:",
324 | " inc snakeHeadH",
325 | " lda #$6",
326 | " cmp snakeHeadH",
327 | " beq collision",
328 | " rts",
329 | "left:",
330 | " dec snakeHeadL",
331 | " lda snakeHeadL",
332 | " and #$1f",
333 | " cmp #$1f",
334 | " beq collision",
335 | " rts",
336 | "collision:",
337 | " jmp gameOver",
338 | "drawApple:",
339 | " ldy #0",
340 | " lda sysRandom",
341 | " sta (appleL),y",
342 | " rts",
343 | "drawSnake:",
344 | " ldx #0",
345 | " lda #1",
346 | " sta (snakeHeadL,x) ; paint head",
347 | " ",
348 | " ldx snakeLength",
349 | " lda #0",
350 | " sta (snakeHeadL,x) ; erase end of tail",
351 | " rts",
352 | "spinWheels:",
353 | " ldx #0",
354 | "spinloop:",
355 | " nop",
356 | " nop",
357 | " dex",
358 | " bne spinloop",
359 | " rts",
360 | "gameOver:", "\n")
361 | assembler.assembleCode(lines)
362 | cpu.testRun()
363 | assertThat(cpu.A, equalTo(0x1f))
364 | assertThat(cpu.X, equalTo(0xff))
365 | assertThat(cpu.Y, equalTo(0x00))
366 | assertThat(cpu.SP, equalTo(0xfb))
367 | assertThat(cpu.PC, equalTo(0x0736))
368 | assertThat(cpu.flags(), equalTo("00110011"))
369 | }
370 | }
371 |
--------------------------------------------------------------------------------
/app/src/test/kotlin/android/emu6502/LabelsTest.kt:
--------------------------------------------------------------------------------
1 | package android.emu6502
2 |
3 | import android.emu6502.instructions.Symbols
4 | import org.hamcrest.CoreMatchers.equalTo
5 | import org.junit.Assert.assertThat
6 | import org.junit.Test
7 | import org.mockito.Mockito.mock
8 |
9 | class LabelsTest {
10 | private val symbols = Symbols()
11 | private val assembler = Assembler(Memory(mock(Display::class.java)), symbols)
12 | private val labels = Labels(assembler, symbols)
13 |
14 | @Test fun testAddLabel() {
15 | labels.indexLines(listOf("test:"))
16 | assertThat(labels["test"], equalTo(assembler.defaultCodePC))
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/test/kotlin/android/emu6502/nes/INESFileParserTest.kt:
--------------------------------------------------------------------------------
1 | package android.emu6502.nes
2 |
3 | import com.google.common.truth.Truth.assertThat
4 | import org.junit.After
5 | import org.junit.Before
6 | import org.junit.Test
7 | import java.io.File
8 |
9 | class INESFileParserTest {
10 | private val tempFile = File.createTempFile("foo", "bar")
11 |
12 | @Before fun setUp() {
13 | tempFile.writeBytes((0..40).map(Int::toByte).toByteArray())
14 | }
15 |
16 | @After fun tearDown() {
17 | tempFile.delete()
18 | }
19 |
20 | @Test fun invalidHeader() {
21 | assertThat(INESFileParser.parseFileHeader(tempFile.inputStream()).isValid()).isFalse()
22 | }
23 |
24 | @Test fun validHeader() {
25 | val testRom = javaClass.classLoader!!.getResource("roms/testrom.nes").toURI()
26 | val header = INESFileParser.parseFileHeader(File(testRom).inputStream())
27 | assertThat(header).isEqualTo(INESFileHeader(
28 | INESFileParser.INES_FILE_MAGIC, 0x10, 0x10, 0x40, 0x0, 0x0, INESFileParser.PADDING))
29 | assertThat(header.isValid()).isTrue()
30 | }
31 |
32 | @Test fun testMapper() {
33 | val testRom = javaClass.classLoader!!.getResource("roms/testrom.nes").toURI()
34 | val cartridge = INESFileParser.parseCartridge(File(testRom))
35 | // super mario bros 3 is Mapper 4 (MMC3)
36 | assertThat(cartridge.mapper).isEqualTo(4)
37 | }
38 | }
--------------------------------------------------------------------------------
/app/src/test/resources/roms/testrom.nes:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/felipecsl/6502Android/b928d84c4911db28cdd2973fd87d3d6ba4d18ea5/app/src/test/resources/roms/testrom.nes
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | google()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.3.0-alpha08'
10 | classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.61'
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | jcenter()
20 | google()
21 | maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/felipecsl/6502Android/b928d84c4911db28cdd2973fd87d3d6ba4d18ea5/demo.gif
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | org.gradle.parallel=true
19 | android.useAndroidX=true
20 | android.enableJetifier=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/felipecsl/6502Android/b928d84c4911db28cdd2973fd87d3d6ba4d18ea5/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Mar 07 20:34:27 PST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------