├── .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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------