Skip to content

Commit

Permalink
Refactor project for kotlin/native and multiplatform support
Browse files Browse the repository at this point in the history
  • Loading branch information
felipecsl committed Aug 29, 2018
1 parent 52d85f8 commit 1185a44
Show file tree
Hide file tree
Showing 79 changed files with 704 additions and 408 deletions.
File renamed without changes.
9 changes: 5 additions & 4 deletions app/build.gradle → android/app/build.gradle
@@ -1,5 +1,5 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-platform-android'
apply plugin: 'kotlin-android-extensions'

android {
Expand Down Expand Up @@ -28,11 +28,12 @@ dependencies {
implementation 'com.google.android.material:material:1.0.0-alpha1'
implementation 'androidx.appcompat:appcompat:1.0.0-alpha1'
implementation 'androidx.cardview:cardview:1.0.0-alpha1'
implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.2.60'
implementation "org.jetbrains.kotlin:kotlin-reflect:1.2.60"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
expectedBy project(':common')

testImplementation 'junit:junit:4.12'
testImplementation 'com.google.truth:truth:0.42'
testImplementation 'org.mockito:mockito-core:1.10.19'
testImplementation "org.robolectric:robolectric:3.8"
}
}
File renamed without changes.
File renamed without changes.
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,8 @@
package com.felipecsl.android

@Suppress("NOTHING_TO_INLINE")
inline infix fun Byte.and(other: Int): Int = (this.toInt() and other)

fun Int.toHexString(): String {
return java.lang.String.format("%02X", this)
}
Expand Down
@@ -1,51 +1,26 @@
package com.felipecsl.android.app

import android.annotation.SuppressLint
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.app.ActionBar
import androidx.appcompat.app.AppCompatActivity
import com.felipecsl.android.R
import com.felipecsl.android.nes.Console
import com.felipecsl.android.nes.INESFileParser
import com.felipecsl.android.toHexString
import com.felipecsl.knes.Bitmap
import com.felipecsl.knes.Director
import com.felipecsl.knes.Surface
import com.felipecsl.knes.startConsole
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.toolbar.*
import java.util.concurrent.Executors
import java.util.logging.Logger

