├── .gitignore ├── README.md ├── app ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── nc1020.fls │ └── obj_lu.bin │ ├── cpp │ ├── CMakeLists.txt │ ├── org_liberty_android_nc1020emu_NC1020JNI.c │ └── wqx │ │ ├── cpu6502.c │ │ ├── cpu6502.h │ │ ├── nc1020.c │ │ ├── nc1020.h │ │ ├── nc1020_io.c │ │ ├── nc1020_io.h │ │ └── nc1020_states.h │ ├── java │ └── org │ │ └── liberty │ │ └── android │ │ └── nc1020emu │ │ ├── KeypadLayout.kt │ │ ├── MainActivity.kt │ │ ├── MainFragment.kt │ │ ├── NC1020JNI.kt │ │ └── SettingsFragment.kt │ └── res │ ├── drawable-mdpi │ ├── f1.png │ ├── f2.png │ ├── f3.png │ ├── f4.png │ ├── ic_launcher.jpg │ ├── keypad.png │ └── onoff.png │ ├── drawable │ └── keypad_button.xml │ ├── layout │ ├── main_activity.xml │ └── main_fragment.xml │ ├── menu │ └── main_menu.xml │ ├── navigation │ └── nav_graph.xml │ ├── values-zh │ └── strings.xml │ ├── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ └── settings.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.sw* 3 | local.properties 4 | build.xml 5 | gen/ 6 | bin/ 7 | libs/armeabi 8 | obj/ 9 | .settings/ 10 | .gradle/ 11 | *.xmi 12 | .project 13 | .classpath 14 | build/ 15 | app/build/ 16 | app/release/ 17 | out/ 18 | .externalNativeBuild 19 | app/.cxx/ 20 | 21 | # This contains secrets and should not be checked in! 22 | AMSecrets.java 23 | 24 | # IntelliJ Idea/Android Studio files 25 | *.iml 26 | *.ipr 27 | *.iws 28 | .idea/ 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WQX Emulator for Android 2 | WQX Emulator on Banxian's C++ sample, reverse engineer document and hackwaly's jswqx work with heavy modification and optimizations 3 | The following features are supported 4 | * Pure C implementation of 6502 emulation and IO emulation 5 | * Clock sync from system time 6 | * Somewhat accurate timimg for authentic WQX experience 7 | * Turbo mode for fast speed 8 | * Reduced input and output delay by multi-threading 9 | * Keyboard skin 10 | * Save state and factory reset 11 | 12 | # How to build 13 | * Use Android studio to import and build 14 | OR 15 | * Use command line `./gradlew assembleDebug` 16 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | 5 | 6 | repositories { 7 | google() 8 | jcenter() 9 | } 10 | 11 | android { 12 | compileSdkVersion 29 13 | 14 | defaultConfig { 15 | targetSdkVersion 29 16 | minSdkVersion 21 17 | versionCode 2 18 | versionName "1.1" 19 | 20 | } 21 | 22 | compileOptions { 23 | sourceCompatibility JavaVersion.VERSION_1_8 24 | targetCompatibility JavaVersion.VERSION_1_8 25 | } 26 | 27 | externalNativeBuild { 28 | cmake { 29 | path file('src/main/cpp/CMakeLists.txt') 30 | } 31 | } 32 | } 33 | 34 | dependencies { 35 | implementation "androidx.appcompat:appcompat:1.2.0" 36 | implementation "androidx.navigation:navigation-fragment-ktx:2.3.1" 37 | implementation "androidx.navigation:navigation-ui-ktx:2.3.1" 38 | implementation "androidx.preference:preference-ktx:1.1.1" 39 | implementation "androidx.core:core-ktx:1.3.2" 40 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 41 | } 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/assets/nc1020.fls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloworld1/Android-WQX-Emulator/975eec503ccd7e9779e0e852c6bd794815a12280/app/src/main/assets/nc1020.fls -------------------------------------------------------------------------------- /app/src/main/assets/obj_lu.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloworld1/Android-WQX-Emulator/975eec503ccd7e9779e0e852c6bd794815a12280/app/src/main/assets/obj_lu.bin -------------------------------------------------------------------------------- /app/src/main/cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4.1) 2 | 3 | project(nc1020 C) 4 | 5 | add_library( 6 | nc1020 7 | SHARED 8 | org_liberty_android_nc1020emu_NC1020JNI.c 9 | wqx/cpu6502.c 10 | wqx/nc1020.c 11 | wqx/nc1020_io.c) 12 | 13 | target_link_libraries( 14 | nc1020 15 | android 16 | log) 17 | 18 | set_property(TARGET nc1020 PROPERTY C_STANDARD 11) 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/cpp/org_liberty_android_nc1020emu_NC1020JNI.c: -------------------------------------------------------------------------------- 1 | #include "./wqx/nc1020.h" 2 | #include 3 | #include 4 | 5 | JNIEXPORT void JNICALL 6 | Java_org_liberty_android_nc1020emu_NC1020JNI_initialize(JNIEnv *env, jclass type, 7 | jstring romFilePath_, jstring norFilePath_, 8 | jstring stateFilePath_) { 9 | const char *romFilePath = (*env)->GetStringUTFChars(env, romFilePath_, 0); 10 | const char *norFilePath = (*env)->GetStringUTFChars(env, norFilePath_, 0); 11 | const char *stateFilePath = (*env)->GetStringUTFChars(env, stateFilePath_, 0); 12 | 13 | initialize(romFilePath, norFilePath, stateFilePath); 14 | 15 | (*env)->ReleaseStringUTFChars(env, romFilePath_, romFilePath); 16 | (*env)->ReleaseStringUTFChars(env, norFilePath_, norFilePath); 17 | (*env)->ReleaseStringUTFChars(env, stateFilePath_, stateFilePath); 18 | } 19 | 20 | JNIEXPORT void JNICALL Java_org_liberty_android_nc1020emu_NC1020JNI_reset 21 | (JNIEnv *env, jclass type) { 22 | reset(); 23 | } 24 | 25 | JNIEXPORT void JNICALL Java_org_liberty_android_nc1020emu_NC1020JNI_load 26 | (JNIEnv *env, jclass type) { 27 | load_nc1020(); 28 | } 29 | 30 | JNIEXPORT void JNICALL Java_org_liberty_android_nc1020emu_NC1020JNI_save 31 | (JNIEnv *env, jclass type) { 32 | save_nc1020(); 33 | } 34 | 35 | JNIEXPORT void JNICALL Java_org_liberty_android_nc1020emu_NC1020JNI_setKey 36 | (JNIEnv *env, jclass type, jint keyId, jboolean downOrUp) { 37 | set_key((uint8_t) (keyId & 0x3F), downOrUp); 38 | } 39 | 40 | JNIEXPORT void JNICALL Java_org_liberty_android_nc1020emu_NC1020JNI_runTimeSlice 41 | (JNIEnv *env, jclass type, jint timeSlice, jboolean speedUp) { 42 | run_time_slice((size_t) timeSlice, speedUp); 43 | } 44 | 45 | /** 46 | * Copy the LCD buffer and convert to Android bitmap format 47 | * 48 | * @param env JNIEnv 49 | * @param type java class 50 | * @param buffer The buffer is size of byte[1600 * 8] 51 | * @return True if buffer is copied. False if buffer is not copied 52 | */ 53 | JNIEXPORT jboolean JNICALL Java_org_liberty_android_nc1020emu_NC1020JNI_copyLcdBufferEx 54 | (JNIEnv *env, jclass type, jbyteArray buffer) { 55 | jbyte* buffer_ex= (*env)->GetByteArrayElements(env, buffer, NULL); 56 | 57 | uint8_t* lcd_buffer = get_lcd_buffer(); 58 | 59 | if (lcd_buffer == NULL) 60 | return false; 61 | 62 | for (int y = 0; y < 80; y++) { 63 | for (int j = 0; j < 20; j++) { 64 | uint8_t p = lcd_buffer[20 * y + j]; 65 | for (int k = 0; k < 8; k++) { 66 | buffer_ex[y * 160 + j * 8 + k] = ((p & (1u << (7u - k))) != 0 ? 0xFFu : 0x00); 67 | } 68 | } 69 | } 70 | 71 | for (int y = 0; y < 80; y++) { 72 | buffer_ex[y * 160] = 0; 73 | } 74 | 75 | 76 | (*env)->ReleaseByteArrayElements(env, buffer, buffer_ex, 0); 77 | return true; 78 | } 79 | 80 | JNIEXPORT jlong JNICALL 81 | Java_org_liberty_android_nc1020emu_NC1020JNI_getCycles(JNIEnv *env, jclass type) { 82 | return get_cycles(); 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/cpp/wqx/cpu6502.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by liberty on 4/12/19. 3 | // 4 | #include "cpu6502.h" 5 | #include 6 | #include 7 | 8 | 9 | static const uint16_t IRQ_VEC = 0xFFFE; 10 | 11 | static uint8_t (*_peek_byte)(uint16_t addr); 12 | 13 | static uint8_t (*_load)(uint16_t addr); 14 | 15 | static void (*_store)(uint16_t addr, uint8_t value); 16 | 17 | static uint16_t peek_word(uint16_t addr) { 18 | return _peek_byte(addr) | (_peek_byte((uint16_t) (addr + 1u)) << 8u); 19 | } 20 | 21 | static void store_stack(uint8_t sp, uint8_t value) { 22 | uint16_t stack_ptr = (uint16_t) (0x100 + sp); 23 | _store(stack_ptr, value); 24 | } 25 | 26 | static uint8_t load_stack(uint8_t sp) { 27 | return _load((uint16_t) (0x100 + sp)); 28 | } 29 | 30 | void init_6502(uint8_t (*peek_byte)(uint16_t addr), 31 | uint8_t (*load)(uint16_t addr), 32 | void (*store)(uint16_t addr, uint8_t value)) { 33 | _peek_byte = peek_byte; 34 | _load = load; 35 | _store = store; 36 | } 37 | 38 | /** 39 | * @return cycles for the execution 40 | */ 41 | uint64_t do_irq(cpu_states_t *cpu_states) { 42 | uint8_t reg_sp = cpu_states -> reg_sp; 43 | uint16_t reg_pc = cpu_states -> reg_pc; 44 | uint8_t reg_ps = cpu_states -> reg_ps; 45 | 46 | if (!(reg_ps & 0x04u)) { 47 | store_stack(reg_sp--, (uint8_t) (reg_pc >> 8u)); 48 | store_stack(reg_sp--, (uint8_t) (reg_pc & 0xFFu)); 49 | reg_ps &= 0xEFu; 50 | store_stack(reg_sp--, reg_ps); 51 | reg_pc = peek_word(IRQ_VEC); 52 | reg_ps |= 0x04u; 53 | 54 | cpu_states -> reg_sp = reg_sp; 55 | cpu_states -> reg_pc = reg_pc; 56 | cpu_states -> reg_ps = reg_ps; 57 | return 7; 58 | } 59 | return 0; 60 | } 61 | 62 | 63 | /** 64 | * @return cycles for the execution 65 | */ 66 | uint64_t execute_6502(cpu_states_t *cpu_states) { 67 | uint64_t cycles = 0; 68 | uint16_t reg_pc = cpu_states -> reg_pc; 69 | uint8_t reg_a = cpu_states -> reg_a; 70 | uint8_t reg_ps = cpu_states -> reg_ps; 71 | uint8_t reg_x = cpu_states -> reg_x; 72 | uint8_t reg_y = cpu_states -> reg_y; 73 | uint8_t reg_sp = cpu_states -> reg_sp; 74 | 75 | switch (_peek_byte(reg_pc++)) { 76 | case 0x00: { 77 | reg_pc++; 78 | store_stack(reg_sp--, (uint8_t) (reg_pc >> 8u)); 79 | store_stack(reg_sp--, (uint8_t) (reg_pc & 0xFFu)); 80 | reg_ps |= 0x10u; 81 | store_stack(reg_sp--, reg_ps); 82 | reg_ps |= 0x04u; 83 | reg_pc = peek_word(IRQ_VEC); 84 | cycles += 7; 85 | } 86 | break; 87 | case 0x01: { 88 | uint16_t addr = peek_word((uint16_t) ((_peek_byte(reg_pc++) + reg_x) & 0xFFu)); 89 | reg_a |= _load(addr); 90 | reg_ps &= 0x7Du; 91 | reg_ps |= (reg_a & 0x80u) | (!reg_a << 1u); 92 | cycles += 6; 93 | } 94 | break; 95 | case 0x02: { 96 | } 97 | break; 98 | case 0x03: { 99 | } 100 | break; 101 | case 0x04: { 102 | } 103 | break; 104 | case 0x05: { 105 | uint16_t addr = _peek_byte(reg_pc++); 106 | reg_a |= _load(addr); 107 | reg_ps &= 0x7Du; 108 | reg_ps |= (reg_a & 0x80u) | (!reg_a << 1u); 109 | cycles += 3; 110 | } 111 | break; 112 | case 0x06: { 113 | uint16_t addr = _peek_byte(reg_pc++); 114 | uint8_t tmp1 = _load(addr); 115 | reg_ps &= 0x7Cu; 116 | reg_ps |= (tmp1 >> 7u); 117 | tmp1 <<= 1u; 118 | reg_ps |= (tmp1 & 0x80u) | (!tmp1 << 1u); 119 | _store(addr, tmp1); 120 | cycles += 5; 121 | } 122 | break; 123 | case 0x07: { 124 | } 125 | break; 126 | case 0x08: { 127 | store_stack(reg_sp--, reg_ps); 128 | cycles += 3; 129 | } 130 | break; 131 | case 0x09: { 132 | uint16_t addr = reg_pc++; 133 | reg_a |= _load(addr); 134 | reg_ps &= 0x7Du; 135 | reg_ps |= (reg_a & 0x80u) | (!reg_a << 1u); 136 | cycles += 2; 137 | } 138 | break; 139 | case 0x0A: { 140 | reg_ps &= 0x7Cu; 141 | reg_ps |= reg_a >> 7u; 142 | reg_a <<= 1u; 143 | reg_ps |= (reg_a & 0x80u) | (!reg_a << 1u); 144 | cycles += 2; 145 | } 146 | break; 147 | case 0x0B: { 148 | } 149 | break; 150 | case 0x0C: { 151 | } 152 | break; 153 | case 0x0D: { 154 | uint16_t addr = peek_word(reg_pc); 155 | reg_pc += 2; 156 | reg_a |= _load(addr); 157 | reg_ps &= 0x7D; 158 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 159 | cycles += 4; 160 | } 161 | break; 162 | case 0x0E: { 163 | uint16_t addr = peek_word(reg_pc); 164 | reg_pc += 2; 165 | uint8_t tmp1 = _load(addr); 166 | reg_ps &= 0x7C; 167 | reg_ps |= (tmp1 >> 7); 168 | tmp1 <<= 1; 169 | reg_ps |= (tmp1 & 0x80) | (!tmp1 << 1); 170 | _store(addr, tmp1); 171 | cycles += 6; 172 | } 173 | break; 174 | case 0x0F: { 175 | } 176 | break; 177 | case 0x10: { 178 | int8_t tmp4 = (int8_t) (_peek_byte(reg_pc++)); 179 | uint16_t addr = reg_pc + tmp4; 180 | if (!(reg_ps & 0x80)) { 181 | cycles += !((reg_pc ^ addr) & 0xFF00) << 1; 182 | reg_pc = addr; 183 | } 184 | cycles += 2; 185 | } 186 | break; 187 | case 0x11: { 188 | uint16_t addr = peek_word(_peek_byte(reg_pc)); 189 | cycles += !!(((addr & 0xFF) + reg_y) & 0xFF00); 190 | addr += reg_y; 191 | reg_pc++; 192 | reg_a |= _load(addr); 193 | reg_ps &= 0x7D; 194 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 195 | cycles += 5; 196 | } 197 | break; 198 | case 0x12: { 199 | } 200 | break; 201 | case 0x13: { 202 | } 203 | break; 204 | case 0x14: { 205 | } 206 | break; 207 | case 0x15: { 208 | uint16_t addr = (_peek_byte(reg_pc++) + reg_x) & 0xFF; 209 | reg_a |= _load(addr); 210 | reg_ps &= 0x7D; 211 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 212 | cycles += 4; 213 | } 214 | break; 215 | case 0x16: { 216 | uint16_t addr = (_peek_byte(reg_pc++) + reg_x) & 0xFF; 217 | uint8_t tmp1 = _load(addr); 218 | reg_ps &= 0x7C; 219 | reg_ps |= (tmp1 >> 7); 220 | tmp1 <<= 1; 221 | reg_ps |= (tmp1 & 0x80) | (!tmp1 << 1); 222 | _store(addr, tmp1); 223 | cycles += 6; 224 | } 225 | break; 226 | case 0x17: { 227 | } 228 | break; 229 | case 0x18: { 230 | reg_ps &= 0xFE; 231 | cycles += 2; 232 | } 233 | break; 234 | case 0x19: { 235 | uint16_t addr = peek_word(reg_pc); 236 | cycles += !!(((addr & 0xFF) + reg_y) & 0xFF00); 237 | addr += reg_y; 238 | reg_pc += 2; 239 | reg_a |= _load(addr); 240 | reg_ps &= 0x7D; 241 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 242 | cycles += 4; 243 | } 244 | break; 245 | case 0x1A: { 246 | } 247 | break; 248 | case 0x1B: { 249 | } 250 | break; 251 | case 0x1C: { 252 | } 253 | break; 254 | case 0x1D: { 255 | uint16_t addr = peek_word(reg_pc); 256 | cycles += !!(((addr & 0xFF) + reg_x) & 0xFF00); 257 | addr += reg_x; 258 | reg_pc += 2; 259 | reg_a |= _load(addr); 260 | reg_ps &= 0x7D; 261 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 262 | cycles += 4; 263 | } 264 | break; 265 | case 0x1E: { 266 | uint16_t addr = peek_word(reg_pc); 267 | addr += reg_x; 268 | reg_pc += 2; 269 | uint8_t tmp1 = _load(addr); 270 | reg_ps &= 0x7C; 271 | reg_ps |= (tmp1 >> 7); 272 | tmp1 <<= 1; 273 | reg_ps |= (tmp1 & 0x80) | (!tmp1 << 1); 274 | _store(addr, tmp1); 275 | cycles += 6; 276 | } 277 | break; 278 | case 0x1F: { 279 | } 280 | break; 281 | case 0x20: { 282 | uint16_t addr = peek_word(reg_pc); 283 | reg_pc += 2; 284 | reg_pc--; 285 | store_stack(reg_sp--, (uint8_t) (reg_pc >> 8)); 286 | store_stack(reg_sp--, (uint8_t) (reg_pc & 0xFF)); 287 | reg_pc = addr; 288 | cycles += 6; 289 | } 290 | break; 291 | case 0x21: { 292 | uint16_t addr = peek_word((_peek_byte(reg_pc++) + reg_x) & 0xFF); 293 | reg_a &= _load(addr); 294 | reg_ps &= 0x7D; 295 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 296 | cycles += 6; 297 | } 298 | break; 299 | case 0x22: { 300 | } 301 | break; 302 | case 0x23: { 303 | } 304 | break; 305 | case 0x24: { 306 | uint16_t addr = _peek_byte(reg_pc++); 307 | uint8_t tmp1 = _load(addr); 308 | reg_ps &= 0x3D; 309 | reg_ps |= (!(reg_a & tmp1) << 1) | (tmp1 & 0xC0); 310 | cycles += 3; 311 | } 312 | break; 313 | case 0x25: { 314 | uint16_t addr = _peek_byte(reg_pc++); 315 | reg_a &= _load(addr); 316 | reg_ps &= 0x7D; 317 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 318 | cycles += 3; 319 | } 320 | break; 321 | case 0x26: { 322 | uint16_t addr = _peek_byte(reg_pc++); 323 | uint8_t tmp1 = _load(addr); 324 | uint8_t tmp2 = (tmp1 << 1) | (reg_ps & 0x01); 325 | reg_ps &= 0x7C; 326 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >> 7); 327 | _store(addr, tmp2); 328 | cycles += 5; 329 | } 330 | break; 331 | case 0x27: { 332 | } 333 | break; 334 | case 0x28: { 335 | reg_ps = load_stack(++reg_sp); 336 | cycles += 4; 337 | } 338 | break; 339 | case 0x29: { 340 | uint16_t addr = reg_pc++; 341 | reg_a &= _load(addr); 342 | reg_ps &= 0x7D; 343 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 344 | cycles += 2; 345 | } 346 | break; 347 | case 0x2A: { 348 | uint8_t tmp1 = reg_a; 349 | reg_a = (reg_a << 1) | (reg_ps & 0x01); 350 | reg_ps &= 0x7C; 351 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1) | (tmp1 >> 7); 352 | cycles += 2; 353 | } 354 | break; 355 | case 0x2B: { 356 | } 357 | break; 358 | case 0x2C: { 359 | uint16_t addr = peek_word(reg_pc); 360 | reg_pc += 2; 361 | uint8_t tmp1 = _load(addr); 362 | reg_ps &= 0x3D; 363 | reg_ps |= (!(reg_a & tmp1) << 1) | (tmp1 & 0xC0); 364 | cycles += 4; 365 | } 366 | break; 367 | case 0x2D: { 368 | uint16_t addr = peek_word(reg_pc); 369 | reg_pc += 2; 370 | reg_a &= _load(addr); 371 | reg_ps &= 0x7D; 372 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 373 | cycles += 4; 374 | } 375 | break; 376 | case 0x2E: { 377 | uint16_t addr = peek_word(reg_pc); 378 | reg_pc += 2; 379 | uint8_t tmp1 = _load(addr); 380 | uint8_t tmp2 = (tmp1 << 1) | (reg_ps & 0x01); 381 | reg_ps &= 0x7C; 382 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >> 7); 383 | _store(addr, tmp2); 384 | cycles += 6; 385 | } 386 | break; 387 | case 0x2F: { 388 | } 389 | break; 390 | case 0x30: { 391 | int8_t tmp4 = (int8_t) (_peek_byte(reg_pc++)); 392 | uint16_t addr = reg_pc + tmp4; 393 | if ((reg_ps & 0x80)) { 394 | cycles += !((reg_pc ^ addr) & 0xFF00) << 1; 395 | reg_pc = addr; 396 | } 397 | cycles += 2; 398 | } 399 | break; 400 | case 0x31: { 401 | uint16_t addr = peek_word(_peek_byte(reg_pc)); 402 | cycles += !!(((addr & 0xFF) + reg_y) & 0xFF00); 403 | addr += reg_y; 404 | reg_pc++; 405 | reg_a &= _load(addr); 406 | reg_ps &= 0x7D; 407 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 408 | cycles += 5; 409 | } 410 | break; 411 | case 0x32: { 412 | } 413 | break; 414 | case 0x33: { 415 | } 416 | break; 417 | case 0x34: { 418 | } 419 | break; 420 | case 0x35: { 421 | uint16_t addr = (_peek_byte(reg_pc++) + reg_x) & 0xFF; 422 | reg_a &= _load(addr); 423 | reg_ps &= 0x7D; 424 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 425 | cycles += 4; 426 | } 427 | break; 428 | case 0x36: { 429 | uint16_t addr = (_peek_byte(reg_pc++) + reg_x) & 0xFF; 430 | uint8_t tmp1 = _load(addr); 431 | uint8_t tmp2 = (tmp1 << 1) | (reg_ps & 0x01); 432 | reg_ps &= 0x7C; 433 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >> 7); 434 | _store(addr, tmp2); 435 | cycles += 6; 436 | } 437 | break; 438 | case 0x37: { 439 | } 440 | break; 441 | case 0x38: { 442 | reg_ps |= 0x01; 443 | cycles += 2; 444 | } 445 | break; 446 | case 0x39: { 447 | uint16_t addr = peek_word(reg_pc); 448 | cycles += !!(((addr & 0xFF) + reg_y) & 0xFF00); 449 | addr += reg_y; 450 | reg_pc += 2; 451 | reg_a &= _load(addr); 452 | reg_ps &= 0x7D; 453 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 454 | cycles += 4; 455 | } 456 | break; 457 | case 0x3A: { 458 | } 459 | break; 460 | case 0x3B: { 461 | } 462 | break; 463 | case 0x3C: { 464 | } 465 | break; 466 | case 0x3D: { 467 | uint16_t addr = peek_word(reg_pc); 468 | cycles += !!(((addr & 0xFF) + reg_x) & 0xFF00); 469 | addr += reg_x; 470 | reg_pc += 2; 471 | reg_a &= _load(addr); 472 | reg_ps &= 0x7D; 473 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 474 | cycles += 4; 475 | } 476 | break; 477 | case 0x3E: { 478 | uint16_t addr = peek_word(reg_pc); 479 | addr += reg_x; 480 | reg_pc += 2; 481 | uint8_t tmp1 = _load(addr); 482 | uint8_t tmp2 = (tmp1 << 1) | (reg_ps & 0x01); 483 | reg_ps &= 0x7C; 484 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >> 7); 485 | _store(addr, tmp2); 486 | cycles += 6; 487 | } 488 | break; 489 | case 0x3F: { 490 | } 491 | break; 492 | case 0x40: { 493 | reg_ps = load_stack(++reg_sp); 494 | reg_pc = load_stack(++reg_sp); 495 | reg_pc |= (load_stack(++reg_sp) << 8); 496 | cycles += 6; 497 | } 498 | break; 499 | case 0x41: { 500 | uint16_t addr = peek_word((_peek_byte(reg_pc++) + reg_x) & 0xFF); 501 | reg_a ^= _load(addr); 502 | reg_ps &= 0x7D; 503 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 504 | cycles += 6; 505 | } 506 | break; 507 | case 0x42: { 508 | } 509 | break; 510 | case 0x43: { 511 | } 512 | break; 513 | case 0x44: { 514 | } 515 | break; 516 | case 0x45: { 517 | uint16_t addr = _peek_byte(reg_pc++); 518 | reg_a ^= _load(addr); 519 | reg_ps &= 0x7D; 520 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 521 | cycles += 3; 522 | } 523 | break; 524 | case 0x46: { 525 | uint16_t addr = _peek_byte(reg_pc++); 526 | uint8_t tmp1 = _load(addr); 527 | reg_ps &= 0x7C; 528 | reg_ps |= (tmp1 & 0x01); 529 | tmp1 >>= 1; 530 | reg_ps |= (!tmp1 << 1); 531 | _store(addr, tmp1); 532 | cycles += 5; 533 | } 534 | break; 535 | case 0x47: { 536 | } 537 | break; 538 | case 0x48: { 539 | store_stack(reg_sp--, reg_a); 540 | cycles += 3; 541 | } 542 | break; 543 | case 0x49: { 544 | uint16_t addr = reg_pc++; 545 | reg_a ^= _load(addr); 546 | reg_ps &= 0x7D; 547 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 548 | cycles += 2; 549 | } 550 | break; 551 | case 0x4A: { 552 | reg_ps &= 0x7C; 553 | reg_ps |= reg_a & 0x01; 554 | reg_a >>= 1; 555 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 556 | cycles += 2; 557 | } 558 | break; 559 | case 0x4B: { 560 | } 561 | break; 562 | case 0x4C: { 563 | uint16_t addr = peek_word(reg_pc); 564 | reg_pc += 2; 565 | reg_pc = addr; 566 | cycles += 3; 567 | } 568 | break; 569 | case 0x4D: { 570 | uint16_t addr = peek_word(reg_pc); 571 | reg_pc += 2; 572 | reg_a ^= _load(addr); 573 | reg_ps &= 0x7D; 574 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 575 | cycles += 4; 576 | } 577 | break; 578 | case 0x4E: { 579 | uint16_t addr = peek_word(reg_pc); 580 | reg_pc += 2; 581 | uint8_t tmp1 = _load(addr); 582 | reg_ps &= 0x7C; 583 | reg_ps |= (tmp1 & 0x01); 584 | tmp1 >>= 1; 585 | reg_ps |= (!tmp1 << 1); 586 | _store(addr, tmp1); 587 | cycles += 6; 588 | } 589 | break; 590 | case 0x4F: { 591 | } 592 | break; 593 | case 0x50: { 594 | int8_t tmp4 = (int8_t) (_peek_byte(reg_pc++)); 595 | uint16_t addr = reg_pc + tmp4; 596 | if (!(reg_ps & 0x40)) { 597 | cycles += !((reg_pc ^ addr) & 0xFF00) << 1; 598 | reg_pc = addr; 599 | } 600 | cycles += 2; 601 | } 602 | break; 603 | case 0x51: { 604 | uint16_t addr = peek_word(_peek_byte(reg_pc)); 605 | cycles += !!(((addr & 0xFF) + reg_y) & 0xFF00); 606 | addr += reg_y; 607 | reg_pc++; 608 | reg_a ^= _load(addr); 609 | reg_ps &= 0x7D; 610 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 611 | cycles += 5; 612 | } 613 | break; 614 | case 0x52: { 615 | } 616 | break; 617 | case 0x53: { 618 | } 619 | break; 620 | case 0x54: { 621 | } 622 | break; 623 | case 0x55: { 624 | uint16_t addr = (_peek_byte(reg_pc++) + reg_x) & 0xFF; 625 | reg_a ^= _load(addr); 626 | reg_ps &= 0x7D; 627 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 628 | cycles += 4; 629 | } 630 | break; 631 | case 0x56: { 632 | uint16_t addr = (_peek_byte(reg_pc++) + reg_x) & 0xFF; 633 | uint8_t tmp1 = _load(addr); 634 | reg_ps &= 0x7C; 635 | reg_ps |= (tmp1 & 0x01); 636 | tmp1 >>= 1; 637 | reg_ps |= (!tmp1 << 1); 638 | _store(addr, tmp1); 639 | cycles += 6; 640 | } 641 | break; 642 | case 0x57: { 643 | } 644 | break; 645 | case 0x58: { 646 | reg_ps &= 0xFB; 647 | cycles += 2; 648 | } 649 | break; 650 | case 0x59: { 651 | uint16_t addr = peek_word(reg_pc); 652 | cycles += !!(((addr & 0xFF) + reg_y) & 0xFF00); 653 | addr += reg_y; 654 | reg_pc += 2; 655 | reg_a ^= _load(addr); 656 | reg_ps &= 0x7D; 657 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 658 | cycles += 4; 659 | } 660 | break; 661 | case 0x5A: { 662 | } 663 | break; 664 | case 0x5B: { 665 | } 666 | break; 667 | case 0x5C: { 668 | } 669 | break; 670 | case 0x5D: { 671 | uint16_t addr = peek_word(reg_pc); 672 | cycles += !!(((addr & 0xFF) + reg_x) & 0xFF00); 673 | addr += reg_x; 674 | reg_pc += 2; 675 | reg_a ^= _load(addr); 676 | reg_ps &= 0x7D; 677 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 678 | cycles += 4; 679 | } 680 | break; 681 | case 0x5E: { 682 | uint16_t addr = peek_word(reg_pc); 683 | addr += reg_x; 684 | reg_pc += 2; 685 | uint8_t tmp1 = _load(addr); 686 | reg_ps &= 0x7C; 687 | reg_ps |= (tmp1 & 0x01); 688 | tmp1 >>= 1; 689 | reg_ps |= (!tmp1 << 1); 690 | _store(addr, tmp1); 691 | cycles += 6; 692 | } 693 | break; 694 | case 0x5F: { 695 | } 696 | break; 697 | case 0x60: { 698 | reg_pc = load_stack(++reg_sp); 699 | reg_pc |= (load_stack(++reg_sp) << 8); 700 | reg_pc++; 701 | cycles += 6; 702 | } 703 | break; 704 | case 0x61: { 705 | uint16_t addr = peek_word((_peek_byte(reg_pc++) + reg_x) & 0xFF); 706 | uint8_t tmp1 = _load(addr); 707 | int16_t tmp2 = reg_a + tmp1 + (reg_ps & 0x01); 708 | uint8_t tmp3 = tmp2 & 0xFF; 709 | reg_ps &= 0x3C; 710 | reg_ps |= (tmp3 & 0x80) | (!tmp3 << 1) | (tmp2 > 0xFF) 711 | | (((reg_a ^ tmp1 ^ 0x80) & (reg_a ^ tmp3) & 0x80) >> 1); 712 | reg_a = tmp3; 713 | cycles += 6; 714 | } 715 | break; 716 | case 0x62: { 717 | } 718 | break; 719 | case 0x63: { 720 | } 721 | break; 722 | case 0x64: { 723 | } 724 | break; 725 | case 0x65: { 726 | uint16_t addr = _peek_byte(reg_pc++); 727 | uint8_t tmp1 = _load(addr); 728 | int16_t tmp2 = reg_a + tmp1 + (reg_ps & 0x01); 729 | uint8_t tmp3 = tmp2 & 0xFF; 730 | reg_ps &= 0x3C; 731 | reg_ps |= (tmp3 & 0x80) | (!tmp3 << 1) | (tmp2 > 0xFF) 732 | | (((reg_a ^ tmp1 ^ 0x80) & (reg_a ^ tmp3) & 0x80) >> 1); 733 | reg_a = tmp3; 734 | cycles += 3; 735 | } 736 | break; 737 | case 0x66: { 738 | uint16_t addr = _peek_byte(reg_pc++); 739 | uint8_t tmp1 = _load(addr); 740 | uint8_t tmp2 = (tmp1 >> 1) | ((reg_ps & 0x01) << 7); 741 | reg_ps &= 0x7C; 742 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 & 0x01); 743 | _store(addr, tmp2); 744 | cycles += 5; 745 | } 746 | break; 747 | case 0x67: { 748 | } 749 | break; 750 | case 0x68: { 751 | reg_a = load_stack(++reg_sp); 752 | reg_ps &= 0x7D; 753 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 754 | cycles += 4; 755 | } 756 | break; 757 | case 0x69: { 758 | uint16_t addr = reg_pc++; 759 | uint8_t tmp1 = _load(addr); 760 | int16_t tmp2 = reg_a + tmp1 + (reg_ps & 0x01); 761 | uint8_t tmp3 = tmp2 & 0xFF; 762 | reg_ps &= 0x3C; 763 | reg_ps |= (tmp3 & 0x80) | (!tmp3 << 1) | (tmp2 > 0xFF) 764 | | (((reg_a ^ tmp1 ^ 0x80) & (reg_a ^ tmp3) & 0x80) >> 1); 765 | reg_a = tmp3; 766 | cycles += 2; 767 | } 768 | break; 769 | case 0x6A: { 770 | uint8_t tmp1 = reg_a; 771 | reg_a = (reg_a >> 1) | ((reg_ps & 0x01) << 7); 772 | reg_ps &= 0x7C; 773 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1) | (tmp1 & 0x01); 774 | cycles += 2; 775 | } 776 | break; 777 | case 0x6B: { 778 | } 779 | break; 780 | case 0x6C: { 781 | uint16_t addr = peek_word(peek_word(reg_pc)); 782 | reg_pc += 2; 783 | reg_pc = addr; 784 | cycles += 6; 785 | } 786 | break; 787 | case 0x6D: { 788 | uint16_t addr = peek_word(reg_pc); 789 | reg_pc += 2; 790 | uint8_t tmp1 = _load(addr); 791 | int16_t tmp2 = reg_a + tmp1 + (reg_ps & 0x01); 792 | uint8_t tmp3 = tmp2 & 0xFF; 793 | reg_ps &= 0x3C; 794 | reg_ps |= (tmp3 & 0x80) | (!tmp3 << 1) | (tmp2 > 0xFF) 795 | | (((reg_a ^ tmp1 ^ 0x80) & (reg_a ^ tmp3) & 0x80) >> 1); 796 | reg_a = tmp3; 797 | cycles += 4; 798 | } 799 | break; 800 | case 0x6E: { 801 | uint16_t addr = peek_word(reg_pc); 802 | reg_pc += 2; 803 | uint8_t tmp1 = _load(addr); 804 | uint8_t tmp2 = (tmp1 >> 1) | ((reg_ps & 0x01) << 7); 805 | reg_ps &= 0x7C; 806 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 & 0x01); 807 | _store(addr, tmp2); 808 | cycles += 6; 809 | } 810 | break; 811 | case 0x6F: { 812 | } 813 | break; 814 | case 0x70: { 815 | int8_t tmp4 = (int8_t) (_peek_byte(reg_pc++)); 816 | uint16_t addr = reg_pc + tmp4; 817 | if ((reg_ps & 0x40)) { 818 | cycles += !((reg_pc ^ addr) & 0xFF00) << 1; 819 | reg_pc = addr; 820 | } 821 | cycles += 2; 822 | } 823 | break; 824 | case 0x71: { 825 | uint16_t addr = peek_word(_peek_byte(reg_pc)); 826 | cycles += !!(((addr & 0xFF) + reg_y) & 0xFF00); 827 | addr += reg_y; 828 | reg_pc++; 829 | uint8_t tmp1 = _load(addr); 830 | int16_t tmp2 = reg_a + tmp1 + (reg_ps & 0x01); 831 | uint8_t tmp3 = tmp2 & 0xFF; 832 | reg_ps &= 0x3C; 833 | reg_ps |= (tmp3 & 0x80) | (!tmp3 << 1) | (tmp2 > 0xFF) 834 | | (((reg_a ^ tmp1 ^ 0x80) & (reg_a ^ tmp3) & 0x80) >> 1); 835 | reg_a = tmp3; 836 | cycles += 5; 837 | } 838 | break; 839 | case 0x72: { 840 | } 841 | break; 842 | case 0x73: { 843 | } 844 | break; 845 | case 0x74: { 846 | } 847 | break; 848 | case 0x75: { 849 | uint16_t addr = (_peek_byte(reg_pc++) + reg_x) & 0xFF; 850 | uint8_t tmp1 = _load(addr); 851 | int16_t tmp2 = reg_a + tmp1 + (reg_ps & 0x01); 852 | uint8_t tmp3 = tmp2 & 0xFF; 853 | reg_ps &= 0x3C; 854 | reg_ps |= (tmp3 & 0x80) | (!tmp3 << 1) | (tmp2 > 0xFF) 855 | | (((reg_a ^ tmp1 ^ 0x80) & (reg_a ^ tmp3) & 0x80) >> 1); 856 | reg_a = tmp3; 857 | cycles += 4; 858 | } 859 | break; 860 | case 0x76: { 861 | uint16_t addr = (_peek_byte(reg_pc++) + reg_x) & 0xFF; 862 | uint8_t tmp1 = _load(addr); 863 | uint8_t tmp2 = (tmp1 >> 1) | ((reg_ps & 0x01) << 7); 864 | reg_ps &= 0x7C; 865 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 & 0x01); 866 | _store(addr, tmp2); 867 | cycles += 6; 868 | } 869 | break; 870 | case 0x77: { 871 | } 872 | break; 873 | case 0x78: { 874 | reg_ps |= 0x04; 875 | cycles += 2; 876 | } 877 | break; 878 | case 0x79: { 879 | uint16_t addr = peek_word(reg_pc); 880 | cycles += !!(((addr & 0xFF) + reg_y) & 0xFF00); 881 | addr += reg_y; 882 | reg_pc += 2; 883 | uint8_t tmp1 = _load(addr); 884 | int16_t tmp2 = reg_a + tmp1 + (reg_ps & 0x01); 885 | uint8_t tmp3 = tmp2 & 0xFF; 886 | reg_ps &= 0x3C; 887 | reg_ps |= (tmp3 & 0x80) | (!tmp3 << 1) | (tmp2 > 0xFF) 888 | | (((reg_a ^ tmp1 ^ 0x80) & (reg_a ^ tmp3) & 0x80) >> 1); 889 | reg_a = tmp3; 890 | cycles += 4; 891 | } 892 | break; 893 | case 0x7A: { 894 | } 895 | break; 896 | case 0x7B: { 897 | } 898 | break; 899 | case 0x7C: { 900 | } 901 | break; 902 | case 0x7D: { 903 | uint16_t addr = peek_word(reg_pc); 904 | cycles += !!(((addr & 0xFF) + reg_x) & 0xFF00); 905 | addr += reg_x; 906 | reg_pc += 2; 907 | uint8_t tmp1 = _load(addr); 908 | int16_t tmp2 = reg_a + tmp1 + (reg_ps & 0x01); 909 | uint8_t tmp3 = tmp2 & 0xFF; 910 | reg_ps &= 0x3C; 911 | reg_ps |= (tmp3 & 0x80) | (!tmp3 << 1) | (tmp2 > 0xFF) 912 | | (((reg_a ^ tmp1 ^ 0x80) & (reg_a ^ tmp3) & 0x80) >> 1); 913 | reg_a = tmp3; 914 | cycles += 4; 915 | } 916 | break; 917 | case 0x7E: { 918 | uint16_t addr = peek_word(reg_pc); 919 | addr += reg_x; 920 | reg_pc += 2; 921 | uint8_t tmp1 = _load(addr); 922 | uint8_t tmp2 = (tmp1 >> 1) | ((reg_ps & 0x01) << 7); 923 | reg_ps &= 0x7C; 924 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 & 0x01); 925 | _store(addr, tmp2); 926 | cycles += 6; 927 | } 928 | break; 929 | case 0x7F: { 930 | } 931 | break; 932 | case 0x80: { 933 | } 934 | break; 935 | case 0x81: { 936 | uint16_t addr = peek_word((_peek_byte(reg_pc++) + reg_x) & 0xFF); 937 | _store(addr, reg_a); 938 | cycles += 6; 939 | } 940 | break; 941 | case 0x82: { 942 | } 943 | break; 944 | case 0x83: { 945 | } 946 | break; 947 | case 0x84: { 948 | uint16_t addr = _peek_byte(reg_pc++); 949 | _store(addr, reg_y); 950 | cycles += 3; 951 | } 952 | break; 953 | case 0x85: { 954 | uint16_t addr = _peek_byte(reg_pc++); 955 | _store(addr, reg_a); 956 | cycles += 3; 957 | } 958 | break; 959 | case 0x86: { 960 | uint16_t addr = _peek_byte(reg_pc++); 961 | _store(addr, reg_x); 962 | cycles += 3; 963 | } 964 | break; 965 | case 0x87: { 966 | } 967 | break; 968 | case 0x88: { 969 | reg_y--; 970 | reg_ps &= 0x7D; 971 | reg_ps |= (reg_y & 0x80) | (!reg_y << 1); 972 | cycles += 2; 973 | } 974 | break; 975 | case 0x89: { 976 | } 977 | break; 978 | case 0x8A: { 979 | reg_a = reg_x; 980 | reg_ps &= 0x7D; 981 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 982 | cycles += 2; 983 | } 984 | break; 985 | case 0x8B: { 986 | } 987 | break; 988 | case 0x8C: { 989 | uint16_t addr = peek_word(reg_pc); 990 | reg_pc += 2; 991 | _store(addr, reg_y); 992 | cycles += 4; 993 | } 994 | break; 995 | case 0x8D: { 996 | uint16_t addr = peek_word(reg_pc); 997 | reg_pc += 2; 998 | _store(addr, reg_a); 999 | cycles += 4; 1000 | } 1001 | break; 1002 | case 0x8E: { 1003 | uint16_t addr = peek_word(reg_pc); 1004 | reg_pc += 2; 1005 | _store(addr, reg_x); 1006 | cycles += 4; 1007 | } 1008 | break; 1009 | case 0x8F: { 1010 | } 1011 | break; 1012 | case 0x90: { 1013 | int8_t tmp4 = (int8_t) (_peek_byte(reg_pc++)); 1014 | uint16_t addr = reg_pc + tmp4; 1015 | if (!(reg_ps & 0x01)) { 1016 | cycles += !((reg_pc ^ addr) & 0xFF00) << 1; 1017 | reg_pc = addr; 1018 | } 1019 | cycles += 2; 1020 | } 1021 | break; 1022 | case 0x91: { 1023 | uint16_t addr = peek_word(_peek_byte(reg_pc)); 1024 | addr += reg_y; 1025 | reg_pc++; 1026 | _store(addr, reg_a); 1027 | cycles += 6; 1028 | } 1029 | break; 1030 | case 0x92: { 1031 | } 1032 | break; 1033 | case 0x93: { 1034 | } 1035 | break; 1036 | case 0x94: { 1037 | uint16_t addr = (_peek_byte(reg_pc++) + reg_x) & 0xFF; 1038 | _store(addr, reg_y); 1039 | cycles += 4; 1040 | } 1041 | break; 1042 | case 0x95: { 1043 | uint16_t addr = (_peek_byte(reg_pc++) + reg_x) & 0xFF; 1044 | _store(addr, reg_a); 1045 | cycles += 4; 1046 | } 1047 | break; 1048 | case 0x96: { 1049 | uint16_t addr = (_peek_byte(reg_pc++) + reg_y) & 0xFF; 1050 | _store(addr, reg_x); 1051 | cycles += 4; 1052 | } 1053 | break; 1054 | case 0x97: { 1055 | } 1056 | break; 1057 | case 0x98: { 1058 | reg_a = reg_y; 1059 | reg_ps &= 0x7D; 1060 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 1061 | cycles += 2; 1062 | } 1063 | break; 1064 | case 0x99: { 1065 | uint16_t addr = peek_word(reg_pc); 1066 | addr += reg_y; 1067 | reg_pc += 2; 1068 | _store(addr, reg_a); 1069 | cycles += 5; 1070 | } 1071 | break; 1072 | case 0x9A: { 1073 | reg_sp = reg_x; 1074 | cycles += 2; 1075 | } 1076 | break; 1077 | case 0x9B: { 1078 | } 1079 | break; 1080 | case 0x9C: { 1081 | } 1082 | break; 1083 | case 0x9D: { 1084 | uint16_t addr = peek_word(reg_pc); 1085 | addr += reg_x; 1086 | reg_pc += 2; 1087 | _store(addr, reg_a); 1088 | cycles += 5; 1089 | } 1090 | break; 1091 | case 0x9E: { 1092 | } 1093 | break; 1094 | case 0x9F: { 1095 | } 1096 | break; 1097 | case 0xA0: { 1098 | uint16_t addr = reg_pc++; 1099 | reg_y = _load(addr); 1100 | reg_ps &= 0x7D; 1101 | reg_ps |= (reg_y & 0x80) | (!reg_y << 1); 1102 | cycles += 2; 1103 | } 1104 | break; 1105 | case 0xA1: { 1106 | uint16_t addr = peek_word((_peek_byte(reg_pc++) + reg_x) & 0xFF); 1107 | reg_a = _load(addr); 1108 | reg_ps &= 0x7D; 1109 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 1110 | cycles += 6; 1111 | } 1112 | break; 1113 | case 0xA2: { 1114 | uint16_t addr = reg_pc++; 1115 | reg_x = _load(addr); 1116 | reg_ps &= 0x7D; 1117 | reg_ps |= (reg_x & 0x80) | (!reg_x << 1); 1118 | cycles += 2; 1119 | } 1120 | break; 1121 | case 0xA3: { 1122 | } 1123 | break; 1124 | case 0xA4: { 1125 | uint16_t addr = _peek_byte(reg_pc++); 1126 | reg_y = _load(addr); 1127 | reg_ps &= 0x7D; 1128 | reg_ps |= (reg_y & 0x80) | (!reg_y << 1); 1129 | cycles += 3; 1130 | } 1131 | break; 1132 | case 0xA5: { 1133 | uint16_t addr = _peek_byte(reg_pc++); 1134 | reg_a = _load(addr); 1135 | reg_ps &= 0x7D; 1136 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 1137 | cycles += 3; 1138 | } 1139 | break; 1140 | case 0xA6: { 1141 | uint16_t addr = _peek_byte(reg_pc++); 1142 | reg_x = _load(addr); 1143 | reg_ps &= 0x7D; 1144 | reg_ps |= (reg_x & 0x80) | (!reg_x << 1); 1145 | cycles += 3; 1146 | } 1147 | break; 1148 | case 0xA7: { 1149 | } 1150 | break; 1151 | case 0xA8: { 1152 | reg_y = reg_a; 1153 | reg_ps &= 0x7D; 1154 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 1155 | cycles += 2; 1156 | } 1157 | break; 1158 | case 0xA9: { 1159 | uint16_t addr = reg_pc++; 1160 | reg_a = _load(addr); 1161 | reg_ps &= 0x7D; 1162 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 1163 | cycles += 2; 1164 | } 1165 | break; 1166 | case 0xAA: { 1167 | reg_x = reg_a; 1168 | reg_ps &= 0x7D; 1169 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 1170 | cycles += 2; 1171 | } 1172 | break; 1173 | case 0xAB: { 1174 | } 1175 | break; 1176 | case 0xAC: { 1177 | uint16_t addr = peek_word(reg_pc); 1178 | reg_pc += 2; 1179 | reg_y = _load(addr); 1180 | reg_ps &= 0x7D; 1181 | reg_ps |= (reg_y & 0x80) | (!reg_y << 1); 1182 | cycles += 4; 1183 | } 1184 | break; 1185 | case 0xAD: { 1186 | uint16_t addr = peek_word(reg_pc); 1187 | reg_pc += 2; 1188 | reg_a = _load(addr); 1189 | reg_ps &= 0x7D; 1190 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 1191 | cycles += 4; 1192 | } 1193 | break; 1194 | case 0xAE: { 1195 | uint16_t addr = peek_word(reg_pc); 1196 | reg_pc += 2; 1197 | reg_x = _load(addr); 1198 | reg_ps &= 0x7D; 1199 | reg_ps |= (reg_x & 0x80) | (!reg_x << 1); 1200 | cycles += 4; 1201 | } 1202 | break; 1203 | case 0xAF: { 1204 | } 1205 | break; 1206 | case 0xB0: { 1207 | int8_t tmp4 = (int8_t) (_peek_byte(reg_pc++)); 1208 | uint16_t addr = reg_pc + tmp4; 1209 | if ((reg_ps & 0x01)) { 1210 | cycles += !((reg_pc ^ addr) & 0xFF00) << 1; 1211 | reg_pc = addr; 1212 | } 1213 | cycles += 2; 1214 | } 1215 | break; 1216 | case 0xB1: { 1217 | uint16_t addr = peek_word(_peek_byte(reg_pc)); 1218 | cycles += !!(((addr & 0xFF) + reg_y) & 0xFF00); 1219 | addr += reg_y; 1220 | reg_pc++; 1221 | reg_a = _load(addr); 1222 | reg_ps &= 0x7D; 1223 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 1224 | cycles += 5; 1225 | } 1226 | break; 1227 | case 0xB2: { 1228 | } 1229 | break; 1230 | case 0xB3: { 1231 | } 1232 | break; 1233 | case 0xB4: { 1234 | uint16_t addr = (_peek_byte(reg_pc++) + reg_x) & 0xFF; 1235 | reg_y = _load(addr); 1236 | reg_ps &= 0x7D; 1237 | reg_ps |= (reg_y & 0x80) | (!reg_y << 1); 1238 | cycles += 4; 1239 | } 1240 | break; 1241 | case 0xB5: { 1242 | uint16_t addr = (_peek_byte(reg_pc++) + reg_x) & 0xFF; 1243 | reg_a = _load(addr); 1244 | reg_ps &= 0x7D; 1245 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 1246 | cycles += 4; 1247 | } 1248 | break; 1249 | case 0xB6: { 1250 | uint16_t addr = (_peek_byte(reg_pc++) + reg_y) & 0xFF; 1251 | reg_x = _load(addr); 1252 | reg_ps &= 0x7D; 1253 | reg_ps |= (reg_x & 0x80) | (!reg_x << 1); 1254 | cycles += 4; 1255 | } 1256 | break; 1257 | case 0xB7: { 1258 | } 1259 | break; 1260 | case 0xB8: { 1261 | reg_ps &= 0xBF; 1262 | cycles += 2; 1263 | } 1264 | break; 1265 | case 0xB9: { 1266 | uint16_t addr = peek_word(reg_pc); 1267 | cycles += !!(((addr & 0xFF) + reg_y) & 0xFF00); 1268 | addr += reg_y; 1269 | reg_pc += 2; 1270 | reg_a = _load(addr); 1271 | reg_ps &= 0x7D; 1272 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 1273 | cycles += 4; 1274 | } 1275 | break; 1276 | case 0xBA: { 1277 | reg_x = reg_sp; 1278 | reg_ps &= 0x7D; 1279 | reg_ps |= (reg_x & 0x80) | (!reg_x << 1); 1280 | cycles += 2; 1281 | } 1282 | break; 1283 | case 0xBB: { 1284 | } 1285 | break; 1286 | case 0xBC: { 1287 | uint16_t addr = peek_word(reg_pc); 1288 | cycles += !!(((addr & 0xFF) + reg_x) & 0xFF00); 1289 | addr += reg_x; 1290 | reg_pc += 2; 1291 | reg_y = _load(addr); 1292 | reg_ps &= 0x7D; 1293 | reg_ps |= (reg_y & 0x80) | (!reg_y << 1); 1294 | cycles += 4; 1295 | } 1296 | break; 1297 | case 0xBD: { 1298 | uint16_t addr = peek_word(reg_pc); 1299 | cycles += !!(((addr & 0xFF) + reg_x) & 0xFF00); 1300 | addr += reg_x; 1301 | reg_pc += 2; 1302 | reg_a = _load(addr); 1303 | reg_ps &= 0x7D; 1304 | reg_ps |= (reg_a & 0x80) | (!reg_a << 1); 1305 | cycles += 4; 1306 | } 1307 | break; 1308 | case 0xBE: { 1309 | uint16_t addr = peek_word(reg_pc); 1310 | cycles += !!(((addr & 0xFF) + reg_y) & 0xFF00); 1311 | addr += reg_y; 1312 | reg_pc += 2; 1313 | reg_x = _load(addr); 1314 | reg_ps &= 0x7D; 1315 | reg_ps |= (reg_x & 0x80) | (!reg_x << 1); 1316 | cycles += 4; 1317 | } 1318 | break; 1319 | case 0xBF: { 1320 | } 1321 | break; 1322 | case 0xC0: { 1323 | uint16_t addr = reg_pc++; 1324 | int16_t tmp1 = reg_y - _load(addr); 1325 | uint8_t tmp2 = tmp1 & 0xFF; 1326 | reg_ps &= 0x7C; 1327 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >= 0); 1328 | cycles += 2; 1329 | } 1330 | break; 1331 | case 0xC1: { 1332 | uint16_t addr = peek_word((_peek_byte(reg_pc++) + reg_x) & 0xFF); 1333 | int16_t tmp1 = reg_a - _load(addr); 1334 | uint8_t tmp2 = tmp1 & 0xFF; 1335 | reg_ps &= 0x7C; 1336 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >= 0); 1337 | cycles += 6; 1338 | } 1339 | break; 1340 | case 0xC2: { 1341 | } 1342 | break; 1343 | case 0xC3: { 1344 | } 1345 | break; 1346 | case 0xC4: { 1347 | uint16_t addr = _peek_byte(reg_pc++); 1348 | int16_t tmp1 = reg_y - _load(addr); 1349 | uint8_t tmp2 = tmp1 & 0xFF; 1350 | reg_ps &= 0x7C; 1351 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >= 0); 1352 | cycles += 3; 1353 | } 1354 | break; 1355 | case 0xC5: { 1356 | uint16_t addr = _peek_byte(reg_pc++); 1357 | int16_t tmp1 = reg_a - _load(addr); 1358 | uint8_t tmp2 = tmp1 & 0xFF; 1359 | reg_ps &= 0x7C; 1360 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >= 0); 1361 | cycles += 3; 1362 | } 1363 | break; 1364 | case 0xC6: { 1365 | uint16_t addr = _peek_byte(reg_pc++); 1366 | uint8_t tmp1 = _load(addr) - 1; 1367 | _store(addr, tmp1); 1368 | reg_ps &= 0x7D; 1369 | reg_ps |= (tmp1 & 0x80) | (!tmp1 << 1); 1370 | cycles += 5; 1371 | } 1372 | break; 1373 | case 0xC7: { 1374 | } 1375 | break; 1376 | case 0xC8: { 1377 | reg_y++; 1378 | reg_ps &= 0x7D; 1379 | reg_ps |= (reg_y & 0x80) | (!reg_y << 1); 1380 | cycles += 2; 1381 | } 1382 | break; 1383 | case 0xC9: { 1384 | uint16_t addr = reg_pc++; 1385 | int16_t tmp1 = reg_a - _load(addr); 1386 | uint8_t tmp2 = tmp1 & 0xFF; 1387 | reg_ps &= 0x7C; 1388 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >= 0); 1389 | cycles += 2; 1390 | } 1391 | break; 1392 | case 0xCA: { 1393 | reg_x--; 1394 | reg_ps &= 0x7D; 1395 | reg_ps |= (reg_x & 0x80) | (!reg_x << 1); 1396 | cycles += 2; 1397 | } 1398 | break; 1399 | case 0xCB: { 1400 | } 1401 | break; 1402 | case 0xCC: { 1403 | uint16_t addr = peek_word(reg_pc); 1404 | reg_pc += 2; 1405 | int16_t tmp1 = reg_y - _load(addr); 1406 | uint8_t tmp2 = tmp1 & 0xFF; 1407 | reg_ps &= 0x7C; 1408 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >= 0); 1409 | cycles += 4; 1410 | } 1411 | break; 1412 | case 0xCD: { 1413 | uint16_t addr = peek_word(reg_pc); 1414 | reg_pc += 2; 1415 | int16_t tmp1 = reg_a - _load(addr); 1416 | uint8_t tmp2 = tmp1 & 0xFF; 1417 | reg_ps &= 0x7C; 1418 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >= 0); 1419 | cycles += 4; 1420 | } 1421 | break; 1422 | case 0xCE: { 1423 | uint16_t addr = peek_word(reg_pc); 1424 | reg_pc += 2; 1425 | uint8_t tmp1 = _load(addr) - 1; 1426 | _store(addr, tmp1); 1427 | reg_ps &= 0x7D; 1428 | reg_ps |= (tmp1 & 0x80) | (!tmp1 << 1); 1429 | cycles += 6; 1430 | } 1431 | break; 1432 | case 0xCF: { 1433 | } 1434 | break; 1435 | case 0xD0: { 1436 | int8_t tmp4 = (int8_t) (_peek_byte(reg_pc++)); 1437 | uint16_t addr = reg_pc + tmp4; 1438 | if (!(reg_ps & 0x02)) { 1439 | cycles += !((reg_pc ^ addr) & 0xFF00) << 1; 1440 | reg_pc = addr; 1441 | } 1442 | cycles += 2; 1443 | } 1444 | break; 1445 | case 0xD1: { 1446 | uint16_t addr = peek_word(_peek_byte(reg_pc)); 1447 | cycles += !!(((addr & 0xFF) + reg_y) & 0xFF00); 1448 | addr += reg_y; 1449 | reg_pc++; 1450 | int16_t tmp1 = reg_a - _load(addr); 1451 | uint8_t tmp2 = tmp1 & 0xFF; 1452 | reg_ps &= 0x7C; 1453 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >= 0); 1454 | cycles += 5; 1455 | } 1456 | break; 1457 | case 0xD2: { 1458 | } 1459 | break; 1460 | case 0xD3: { 1461 | } 1462 | break; 1463 | case 0xD4: { 1464 | } 1465 | break; 1466 | case 0xD5: { 1467 | uint16_t addr = (_peek_byte(reg_pc++) + reg_x) & 0xFF; 1468 | int16_t tmp1 = reg_a - _load(addr); 1469 | uint8_t tmp2 = tmp1 & 0xFF; 1470 | reg_ps &= 0x7C; 1471 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >= 0); 1472 | cycles += 4; 1473 | } 1474 | break; 1475 | case 0xD6: { 1476 | uint16_t addr = (_peek_byte(reg_pc++) + reg_x) & 0xFF; 1477 | uint8_t tmp1 = _load(addr) - 1; 1478 | _store(addr, tmp1); 1479 | reg_ps &= 0x7D; 1480 | reg_ps |= (tmp1 & 0x80) | (!tmp1 << 1); 1481 | cycles += 6; 1482 | } 1483 | break; 1484 | case 0xD7: { 1485 | } 1486 | break; 1487 | case 0xD8: { 1488 | reg_ps &= 0xF7; 1489 | cycles += 2; 1490 | } 1491 | break; 1492 | case 0xD9: { 1493 | uint16_t addr = peek_word(reg_pc); 1494 | cycles += !!(((addr & 0xFF) + reg_y) & 0xFF00); 1495 | addr += reg_y; 1496 | reg_pc += 2; 1497 | int16_t tmp1 = reg_a - _load(addr); 1498 | uint8_t tmp2 = tmp1 & 0xFF; 1499 | reg_ps &= 0x7C; 1500 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >= 0); 1501 | cycles += 4; 1502 | } 1503 | break; 1504 | case 0xDA: { 1505 | } 1506 | break; 1507 | case 0xDB: { 1508 | } 1509 | break; 1510 | case 0xDC: { 1511 | } 1512 | break; 1513 | case 0xDD: { 1514 | uint16_t addr = peek_word(reg_pc); 1515 | cycles += !!(((addr & 0xFF) + reg_x) & 0xFF00); 1516 | addr += reg_x; 1517 | reg_pc += 2; 1518 | int16_t tmp1 = reg_a - _load(addr); 1519 | uint8_t tmp2 = tmp1 & 0xFF; 1520 | reg_ps &= 0x7C; 1521 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >= 0); 1522 | cycles += 4; 1523 | } 1524 | break; 1525 | case 0xDE: { 1526 | uint16_t addr = peek_word(reg_pc); 1527 | addr += reg_x; 1528 | reg_pc += 2; 1529 | uint8_t tmp1 = _load(addr) - 1; 1530 | _store(addr, tmp1); 1531 | reg_ps &= 0x7D; 1532 | reg_ps |= (tmp1 & 0x80) | (!tmp1 << 1); 1533 | cycles += 6; 1534 | } 1535 | break; 1536 | case 0xDF: { 1537 | } 1538 | break; 1539 | case 0xE0: { 1540 | uint16_t addr = reg_pc++; 1541 | int16_t tmp1 = reg_x - _load(addr); 1542 | uint8_t tmp2 = tmp1 & 0xFF; 1543 | reg_ps &= 0x7C; 1544 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >= 0); 1545 | cycles += 2; 1546 | } 1547 | break; 1548 | case 0xE1: { 1549 | uint16_t addr = peek_word((_peek_byte(reg_pc++) + reg_x) & 0xFF); 1550 | uint8_t tmp1 = _load(addr); 1551 | int16_t tmp2 = reg_a - tmp1 + (reg_ps & 0x01u) - 1u; 1552 | uint8_t tmp3 = tmp2 & 0xFFu; 1553 | reg_ps &= 0x3C; 1554 | reg_ps |= (tmp3 & 0x80) | (!tmp3 << 1) | (tmp2 >= 0) 1555 | | (((reg_a ^ tmp1) & (reg_a ^ tmp3) & 0x80) >> 1); 1556 | reg_a = tmp3; 1557 | cycles += 6; 1558 | } 1559 | break; 1560 | case 0xE2: { 1561 | } 1562 | break; 1563 | case 0xE3: { 1564 | } 1565 | break; 1566 | case 0xE4: { 1567 | uint16_t addr = _peek_byte(reg_pc++); 1568 | int16_t tmp1 = reg_x - _load(addr); 1569 | uint8_t tmp2 = tmp1 & 0xFF; 1570 | reg_ps &= 0x7C; 1571 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >= 0); 1572 | cycles += 3; 1573 | } 1574 | break; 1575 | case 0xE5: { 1576 | uint16_t addr = _peek_byte(reg_pc++); 1577 | uint8_t tmp1 = _load(addr); 1578 | int16_t tmp2 = reg_a - tmp1 + (reg_ps & 0x01) - 1; 1579 | uint8_t tmp3 = tmp2 & 0xFF; 1580 | reg_ps &= 0x3C; 1581 | reg_ps |= (tmp3 & 0x80) | (!tmp3 << 1) | (tmp2 >= 0) 1582 | | (((reg_a ^ tmp1) & (reg_a ^ tmp3) & 0x80) >> 1); 1583 | reg_a = tmp3; 1584 | cycles += 3; 1585 | } 1586 | break; 1587 | case 0xE6: { 1588 | uint16_t addr = _peek_byte(reg_pc++); 1589 | uint8_t tmp1 = _load(addr) + 1; 1590 | _store(addr, tmp1); 1591 | reg_ps &= 0x7D; 1592 | reg_ps |= (tmp1 & 0x80) | (!tmp1 << 1); 1593 | cycles += 5; 1594 | } 1595 | break; 1596 | case 0xE7: { 1597 | } 1598 | break; 1599 | case 0xE8: { 1600 | reg_x++; 1601 | reg_ps &= 0x7D; 1602 | reg_ps |= (reg_x & 0x80) | (!reg_x << 1); 1603 | cycles += 2; 1604 | } 1605 | break; 1606 | case 0xE9: { 1607 | uint16_t addr = reg_pc++; 1608 | uint8_t tmp1 = _load(addr); 1609 | int16_t tmp2 = reg_a - tmp1 + (reg_ps & 0x01) - 1; 1610 | uint8_t tmp3 = tmp2 & 0xFF; 1611 | reg_ps &= 0x3C; 1612 | reg_ps |= (tmp3 & 0x80) | (!tmp3 << 1) | (tmp2 >= 0) 1613 | | (((reg_a ^ tmp1) & (reg_a ^ tmp3) & 0x80) >> 1); 1614 | reg_a = tmp3; 1615 | cycles += 2; 1616 | } 1617 | break; 1618 | case 0xEA: { 1619 | cycles += 2; 1620 | } 1621 | break; 1622 | case 0xEB: { 1623 | } 1624 | break; 1625 | case 0xEC: { 1626 | uint16_t addr = peek_word(reg_pc); 1627 | reg_pc += 2; 1628 | int16_t tmp1 = reg_x - _load(addr); 1629 | uint8_t tmp2 = tmp1 & 0xFF; 1630 | reg_ps &= 0x7C; 1631 | reg_ps |= (tmp2 & 0x80) | (!tmp2 << 1) | (tmp1 >= 0); 1632 | cycles += 4; 1633 | } 1634 | break; 1635 | case 0xED: { 1636 | uint16_t addr = peek_word(reg_pc); 1637 | reg_pc += 2; 1638 | uint8_t tmp1 = _load(addr); 1639 | int16_t tmp2 = reg_a - tmp1 + (reg_ps & 0x01) - 1; 1640 | uint8_t tmp3 = tmp2 & 0xFF; 1641 | reg_ps &= 0x3C; 1642 | reg_ps |= (tmp3 & 0x80) | (!tmp3 << 1) | (tmp2 >= 0) 1643 | | (((reg_a ^ tmp1) & (reg_a ^ tmp3) & 0x80) >> 1); 1644 | reg_a = tmp3; 1645 | cycles += 4; 1646 | } 1647 | break; 1648 | case 0xEE: { 1649 | uint16_t addr = peek_word(reg_pc); 1650 | reg_pc += 2; 1651 | uint8_t tmp1 = _load(addr) + 1; 1652 | _store(addr, tmp1); 1653 | reg_ps &= 0x7D; 1654 | reg_ps |= (tmp1 & 0x80) | (!tmp1 << 1); 1655 | cycles += 6; 1656 | } 1657 | break; 1658 | case 0xEF: { 1659 | } 1660 | break; 1661 | case 0xF0: { 1662 | int8_t tmp4 = (int8_t) (_peek_byte(reg_pc++)); 1663 | uint16_t addr = reg_pc + tmp4; 1664 | if ((reg_ps & 0x02)) { 1665 | cycles += !((reg_pc ^ addr) & 0xFF00) << 1; 1666 | reg_pc = addr; 1667 | } 1668 | cycles += 2; 1669 | } 1670 | break; 1671 | case 0xF1: { 1672 | uint16_t addr = peek_word(_peek_byte(reg_pc)); 1673 | cycles += !!(((addr & 0xFF) + reg_y) & 0xFF00); 1674 | addr += reg_y; 1675 | reg_pc++; 1676 | uint8_t tmp1 = _load(addr); 1677 | int16_t tmp2 = reg_a - tmp1 + (reg_ps & 0x01) - 1; 1678 | uint8_t tmp3 = tmp2 & 0xFF; 1679 | reg_ps &= 0x3C; 1680 | reg_ps |= (tmp3 & 0x80) | (!tmp3 << 1) | (tmp2 >= 0) 1681 | | (((reg_a ^ tmp1) & (reg_a ^ tmp3) & 0x80) >> 1); 1682 | reg_a = tmp3; 1683 | cycles += 5; 1684 | } 1685 | break; 1686 | case 0xF2: { 1687 | } 1688 | break; 1689 | case 0xF3: { 1690 | } 1691 | break; 1692 | case 0xF4: { 1693 | } 1694 | break; 1695 | case 0xF5: { 1696 | uint16_t addr = (_peek_byte(reg_pc++) + reg_x) & 0xFF; 1697 | uint8_t tmp1 = _load(addr); 1698 | int16_t tmp2 = reg_a - tmp1 + (reg_ps & 0x01) - 1; 1699 | uint8_t tmp3 = tmp2 & 0xFF; 1700 | reg_ps &= 0x3C; 1701 | reg_ps |= (tmp3 & 0x80) | (!tmp3 << 1) | (tmp2 >= 0) 1702 | | (((reg_a ^ tmp1) & (reg_a ^ tmp3) & 0x80) >> 1); 1703 | reg_a = tmp3; 1704 | cycles += 4; 1705 | } 1706 | break; 1707 | case 0xF6: { 1708 | uint16_t addr = (_peek_byte(reg_pc++) + reg_x) & 0xFF; 1709 | uint8_t tmp1 = _load(addr) + 1; 1710 | _store(addr, tmp1); 1711 | reg_ps &= 0x7D; 1712 | reg_ps |= (tmp1 & 0x80) | (!tmp1 << 1); 1713 | cycles += 6; 1714 | } 1715 | break; 1716 | case 0xF7: { 1717 | } 1718 | break; 1719 | case 0xF8: { 1720 | reg_ps |= 0x08; 1721 | cycles += 2; 1722 | } 1723 | break; 1724 | case 0xF9: { 1725 | uint16_t addr = peek_word(reg_pc); 1726 | cycles += !!(((addr & 0xFF) + reg_y) & 0xFF00); 1727 | addr += reg_y; 1728 | reg_pc += 2; 1729 | uint8_t tmp1 = _load(addr); 1730 | int16_t tmp2 = reg_a - tmp1 + (reg_ps & 0x01) - 1; 1731 | uint8_t tmp3 = tmp2 & 0xFF; 1732 | reg_ps &= 0x3C; 1733 | reg_ps |= (tmp3 & 0x80) | (!tmp3 << 1) | (tmp2 >= 0) 1734 | | (((reg_a ^ tmp1) & (reg_a ^ tmp3) & 0x80) >> 1); 1735 | reg_a = tmp3; 1736 | cycles += 4; 1737 | } 1738 | break; 1739 | case 0xFA: { 1740 | } 1741 | break; 1742 | case 0xFB: { 1743 | } 1744 | break; 1745 | case 0xFC: { 1746 | } 1747 | break; 1748 | case 0xFD: { 1749 | uint16_t addr = peek_word(reg_pc); 1750 | cycles += !!(((addr & 0xFF) + reg_x) & 0xFF00); 1751 | addr += reg_x; 1752 | reg_pc += 2; 1753 | uint8_t tmp1 = _load(addr); 1754 | int16_t tmp2 = reg_a - tmp1 + (reg_ps & 0x01) - 1; 1755 | uint8_t tmp3 = tmp2 & 0xFF; 1756 | reg_ps &= 0x3C; 1757 | reg_ps |= (tmp3 & 0x80) | (!tmp3 << 1) | (tmp2 >= 0) 1758 | | (((reg_a ^ tmp1) & (reg_a ^ tmp3) & 0x80) >> 1); 1759 | reg_a = tmp3; 1760 | cycles += 4; 1761 | } 1762 | break; 1763 | case 0xFE: { 1764 | uint16_t addr = peek_word(reg_pc); 1765 | addr += reg_x; 1766 | reg_pc += 2; 1767 | uint8_t tmp1 = _load(addr) + 1; 1768 | _store(addr, tmp1); 1769 | reg_ps &= 0x7D; 1770 | reg_ps |= (tmp1 & 0x80) | (!tmp1 << 1); 1771 | cycles += 6; 1772 | } 1773 | break; 1774 | case 0xFF: { 1775 | } 1776 | break; 1777 | } 1778 | 1779 | cpu_states -> reg_pc = reg_pc; 1780 | cpu_states -> reg_a = reg_a; 1781 | cpu_states -> reg_ps = reg_ps; 1782 | cpu_states -> reg_x = reg_x; 1783 | cpu_states -> reg_y = reg_y; 1784 | cpu_states -> reg_sp = reg_sp; 1785 | 1786 | 1787 | return cycles; 1788 | } 1789 | -------------------------------------------------------------------------------- /app/src/main/cpp/wqx/cpu6502.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by liberty on 4/12/19. 3 | // 4 | 5 | #ifndef NC1020_CPU6502_H 6 | #define NC1020_CPU6502_H 7 | 8 | #include 9 | 10 | typedef struct { 11 | uint16_t reg_pc; 12 | uint8_t reg_a; 13 | uint8_t reg_ps; 14 | uint8_t reg_x; 15 | uint8_t reg_y; 16 | uint8_t reg_sp; 17 | } cpu_states_t; 18 | 19 | void init_6502(uint8_t (*Peek_func)(uint16_t addr), 20 | uint8_t (*Load_func)(uint16_t addr), 21 | void (*Store_func)(uint16_t addr, uint8_t value)); 22 | 23 | uint64_t execute_6502(cpu_states_t *cpu_states); 24 | 25 | uint64_t do_irq(cpu_states_t *cpu_states); 26 | 27 | #endif //NC1020_CPU6502_H 28 | -------------------------------------------------------------------------------- /app/src/main/cpp/wqx/nc1020.c: -------------------------------------------------------------------------------- 1 | #include "nc1020.h" 2 | #include "cpu6502.h" 3 | #include "nc1020_states.h" 4 | #include "nc1020_io.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // cpu cycles per second (cpu freq). 12 | const uint64_t CYCLES_SECOND = 5120000; 13 | const uint64_t TIMER0_FREQ = 2; 14 | const uint64_t TIMER1_FREQ = 0x100; 15 | // cpu cycles per timer0 period (1/2 s). 16 | const uint64_t CYCLES_TIMER0 = CYCLES_SECOND / TIMER0_FREQ; 17 | // cpu cycles per timer1 period (1/256 s). 18 | const uint64_t CYCLES_TIMER1 = CYCLES_SECOND / TIMER1_FREQ; 19 | // speed up 20 | const uint64_t CYCLES_TIMER1_SPEED_UP = CYCLES_SECOND / TIMER1_FREQ / 20; 21 | // cpu cycles per ms (1/1000 s). 22 | const uint64_t CYCLES_MS = CYCLES_SECOND / 1000; 23 | 24 | static const uint64_t ROM_SIZE = 0x8000 * 0x300; 25 | static const uint64_t NOR_SIZE = 0x8000 * 0x20; 26 | 27 | static const uint16_t IO_LIMIT = 0x40; 28 | 29 | static const uint16_t NMI_VEC = 0xFFFA; 30 | static const uint16_t RESET_VEC = 0xFFFC; 31 | 32 | static const uint64_t VERSION = 0x06; 33 | 34 | static const int MAX_FILE_NAME_LENGTH = 255; 35 | 36 | static char _rom_file_path[MAX_FILE_NAME_LENGTH]; 37 | static char _nor_file_path[MAX_FILE_NAME_LENGTH]; 38 | static char _state_file_path[MAX_FILE_NAME_LENGTH]; 39 | 40 | static uint8_t _rom_buff[ROM_SIZE]; 41 | static uint8_t _nor_buff[NOR_SIZE]; 42 | 43 | static uint8_t *_nor_banks[0x20]; 44 | 45 | static uint8_t *_memmap[8]; 46 | static nc1020_states_t _nc1020_states; 47 | 48 | static uint8_t *_ram_buff; 49 | static uint8_t *_ram_page0; 50 | static uint8_t *_ram_page2; 51 | static uint8_t *_ram_page3; 52 | 53 | static uint8_t *_clock_buff; 54 | 55 | static uint8_t *_jg_wav_buff; 56 | 57 | static uint8_t *_fp_buff; 58 | 59 | static uint8_t *_keypad_matrix; 60 | 61 | static void adjust_time(){ 62 | if (++ _clock_buff[0] >= 60) { 63 | _clock_buff[0] = 0; 64 | if (++ _clock_buff[1] >= 60) { 65 | _clock_buff[1] = 0; 66 | if (++ _clock_buff[2] >= 24) { 67 | _clock_buff[2] &= 0xC0u; 68 | ++ _clock_buff[3]; 69 | } 70 | } 71 | } 72 | } 73 | 74 | static bool is_count_down(){ 75 | if (!(_clock_buff[10] & 0x02u) || 76 | !(_nc1020_states.clock_flags & 0x02u)) { 77 | return false; 78 | } 79 | return ( 80 | ((_clock_buff[7] & 0x80u) && !(((_clock_buff[7] ^ _clock_buff[2])) & 0x1Fu)) || 81 | ((_clock_buff[6] & 0x80u) && !(((_clock_buff[6] ^ _clock_buff[1])) & 0x3Fu)) || 82 | ((_clock_buff[5] & 0x80u) && !(((_clock_buff[5] ^ _clock_buff[0])) & 0x3Fu)) 83 | ); 84 | } 85 | 86 | /** 87 | * ProcessBinary 88 | * encrypt or decrypt wqx's binary file. just flip every bank. 89 | */ 90 | static void process_binary(uint8_t *dest, uint8_t *src, uint64_t size){ 91 | uint64_t offset = 0; 92 | while (offset < size) { 93 | memcpy(dest + offset + 0x4000, src + offset, 0x4000); 94 | memcpy(dest + offset, src + offset + 0x4000, 0x4000); 95 | offset += 0x8000; 96 | } 97 | } 98 | 99 | static void load_rom(){ 100 | uint8_t* temp_buff = (uint8_t*)malloc(ROM_SIZE); 101 | FILE* file = fopen(_rom_file_path, "rbe"); 102 | fread(temp_buff, 1, ROM_SIZE, file); 103 | process_binary(_rom_buff, temp_buff, ROM_SIZE); 104 | free(temp_buff); 105 | fclose(file); 106 | } 107 | 108 | static void load_nor(){ 109 | uint8_t* temp_buff = (uint8_t*)malloc(NOR_SIZE); 110 | FILE* file = fopen(_nor_file_path, "rbe"); 111 | fread(temp_buff, 1, NOR_SIZE, file); 112 | process_binary(_nor_buff, temp_buff, NOR_SIZE); 113 | free(temp_buff); 114 | fclose(file); 115 | } 116 | 117 | static void save_nor(){ 118 | uint8_t* temp_buff = (uint8_t*)malloc(NOR_SIZE); 119 | FILE* file = fopen(_nor_file_path, "wbe"); 120 | process_binary(temp_buff, _nor_buff, NOR_SIZE); 121 | fwrite(temp_buff, 1, NOR_SIZE, file); 122 | fflush(file); 123 | free(temp_buff); 124 | fclose(file); 125 | } 126 | 127 | static uint8_t peek_byte(uint16_t addr) { 128 | return _memmap[addr / 0x2000][addr % 0x2000]; 129 | } 130 | 131 | static uint16_t peek_word(uint16_t addr) { 132 | return peek_byte(addr) | (peek_byte((uint16_t) (addr + 1u)) << 8u); 133 | } 134 | static uint8_t load(uint16_t addr) { 135 | if (addr < IO_LIMIT) { 136 | return read_io((uint8_t) addr); 137 | } 138 | if (((_nc1020_states.fp_step == 4 && _nc1020_states.fp_type == 2) || 139 | (_nc1020_states.fp_step == 6 && _nc1020_states.fp_type == 3)) && 140 | (addr >= 0x4000 && addr < 0xC000)) { 141 | _nc1020_states.fp_step = 0; 142 | return 0x88; 143 | } 144 | if (addr == 0x45F && _nc1020_states.pending_wake_up) { 145 | _nc1020_states.pending_wake_up = false; 146 | _memmap[0][0x45F] = _nc1020_states.wake_up_flags; 147 | } 148 | return peek_byte(addr); 149 | } 150 | 151 | static void store(uint16_t addr, uint8_t value) { 152 | if (addr < IO_LIMIT) { 153 | write_io((uint8_t) addr, value); 154 | return; 155 | } 156 | if (addr < 0x4000) { 157 | _memmap[addr / 0x2000][addr % 0x2000] = value; 158 | return; 159 | } 160 | uint8_t* page = _memmap[addr >> 13u]; 161 | if (page == _ram_page2 || page == _ram_page3) { 162 | page[addr & 0x1FFFu] = value; 163 | return; 164 | } 165 | if (addr >= 0xE000) { 166 | return; 167 | } 168 | 169 | // write to nor_flash address space. 170 | // there must select a nor_bank. 171 | 172 | uint8_t bank_idx = read_io(0x00); 173 | if (bank_idx >= 0x20) { 174 | return; 175 | } 176 | 177 | uint8_t* bank = _nor_banks[bank_idx]; 178 | 179 | if (_nc1020_states.fp_step == 0) { 180 | if (addr == 0x5555 && value == 0xAA) { 181 | _nc1020_states.fp_step = 1; 182 | } 183 | return; 184 | } 185 | if (_nc1020_states.fp_step == 1) { 186 | if (addr == 0xAAAA && value == 0x55) { 187 | _nc1020_states.fp_step = 2; 188 | return; 189 | } 190 | } else if (_nc1020_states.fp_step == 2) { 191 | if (addr == 0x5555) { 192 | switch (value) { 193 | case 0x90: _nc1020_states.fp_type = 1; break; 194 | case 0xA0: _nc1020_states.fp_type = 2; break; 195 | case 0x80: _nc1020_states.fp_type = 3; break; 196 | case 0xA8: _nc1020_states.fp_type = 4; break; 197 | case 0x88: _nc1020_states.fp_type = 5; break; 198 | case 0x78: _nc1020_states.fp_type = 6; break; 199 | default:break; 200 | } 201 | if (_nc1020_states.fp_type) { 202 | if (_nc1020_states.fp_type == 1) { 203 | _nc1020_states.fp_bank_idx = bank_idx; 204 | _nc1020_states.fp_bak1 = bank[0x4000]; 205 | _nc1020_states.fp_bak1 = bank[0x4001]; 206 | } 207 | _nc1020_states.fp_step = 3; 208 | return; 209 | } 210 | } 211 | } else if (_nc1020_states.fp_step == 3) { 212 | if (_nc1020_states.fp_type == 1) { 213 | if (value == 0xF0) { 214 | bank[0x4000] = _nc1020_states.fp_bak1; 215 | bank[0x4001] = _nc1020_states.fp_bak2; 216 | _nc1020_states.fp_step = 0; 217 | return; 218 | } 219 | } else if (_nc1020_states.fp_type == 2) { 220 | bank[addr - 0x4000] &= value; 221 | _nc1020_states.fp_step = 4; 222 | return; 223 | } else if (_nc1020_states.fp_type == 4) { 224 | _fp_buff[addr & 0xFFu] &= value; 225 | _nc1020_states.fp_step = 4; 226 | return; 227 | } else if (_nc1020_states.fp_type == 3 || _nc1020_states.fp_type == 5) { 228 | if (addr == 0x5555 && value == 0xAA) { 229 | _nc1020_states.fp_step = 4; 230 | return; 231 | } 232 | } 233 | } else if (_nc1020_states.fp_step == 4) { 234 | if (_nc1020_states.fp_type == 3 || _nc1020_states.fp_type == 5) { 235 | if (addr == 0xAAAA && value == 0x55) { 236 | _nc1020_states.fp_step = 5; 237 | return; 238 | } 239 | } 240 | } else if (_nc1020_states.fp_step == 5) { 241 | if (addr == 0x5555 && value == 0x10) { 242 | for (uint64_t i=0; i<0x20; i++) { 243 | memset(_nor_banks[i], 0xFF, 0x8000); 244 | } 245 | if (_nc1020_states.fp_type == 5) { 246 | memset(_fp_buff, 0xFF, 0x100); 247 | } 248 | _nc1020_states.fp_step = 6; 249 | return; 250 | } 251 | if (_nc1020_states.fp_type == 3) { 252 | if (value == 0x30) { 253 | memset(bank + (addr - (addr % 0x800) - 0x4000), 0xFF, 0x800); 254 | _nc1020_states.fp_step = 6; 255 | return; 256 | } 257 | } else if (_nc1020_states.fp_type == 5) { 258 | if (value == 0x48) { 259 | memset(_fp_buff, 0xFF, 0x100); 260 | _nc1020_states.fp_step = 6; 261 | return; 262 | } 263 | } 264 | } 265 | if (addr == 0x8000 && value == 0xF0) { 266 | _nc1020_states.fp_step = 0; 267 | return; 268 | } 269 | printf("error occurs when operate in flash!"); 270 | } 271 | 272 | static void sync_time() { 273 | time_t time_raw_format; 274 | struct tm * ptr_time; 275 | time ( &time_raw_format ); 276 | ptr_time = localtime ( &time_raw_format ); 277 | store(1138, (uint8_t) (1900 + ptr_time -> tm_year - 1881)); 278 | store(1139, (uint8_t) (ptr_time -> tm_mon + 1)); 279 | store(1140, (uint8_t) (ptr_time -> tm_mday + 1)); 280 | store(1141, (uint8_t) (ptr_time -> tm_wday)); 281 | store(1135, (uint8_t) (ptr_time -> tm_hour)); 282 | store(1136, (uint8_t) (ptr_time -> tm_min)); 283 | store(1137, (uint8_t) (ptr_time -> tm_sec / 2)); 284 | 285 | _clock_buff[0] = (uint8_t) ptr_time -> tm_sec; 286 | _clock_buff[1] = (uint8_t) ptr_time -> tm_min; 287 | _clock_buff[2] = (uint8_t) ptr_time -> tm_hour; 288 | } 289 | 290 | void initialize(const char *rom_file_path, const char *nor_file_path, const char *state_file_path) { 291 | strncpy(_rom_file_path, rom_file_path, MAX_FILE_NAME_LENGTH); 292 | strncpy(_nor_file_path, nor_file_path, MAX_FILE_NAME_LENGTH); 293 | strncpy(_state_file_path, state_file_path, MAX_FILE_NAME_LENGTH); 294 | 295 | _ram_buff = _nc1020_states.ram; 296 | _ram_page0 = _ram_buff; 297 | _ram_page2 = _ram_buff + 0x4000; 298 | _ram_page3 = _ram_buff + 0x6000; 299 | _clock_buff = _nc1020_states.clock_data; 300 | _jg_wav_buff = _nc1020_states.jg_wav_data; 301 | _fp_buff = _nc1020_states.fp_buff; 302 | _keypad_matrix = _nc1020_states.keypad_matrix; 303 | 304 | for (uint64_t i=0; i<0x20; i++) { 305 | _nor_banks[i] = _nor_buff + (0x8000 * i); 306 | } 307 | 308 | init_6502(peek_byte, load, store); 309 | init_nc1020_io(&_nc1020_states, _rom_buff, _nor_buff, _memmap); 310 | 311 | load_rom(); 312 | } 313 | 314 | static void reset_states(){ 315 | _nc1020_states.version = VERSION; 316 | 317 | memset(_ram_buff, 0, 0x8000); 318 | _memmap[0] = _ram_page0; 319 | _memmap[2] = _ram_page2; 320 | switch_volume(); 321 | 322 | memset(_keypad_matrix, 0, 8); 323 | 324 | memset(_clock_buff, 0, 80); 325 | _nc1020_states.clock_flags = 0; 326 | 327 | _nc1020_states.timer0_toggle = false; 328 | 329 | memset(_jg_wav_buff, 0, 0x20); 330 | _nc1020_states.jg_wav_flags = 0; 331 | _nc1020_states.jg_wav_idx = 0; 332 | 333 | _nc1020_states.should_wake_up = false; 334 | _nc1020_states.pending_wake_up = false; 335 | 336 | memset(_fp_buff, 0, 0x100); 337 | _nc1020_states.fp_step = 0; 338 | 339 | _nc1020_states.should_irq = false; 340 | 341 | _nc1020_states.cycles = 0; 342 | _nc1020_states.cpu.reg_a = 0; 343 | _nc1020_states.cpu.reg_ps = 0x24; 344 | _nc1020_states.cpu.reg_x = 0; 345 | _nc1020_states.cpu.reg_y = 0; 346 | _nc1020_states.cpu.reg_sp = 0xFF; 347 | _nc1020_states.cpu.reg_pc = peek_word(RESET_VEC); 348 | _nc1020_states.timer0_cycles = CYCLES_TIMER0; 349 | _nc1020_states.timer1_cycles = CYCLES_TIMER1; 350 | } 351 | 352 | static void load_states(){ 353 | reset_states(); 354 | FILE* file = fopen(_state_file_path, "rbe"); 355 | if (file == NULL) { 356 | return; 357 | } 358 | fread(&_nc1020_states, 1, sizeof(_nc1020_states), file); 359 | fclose(file); 360 | if (_nc1020_states.version != VERSION) { 361 | return; 362 | } 363 | switch_volume(); 364 | } 365 | 366 | static void save_states(){ 367 | FILE* file = fopen(_state_file_path, "wbe"); 368 | fwrite(&_nc1020_states, 1, sizeof(_nc1020_states), file); 369 | fflush(file); 370 | fclose(file); 371 | } 372 | 373 | void reset() { 374 | load_nor(); 375 | reset_states(); 376 | } 377 | 378 | void load_nc1020(){ 379 | load_nor(); 380 | load_states(); 381 | sync_time(); 382 | } 383 | 384 | void save_nc1020(){ 385 | save_nor(); 386 | save_states(); 387 | } 388 | 389 | void set_key(uint8_t key_id, bool down_or_up){ 390 | uint8_t row = (uint8_t) (key_id % 8u); 391 | uint8_t col = (uint8_t) (key_id / 8u); 392 | uint8_t bits = (uint8_t) (1u << col); 393 | if (key_id == 0x0F) { 394 | bits = 0xFE; 395 | } 396 | if (down_or_up) { 397 | _keypad_matrix[row] |= bits; 398 | } else { 399 | _keypad_matrix[row] &= ~bits; 400 | } 401 | 402 | if (down_or_up) { 403 | if (_nc1020_states.slept) { 404 | if (key_id >= 0x08 && key_id <= 0x0F && key_id != 0x0E) { 405 | switch (key_id) { 406 | case 0x08: _nc1020_states.wake_up_flags = 0x00; break; 407 | case 0x09: _nc1020_states.wake_up_flags = 0x0A; break; 408 | case 0x0A: _nc1020_states.wake_up_flags = 0x08; break; 409 | case 0x0B: _nc1020_states.wake_up_flags = 0x06; break; 410 | case 0x0C: _nc1020_states.wake_up_flags = 0x04; break; 411 | case 0x0D: _nc1020_states.wake_up_flags = 0x02; break; 412 | case 0x0E: _nc1020_states.wake_up_flags = 0x0C; break; 413 | case 0x0F: _nc1020_states.wake_up_flags = 0x00; break; 414 | default:break; 415 | } 416 | _nc1020_states.should_wake_up = true; 417 | _nc1020_states.pending_wake_up = true; 418 | _nc1020_states.slept = false; 419 | } 420 | } else { 421 | if (key_id == 0x0F) { 422 | _nc1020_states.slept = true; 423 | } 424 | } 425 | } 426 | } 427 | 428 | uint64_t get_cycles() { 429 | return _nc1020_states.cycles; 430 | } 431 | 432 | /** 433 | * @return The LCD buffer, size is 1600 uint_8 434 | */ 435 | uint8_t* get_lcd_buffer(){ 436 | if (_nc1020_states.lcd_addr == 0) 437 | return NULL; 438 | 439 | uint8_t *lcd_buffer = _ram_buff + _nc1020_states.lcd_addr; 440 | return lcd_buffer; 441 | } 442 | 443 | 444 | void run_time_slice(uint64_t time_slice, bool speed_up) { 445 | uint64_t end_cycles = time_slice * CYCLES_MS; 446 | 447 | uint64_t cycles = 0; 448 | 449 | while (cycles < end_cycles) { 450 | cycles += execute_6502(&_nc1020_states.cpu); 451 | if (cycles >= _nc1020_states.timer0_cycles) { 452 | _nc1020_states.timer0_cycles += CYCLES_TIMER0; 453 | _nc1020_states.timer0_toggle = !_nc1020_states.timer0_toggle; 454 | if (!_nc1020_states.timer0_toggle) { 455 | adjust_time(); 456 | } 457 | if (!is_count_down() || _nc1020_states.timer0_toggle) { 458 | write_io(0x3D, 0); 459 | } else { 460 | write_io(0x3D, 0x20); 461 | _nc1020_states.clock_flags &= 0xFD; 462 | } 463 | _nc1020_states.should_irq = true; 464 | } 465 | if (_nc1020_states.should_irq) { 466 | _nc1020_states.should_irq = false; 467 | cycles += do_irq(&_nc1020_states.cpu); 468 | } 469 | if (cycles >= _nc1020_states.timer1_cycles) { 470 | if (speed_up) { 471 | _nc1020_states.timer1_cycles += CYCLES_TIMER1_SPEED_UP; 472 | } else { 473 | _nc1020_states.timer1_cycles += CYCLES_TIMER1; 474 | } 475 | _clock_buff[4] ++; 476 | if (_nc1020_states.should_wake_up) { 477 | _nc1020_states.should_wake_up = false; 478 | write_io(0x01, (uint8_t) (read_io(0x01) | 0x01u)); 479 | write_io(0x02, (uint8_t) (read_io(0x02) | 0x01u)); 480 | _nc1020_states.cpu.reg_pc = peek_word(RESET_VEC); 481 | } else { 482 | write_io(0x01, (uint8_t) (read_io(0x01) | 0x08u)); 483 | _nc1020_states.should_irq = true; 484 | } 485 | } 486 | } 487 | 488 | _nc1020_states.cycles += cycles; 489 | _nc1020_states.timer0_cycles -= end_cycles; 490 | _nc1020_states.timer1_cycles -= end_cycles; 491 | } 492 | -------------------------------------------------------------------------------- /app/src/main/cpp/wqx/nc1020.h: -------------------------------------------------------------------------------- 1 | #ifndef NC1020_H_ 2 | #define NC1020_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | void initialize(const char * rom_file_path, const char *nor_file_path, const char *state_file_path); 9 | void reset(); 10 | void set_key(uint8_t, bool); 11 | void run_time_slice(uint64_t, bool); 12 | uint8_t* get_lcd_buffer(); 13 | void load_nc1020(); 14 | void save_nc1020(); 15 | uint64_t get_cycles(); 16 | 17 | #endif /* NC1020_H_ */ 18 | -------------------------------------------------------------------------------- /app/src/main/cpp/wqx/nc1020_io.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "nc1020_states.h" 7 | 8 | static nc1020_states_t *_nc1020_states; 9 | 10 | static uint8_t *_rom_volume0[0x100]; 11 | static uint8_t *_rom_volume1[0x100]; 12 | static uint8_t *_rom_volume2[0x100]; 13 | 14 | static uint8_t *_nor_banks[0x20]; 15 | static uint8_t *_bbs_pages[0x10]; 16 | 17 | static uint8_t **_memmap; 18 | 19 | static uint8_t *_ram_buff; 20 | static uint8_t *_ram_io; 21 | static uint8_t *_ram_40; 22 | static uint8_t *_ram_page1; 23 | static uint8_t *_ram_page2; 24 | static uint8_t *_ram_page3; 25 | 26 | static uint8_t *_clock_buff; 27 | static uint8_t *_jg_wav_buff; 28 | static uint8_t *_bak_40; 29 | static uint8_t *_keypad_matrix; 30 | 31 | static uint8_t* get_bank(uint8_t bank_idx){ 32 | uint8_t volume_idx = _ram_io[0x0D]; 33 | if (bank_idx < 0x20) { 34 | return _nor_banks[bank_idx]; 35 | } else if (bank_idx >= 0x80) { 36 | if (volume_idx & 0x01u) { 37 | return _rom_volume1[bank_idx]; 38 | } else if (volume_idx & 0x02u) { 39 | return _rom_volume2[bank_idx]; 40 | } else { 41 | return _rom_volume0[bank_idx]; 42 | } 43 | } 44 | return NULL; 45 | } 46 | 47 | static void switch_bank(){ 48 | uint8_t bank_idx = _ram_io[0x00]; 49 | uint8_t* bank = get_bank(bank_idx); 50 | _memmap[2] = bank; 51 | _memmap[3] = bank + 0x2000; 52 | _memmap[4] = bank + 0x4000; 53 | _memmap[5] = bank + 0x6000; 54 | } 55 | 56 | static uint8_t** get_volume(uint8_t volume_idx){ 57 | if ((volume_idx & 0x03u) == 0x01) { 58 | return _rom_volume1; 59 | } else if ((volume_idx & 0x03u) == 0x03) { 60 | return _rom_volume2; 61 | } else { 62 | return _rom_volume0; 63 | } 64 | } 65 | 66 | void switch_volume(){ 67 | uint8_t volume_idx = _ram_io[0x0D]; 68 | uint8_t** volume = get_volume(volume_idx); 69 | for (int i=0; i<4; i++) { 70 | _bbs_pages[i * 4] = volume[i]; 71 | _bbs_pages[i * 4 + 1] = volume[i] + 0x2000; 72 | _bbs_pages[i * 4 + 2] = volume[i] + 0x4000; 73 | _bbs_pages[i * 4 + 3] = volume[i] + 0x6000; 74 | } 75 | _bbs_pages[1] = _ram_page3; 76 | _memmap[7] = volume[0] + 0x2000; 77 | uint8_t roa_bbs = _ram_io[0x0A]; 78 | _memmap[1] = (roa_bbs & 0x04u ? _ram_page2 : _ram_page1); 79 | _memmap[6] = _bbs_pages[roa_bbs & 0x0Fu]; 80 | switch_bank(); 81 | } 82 | 83 | static void generate_and_play_jg_wav(){ 84 | 85 | } 86 | 87 | static uint8_t* get_zero_page_pointer(uint8_t index){ 88 | if (index < 4) { 89 | return _ram_io; 90 | } else { 91 | return _ram_buff + ((index) << 6u); 92 | } 93 | } 94 | 95 | static uint8_t read_io_generic(uint8_t addr){ 96 | return _ram_io[addr]; 97 | } 98 | 99 | static uint8_t read_io_3b_unknown(uint8_t addr){ 100 | if (!(_ram_io[0x3D] & 0x03u)) { 101 | return (uint8_t) (_clock_buff[0x3Bu] & 0xFEu); 102 | } 103 | return _ram_io[addr]; 104 | } 105 | 106 | static uint8_t read_io_3f_clock(uint8_t addr){ 107 | uint8_t idx = _ram_io[0x3E]; 108 | return (uint8_t) (idx < 80 ? _clock_buff[idx] : 0); 109 | } 110 | 111 | static void write_io_generic(uint8_t addr, uint8_t value){ 112 | _ram_io[addr] = value; 113 | } 114 | 115 | // switch bank. 116 | static void write_io_00_bank_switch(uint8_t addr, uint8_t value){ 117 | uint8_t old_value = _ram_io[addr]; 118 | _ram_io[addr] = value; 119 | if (value != old_value) { 120 | switch_bank(); 121 | } 122 | } 123 | 124 | static void write_io_05_clock_ctrl(uint8_t addr, uint8_t value){ 125 | uint8_t old_value = _ram_io[addr]; 126 | _ram_io[addr] = value; 127 | if ((old_value ^ value) & 0x08u) { 128 | _nc1020_states -> slept = !(value & 0x08u); 129 | } 130 | } 131 | 132 | static void write_io_06_lcd_start_addr(uint8_t addr, uint8_t value){ 133 | _ram_io[addr] = value; 134 | if (!_nc1020_states -> lcd_addr) { 135 | _nc1020_states -> lcd_addr = ((_ram_io[0x0C] & 0x03u) << 12u) | (value << 4u); 136 | } 137 | _ram_io[0x09] &= 0xFEu; 138 | } 139 | 140 | static void write_io_08_port0(uint8_t addr, uint8_t value){ 141 | _ram_io[addr] = value; 142 | _ram_io[0x0B] &= 0xFEu; 143 | } 144 | 145 | // keypad matrix. 146 | static void write_io_09_port1(uint8_t addr, uint8_t value){ 147 | _ram_io[addr] = value; 148 | switch (value){ 149 | case 0x01: _ram_io[0x08] = _keypad_matrix[0]; break; 150 | case 0x02: _ram_io[0x08] = _keypad_matrix[1]; break; 151 | case 0x04: _ram_io[0x08] = _keypad_matrix[2]; break; 152 | case 0x08: _ram_io[0x08] = _keypad_matrix[3]; break; 153 | case 0x10: _ram_io[0x08] = _keypad_matrix[4]; break; 154 | case 0x20: _ram_io[0x08] = _keypad_matrix[5]; break; 155 | case 0x40: _ram_io[0x08] = _keypad_matrix[6]; break; 156 | case 0x80: _ram_io[0x08] = _keypad_matrix[7]; break; 157 | case 0: 158 | _ram_io[0x0B] |= 1u; 159 | if (_keypad_matrix[7] == 0xFE) { 160 | _ram_io[0x0B] &= 0xFEu; 161 | } 162 | break; 163 | case 0x7F: 164 | if (_ram_io[0x15] == 0x7Fu) { 165 | _ram_io[0x08] = _keypad_matrix[0] | 166 | _keypad_matrix[1] | 167 | _keypad_matrix[2] | 168 | _keypad_matrix[3] | 169 | _keypad_matrix[4] | 170 | _keypad_matrix[5] | 171 | _keypad_matrix[6] | 172 | _keypad_matrix[7]; 173 | } 174 | break; 175 | default:break; 176 | } 177 | } 178 | 179 | // roabbs 180 | static void write_io_0a_roabbs(uint8_t addr, uint8_t value) { 181 | uint8_t old_value = _ram_io[addr]; 182 | _ram_io[addr] = value; 183 | if (value != old_value) { 184 | _memmap[6] = _bbs_pages[value & 0x0Fu]; 185 | } 186 | } 187 | 188 | // switch volume 189 | static void write_io_0d_volume_switch(uint8_t addr, uint8_t value){ 190 | uint8_t old_value = _ram_io[addr]; 191 | _ram_io[addr] = value; 192 | if (value != old_value) { 193 | switch_volume(); 194 | } 195 | } 196 | 197 | // zp40 switch 198 | static void write_io_0f_zero_page_bank_switch(uint8_t addr, uint8_t value){ 199 | uint8_t old_value = _ram_io[addr]; 200 | _ram_io[addr] = value; 201 | old_value &= 0x07u; 202 | value &= 0x07u; 203 | if (value != old_value) { 204 | uint8_t* ptr_new = get_zero_page_pointer(value); 205 | if (old_value) { 206 | memcpy(get_zero_page_pointer(old_value), _ram_40, 0x40); 207 | memcpy(_ram_40, value ? ptr_new : _bak_40, 0x40); 208 | } else { 209 | memcpy(_bak_40, _ram_40, 0x40); 210 | memcpy(_ram_40, ptr_new, 0x40); 211 | } 212 | } 213 | } 214 | 215 | static void write_io_20_jg(uint8_t addr, uint8_t value){ 216 | _ram_io[addr] = value; 217 | if (value == 0x80 || value == 0x40) { 218 | memset(_jg_wav_buff, 0, 0x20); 219 | _ram_io[0x20] = 0; 220 | _nc1020_states -> jg_wav_flags = 1; 221 | _nc1020_states -> jg_wav_idx= 0; 222 | } 223 | } 224 | 225 | static void write_io_23_jg_wav(uint8_t addr, uint8_t value){ 226 | _ram_io[addr] = value; 227 | if (value == 0xC2) { 228 | _jg_wav_buff[_nc1020_states -> jg_wav_idx] = _ram_io[0x22]; 229 | } else if (value == 0xC4) { 230 | if (_nc1020_states -> jg_wav_idx < 0x20) { 231 | _jg_wav_buff[_nc1020_states -> jg_wav_idx] = _ram_io[0x22]; 232 | _nc1020_states -> jg_wav_idx ++; 233 | } 234 | } else if (value == 0x80) { 235 | _ram_io[0x20] = 0x80; 236 | _nc1020_states -> jg_wav_flags = 0; 237 | if (_nc1020_states -> jg_wav_idx) { 238 | if (!_nc1020_states -> jg_wav_playing) { 239 | generate_and_play_jg_wav(); 240 | _nc1020_states -> jg_wav_idx = 0; 241 | } 242 | } 243 | } 244 | if (_nc1020_states -> jg_wav_playing) { 245 | // todo. 246 | } 247 | } 248 | 249 | static void write_io_3f_clock(uint8_t addr, uint8_t value){ 250 | _ram_io[addr] = value; 251 | uint8_t idx = _ram_io[0x3E]; 252 | if (idx >= 0x07) { 253 | if (idx == 0x0B) { 254 | _ram_io[0x3D] = 0xF8; 255 | _nc1020_states -> clock_flags |= value & 0x07u; 256 | _clock_buff[0x0B] = (uint8_t) (value ^ ((_clock_buff[0x0B] ^ value) & 0x7Fu)); 257 | } else if (idx == 0x0A) { 258 | _nc1020_states -> clock_flags |= value & 0x07u; 259 | _clock_buff[0x0A] = value; 260 | } else { 261 | _clock_buff[idx % 80] = value; 262 | } 263 | } else { 264 | if (!(_clock_buff[0x0B] & 0x80u) && idx < 80u) { 265 | _clock_buff[idx] = value; 266 | } 267 | } 268 | } 269 | 270 | void init_nc1020_io(nc1020_states_t *states, uint8_t rom_buff[], uint8_t nor_buff[], uint8_t* mmap[8]) { 271 | _nc1020_states = states; 272 | 273 | _ram_buff = _nc1020_states -> ram; 274 | _ram_io = _ram_buff; 275 | _ram_40 = _ram_buff + 0x40; 276 | _ram_page1 = _ram_buff + 0x2000; 277 | _ram_page2 = _ram_buff + 0x4000; 278 | _ram_page3 = _ram_buff + 0x6000; 279 | _clock_buff = _nc1020_states -> clock_data; 280 | _jg_wav_buff = _nc1020_states -> jg_wav_data; 281 | _bak_40 = _nc1020_states -> bak_40; 282 | _keypad_matrix = _nc1020_states -> keypad_matrix; 283 | _memmap = mmap; 284 | 285 | for (uint64_t i=0; i<0x100; i++) { 286 | _rom_volume0[i] = rom_buff + (0x8000 * i); 287 | _rom_volume1[i] = rom_buff + (0x8000 * (0x100 + i)); 288 | _rom_volume2[i] = rom_buff + (0x8000 * (0x200 + i)); 289 | } 290 | for (uint64_t i=0; i<0x20; i++) { 291 | _nor_banks[i] = nor_buff + (0x8000 * i); 292 | } 293 | } 294 | 295 | 296 | uint8_t read_io(uint8_t addr) { 297 | switch (addr) { 298 | case 0x3B: 299 | return read_io_3b_unknown(addr); 300 | case 0x3F: 301 | return read_io_3f_clock(addr); 302 | default: 303 | return read_io_generic(addr); 304 | } 305 | } 306 | 307 | uint8_t write_io(uint8_t addr, uint8_t value) { 308 | switch (addr) { 309 | case 0x00: 310 | write_io_00_bank_switch(addr, value); 311 | break; 312 | case 0x05: 313 | write_io_05_clock_ctrl(addr, value); 314 | break; 315 | case 0x06: 316 | write_io_06_lcd_start_addr(addr, value); 317 | break; 318 | case 0x08: 319 | write_io_08_port0(addr, value); 320 | break; 321 | case 0x09: 322 | write_io_09_port1(addr, value); 323 | break; 324 | case 0x0A: 325 | write_io_0a_roabbs(addr, value); 326 | break; 327 | case 0x0D: 328 | write_io_0d_volume_switch(addr, value); 329 | break; 330 | case 0x0F: 331 | write_io_0f_zero_page_bank_switch(addr, value); 332 | break; 333 | case 0x20: 334 | write_io_20_jg(addr, value); 335 | break; 336 | case 0x23: 337 | write_io_23_jg_wav(addr, value); 338 | break; 339 | case 0x3F: 340 | write_io_3f_clock(addr, value); 341 | break; 342 | default: 343 | write_io_generic(addr, value); 344 | } 345 | } 346 | -------------------------------------------------------------------------------- /app/src/main/cpp/wqx/nc1020_io.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by liberty on 4/15/19. 3 | // 4 | 5 | #ifndef NC1020_NC1020_IO_H 6 | #define NC1020_NC1020_IO_H 7 | #include "nc1020_states.h" 8 | 9 | void init_nc1020_io(nc1020_states_t *states, uint8_t rom_buff[], uint8_t nor_buff[], uint8_t* mmap[8]); 10 | uint8_t read_io(uint8_t addr); 11 | uint8_t write_io(uint8_t addr, uint8_t value); 12 | void switch_volume(); 13 | 14 | #endif //NC1020_NC1020_IO_H 15 | -------------------------------------------------------------------------------- /app/src/main/cpp/wqx/nc1020_states.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by liberty on 4/15/19. 3 | // 4 | #include 5 | #include 6 | #include "cpu6502.h" 7 | 8 | #ifndef NC1020_NC1020_STATES_H 9 | #define NC1020_NC1020_STATES_H 10 | 11 | typedef struct { 12 | uint64_t version; 13 | cpu_states_t cpu; 14 | uint8_t ram[0x8000]; 15 | 16 | uint8_t bak_40[0x40]; 17 | 18 | uint8_t clock_data[80]; 19 | uint8_t clock_flags; 20 | 21 | uint8_t jg_wav_data[0x20]; 22 | uint8_t jg_wav_flags; 23 | uint8_t jg_wav_idx; 24 | bool jg_wav_playing; 25 | 26 | uint8_t fp_step; 27 | uint8_t fp_type; 28 | uint8_t fp_bank_idx; 29 | uint8_t fp_bak1; 30 | uint8_t fp_bak2; 31 | uint8_t fp_buff[0x100]; 32 | 33 | bool slept; 34 | bool should_wake_up; 35 | bool pending_wake_up; 36 | uint8_t wake_up_flags; 37 | 38 | bool timer0_toggle; 39 | uint64_t cycles; 40 | uint64_t timer0_cycles; 41 | uint64_t timer1_cycles; 42 | bool should_irq; 43 | 44 | uint64_t lcd_addr; 45 | uint8_t keypad_matrix[8]; 46 | } nc1020_states_t; 47 | 48 | 49 | #endif //NC1020_NC1020_STATES_H 50 | -------------------------------------------------------------------------------- /app/src/main/java/org/liberty/android/nc1020emu/KeypadLayout.kt: -------------------------------------------------------------------------------- 1 | package org.liberty.android.nc1020emu 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.widget.LinearLayout 6 | import org.liberty.android.nc1020emu.KeypadLayout.OnButtonPressedListener 7 | import android.view.View.OnTouchListener 8 | import android.view.MotionEvent 9 | import android.view.ViewGroup 10 | import org.liberty.android.nc1020emu.R 11 | import android.view.Gravity 12 | import android.widget.Button 13 | import android.widget.ImageButton 14 | import android.widget.ImageView 15 | 16 | class KeypadLayout : LinearLayout { 17 | private val functionButtonsKeycode = intArrayOf(0x10, 0x11, 0x12, 0x13, 0x0f) 18 | private val mainButtonsKeycode = arrayOf(intArrayOf(-1, -1, -1, 0x0B, 0x0C, 0x0D, 0x0A, 0x09, 0x08, 0x0E), intArrayOf(0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x18, 0x1C), intArrayOf(0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x19, 0x1D), intArrayOf(0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x1A, 0x1E), intArrayOf(0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x1B, 0x1F)) 19 | private var onButtonPressedListener: OnButtonPressedListener? = null 20 | private val onButtonTouchListener = OnTouchListener { v, event -> 21 | val keyCode = v.tag as Int 22 | if (keyCode == -1 || onButtonPressedListener == null) { 23 | return@OnTouchListener false 24 | } 25 | val action = event.action 26 | if (action == MotionEvent.ACTION_DOWN) { 27 | onButtonPressedListener!!.onKeyDown(keyCode) 28 | } else if (action == MotionEvent.ACTION_UP 29 | || action == MotionEvent.ACTION_CANCEL) { 30 | onButtonPressedListener!!.onKeyUp(keyCode) 31 | } 32 | false 33 | } 34 | 35 | constructor(context: Context?) : super(context) { 36 | init() 37 | } 38 | 39 | constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) { 40 | init() 41 | } 42 | 43 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { 44 | init() 45 | } 46 | 47 | fun init() { 48 | orientation = VERTICAL 49 | val functionKeypadLayout = LinearLayout(context) 50 | val functionKeypadParam = LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) 51 | functionKeypadParam.bottomMargin = resources.getDimensionPixelSize(R.dimen.function_keypad_bottom_margin) 52 | functionKeypadLayout.layoutParams = functionKeypadParam 53 | functionKeypadLayout.orientation = HORIZONTAL 54 | functionKeypadLayout.setHorizontalGravity(Gravity.END) 55 | val functionButtonParams = LayoutParams(resources.getDimensionPixelSize(R.dimen.function_keypad_width), resources.getDimensionPixelSize(R.dimen.function_keypad_height)) 56 | val f1Button = ImageButton(context) 57 | f1Button.setImageResource(R.drawable.f1) 58 | val padding = resources.getDimensionPixelSize(R.dimen.function_key_padding) 59 | f1Button.layoutParams = functionButtonParams 60 | f1Button.scaleType = ImageView.ScaleType.FIT_XY 61 | f1Button.setOnTouchListener(onButtonTouchListener) 62 | f1Button.tag = functionButtonsKeycode[0] 63 | functionKeypadLayout.addView(f1Button) 64 | val f2Button = ImageButton(context) 65 | f2Button.setImageResource(R.drawable.f2) 66 | f2Button.layoutParams = functionButtonParams 67 | f2Button.scaleType = ImageView.ScaleType.FIT_XY 68 | f2Button.setOnTouchListener(onButtonTouchListener) 69 | f2Button.tag = functionButtonsKeycode[1] 70 | functionKeypadLayout.addView(f2Button) 71 | val f3Button = ImageButton(context) 72 | f3Button.setImageResource(R.drawable.f3) 73 | f3Button.layoutParams = functionButtonParams 74 | f3Button.scaleType = ImageView.ScaleType.FIT_XY 75 | f3Button.setOnTouchListener(onButtonTouchListener) 76 | f3Button.tag = functionButtonsKeycode[2] 77 | functionKeypadLayout.addView(f3Button) 78 | val f4Button = ImageButton(context) 79 | f4Button.setImageResource(R.drawable.f4) 80 | f4Button.layoutParams = functionButtonParams 81 | f4Button.scaleType = ImageView.ScaleType.FIT_XY 82 | f4Button.setOnTouchListener(onButtonTouchListener) 83 | f4Button.tag = functionButtonsKeycode[3] 84 | functionKeypadLayout.addView(f4Button) 85 | val onoffButton = ImageButton(context) 86 | onoffButton.setImageResource(R.drawable.onoff) 87 | onoffButton.layoutParams = functionButtonParams 88 | onoffButton.scaleType = ImageView.ScaleType.FIT_XY 89 | onoffButton.setOnTouchListener(onButtonTouchListener) 90 | onoffButton.tag = functionButtonsKeycode[4] 91 | functionKeypadLayout.addView(onoffButton) 92 | addView(functionKeypadLayout) 93 | val mainKeypadLayout = LinearLayout(context) 94 | mainKeypadLayout.orientation = VERTICAL 95 | mainKeypadLayout.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, 96 | resources.getDimensionPixelSize(R.dimen.main_keypad_height)) 97 | mainKeypadLayout.background = context.getDrawable(R.drawable.keypad) 98 | val rowParam = LayoutParams(0, LayoutParams.MATCH_PARENT) 99 | rowParam.weight = 1f 100 | rowParam.leftMargin = 0 101 | rowParam.rightMargin = 0 102 | for (j in 0..4) { 103 | val rowLayout = LinearLayout(context) 104 | for (i in 0..9) { 105 | val button = Button(context) 106 | button.layoutParams = rowParam 107 | button.setBackgroundResource(R.drawable.keypad_button) 108 | button.tag = mainButtonsKeycode[j][i] 109 | button.setOnTouchListener(onButtonTouchListener) 110 | rowLayout.addView(button) 111 | } 112 | mainKeypadLayout.addView(rowLayout) 113 | } 114 | addView(mainKeypadLayout) 115 | } 116 | 117 | fun setOnButtonTouchListener(onButtonPressedListener: OnButtonPressedListener?) { 118 | this.onButtonPressedListener = onButtonPressedListener 119 | } 120 | 121 | interface OnButtonPressedListener { 122 | fun onKeyDown(keyCode: Int) 123 | fun onKeyUp(keyCode: Int) 124 | } 125 | } -------------------------------------------------------------------------------- /app/src/main/java/org/liberty/android/nc1020emu/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package org.liberty.android.nc1020emu 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | 6 | class MainActivity : AppCompatActivity() { 7 | override fun onCreate(savedInstanceState: Bundle?) { 8 | super.onCreate(savedInstanceState) 9 | setContentView(R.layout.main_activity) 10 | } 11 | } -------------------------------------------------------------------------------- /app/src/main/java/org/liberty/android/nc1020emu/MainFragment.kt: -------------------------------------------------------------------------------- 1 | package org.liberty.android.nc1020emu 2 | 3 | import org.liberty.android.nc1020emu.NC1020JNI.runTimeSlice 4 | import org.liberty.android.nc1020emu.NC1020JNI.copyLcdBufferEx 5 | import org.liberty.android.nc1020emu.NC1020JNI.save 6 | import org.liberty.android.nc1020emu.NC1020JNI.setKey 7 | import org.liberty.android.nc1020emu.NC1020JNI.reset 8 | import org.liberty.android.nc1020emu.NC1020JNI.load 9 | import org.liberty.android.nc1020emu.NC1020JNI.initialize 10 | import org.liberty.android.nc1020emu.NC1020JNI.cycles 11 | import android.view.SurfaceHolder 12 | import android.view.Choreographer.FrameCallback 13 | import android.graphics.Bitmap 14 | import android.content.SharedPreferences 15 | import android.view.LayoutInflater 16 | import android.view.ViewGroup 17 | import android.os.Bundle 18 | import org.liberty.android.nc1020emu.KeypadLayout.OnButtonPressedListener 19 | import android.widget.LinearLayout 20 | import android.view.Gravity 21 | import androidx.navigation.Navigation 22 | import android.view.Choreographer 23 | import android.content.DialogInterface 24 | import android.graphics.Matrix 25 | import android.graphics.Point 26 | import android.util.Log 27 | import kotlin.Throws 28 | import android.view.MenuItem 29 | import android.view.View 30 | import androidx.appcompat.app.AlertDialog 31 | import androidx.appcompat.widget.Toolbar 32 | import androidx.core.content.ContextCompat 33 | import androidx.fragment.app.Fragment 34 | import androidx.preference.PreferenceManager 35 | import kotlinx.android.synthetic.main.main_fragment.* 36 | import java.io.File 37 | import java.io.FileOutputStream 38 | import java.io.IOException 39 | import java.lang.RuntimeException 40 | import java.nio.ByteBuffer 41 | import java.util.concurrent.Executors 42 | import kotlin.math.max 43 | 44 | class MainFragment : Fragment(), SurfaceHolder.Callback, FrameCallback { 45 | private val lcdBufferEx = ByteArray(1600 * 8) 46 | private var lcdBitmap= Bitmap.createBitmap(160, 80, Bitmap.Config.ALPHA_8) 47 | private var lcdMatrix = Matrix() 48 | private var speedUp = false 49 | private val executorService = Executors.newSingleThreadExecutor() 50 | private var isRunning = true 51 | private var displayScale = 1f 52 | private var lastFrameTime: Long = 0 53 | private var lastCycles: Long = 0 54 | private var frames: Long = 0 55 | private lateinit var preferences: SharedPreferences 56 | 57 | private val runnable = Runnable { 58 | var interval = 0L 59 | while (isRunning) { 60 | val startTime = System.currentTimeMillis() 61 | runTimeSlice(interval.toInt(), speedUp) 62 | copyLcdBufferEx(lcdBufferEx) 63 | val elapsed = System.currentTimeMillis() - startTime 64 | if (elapsed < FRAME_INTERVAL) { 65 | try { 66 | // If speedUp, don't sleep, run as much frames as system can 67 | Thread.sleep(if (speedUp) 0 else FRAME_INTERVAL - elapsed) 68 | } catch (e: InterruptedException) { 69 | e.printStackTrace() 70 | } 71 | } 72 | interval = max(elapsed, FRAME_INTERVAL.toLong()) 73 | } 74 | if (saveStatesSetting) { 75 | save() 76 | } 77 | } 78 | 79 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 80 | return LayoutInflater.from(context).inflate(R.layout.main_fragment, container, false) 81 | } 82 | 83 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 84 | super.onViewCreated(view, savedInstanceState) 85 | preferences = PreferenceManager.getDefaultSharedPreferences(activity) 86 | keypad_layout.setOnButtonTouchListener(object : OnButtonPressedListener { 87 | override fun onKeyDown(keyCode: Int) { 88 | setKey(keyCode, true) 89 | } 90 | 91 | override fun onKeyUp(keyCode: Int) { 92 | setKey(keyCode, false) 93 | } 94 | }) 95 | val width = screenWidth 96 | displayScale = width.toFloat() / 160 97 | val params = LinearLayout.LayoutParams(width, width / 2) 98 | params.gravity = Gravity.CENTER_HORIZONTAL 99 | lcd_surface.layoutParams = params 100 | lcd_surface.holder.addCallback(this) 101 | val toolbar: Toolbar = view.findViewById(R.id.toolbar) 102 | setupToolbar(toolbar) 103 | initEmulation() 104 | } 105 | 106 | private fun setupToolbar(toolbar: Toolbar) { 107 | toolbar.inflateMenu(R.menu.main_menu) 108 | toolbar.setOnMenuItemClickListener { item: MenuItem -> 109 | when (item.itemId) { 110 | R.id.action_quit -> { 111 | requireActivity().finish() 112 | return@setOnMenuItemClickListener true 113 | } 114 | R.id.action_restart -> { 115 | reset() 116 | return@setOnMenuItemClickListener true 117 | } 118 | R.id.action_speed_up -> { 119 | item.isChecked = !item.isChecked 120 | speedUp = item.isChecked 121 | return@setOnMenuItemClickListener true 122 | } 123 | R.id.action_load -> { 124 | load() 125 | return@setOnMenuItemClickListener true 126 | } 127 | R.id.action_save -> { 128 | save() 129 | return@setOnMenuItemClickListener true 130 | } 131 | R.id.action_factory_reset -> { 132 | showFactoryResetDialog() 133 | return@setOnMenuItemClickListener true 134 | } 135 | R.id.action_settings -> { 136 | Navigation.findNavController(toolbar).navigate(R.id.action_mainFragment_to_settingsFragment) 137 | return@setOnMenuItemClickListener true 138 | } 139 | else -> return@setOnMenuItemClickListener false 140 | } 141 | } 142 | } 143 | 144 | override fun onResume() { 145 | super.onResume() 146 | startEmulation() 147 | } 148 | 149 | override fun onPause() { 150 | super.onPause() 151 | stopEmulation() 152 | } 153 | 154 | override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, 155 | height: Int) { 156 | } 157 | 158 | override fun surfaceCreated(holder: SurfaceHolder) { 159 | lcdMatrix.setScale(displayScale, displayScale) 160 | val lcdCanvas = lcd_surface.holder.lockCanvas() 161 | lcdCanvas.drawColor(ContextCompat.getColor(requireContext(), R.color.lcd_background)) 162 | lcd_surface.holder.unlockCanvasAndPost(lcdCanvas) 163 | } 164 | 165 | override fun surfaceDestroyed(holder: SurfaceHolder) {} 166 | private fun initEmulation() { 167 | initDataFolder() 168 | val fileDir = requireContext().applicationContext.filesDir.absolutePath 169 | val romPath = "$fileDir/$ROM_FILE_NAME" 170 | val norPath = "$fileDir/$NOR_FILE_NAME" 171 | val statePath = "$fileDir/$STATE_FILE_NAME" 172 | initialize(romPath, norPath, statePath) 173 | load() 174 | } 175 | 176 | private fun startEmulation() { 177 | Choreographer.getInstance().postFrameCallback(this) 178 | isRunning = true 179 | executorService.submit(runnable) 180 | } 181 | 182 | private fun stopEmulation() { 183 | isRunning = false 184 | Choreographer.getInstance().removeFrameCallback(this) 185 | } 186 | 187 | private val saveStatesSetting: Boolean 188 | get() = preferences.getBoolean(SAVE_STATES_KEY, true) 189 | 190 | private fun showFactoryResetDialog() { 191 | AlertDialog.Builder(requireContext()) 192 | .setTitle(R.string.factory_reset) 193 | .setMessage(R.string.factory_reset_message) 194 | .setPositiveButton(R.string.yes) { _: DialogInterface?, _: Int -> factoryReset() } 195 | .setNegativeButton(R.string.cancel, null) 196 | .show() 197 | } 198 | 199 | private fun initDataFolder() { 200 | val filesDir = requireContext().applicationContext.filesDir 201 | try { 202 | copyFileFromAsset(ROM_FILE_NAME, filesDir) 203 | copyFileFromAsset(NOR_FILE_NAME, filesDir) 204 | } catch (e: IOException) { 205 | throw RuntimeException(e) 206 | } 207 | } 208 | 209 | @Throws(IOException::class) 210 | private fun copyFileFromAsset(fileName: String, folder: File) { 211 | val dest = File(folder.absoluteFile.toString() + "/" + fileName) 212 | if (dest.exists()) { 213 | return 214 | } 215 | resources.assets.open(fileName).use { `in` -> 216 | FileOutputStream(dest).use { out -> 217 | val buffer = ByteArray(8192) 218 | var count: Int 219 | while (`in`.read(buffer).also { count = it } != -1) { 220 | out.write(buffer, 0, count) 221 | } 222 | } 223 | } 224 | } 225 | 226 | private fun factoryReset() { 227 | val filesDir = requireContext().applicationContext.filesDir.absolutePath 228 | val norFile = File("$filesDir/$NOR_FILE_NAME") 229 | val stateFile = File("$filesDir/$STATE_FILE_NAME") 230 | if (!norFile.delete()) { 231 | Log.e(TAG, "Error deleting nor file") 232 | } 233 | if (!stateFile.delete()) { 234 | Log.e(TAG, "Error deleting state file") 235 | } 236 | initEmulation() 237 | reset() 238 | } 239 | 240 | private val screenWidth: Int 241 | get() { 242 | val display = requireActivity().windowManager.defaultDisplay 243 | val size = Point() 244 | display.getSize(size) 245 | return size.x 246 | } 247 | 248 | private fun updateLcd() { 249 | val lcdCanvas = lcd_surface.holder.lockCanvas() ?: return 250 | synchronized(lcdBufferEx) { lcdBitmap.copyPixelsFromBuffer(ByteBuffer.wrap(lcdBufferEx)) } 251 | lcdCanvas.drawColor(ContextCompat.getColor(requireContext(), R.color.lcd_background)) 252 | lcdCanvas.drawBitmap(lcdBitmap, lcdMatrix, null) 253 | lcd_surface.holder.unlockCanvasAndPost(lcdCanvas) 254 | } 255 | 256 | private fun displayPerf() { 257 | frames++ 258 | val now = System.currentTimeMillis() 259 | val elapse = now - lastFrameTime 260 | if (elapse > 1000L) { 261 | val fps = frames * 1000 / elapse 262 | val percentage = (cycles - lastCycles) * 100 / CYCLES_SECOND 263 | info_text.text = String.format(getString(R.string.perf_text), fps, cycles, percentage) 264 | lastCycles = cycles 265 | lastFrameTime = now 266 | frames = 0 267 | } 268 | } 269 | 270 | override fun doFrame(frameTimeNanos: Long) { 271 | displayPerf() 272 | updateLcd() 273 | Choreographer.getInstance().postFrameCallback(this) 274 | } 275 | 276 | companion object { 277 | private val TAG = MainFragment::class.java.simpleName 278 | private const val FRAME_RATE = 60 279 | private const val FRAME_INTERVAL = 1000 / FRAME_RATE 280 | private const val CYCLES_SECOND: Long = 5120000 281 | private const val ROM_FILE_NAME = "obj_lu.bin" 282 | private const val NOR_FILE_NAME = "nc1020.fls" 283 | private const val STATE_FILE_NAME = "nc1020.sts" 284 | private const val SAVE_STATES_KEY = "save_states" 285 | } 286 | } -------------------------------------------------------------------------------- /app/src/main/java/org/liberty/android/nc1020emu/NC1020JNI.kt: -------------------------------------------------------------------------------- 1 | package org.liberty.android.nc1020emu 2 | 3 | object NC1020JNI { 4 | @JvmStatic external fun initialize(romFilePath: String?, norFilePath: String?, stateFilePath: String?) 5 | @JvmStatic external fun reset() 6 | @JvmStatic external fun load() 7 | @JvmStatic external fun save() 8 | @JvmStatic external fun setKey(keyId: Int, downOrUp: Boolean) 9 | @JvmStatic external fun runTimeSlice(timeSlice: Int, speedUp: Boolean) 10 | @JvmStatic external fun copyLcdBufferEx(buffer: ByteArray?): Boolean 11 | @JvmStatic val cycles: Long external get 12 | 13 | init { 14 | System.loadLibrary("nc1020") 15 | } 16 | } -------------------------------------------------------------------------------- /app/src/main/java/org/liberty/android/nc1020emu/SettingsFragment.kt: -------------------------------------------------------------------------------- 1 | package org.liberty.android.nc1020emu 2 | 3 | import android.os.Bundle 4 | import androidx.preference.PreferenceFragmentCompat 5 | 6 | class SettingsFragment : PreferenceFragmentCompat() { 7 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 8 | setPreferencesFromResource(R.xml.settings, rootKey) 9 | } 10 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/f1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloworld1/Android-WQX-Emulator/975eec503ccd7e9779e0e852c6bd794815a12280/app/src/main/res/drawable-mdpi/f1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/f2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloworld1/Android-WQX-Emulator/975eec503ccd7e9779e0e852c6bd794815a12280/app/src/main/res/drawable-mdpi/f2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/f3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloworld1/Android-WQX-Emulator/975eec503ccd7e9779e0e852c6bd794815a12280/app/src/main/res/drawable-mdpi/f3.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/f4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloworld1/Android-WQX-Emulator/975eec503ccd7e9779e0e852c6bd794815a12280/app/src/main/res/drawable-mdpi/f4.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloworld1/Android-WQX-Emulator/975eec503ccd7e9779e0e852c6bd794815a12280/app/src/main/res/drawable-mdpi/ic_launcher.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/keypad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloworld1/Android-WQX-Emulator/975eec503ccd7e9779e0e852c6bd794815a12280/app/src/main/res/drawable-mdpi/keypad.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/onoff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloworld1/Android-WQX-Emulator/975eec503ccd7e9779e0e852c6bd794815a12280/app/src/main/res/drawable-mdpi/onoff.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/keypad_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/main_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/main_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | 18 | 24 | 25 | 26 | 27 | 28 | 32 | 37 | 38 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/menu/main_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | 12 | 16 | 19 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/navigation/nav_graph.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 9 | 12 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 文曲星模拟器 5 | 重启 6 | 加速 7 | 读档 8 | 存档 9 | 退出 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #3F51B5 5 | #303F9F 6 | #FF4081 7 | @android:color/white 8 | 9 | #60AAAAAA 10 | #A8CE97 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 240dp 7 | 60dp 8 | 40dp 9 | 12dp 10 | 8dp 11 | 48dp 12 | 32dp 13 | 32dp 14 | 8dp 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WQX Emulator 5 | Restart 6 | SpeedUp 7 | Load 8 | Save 9 | Quit 10 | FPS: %d, Cycles: %d, Speed: %d%% 11 | Factory reset 12 | Would you like to reset to factory state? 13 | Yes 14 | Cancel 15 | Settings 16 | Save states 17 | Save states automatically upon exiting 18 | Do not save states automatically upon exiting 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/xml/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.4.10' 3 | repositories { 4 | jcenter() 5 | google() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.1' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## For more details on how to configure your build environment visit 2 | # http://www.gradle.org/docs/current/userguide/build_environment.html 3 | # 4 | # Specifies the JVM arguments used for the daemon process. 5 | # The setting is particularly useful for tweaking memory settings. 6 | # Default value: -Xmx1024m -XX:MaxPermSize=256m 7 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 8 | # 9 | # When configured, Gradle will run in incubating parallel mode. 10 | # This option should only be used with decoupled projects. More details, visit 11 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 12 | # org.gradle.parallel=true 13 | #Fri Nov 13 21:53:22 PST 2020 14 | android.enableJetifier=true 15 | android.useAndroidX=true 16 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloworld1/Android-WQX-Emulator/975eec503ccd7e9779e0e852c6bd794815a12280/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Nov 13 21:50:40 PST 2020 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-6.5-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 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 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /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 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 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 Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------