class MainActivity : AppCompatActivity() {
private lateinit var console: Console
private val LOG = Logger.getLogger("NesGLRenderer")
private var lastSecond: Long = 0
private var totalCycles: Long = 0
private val executor = Executors.newSingleThreadExecutor {
Thread(it).also { t ->
t.priority = Thread.MAX_PRIORITY
}
}
private val cpuRunnable = object : Runnable {
@SuppressLint("SetTextI18n")
override fun run() {
totalCycles += console.step()
val cycleEnd = System.currentTimeMillis()
if (cycleEnd - lastSecond >= 1000) {
val finalCycles = totalCycles
// a second has passed
runOnUiThread {
frequency.text = "Frequency=${finalCycles / 1000}KHz"
A.text = "A=$${console.cpu.A.toHexString()}"
X.text = "X=$${console.cpu.X.toHexString()}"
Y.text = "Y=$${console.cpu.Y.toHexString()}"
SP.text = "SP=$${console.cpu.SP.toHexString()}"
PC.text = "PC=$${console.cpu.PC.toHexString()}"
flags.text = "flags=$${console.cpu.flags().toHexString()}"
}
lastSecond = System.currentTimeMillis()
totalCycles = 0
}
executor.submit(this)
private val executor = Executors.newSingleThreadExecutor()
private val surface = object : Surface {
override fun setTexture(bitmap: Bitmap) {
surface_view.setTexture(bitmap.delegate)
}
}

Expand All @@ -56,14 +31,17 @@ class MainActivity : AppCompatActivity() {
val actionBar: ActionBar = supportActionBar!!
actionBar.setDisplayHomeAsUpEnabled(true)
fabRun.setOnClickListener {
val cartridge = INESFileParser.parseCartridge(resources.openRawResource(R.raw.smb3))
console = Console.newConsole(cartridge, surface_view)
console.reset()
lastSecond = System.currentTimeMillis()
executor.submit(cpuRunnable)
val cartridgeData = resources.openRawResource(R.raw.smb3).readBytes()
executor.submit {
if (USE_NATIVE_CONSOLE_IMPL) {
startConsole(cartridgeData)
} else {
Director.startConsole(cartridgeData, surface)
}
}
}

btnReset.setOnClickListener { console.cpu.reset() }
// btnReset.setOnClickListener { console.cpu.reset() }

val onClickButton = { code: Int ->
// console.cpu.memory.storeKeypress(code)
Expand Down Expand Up @@ -91,4 +69,12 @@ class MainActivity : AppCompatActivity() {
super.onOptionsItemSelected(item)
}
}

companion object {
private const val USE_NATIVE_CONSOLE_IMPL = false

init {
System.loadLibrary("knes")
}
}
}
3 changes: 3 additions & 0 deletions android/app/src/main/kotlin/com/felipecsl/knes/jni.kt
@@ -0,0 +1,3 @@
package com.felipecsl.knes

external fun startConsole(cartridgeData: ByteArray)
14 changes: 14 additions & 0 deletions android/app/src/main/kotlin/com/felipecsl/knes/platform.kt
@@ -0,0 +1,14 @@
package com.felipecsl.knes

actual fun currentTimeMs(): Long {
return System.currentTimeMillis()
}

actual class Bitmap actual constructor(width: Int, height: Int) {
val delegate = android.graphics.Bitmap.createBitmap(width, height,
android.graphics.Bitmap.Config.RGB_565)

actual fun setPixel(x: Int, y: Int, color: Int) {
delegate.setPixel(x, y, color)
}
}
Expand Up @@ -77,76 +77,15 @@
android:layout_marginBottom="5dp"
android:orientation="horizontal">

<TextView
android:id="@+id/A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:fontFamily="monospace"
android:text="A=$00"/>

<TextView
android:id="@+id/X"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:fontFamily="monospace"
android:text="X=$00"/>

<TextView
android:id="@+id/Y"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:fontFamily="monospace"
android:text="Y=$00"/>

<TextView
android:id="@+id/frequency"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="monospace"
android:text="Frequency=0MHz"/>

</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:orientation="horizontal">

<TextView
android:id="@+id/SP"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:fontFamily="monospace"
android:text="SP=$ff"/>

<TextView
android:id="@+id/PC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:fontFamily="monospace"
android:text="PC=$0600"/>
android:text="Clock=0MHz"/>

</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">

<TextView
android:id="@+id/flags"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="monospace"
android:text="flags=00110000"/>

</LinearLayout>
</LinearLayout>

</LinearLayout>
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
44 changes: 44 additions & 0 deletions android/native-lib/build.gradle
@@ -0,0 +1,44 @@
apply plugin: 'konan'

konan.targets = [ "android_arm64", "android_arm32"]

konanArtifacts {
dynamic("knes") {
enableMultiplatform true
}
}

def outDir = project(':android:app').file("src/main/jniLibs")
def platforms = [
"armeabi-v7a": [konanTarget: "android_arm32"],
"arm64-v8a" : [konanTarget: "android_arm64"]
]

task copyLibs(type: Copy) {
dependsOn konanArtifacts.knes
destinationDir outDir

platforms.each { name, platform ->
into(name) {
from konanArtifacts.knes."${platform.konanTarget}".artifact
}
}
}

task deleteOut(type: Delete) {
delete outDir
}

build {
finalizedBy copyLibs
}

clean.dependsOn deleteOut

tasks.matching { it.name == 'preBuild' }.all {
it.dependsOn copyLibs
}

dependencies {
expectedBy project(':common')
}
1 change: 1 addition & 0 deletions android/native-lib/knes.def
@@ -0,0 +1 @@
pkg = com.felipecsl.knes
16 changes: 16 additions & 0 deletions android/native-lib/src/main/kotlin/com/felipecsl/knes/api.kt
@@ -0,0 +1,16 @@
package com.felipecsl.knes

import konan.internal.CName
import kotlinx.cinterop.*
import platform.android.*

@CName(fullName = "Java_com_felipecsl_knes_JniKt_startConsole")
fun startConsole(env: CPointer<JNIEnvVar>, self: jobject, cartridgeData: jbyteArray) {
val jni = env.pointed.pointed!!
val len = jni.GetArrayLength!!.invoke(env, cartridgeData)
memScoped {
val buffer = ByteArray(len)
jni.GetByteArrayRegion!!.invoke(env, cartridgeData, 0, len, buffer.refTo(0).getPointer(this))
Director.startConsole(buffer)
}
}
18 changes: 18 additions & 0 deletions android/native-lib/src/main/kotlin/com/felipecsl/knes/platform.kt
@@ -0,0 +1,18 @@
package com.felipecsl.knes

import kotlinx.cinterop.*
import platform.posix.*

actual fun currentTimeMs(): Long {
memScoped {
val now = alloc<timeval>()
gettimeofday(now.ptr, null)
return (now.tv_sec.toLong() * 1000) + (now.tv_usec.toLong() / 1000)
}
}

actual class Bitmap actual constructor(width: Int, height: Int) {
actual fun setPixel(x: Int, y: Int, color: Int) {
// TODO
}
}
5 changes: 0 additions & 5 deletions app/src/main/kotlin/com/felipecsl/android/Interrupt.kt

This file was deleted.

7 changes: 0 additions & 7 deletions app/src/main/kotlin/com/felipecsl/android/StepInfo.kt

This file was deleted.

64 changes: 0 additions & 64 deletions app/src/main/kotlin/com/felipecsl/android/nes/INESFileParser.kt

This file was deleted.

0 comments on commit 1185a44

Please sign in to comment.