gemba 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) hide show
  1. checksums.yaml +4 -4
  2. data/THIRD_PARTY_NOTICES +37 -2
  3. data/assets/placeholder_boxart.png +0 -0
  4. data/bin/gemba +2 -2
  5. data/ext/gemba/extconf.rb +23 -1
  6. data/ext/gemba/gemba_ext.c +436 -2
  7. data/ext/gemba/gemba_ext.h +2 -0
  8. data/gemba.gemspec +5 -3
  9. data/lib/gemba/achievements/achievement.rb +23 -0
  10. data/lib/gemba/achievements/backend.rb +186 -0
  11. data/lib/gemba/achievements/cache.rb +70 -0
  12. data/lib/gemba/achievements/credentials_presenter.rb +142 -0
  13. data/lib/gemba/achievements/fake_backend.rb +205 -0
  14. data/lib/gemba/achievements/null_backend.rb +11 -0
  15. data/lib/gemba/achievements/offline_backend.rb +168 -0
  16. data/lib/gemba/achievements/retro_achievements/backend.rb +453 -0
  17. data/lib/gemba/achievements/retro_achievements/cli_sync_requester.rb +64 -0
  18. data/lib/gemba/achievements/retro_achievements/ping_worker.rb +27 -0
  19. data/lib/gemba/achievements.rb +19 -0
  20. data/lib/gemba/achievements_window.rb +556 -0
  21. data/lib/gemba/app_controller.rb +1015 -0
  22. data/lib/gemba/bios.rb +54 -0
  23. data/lib/gemba/boxart_fetcher/libretro_backend.rb +39 -0
  24. data/lib/gemba/boxart_fetcher/null_backend.rb +12 -0
  25. data/lib/gemba/boxart_fetcher.rb +79 -0
  26. data/lib/gemba/bus_emitter.rb +13 -0
  27. data/lib/gemba/child_window.rb +24 -1
  28. data/lib/gemba/cli/commands/config_cmd.rb +83 -0
  29. data/lib/gemba/cli/commands/decode.rb +154 -0
  30. data/lib/gemba/cli/commands/patch.rb +78 -0
  31. data/lib/gemba/cli/commands/play.rb +78 -0
  32. data/lib/gemba/cli/commands/record.rb +114 -0
  33. data/lib/gemba/cli/commands/replay.rb +161 -0
  34. data/lib/gemba/cli/commands/retro_achievements.rb +213 -0
  35. data/lib/gemba/cli/commands/version.rb +22 -0
  36. data/lib/gemba/cli.rb +52 -364
  37. data/lib/gemba/config.rb +134 -1
  38. data/lib/gemba/data/gb_games.json +1 -0
  39. data/lib/gemba/data/gb_md5.json +1 -0
  40. data/lib/gemba/data/gba_games.json +1 -0
  41. data/lib/gemba/data/gba_md5.json +1 -0
  42. data/lib/gemba/data/gbc_games.json +1 -0
  43. data/lib/gemba/data/gbc_md5.json +1 -0
  44. data/lib/gemba/emulator_frame.rb +1060 -0
  45. data/lib/gemba/event_bus.rb +48 -0
  46. data/lib/gemba/frame_stack.rb +60 -0
  47. data/lib/gemba/game_index.rb +84 -0
  48. data/lib/gemba/game_picker_frame.rb +268 -0
  49. data/lib/gemba/gamepad_map.rb +103 -0
  50. data/lib/gemba/headless.rb +6 -5
  51. data/lib/gemba/headless_player.rb +33 -3
  52. data/lib/gemba/help_window.rb +61 -0
  53. data/lib/gemba/hotkey_map.rb +3 -1
  54. data/lib/gemba/input_recorder.rb +107 -0
  55. data/lib/gemba/input_replayer.rb +119 -0
  56. data/lib/gemba/keyboard_map.rb +90 -0
  57. data/lib/gemba/locales/en.yml +97 -5
  58. data/lib/gemba/locales/ja.yml +97 -5
  59. data/lib/gemba/main_window.rb +56 -0
  60. data/lib/gemba/modal_stack.rb +81 -0
  61. data/lib/gemba/patcher_window.rb +223 -0
  62. data/lib/gemba/platform/gb.rb +21 -0
  63. data/lib/gemba/platform/gba.rb +21 -0
  64. data/lib/gemba/platform/gbc.rb +23 -0
  65. data/lib/gemba/platform.rb +20 -0
  66. data/lib/gemba/platform_open.rb +19 -0
  67. data/lib/gemba/recorder.rb +4 -3
  68. data/lib/gemba/replay_player.rb +691 -0
  69. data/lib/gemba/rom_info.rb +57 -0
  70. data/lib/gemba/rom_info_window.rb +16 -3
  71. data/lib/gemba/rom_library.rb +106 -0
  72. data/lib/gemba/rom_overrides.rb +47 -0
  73. data/lib/gemba/rom_patcher/bps.rb +161 -0
  74. data/lib/gemba/rom_patcher/ips.rb +101 -0
  75. data/lib/gemba/rom_patcher/ups.rb +118 -0
  76. data/lib/gemba/rom_patcher.rb +109 -0
  77. data/lib/gemba/{rom_loader.rb → rom_resolver.rb} +7 -6
  78. data/lib/gemba/runtime.rb +59 -26
  79. data/lib/gemba/save_state_manager.rb +4 -7
  80. data/lib/gemba/save_state_picker.rb +17 -4
  81. data/lib/gemba/session_logger.rb +64 -0
  82. data/lib/gemba/settings/audio_tab.rb +77 -0
  83. data/lib/gemba/settings/gamepad_tab.rb +351 -0
  84. data/lib/gemba/settings/hotkeys_tab.rb +259 -0
  85. data/lib/gemba/settings/paths.rb +11 -0
  86. data/lib/gemba/settings/recording_tab.rb +83 -0
  87. data/lib/gemba/settings/save_states_tab.rb +91 -0
  88. data/lib/gemba/settings/system_tab.rb +362 -0
  89. data/lib/gemba/settings/video_tab.rb +318 -0
  90. data/lib/gemba/settings_window.rb +162 -1036
  91. data/lib/gemba/version.rb +1 -1
  92. data/lib/gemba/virtual_keyboard.rb +19 -0
  93. data/lib/gemba.rb +2 -12
  94. data/test/achievements_window/test_bulk_sync.rb +218 -0
  95. data/test/achievements_window/test_bus_events.rb +125 -0
  96. data/test/achievements_window/test_close_confirmation.rb +201 -0
  97. data/test/achievements_window/test_initial_state.rb +164 -0
  98. data/test/achievements_window/test_sorting.rb +227 -0
  99. data/test/achievements_window/test_tree_rendering.rb +133 -0
  100. data/test/fixtures/fake_bios.bin +0 -0
  101. data/test/fixtures/pong.gba +0 -0
  102. data/test/fixtures/test.gb +0 -0
  103. data/test/fixtures/test.gbc +0 -0
  104. data/test/fixtures/test_quicksave.ss +0 -0
  105. data/test/screenshots/no_focus.png +0 -0
  106. data/test/shared/teek_test_worker.rb +17 -1
  107. data/test/shared/tk_test_helper.rb +91 -4
  108. data/test/support/achievements_window_helpers.rb +18 -0
  109. data/test/support/fake_core.rb +25 -0
  110. data/test/support/fake_ra_runtime.rb +74 -0
  111. data/test/support/fake_requester.rb +68 -0
  112. data/test/support/player_helpers.rb +20 -5
  113. data/test/test_achievement.rb +32 -0
  114. data/test/{test_player.rb → test_app_controller.rb} +353 -85
  115. data/test/test_bios.rb +123 -0
  116. data/test/test_boxart_fetcher.rb +150 -0
  117. data/test/test_cli.rb +17 -265
  118. data/test/test_cli_config.rb +64 -0
  119. data/test/test_cli_decode.rb +97 -0
  120. data/test/test_cli_patch.rb +58 -0
  121. data/test/test_cli_play.rb +213 -0
  122. data/test/test_cli_ra.rb +175 -0
  123. data/test/test_cli_record.rb +69 -0
  124. data/test/test_cli_replay.rb +72 -0
  125. data/test/test_cli_sync_requester.rb +152 -0
  126. data/test/test_cli_version.rb +27 -0
  127. data/test/test_config.rb +2 -3
  128. data/test/test_config_ra.rb +69 -0
  129. data/test/test_core.rb +62 -1
  130. data/test/test_credentials_presenter.rb +192 -0
  131. data/test/test_event_bus.rb +100 -0
  132. data/test/test_fake_backend_achievements.rb +130 -0
  133. data/test/test_fake_backend_auth.rb +68 -0
  134. data/test/test_game_index.rb +77 -0
  135. data/test/test_game_picker_frame.rb +310 -0
  136. data/test/test_gamepad_map.rb +1 -3
  137. data/test/test_headless_player.rb +17 -3
  138. data/test/test_help_window.rb +82 -0
  139. data/test/test_hotkey_map.rb +22 -1
  140. data/test/test_input_recorder.rb +179 -0
  141. data/test/test_input_replay_determinism.rb +113 -0
  142. data/test/test_input_replayer.rb +162 -0
  143. data/test/test_keyboard_map.rb +1 -3
  144. data/test/test_libretro_backend.rb +41 -0
  145. data/test/test_locale.rb +1 -1
  146. data/test/test_logging.rb +123 -0
  147. data/test/test_null_backend.rb +42 -0
  148. data/test/test_offline_backend.rb +116 -0
  149. data/test/test_overlay_renderer.rb +1 -1
  150. data/test/test_platform.rb +149 -0
  151. data/test/test_ra_backend.rb +313 -0
  152. data/test/test_ra_backend_unlock_gate.rb +56 -0
  153. data/test/test_recorder.rb +0 -3
  154. data/test/test_replay_player.rb +316 -0
  155. data/test/test_rom_info.rb +149 -0
  156. data/test/test_rom_overrides.rb +86 -0
  157. data/test/test_rom_patcher.rb +382 -0
  158. data/test/{test_rom_loader.rb → test_rom_resolver.rb} +25 -26
  159. data/test/test_save_state_manager.rb +2 -4
  160. data/test/test_settings_audio.rb +107 -0
  161. data/test/test_settings_hotkeys.rb +83 -66
  162. data/test/test_settings_recording.rb +49 -0
  163. data/test/test_settings_save_states.rb +97 -0
  164. data/test/test_settings_system.rb +133 -0
  165. data/test/test_settings_video.rb +450 -0
  166. data/test/test_settings_window.rb +76 -507
  167. data/test/test_tip_service.rb +6 -6
  168. data/test/test_toast_overlay.rb +1 -1
  169. data/test/test_virtual_events.rb +156 -0
  170. data/test/test_virtual_keyboard.rb +1 -1
  171. data/vendor/rcheevos/CHANGELOG.md +495 -0
  172. data/vendor/rcheevos/LICENSE +21 -0
  173. data/vendor/rcheevos/Package.swift +33 -0
  174. data/vendor/rcheevos/README.md +67 -0
  175. data/vendor/rcheevos/include/module.modulemap +70 -0
  176. data/vendor/rcheevos/include/rc_api_editor.h +296 -0
  177. data/vendor/rcheevos/include/rc_api_info.h +280 -0
  178. data/vendor/rcheevos/include/rc_api_request.h +77 -0
  179. data/vendor/rcheevos/include/rc_api_runtime.h +417 -0
  180. data/vendor/rcheevos/include/rc_api_user.h +262 -0
  181. data/vendor/rcheevos/include/rc_client.h +877 -0
  182. data/vendor/rcheevos/include/rc_client_raintegration.h +101 -0
  183. data/vendor/rcheevos/include/rc_consoles.h +138 -0
  184. data/vendor/rcheevos/include/rc_error.h +59 -0
  185. data/vendor/rcheevos/include/rc_export.h +100 -0
  186. data/vendor/rcheevos/include/rc_hash.h +200 -0
  187. data/vendor/rcheevos/include/rc_runtime.h +148 -0
  188. data/vendor/rcheevos/include/rc_runtime_types.h +452 -0
  189. data/vendor/rcheevos/include/rc_util.h +51 -0
  190. data/vendor/rcheevos/include/rcheevos.h +8 -0
  191. data/vendor/rcheevos/src/rapi/rc_api_common.c +1379 -0
  192. data/vendor/rcheevos/src/rapi/rc_api_common.h +88 -0
  193. data/vendor/rcheevos/src/rapi/rc_api_editor.c +625 -0
  194. data/vendor/rcheevos/src/rapi/rc_api_info.c +587 -0
  195. data/vendor/rcheevos/src/rapi/rc_api_runtime.c +901 -0
  196. data/vendor/rcheevos/src/rapi/rc_api_user.c +483 -0
  197. data/vendor/rcheevos/src/rc_client.c +6941 -0
  198. data/vendor/rcheevos/src/rc_client_external.c +281 -0
  199. data/vendor/rcheevos/src/rc_client_external.h +177 -0
  200. data/vendor/rcheevos/src/rc_client_external_versions.h +171 -0
  201. data/vendor/rcheevos/src/rc_client_internal.h +409 -0
  202. data/vendor/rcheevos/src/rc_client_raintegration.c +566 -0
  203. data/vendor/rcheevos/src/rc_client_raintegration_internal.h +61 -0
  204. data/vendor/rcheevos/src/rc_client_types.natvis +396 -0
  205. data/vendor/rcheevos/src/rc_compat.c +251 -0
  206. data/vendor/rcheevos/src/rc_compat.h +121 -0
  207. data/vendor/rcheevos/src/rc_libretro.c +915 -0
  208. data/vendor/rcheevos/src/rc_libretro.h +98 -0
  209. data/vendor/rcheevos/src/rc_util.c +199 -0
  210. data/vendor/rcheevos/src/rc_version.c +11 -0
  211. data/vendor/rcheevos/src/rc_version.h +32 -0
  212. data/vendor/rcheevos/src/rcheevos/alloc.c +312 -0
  213. data/vendor/rcheevos/src/rcheevos/condition.c +754 -0
  214. data/vendor/rcheevos/src/rcheevos/condset.c +777 -0
  215. data/vendor/rcheevos/src/rcheevos/consoleinfo.c +1215 -0
  216. data/vendor/rcheevos/src/rcheevos/format.c +330 -0
  217. data/vendor/rcheevos/src/rcheevos/lboard.c +287 -0
  218. data/vendor/rcheevos/src/rcheevos/memref.c +805 -0
  219. data/vendor/rcheevos/src/rcheevos/operand.c +607 -0
  220. data/vendor/rcheevos/src/rcheevos/rc_internal.h +390 -0
  221. data/vendor/rcheevos/src/rcheevos/rc_runtime_types.natvis +541 -0
  222. data/vendor/rcheevos/src/rcheevos/rc_validate.c +1406 -0
  223. data/vendor/rcheevos/src/rcheevos/rc_validate.h +18 -0
  224. data/vendor/rcheevos/src/rcheevos/richpresence.c +922 -0
  225. data/vendor/rcheevos/src/rcheevos/runtime.c +852 -0
  226. data/vendor/rcheevos/src/rcheevos/runtime_progress.c +1073 -0
  227. data/vendor/rcheevos/src/rcheevos/trigger.c +344 -0
  228. data/vendor/rcheevos/src/rcheevos/value.c +935 -0
  229. data/vendor/rcheevos/src/rhash/aes.c +480 -0
  230. data/vendor/rcheevos/src/rhash/aes.h +49 -0
  231. data/vendor/rcheevos/src/rhash/cdreader.c +838 -0
  232. data/vendor/rcheevos/src/rhash/hash.c +1402 -0
  233. data/vendor/rcheevos/src/rhash/hash_disc.c +1340 -0
  234. data/vendor/rcheevos/src/rhash/hash_encrypted.c +566 -0
  235. data/vendor/rcheevos/src/rhash/hash_rom.c +426 -0
  236. data/vendor/rcheevos/src/rhash/hash_zip.c +460 -0
  237. data/vendor/rcheevos/src/rhash/md5.c +382 -0
  238. data/vendor/rcheevos/src/rhash/md5.h +91 -0
  239. data/vendor/rcheevos/src/rhash/rc_hash_internal.h +116 -0
  240. data/vendor/rcheevos/test/libretro.h +205 -0
  241. data/vendor/rcheevos/test/rapi/test_rc_api_common.c +941 -0
  242. data/vendor/rcheevos/test/rapi/test_rc_api_editor.c +931 -0
  243. data/vendor/rcheevos/test/rapi/test_rc_api_info.c +545 -0
  244. data/vendor/rcheevos/test/rapi/test_rc_api_runtime.c +2213 -0
  245. data/vendor/rcheevos/test/rapi/test_rc_api_user.c +998 -0
  246. data/vendor/rcheevos/test/rcheevos/mock_memory.h +32 -0
  247. data/vendor/rcheevos/test/rcheevos/test_condition.c +570 -0
  248. data/vendor/rcheevos/test/rcheevos/test_condset.c +5170 -0
  249. data/vendor/rcheevos/test/rcheevos/test_consoleinfo.c +203 -0
  250. data/vendor/rcheevos/test/rcheevos/test_format.c +112 -0
  251. data/vendor/rcheevos/test/rcheevos/test_lboard.c +746 -0
  252. data/vendor/rcheevos/test/rcheevos/test_memref.c +520 -0
  253. data/vendor/rcheevos/test/rcheevos/test_operand.c +692 -0
  254. data/vendor/rcheevos/test/rcheevos/test_rc_validate.c +502 -0
  255. data/vendor/rcheevos/test/rcheevos/test_richpresence.c +1564 -0
  256. data/vendor/rcheevos/test/rcheevos/test_runtime.c +1667 -0
  257. data/vendor/rcheevos/test/rcheevos/test_runtime_progress.c +1821 -0
  258. data/vendor/rcheevos/test/rcheevos/test_timing.c +166 -0
  259. data/vendor/rcheevos/test/rcheevos/test_trigger.c +2521 -0
  260. data/vendor/rcheevos/test/rcheevos/test_value.c +870 -0
  261. data/vendor/rcheevos/test/rcheevos-test.sln +46 -0
  262. data/vendor/rcheevos/test/rcheevos-test.vcxproj +239 -0
  263. data/vendor/rcheevos/test/rcheevos-test.vcxproj.filters +335 -0
  264. data/vendor/rcheevos/test/rhash/data.c +657 -0
  265. data/vendor/rcheevos/test/rhash/data.h +32 -0
  266. data/vendor/rcheevos/test/rhash/mock_filereader.c +236 -0
  267. data/vendor/rcheevos/test/rhash/mock_filereader.h +31 -0
  268. data/vendor/rcheevos/test/rhash/test_cdreader.c +920 -0
  269. data/vendor/rcheevos/test/rhash/test_hash.c +310 -0
  270. data/vendor/rcheevos/test/rhash/test_hash_disc.c +1450 -0
  271. data/vendor/rcheevos/test/rhash/test_hash_rom.c +899 -0
  272. data/vendor/rcheevos/test/rhash/test_hash_zip.c +551 -0
  273. data/vendor/rcheevos/test/test.c +113 -0
  274. data/vendor/rcheevos/test/test_framework.h +205 -0
  275. data/vendor/rcheevos/test/test_rc_client.c +10509 -0
  276. data/vendor/rcheevos/test/test_rc_client_external.c +2197 -0
  277. data/vendor/rcheevos/test/test_rc_client_raintegration.c +441 -0
  278. data/vendor/rcheevos/test/test_rc_libretro.c +952 -0
  279. data/vendor/rcheevos/test/test_types.natvis +9 -0
  280. data/vendor/rcheevos/validator/validator.c +658 -0
  281. data/vendor/rcheevos/validator/validator.vcxproj +152 -0
  282. data/vendor/rcheevos/validator/validator.vcxproj.filters +82 -0
  283. metadata +274 -11
  284. data/lib/gemba/input_mappings.rb +0 -214
  285. data/lib/gemba/player.rb +0 -1525
@@ -0,0 +1,1406 @@
1
+ #include "rc_validate.h"
2
+
3
+ #include "rc_consoles.h"
4
+ #include "rc_internal.h"
5
+
6
+ #include "../rc_compat.h"
7
+
8
+ #include <stddef.h>
9
+ #include <stdlib.h>
10
+
11
+ enum
12
+ {
13
+ RC_VALIDATION_ERR_NONE,
14
+
15
+ /* sorted by severity - most severe first */
16
+
17
+ /* errors that prevent the achievement from functioning */
18
+ RC_VALIDATION_ERR_ADDRESS_OUT_OF_RANGE,
19
+ RC_VALIDATION_ERR_RECALL_WITHOUT_REMEMBER,
20
+ RC_VALIDATION_ERR_RECALL_BEFORE_REMEMBER,
21
+ RC_VALIDATION_ERR_COMPARISON_NEVER_TRUE_WITH_MAX,
22
+ RC_VALIDATION_ERR_COMPARISON_NEVER_TRUE_INTEGER_TO_FLOAT,
23
+ RC_VALIDATION_ERR_COMPARISON_NEVER_TRUE,
24
+ RC_VALIDATION_ERR_CONFLICTING_CONDITION,
25
+
26
+ /* warnings about logic that does nothing */
27
+ RC_VALIDATION_ERR_COMPARISON_ALWAYS_TRUE_INTEGER_TO_FLOAT,
28
+ RC_VALIDATION_ERR_COMPARISON_ALWAYS_TRUE_WITH_MAX,
29
+ RC_VALIDATION_ERR_TRAILING_CHAINING_CONDITION,
30
+ RC_VALIDATION_ERR_MEASUREDIF_WITHOUT_MEASURED,
31
+ RC_VALIDATION_ERR_ADDHITS_WITHOUT_TARGET,
32
+
33
+ /* warnings about pointer math */
34
+ RC_VALIDATION_ERR_POINTER_FROM_PREVIOUS_FRAME,
35
+ RC_VALIDATION_ERR_POINTER_NON_INTEGER_OFFSET,
36
+ RC_VALIDATION_ERR_POINTER_TRANSFORMED_OFFSET,
37
+
38
+ /* warnings about potential logic errors */
39
+ RC_VALIDATION_ERR_COMPARING_DIFFERENT_MEMORY_SIZES,
40
+ RC_VALIDATION_ERR_MASK_RESULT_ALWAYS_ZERO,
41
+
42
+ /* warnings that some areas of memory should be avoided */
43
+ RC_VALIDATION_ERR_KERNAL_RAM_REQUIRES_BIOS,
44
+ RC_VALIDATION_ERR_VIRTUAL_RAM_MAY_NOT_BE_EXPOSED,
45
+
46
+ /* warnings about redundant logic */
47
+ RC_VALIDATION_ERR_REDUNDANT_CONDITION,
48
+ RC_VALIDATION_ERR_NO_HITS_TO_RESET,
49
+ RC_VALIDATION_ERR_RESET_HIT_TARGET_OF_ONE,
50
+ RC_VALIDATION_ERR_MASK_TOO_LARGE,
51
+
52
+ RC_VALIDATION_ERR_COUNT
53
+ };
54
+
55
+ enum
56
+ {
57
+ RC_VALIDATION_VIRTUAL_RAM_OTHER,
58
+ RC_VALIDATION_VIRTUAL_RAM_MIRROR,
59
+ RC_VALIDATION_VIRTUAL_RAM_ECHO
60
+ };
61
+
62
+ typedef struct rc_validation_error_t
63
+ {
64
+ uint32_t err;
65
+ uint16_t group_index;
66
+ uint16_t cond_index;
67
+ uint32_t data1;
68
+ uint32_t data2;
69
+ } rc_validation_error_t;
70
+
71
+ typedef struct rc_validation_state_t
72
+ {
73
+ rc_validation_error_t errors[64];
74
+ uint32_t error_count;
75
+ uint16_t group_index;
76
+ uint16_t cond_index;
77
+ uint32_t console_id;
78
+ uint32_t max_address;
79
+ uint8_t has_alt_groups;
80
+ uint8_t has_hit_targets;
81
+ } rc_validation_state_t;
82
+
83
+ /* this returns a negative value if err1 is more severe than err2, or
84
+ * a positive value is err2 is more severe than err1. */
85
+ static int rc_validation_compare_severity(const rc_validation_error_t* err1, const rc_validation_error_t* err2)
86
+ {
87
+ /* lower err value is more severe */
88
+ int diff = (err1->err - err2->err);
89
+ if (diff != 0)
90
+ return diff;
91
+
92
+ /* lower group index is more severe */
93
+ diff = (err1->group_index - err2->group_index);
94
+ if (diff != 0)
95
+ return diff;
96
+
97
+ /* lower condition value is more severe */
98
+ return (err1->cond_index - err2->cond_index);
99
+ }
100
+
101
+ static const rc_validation_error_t* rc_validate_find_most_severe_error(const rc_validation_state_t* state)
102
+ {
103
+ const rc_validation_error_t* error = &state->errors[0];
104
+ const rc_validation_error_t* most_severe_error = error;
105
+ const rc_validation_error_t* stop = &state->errors[state->error_count];
106
+
107
+ while (++error < stop) {
108
+ if (rc_validation_compare_severity(error, most_severe_error) < 0)
109
+ most_severe_error = error;
110
+ }
111
+
112
+ return most_severe_error;
113
+ }
114
+
115
+ static rc_validation_error_t* rc_validate_find_least_severe_error(rc_validation_state_t* state)
116
+ {
117
+ rc_validation_error_t* error = &state->errors[0];
118
+ rc_validation_error_t* least_severe_error = error;
119
+ rc_validation_error_t* stop = &state->errors[state->error_count];
120
+
121
+ while (++error < stop) {
122
+ if (rc_validation_compare_severity(error, least_severe_error) > 0)
123
+ least_severe_error = error;
124
+ }
125
+
126
+ return least_severe_error;
127
+ }
128
+
129
+ static size_t rc_validate_format_cond_index(char buffer[], size_t buffer_size, const rc_validation_state_t* state, uint32_t group_index, uint32_t cond_index)
130
+ {
131
+ int written = 0;
132
+
133
+ if (cond_index == 0)
134
+ return 0;
135
+
136
+ if (state->has_alt_groups) {
137
+ if (group_index == 0)
138
+ written = snprintf(buffer, buffer_size, "Core ");
139
+ else
140
+ written = snprintf(buffer, buffer_size, "Alt%u ", group_index);
141
+
142
+ buffer += written;
143
+ buffer_size -= written;
144
+ }
145
+
146
+ written += snprintf(buffer, buffer_size, "Condition %u", cond_index);
147
+ return written;
148
+ }
149
+
150
+ static const char* rc_validate_get_condition_type_string(uint32_t type)
151
+ {
152
+ switch (type) {
153
+ case RC_CONDITION_ADD_ADDRESS: return "AddAddress";
154
+ case RC_CONDITION_ADD_HITS: return "AddHits";
155
+ case RC_CONDITION_ADD_SOURCE: return "AddSource";
156
+ case RC_CONDITION_AND_NEXT: return "AndNext";
157
+ case RC_CONDITION_MEASURED: return "Measured";
158
+ case RC_CONDITION_MEASURED_IF: return "MeasuredIf";
159
+ case RC_CONDITION_OR_NEXT: return "OrNext";
160
+ case RC_CONDITION_PAUSE_IF: return "PauseIf";
161
+ case RC_CONDITION_REMEMBER: return "Remember";
162
+ case RC_CONDITION_RESET_IF: return "ResetIf";
163
+ case RC_CONDITION_RESET_NEXT_IF: return "ResetNextIf";
164
+ case RC_CONDITION_SUB_HITS: return "SubHits";
165
+ case RC_CONDITION_SUB_SOURCE: return "SubSource";
166
+ case RC_CONDITION_TRIGGER: return "Trigger";
167
+ default: return "???";
168
+ }
169
+ }
170
+
171
+ static void rc_validate_format_error_compare_int_to_float(char buffer[], size_t buffer_size, uint32_t encoded_data, const char* limiter)
172
+ {
173
+ int written;
174
+ rc_typed_value_t value;
175
+ value.value.u32 = encoded_data;
176
+
177
+ written = snprintf(buffer, buffer_size, "Comparison is %s true (integer can never be %.06f", limiter, value.value.f32);
178
+ while (buffer[written - 1] == '0')
179
+ written--;
180
+ if (buffer[written] == '.')
181
+ written++;
182
+ buffer[written] = ')';
183
+ buffer[written + 1] = '\0';
184
+ }
185
+
186
+ static int rc_validate_format_error(char buffer[], size_t buffer_size, const rc_validation_state_t* state, const rc_validation_error_t* error)
187
+ {
188
+ size_t written = rc_validate_format_cond_index(buffer, buffer_size, state, error->group_index, error->cond_index);
189
+ buffer += written;
190
+ buffer_size -= written;
191
+
192
+ if (buffer_size < 2)
193
+ return 0;
194
+
195
+ buffer_size -= 2;
196
+ *buffer++ = ':';
197
+ *buffer++ = ' ';
198
+
199
+ switch (error->err) {
200
+ case RC_VALIDATION_ERR_ADDHITS_WITHOUT_TARGET:
201
+ snprintf(buffer, buffer_size, "Final condition in AddHits chain must have a hit target");
202
+ break;
203
+
204
+ case RC_VALIDATION_ERR_ADDRESS_OUT_OF_RANGE:
205
+ snprintf(buffer, buffer_size, "Address %04X out of range (max %04X)", error->data1, error->data2);
206
+ break;
207
+
208
+ case RC_VALIDATION_ERR_COMPARING_DIFFERENT_MEMORY_SIZES:
209
+ snprintf(buffer, buffer_size, "Comparing different memory sizes");
210
+ break;
211
+
212
+ case RC_VALIDATION_ERR_COMPARISON_ALWAYS_TRUE_INTEGER_TO_FLOAT:
213
+ rc_validate_format_error_compare_int_to_float(buffer, buffer_size, error->data1, "always");
214
+ break;
215
+
216
+ case RC_VALIDATION_ERR_COMPARISON_ALWAYS_TRUE_WITH_MAX:
217
+ snprintf(buffer, buffer_size, "Comparison is always true (max %u)", error->data1);
218
+ break;
219
+
220
+ case RC_VALIDATION_ERR_COMPARISON_NEVER_TRUE:
221
+ snprintf(buffer, buffer_size, "Comparison is never true");
222
+ break;
223
+
224
+ case RC_VALIDATION_ERR_COMPARISON_NEVER_TRUE_INTEGER_TO_FLOAT:
225
+ rc_validate_format_error_compare_int_to_float(buffer, buffer_size, error->data1, "never");
226
+ break;
227
+
228
+ case RC_VALIDATION_ERR_COMPARISON_NEVER_TRUE_WITH_MAX:
229
+ snprintf(buffer, buffer_size, "Comparison is never true (max %u)", error->data1);
230
+ break;
231
+
232
+ case RC_VALIDATION_ERR_CONFLICTING_CONDITION:
233
+ written = snprintf(buffer, buffer_size, "Conflicts with ");
234
+ buffer += written;
235
+ buffer_size -= written;
236
+ rc_validate_format_cond_index(buffer, buffer_size, state, error->data1, error->data2);
237
+ break;
238
+
239
+ case RC_VALIDATION_ERR_KERNAL_RAM_REQUIRES_BIOS:
240
+ snprintf(buffer, buffer_size, "Kernel RAM may not be initialized without real BIOS (address %04X)", error->data1);
241
+ break;
242
+
243
+ case RC_VALIDATION_ERR_MASK_RESULT_ALWAYS_ZERO:
244
+ snprintf(buffer, buffer_size, "Result of mask is always 0");
245
+ break;
246
+
247
+ case RC_VALIDATION_ERR_MASK_TOO_LARGE:
248
+ snprintf(buffer, buffer_size, "Mask has more bits than source");
249
+ break;
250
+
251
+ case RC_VALIDATION_ERR_MEASUREDIF_WITHOUT_MEASURED:
252
+ snprintf(buffer, buffer_size, "MeasuredIf without Measured");
253
+ break;
254
+
255
+ case RC_VALIDATION_ERR_NO_HITS_TO_RESET:
256
+ snprintf(buffer, buffer_size, "No captured hits to reset");
257
+ break;
258
+
259
+ case RC_VALIDATION_ERR_POINTER_FROM_PREVIOUS_FRAME:
260
+ snprintf(buffer, buffer_size, "Using pointer from previous frame");
261
+ break;
262
+
263
+ case RC_VALIDATION_ERR_POINTER_NON_INTEGER_OFFSET:
264
+ snprintf(buffer, buffer_size, "Using non-integer value in AddAddress calculation");
265
+ break;
266
+
267
+ case RC_VALIDATION_ERR_POINTER_TRANSFORMED_OFFSET:
268
+ snprintf(buffer, buffer_size, "Using transformed value in AddAddress calculation");
269
+ break;
270
+
271
+ case RC_VALIDATION_ERR_RECALL_BEFORE_REMEMBER:
272
+ if (error->data1 == RC_CONDITION_PAUSE_IF)
273
+ snprintf(buffer, buffer_size, "PauseIf cannot use Remembered value not associated to PauseIf chain");
274
+ else
275
+ snprintf(buffer, buffer_size, "Recall used before Remember");
276
+ break;
277
+
278
+ case RC_VALIDATION_ERR_RECALL_WITHOUT_REMEMBER:
279
+ snprintf(buffer, buffer_size, "Recall used without Remember");
280
+ break;
281
+
282
+ case RC_VALIDATION_ERR_RESET_HIT_TARGET_OF_ONE:
283
+ snprintf(buffer, buffer_size, "Hit target of 1 is redundant on ResetIf");
284
+ break;
285
+
286
+ case RC_VALIDATION_ERR_REDUNDANT_CONDITION:
287
+ written = snprintf(buffer, buffer_size, "Redundant with ");
288
+ buffer += written;
289
+ buffer_size -= written;
290
+ rc_validate_format_cond_index(buffer, buffer_size, state, error->data1, error->data2);
291
+ break;
292
+
293
+ case RC_VALIDATION_ERR_TRAILING_CHAINING_CONDITION:
294
+ snprintf(buffer, buffer_size, "%s condition type expects another condition to follow", rc_validate_get_condition_type_string(error->data1));
295
+ break;
296
+
297
+ case RC_VALIDATION_ERR_VIRTUAL_RAM_MAY_NOT_BE_EXPOSED:
298
+ snprintf(buffer, buffer_size, "%s RAM may not be exposed by emulator (address %04X)",
299
+ error->data2 == RC_VALIDATION_VIRTUAL_RAM_MIRROR ? "Mirror" :
300
+ error->data2 == RC_VALIDATION_VIRTUAL_RAM_ECHO ? "Echo" : "Virtual",
301
+ error->data1);
302
+ break;
303
+ }
304
+
305
+ return 0;
306
+ }
307
+
308
+ static void rc_validate_add_error(rc_validation_state_t* state, uint32_t error_code, uint32_t data1, uint32_t data2)
309
+ {
310
+ rc_validation_error_t* error;
311
+ if (state->error_count == sizeof(state->errors) / sizeof(state->errors[0]))
312
+ error = rc_validate_find_least_severe_error(state);
313
+ else
314
+ error = &state->errors[state->error_count++];
315
+
316
+ error->err = error_code;
317
+ error->group_index = state->group_index;
318
+ error->cond_index = state->cond_index;
319
+ error->data1 = data1;
320
+ error->data2 = data2;
321
+ }
322
+
323
+ /* rc_condition_is_combining doesn't look at conditions that build a memref (like AddSource) */
324
+ static int rc_validate_is_combining_condition(const rc_condition_t* condition)
325
+ {
326
+ switch (condition->type)
327
+ {
328
+ case RC_CONDITION_ADD_ADDRESS:
329
+ case RC_CONDITION_ADD_HITS:
330
+ case RC_CONDITION_ADD_SOURCE:
331
+ case RC_CONDITION_AND_NEXT:
332
+ case RC_CONDITION_OR_NEXT:
333
+ case RC_CONDITION_RESET_NEXT_IF:
334
+ case RC_CONDITION_SUB_HITS:
335
+ case RC_CONDITION_SUB_SOURCE:
336
+ case RC_CONDITION_REMEMBER:
337
+ return 1;
338
+
339
+ default:
340
+ return 0;
341
+ }
342
+ }
343
+
344
+ static const rc_condition_t* rc_validate_get_next_non_combining_condition(const rc_condition_t* cond)
345
+ {
346
+ while (cond && rc_validate_is_combining_condition(cond))
347
+ cond = cond->next;
348
+
349
+ return cond;
350
+ }
351
+
352
+ static int rc_validate_has_condition(const rc_condition_t* cond, uint8_t type)
353
+ {
354
+ for (; cond; cond = cond->next) {
355
+ if (cond->type == type)
356
+ return 1;
357
+ }
358
+
359
+ return 0;
360
+ }
361
+
362
+ static int rc_validate_is_invalid_recall(const rc_operand_t* operand)
363
+ {
364
+ /* if operand is {recall}, but memref is null, that means the Remember wasn't found */
365
+ return rc_operand_is_recall(operand) &&
366
+ rc_operand_type_is_memref(operand->memref_access_type) &&
367
+ !operand->value.memref;
368
+ }
369
+
370
+ static void rc_validate_memref(const rc_memref_t* memref, rc_validation_state_t* state)
371
+ {
372
+ if (memref->address > state->max_address) {
373
+ rc_validate_add_error(state, RC_VALIDATION_ERR_ADDRESS_OUT_OF_RANGE, memref->address, state->max_address);
374
+ return;
375
+ }
376
+
377
+ switch (state->console_id) {
378
+ case RC_CONSOLE_NINTENDO:
379
+ case RC_CONSOLE_FAMICOM_DISK_SYSTEM:
380
+ if (memref->address >= 0x0800 && memref->address <= 0x1FFF)
381
+ rc_validate_add_error(state, RC_VALIDATION_ERR_VIRTUAL_RAM_MAY_NOT_BE_EXPOSED, memref->address, RC_VALIDATION_VIRTUAL_RAM_MIRROR);
382
+ break;
383
+
384
+ case RC_CONSOLE_GAMEBOY:
385
+ case RC_CONSOLE_GAMEBOY_COLOR:
386
+ if (memref->address >= 0xE000 && memref->address <= 0xFDFF)
387
+ rc_validate_add_error(state, RC_VALIDATION_ERR_VIRTUAL_RAM_MAY_NOT_BE_EXPOSED, memref->address, RC_VALIDATION_VIRTUAL_RAM_ECHO);
388
+ break;
389
+
390
+ case RC_CONSOLE_PLAYSTATION:
391
+ if (memref->address <= 0xFFFF)
392
+ rc_validate_add_error(state, RC_VALIDATION_ERR_KERNAL_RAM_REQUIRES_BIOS, memref->address, 0);
393
+ break;
394
+ }
395
+ }
396
+
397
+ static uint32_t rc_console_max_address(uint32_t console_id)
398
+ {
399
+ const rc_memory_regions_t* memory_regions;
400
+ memory_regions = rc_console_memory_regions(console_id);
401
+ if (memory_regions && memory_regions->num_regions > 0)
402
+ return memory_regions->region[memory_regions->num_regions - 1].end_address;
403
+
404
+ return 0xFFFFFFFF;
405
+ }
406
+
407
+ int rc_validate_memrefs_for_console(const rc_memrefs_t* memrefs, char result[], const size_t result_size, uint32_t console_id)
408
+ {
409
+ const rc_memref_list_t* memref_list = &memrefs->memrefs;
410
+
411
+ rc_validation_state_t state;
412
+ memset(&state, 0, sizeof(state));
413
+ state.console_id = console_id;
414
+ state.max_address = rc_console_max_address(console_id);
415
+
416
+ result[0] = '\0';
417
+ do
418
+ {
419
+ const rc_memref_t* memref = memref_list->items;
420
+ const rc_memref_t* memref_stop = memref + memref_list->count;
421
+ for (; memref < memref_stop; ++memref)
422
+ {
423
+ rc_validate_memref(memref, &state);
424
+ if (state.error_count) {
425
+ rc_validate_format_error(result, result_size, &state, &state.errors[0]);
426
+ return 0;
427
+ }
428
+ }
429
+
430
+ memref_list = memref_list->next;
431
+ } while (memref_list);
432
+
433
+ return 1;
434
+ }
435
+
436
+ static uint32_t rc_max_value(const rc_operand_t* operand)
437
+ {
438
+ if (operand->type == RC_OPERAND_CONST)
439
+ return operand->value.num;
440
+
441
+ if (!rc_operand_is_memref(operand))
442
+ return 0xFFFFFFFF;
443
+
444
+ switch (operand->size) {
445
+ case RC_MEMSIZE_BIT_0:
446
+ case RC_MEMSIZE_BIT_1:
447
+ case RC_MEMSIZE_BIT_2:
448
+ case RC_MEMSIZE_BIT_3:
449
+ case RC_MEMSIZE_BIT_4:
450
+ case RC_MEMSIZE_BIT_5:
451
+ case RC_MEMSIZE_BIT_6:
452
+ case RC_MEMSIZE_BIT_7:
453
+ return 1;
454
+
455
+ case RC_MEMSIZE_LOW:
456
+ case RC_MEMSIZE_HIGH:
457
+ return 0xF;
458
+
459
+ case RC_MEMSIZE_BITCOUNT:
460
+ return 8;
461
+
462
+ case RC_MEMSIZE_8_BITS:
463
+ /* NOTE: BCD should max out at 0x99, but because each digit can be 15, it actually maxes at 15*10 + 15 */
464
+ return (operand->type == RC_OPERAND_BCD) ? 165 : 0xFF;
465
+
466
+ case RC_MEMSIZE_16_BITS:
467
+ case RC_MEMSIZE_16_BITS_BE:
468
+ return (operand->type == RC_OPERAND_BCD) ? 16665 : 0xFFFF;
469
+
470
+ case RC_MEMSIZE_24_BITS:
471
+ case RC_MEMSIZE_24_BITS_BE:
472
+ return (operand->type == RC_OPERAND_BCD) ? 1666665 : 0xFFFFFF;
473
+
474
+ default:
475
+ return (operand->type == RC_OPERAND_BCD) ? 166666665 : 0xFFFFFFFF;
476
+ }
477
+ }
478
+
479
+ static void rc_combine_ranges(uint32_t* min_val, uint32_t* max_val, uint8_t oper, uint32_t oper_min_val, uint32_t oper_max_val)
480
+ {
481
+ switch (oper) {
482
+ case RC_OPERATOR_MULT:
483
+ {
484
+ unsigned long long scaled = ((unsigned long long)*min_val) * oper_min_val;
485
+ *min_val = (scaled > 0xFFFFFFFF) ? 0xFFFFFFFF : (uint32_t)scaled;
486
+
487
+ scaled = ((unsigned long long)*max_val) * oper_max_val;
488
+ *max_val = (scaled > 0xFFFFFFFF) ? 0xFFFFFFFF : (uint32_t)scaled;
489
+ break;
490
+ }
491
+
492
+ case RC_OPERATOR_DIV:
493
+ *min_val = (oper_max_val == 0) ? *min_val : (*min_val / oper_max_val);
494
+ *max_val = (oper_min_val == 0) ? *max_val : (*max_val / oper_min_val);
495
+ break;
496
+
497
+ case RC_OPERATOR_AND:
498
+ *min_val = 0;
499
+ *max_val &= oper_max_val;
500
+ break;
501
+
502
+ case RC_OPERATOR_XOR:
503
+ *min_val = 0;
504
+ *max_val |= oper_max_val;
505
+ break;
506
+
507
+ case RC_OPERATOR_MOD:
508
+ *min_val = 0;
509
+ *max_val = (*max_val >= oper_max_val) ? oper_max_val - 1 : *max_val;
510
+ break;
511
+
512
+ case RC_OPERATOR_ADD:
513
+ case RC_OPERATOR_ADD_ACCUMULATOR:
514
+ if (*min_val > *max_val) { /* underflow occurred */
515
+ *max_val += oper_max_val;
516
+ }
517
+ else {
518
+ unsigned long long scaled = ((unsigned long long)*max_val) + oper_max_val;
519
+ *max_val = (scaled > 0xFFFFFFFF) ? 0xFFFFFFFF : (uint32_t)scaled;
520
+ }
521
+
522
+ *min_val += oper_min_val;
523
+ break;
524
+
525
+ case RC_OPERATOR_SUB:
526
+ case RC_OPERATOR_SUB_ACCUMULATOR:
527
+ *min_val -= oper_max_val;
528
+ *max_val -= oper_min_val;
529
+ break;
530
+
531
+ case RC_OPERATOR_SUB_PARENT:
532
+ {
533
+ uint32_t temp = oper_min_val - *max_val;
534
+ *max_val = oper_max_val - *min_val;
535
+ *min_val = temp;
536
+ break;
537
+ }
538
+
539
+ default:
540
+ break;
541
+ }
542
+ }
543
+
544
+ static void rc_chain_get_value_range(const rc_operand_t* operand, uint32_t* min_val, uint32_t* max_val)
545
+ {
546
+ if (rc_operand_is_memref(operand) && operand->value.memref->value.memref_type == RC_MEMREF_TYPE_MODIFIED_MEMREF) {
547
+ const rc_modified_memref_t* modified_memref = (const rc_modified_memref_t*)operand->value.memref;
548
+ if (modified_memref->modifier_type != RC_OPERATOR_INDIRECT_READ) {
549
+ if (modified_memref->modifier_type == RC_OPERATOR_DIV &&
550
+ rc_operand_is_memref(&modified_memref->modifier) &&
551
+ rc_operands_are_equal(&modified_memref->modifier, &modified_memref->parent)) {
552
+ /* division by self can only return 0 or 1. */
553
+ *min_val = 0;
554
+ *max_val = 1;
555
+ }
556
+ else {
557
+ uint32_t modifier_min_val, modifier_max_val;
558
+ rc_chain_get_value_range(&modified_memref->parent, min_val, max_val);
559
+ rc_chain_get_value_range(&modified_memref->modifier, &modifier_min_val, &modifier_max_val);
560
+ rc_combine_ranges(min_val, max_val, modified_memref->modifier_type, modifier_min_val, modifier_max_val);
561
+ }
562
+ return;
563
+ }
564
+ }
565
+
566
+ *min_val = (operand->type == RC_OPERAND_CONST) ? operand->value.num : 0;
567
+ *max_val = rc_max_value(operand);
568
+ }
569
+
570
+ static int rc_validate_get_condition_index(const rc_condset_t* condset, const rc_condition_t* condition)
571
+ {
572
+ int index = 1;
573
+ const rc_condition_t* scan;
574
+ for (scan = condset->conditions; scan != NULL; scan = scan->next)
575
+ {
576
+ if (scan == condition)
577
+ return index;
578
+
579
+ ++index;
580
+ }
581
+
582
+ return 0;
583
+ }
584
+
585
+ static void rc_validate_range(uint32_t min_val, uint32_t max_val, char oper, uint32_t max, rc_validation_state_t* state)
586
+ {
587
+ switch (oper) {
588
+ case RC_OPERATOR_AND:
589
+ if (min_val > max)
590
+ rc_validate_add_error(state, RC_VALIDATION_ERR_MASK_TOO_LARGE, 0, 0);
591
+ else if (min_val == 0 && max_val == 0)
592
+ rc_validate_add_error(state, RC_VALIDATION_ERR_MASK_RESULT_ALWAYS_ZERO, 0, 0);
593
+ break;
594
+
595
+ case RC_OPERATOR_EQ:
596
+ if (min_val > max)
597
+ rc_validate_add_error(state, RC_VALIDATION_ERR_COMPARISON_NEVER_TRUE_WITH_MAX, max, 0);
598
+ break;
599
+
600
+ case RC_OPERATOR_NE:
601
+ if (min_val > max)
602
+ rc_validate_add_error(state, RC_VALIDATION_ERR_COMPARISON_ALWAYS_TRUE_WITH_MAX, max, 0);
603
+ break;
604
+
605
+ case RC_OPERATOR_GE:
606
+ if (min_val > max)
607
+ rc_validate_add_error(state, RC_VALIDATION_ERR_COMPARISON_NEVER_TRUE_WITH_MAX, max, 0);
608
+ else if (max_val == 0)
609
+ rc_validate_add_error(state, RC_VALIDATION_ERR_COMPARISON_ALWAYS_TRUE_WITH_MAX, max, 0);
610
+ break;
611
+
612
+ case RC_OPERATOR_GT:
613
+ if (min_val >= max)
614
+ rc_validate_add_error(state, RC_VALIDATION_ERR_COMPARISON_NEVER_TRUE_WITH_MAX, max, 0);
615
+ break;
616
+
617
+ case RC_OPERATOR_LE:
618
+ if (min_val >= max)
619
+ rc_validate_add_error(state, RC_VALIDATION_ERR_COMPARISON_ALWAYS_TRUE_WITH_MAX, max, 0);
620
+ break;
621
+
622
+ case RC_OPERATOR_LT:
623
+ if (min_val > max)
624
+ rc_validate_add_error(state, RC_VALIDATION_ERR_COMPARISON_ALWAYS_TRUE_WITH_MAX, max, 0);
625
+ else if (max_val == 0)
626
+ rc_validate_add_error(state, RC_VALIDATION_ERR_COMPARISON_NEVER_TRUE, 0, 0);
627
+ break;
628
+ }
629
+ }
630
+
631
+ static int rc_validate_condset_internal(const rc_condset_t* condset, rc_validation_state_t* state)
632
+ {
633
+ const rc_condition_t* cond;
634
+ int in_add_hits = 0;
635
+ int in_add_address = 0;
636
+ int is_combining = 0;
637
+ int has_measured = 0;
638
+ int measuredif_index = -1;
639
+ uint32_t errors_before = state->error_count;
640
+
641
+ if (!condset)
642
+ return 1;
643
+
644
+ state->cond_index = 1;
645
+
646
+ for (cond = condset->conditions; cond; cond = cond->next, ++state->cond_index) {
647
+ /* validate the original operands first */
648
+ const rc_operand_t* operand1 = rc_condition_get_real_operand1(cond);
649
+ int is_memref1 = rc_operand_is_memref(operand1);
650
+ const int is_memref2 = rc_operand_is_memref(&cond->operand2);
651
+
652
+ if (!in_add_address) {
653
+ if (is_memref1)
654
+ rc_validate_memref(operand1->value.memref, state);
655
+ if (is_memref2)
656
+ rc_validate_memref(cond->operand2.value.memref, state);
657
+ }
658
+ else {
659
+ in_add_address = 0;
660
+ }
661
+
662
+ /* if operand is {recall}, but memref is null, that means the Remember wasn't found */
663
+ if (rc_validate_is_invalid_recall(operand1) || rc_validate_is_invalid_recall(&cond->operand2)) {
664
+ if (!rc_validate_has_condition(condset->conditions, RC_CONDITION_REMEMBER)) {
665
+ rc_validate_add_error(state, RC_VALIDATION_ERR_RECALL_WITHOUT_REMEMBER, 0, 0);
666
+ }
667
+ else {
668
+ const rc_condition_t* next_cond = rc_validate_get_next_non_combining_condition(cond);
669
+ const uint8_t next_cond_type = next_cond ? next_cond->type : RC_CONDITION_STANDARD;
670
+ rc_validate_add_error(state, RC_VALIDATION_ERR_RECALL_BEFORE_REMEMBER, next_cond_type, 0);
671
+ }
672
+ }
673
+
674
+ switch (cond->type) {
675
+ case RC_CONDITION_ADD_SOURCE:
676
+ case RC_CONDITION_SUB_SOURCE:
677
+ case RC_CONDITION_REMEMBER:
678
+ is_combining = 1;
679
+ continue;
680
+
681
+ case RC_CONDITION_ADD_ADDRESS:
682
+ if (operand1->type == RC_OPERAND_DELTA || operand1->type == RC_OPERAND_PRIOR)
683
+ rc_validate_add_error(state, RC_VALIDATION_ERR_POINTER_FROM_PREVIOUS_FRAME, 0, 0);
684
+ else if (rc_operand_is_float(operand1) || rc_operand_is_float(&cond->operand2))
685
+ rc_validate_add_error(state, RC_VALIDATION_ERR_POINTER_NON_INTEGER_OFFSET, 0, 0);
686
+ else if (rc_operand_type_is_transform(operand1->type) && cond->oper != RC_OPERATOR_MULT)
687
+ rc_validate_add_error(state, RC_VALIDATION_ERR_POINTER_TRANSFORMED_OFFSET, 0, 0);
688
+
689
+ in_add_address = 1;
690
+ is_combining = 1;
691
+ continue;
692
+
693
+ case RC_CONDITION_ADD_HITS:
694
+ case RC_CONDITION_SUB_HITS:
695
+ in_add_hits = 1;
696
+ is_combining = 1;
697
+ break;
698
+
699
+ case RC_CONDITION_AND_NEXT:
700
+ case RC_CONDITION_OR_NEXT:
701
+ case RC_CONDITION_RESET_NEXT_IF:
702
+ is_combining = 1;
703
+ break;
704
+
705
+ case RC_CONDITION_RESET_IF:
706
+ if (in_add_hits) {
707
+ /* ResetIf at the end of a hit chain does not require a hit target.
708
+ * It's meant to reset things if some subset of conditions have been true. */
709
+ in_add_hits = 0;
710
+ is_combining = 0;
711
+ break;
712
+ }
713
+ if (!state->has_hit_targets)
714
+ rc_validate_add_error(state, RC_VALIDATION_ERR_NO_HITS_TO_RESET, 0, 0);
715
+ else if (cond->required_hits == 1)
716
+ rc_validate_add_error(state, RC_VALIDATION_ERR_RESET_HIT_TARGET_OF_ONE, 0, 0);
717
+ /* fallthrough */ /* to default */
718
+ default:
719
+ if (in_add_hits) {
720
+ if (cond->required_hits == 0)
721
+ rc_validate_add_error(state, RC_VALIDATION_ERR_ADDHITS_WITHOUT_TARGET, 0, 0);
722
+
723
+ in_add_hits = 0;
724
+ }
725
+
726
+ has_measured |= (cond->type == RC_CONDITION_MEASURED);
727
+ if (cond->type == RC_CONDITION_MEASURED_IF && measuredif_index == -1)
728
+ measuredif_index = state->cond_index;
729
+
730
+ is_combining = 0;
731
+ break;
732
+ }
733
+
734
+ /* original operands are valid. now switch to the derived operands for logic
735
+ * combining/comparing them */
736
+ operand1 = &cond->operand1;
737
+ is_memref1 = rc_operand_is_memref(operand1);
738
+
739
+ /* check for comparing two differently sized memrefs */
740
+ if (is_memref1 && is_memref2 &&
741
+ operand1->value.memref->value.memref_type == RC_MEMREF_TYPE_MEMREF &&
742
+ cond->operand2.value.memref->value.memref_type == RC_MEMREF_TYPE_MEMREF &&
743
+ rc_max_value(operand1) != rc_max_value(&cond->operand2)) {
744
+ rc_validate_add_error(state, RC_VALIDATION_ERR_COMPARING_DIFFERENT_MEMORY_SIZES, 0, 0);
745
+ }
746
+
747
+ if (is_memref1 && rc_operand_is_float(operand1)) {
748
+ /* if left side is a float, right side will be converted to a float, so don't do range validation */
749
+ }
750
+ else if (is_memref1 || is_memref2) {
751
+ /* if either side is a memref, check for impossible comparisons */
752
+ const rc_operand_t* operand2 = &cond->operand2;
753
+ uint8_t oper = cond->oper;
754
+ uint32_t min, max;
755
+ uint32_t max_val = rc_max_value(operand2);
756
+ uint32_t min_val;
757
+ rc_typed_value_t typed_value;
758
+
759
+ rc_chain_get_value_range(operand1, &min, &max);
760
+ if (min > max) { /* underflow */
761
+ min = 0;
762
+ max = 0xFFFFFFFF;
763
+ }
764
+
765
+ if (!is_memref1) {
766
+ /* pretend constant was on right side */
767
+ operand2 = operand1;
768
+ operand1 = &cond->operand2;
769
+ max_val = max;
770
+ max = rc_max_value(&cond->operand2);
771
+
772
+ switch (oper) {
773
+ case RC_OPERATOR_LT: oper = RC_OPERATOR_GT; break;
774
+ case RC_OPERATOR_LE: oper = RC_OPERATOR_GE; break;
775
+ case RC_OPERATOR_GT: oper = RC_OPERATOR_LT; break;
776
+ case RC_OPERATOR_GE: oper = RC_OPERATOR_LE; break;
777
+ }
778
+ }
779
+
780
+ switch (operand2->type) {
781
+ case RC_OPERAND_CONST:
782
+ min_val = operand2->value.num;
783
+ break;
784
+
785
+ case RC_OPERAND_FP:
786
+ min_val = (int)operand2->value.dbl;
787
+
788
+ /* cannot compare an integer memory reference to a non-integral floating point value */
789
+ if (!rc_operand_is_float_memref(operand1) && (float)min_val != operand2->value.dbl) {
790
+ switch (oper) {
791
+ case RC_OPERATOR_EQ:
792
+ typed_value.value.f32 = (float)operand2->value.dbl;
793
+ rc_validate_add_error(state, RC_VALIDATION_ERR_COMPARISON_NEVER_TRUE_INTEGER_TO_FLOAT, typed_value.value.u32, 0);
794
+ break;
795
+
796
+ case RC_OPERATOR_NE:
797
+ typed_value.value.f32 = (float)operand2->value.dbl;
798
+ rc_validate_add_error(state, RC_VALIDATION_ERR_COMPARISON_ALWAYS_TRUE_INTEGER_TO_FLOAT, typed_value.value.u32, 0);
799
+ break;
800
+
801
+ case RC_OPERATOR_GT: /* value could be greater than floor(float) */
802
+ case RC_OPERATOR_LE: /* value could be less than or equal to floor(float) */
803
+ break;
804
+
805
+ case RC_OPERATOR_GE: /* value could be greater than or equal to ceil(float) */
806
+ case RC_OPERATOR_LT: /* value could be less than ceil(float) */
807
+ ++min_val;
808
+ break;
809
+ }
810
+ }
811
+
812
+ break;
813
+
814
+ default: /* right side is memref or add source chain */
815
+ min_val = 0;
816
+ break;
817
+ }
818
+
819
+ /* min_val and max_val are the range allowed by operand2. max is the upper value from operand1. */
820
+ rc_validate_range(min_val, max_val, oper, max, state);
821
+ }
822
+ }
823
+
824
+ if (is_combining) {
825
+ /* find the final condition so we can extract the type */
826
+ state->cond_index--;
827
+ cond = condset->conditions;
828
+ while (cond->next)
829
+ cond = cond->next;
830
+
831
+ rc_validate_add_error(state, RC_VALIDATION_ERR_TRAILING_CHAINING_CONDITION, cond->type, 0);
832
+ }
833
+
834
+ if (measuredif_index != -1 && !has_measured) {
835
+ state->cond_index = measuredif_index;
836
+ rc_validate_add_error(state, RC_VALIDATION_ERR_MEASUREDIF_WITHOUT_MEASURED, 0, 0);
837
+ }
838
+
839
+ return (state->error_count == errors_before);
840
+ }
841
+
842
+ static int rc_condset_has_hittargets(const rc_condset_t* condset)
843
+ {
844
+ if (condset->num_hittarget_conditions > 0)
845
+ return 1;
846
+
847
+ /* pause and reset conditions may have hittargets and won't be classified as hittarget conditions.
848
+ * measured conditions may also have hittargets.
849
+ * other conditions may have hittarget conditions in an AndNext/OrNext chain.
850
+ * basically, check everything other than hittarget (explicitly known) and indirect (cannot have).
851
+ */
852
+ if (condset->num_pause_conditions || condset->num_reset_conditions || condset->num_measured_conditions || condset->num_other_conditions) {
853
+ const rc_condition_t* condition = rc_condset_get_conditions((rc_condset_t*)condset);
854
+ /* ASSERT: don't need to add num_hittarget_conditions because it must be 0 per earlier check */
855
+ const rc_condition_t* stop = condition + condset->num_pause_conditions
856
+ + condset->num_reset_conditions + condset->num_measured_conditions
857
+ + condset->num_other_conditions;
858
+ for (; condition < stop; ++condition) {
859
+ if (condition->required_hits)
860
+ return 1;
861
+ }
862
+ }
863
+
864
+ return 0;
865
+ }
866
+
867
+ int rc_validate_condset(const rc_condset_t* condset, char result[], const size_t result_size, uint32_t max_address)
868
+ {
869
+ rc_validation_state_t state;
870
+ memset(&state, 0, sizeof(state));
871
+ state.has_hit_targets = rc_condset_has_hittargets(condset);
872
+ state.max_address = max_address;
873
+
874
+ result[0] = '\0';
875
+ if (rc_validate_condset_internal(condset, &state)) {
876
+ const rc_validation_error_t* most_severe_error = rc_validate_find_most_severe_error(&state);
877
+ return rc_validate_format_error(result, result_size, &state, most_severe_error);
878
+ }
879
+
880
+ return 1;
881
+ }
882
+
883
+ int rc_validate_condset_for_console(const rc_condset_t* condset, char result[], const size_t result_size, uint32_t console_id)
884
+ {
885
+ rc_validation_state_t state;
886
+ memset(&state, 0, sizeof(state));
887
+ state.console_id = console_id;
888
+ state.max_address = rc_console_max_address(console_id);
889
+ state.has_hit_targets = rc_condset_has_hittargets(condset);
890
+
891
+ result[0] = '\0';
892
+ if (rc_validate_condset_internal(condset, &state)) {
893
+ const rc_validation_error_t* most_severe_error = rc_validate_find_most_severe_error(&state);
894
+ return rc_validate_format_error(result, result_size, &state, most_severe_error);
895
+ }
896
+
897
+ return 1;
898
+ }
899
+
900
+ static int rc_validate_get_opposite_comparison(int oper)
901
+ {
902
+ switch (oper)
903
+ {
904
+ case RC_OPERATOR_EQ: return RC_OPERATOR_NE;
905
+ case RC_OPERATOR_NE: return RC_OPERATOR_EQ;
906
+ case RC_OPERATOR_LT: return RC_OPERATOR_GE;
907
+ case RC_OPERATOR_LE: return RC_OPERATOR_GT;
908
+ case RC_OPERATOR_GT: return RC_OPERATOR_LE;
909
+ case RC_OPERATOR_GE: return RC_OPERATOR_LT;
910
+ default: return oper;
911
+ }
912
+ }
913
+
914
+ static const rc_operand_t* rc_validate_get_comparison(const rc_condition_t* condition, int* comparison, unsigned* value)
915
+ {
916
+ if (rc_operand_is_memref(&condition->operand1))
917
+ {
918
+ if (condition->operand2.type != RC_OPERAND_CONST)
919
+ return NULL;
920
+
921
+ *comparison = condition->oper;
922
+ *value = condition->operand2.value.num;
923
+ return &condition->operand1;
924
+ }
925
+
926
+ if (condition->operand1.type != RC_OPERAND_CONST)
927
+ return NULL;
928
+
929
+ if (!rc_operand_is_memref(&condition->operand2))
930
+ return NULL;
931
+
932
+ *comparison = rc_validate_get_opposite_comparison(condition->oper);
933
+ *value = condition->operand1.value.num;
934
+ return &condition->operand2;
935
+ }
936
+
937
+ enum {
938
+ RC_OVERLAP_NONE = 0,
939
+ RC_OVERLAP_CONFLICTING,
940
+ RC_OVERLAP_REDUNDANT,
941
+ RC_OVERLAP_DEFER
942
+ };
943
+
944
+ static int rc_validate_comparison_overlap(int comparison1, uint32_t value1, int comparison2, uint32_t value2)
945
+ {
946
+ /* NOTE: this only cares if comp2 conflicts with comp1.
947
+ * If comp1 conflicts with comp2, we'll catch that later (return RC_OVERLAP_NONE for now) */
948
+ switch (comparison2)
949
+ {
950
+ case RC_OPERATOR_EQ:
951
+ switch (comparison1) /* comp1 comp2 comp1 comp2 comp1 comp2 */
952
+ { /* value1 = value2 value1 < value2 value1 > value2 */
953
+ case RC_OPERATOR_EQ: /* a == 1 && a == 1 | a == 1 && a == 2 | a == 2 && a == 1 */
954
+ /* redundant conflict conflict */
955
+ return (value1 == value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_CONFLICTING;
956
+ case RC_OPERATOR_LE: /* a <= 1 && a == 1 | a <= 1 && a == 2 | a <= 2 && a == 1 */
957
+ /* defer conflict defer */
958
+ return (value1 < value2) ? RC_OVERLAP_CONFLICTING : RC_OVERLAP_DEFER;
959
+ case RC_OPERATOR_GE: /* a >= 1 && a == 1 | a >= 1 && a == 2 | a >= 2 && a == 1 */
960
+ /* defer defer conflict */
961
+ return (value1 > value2) ? RC_OVERLAP_CONFLICTING : RC_OVERLAP_DEFER;
962
+ case RC_OPERATOR_NE: /* a != 1 && a == 1 | a != 1 && a == 2 | a != 2 && a == 1 */
963
+ /* conflict defer defer */
964
+ return (value1 == value2) ? RC_OVERLAP_CONFLICTING : RC_OVERLAP_DEFER;
965
+ case RC_OPERATOR_LT: /* a < 1 && a == 1 | a < 1 && a == 2 | a < 2 && a == 1 */
966
+ /* conflict conflict defer */
967
+ return (value1 <= value2) ? RC_OVERLAP_CONFLICTING : RC_OVERLAP_DEFER;
968
+ case RC_OPERATOR_GT: /* a > 1 && a == 1 | a > 1 && a == 2 | a > 2 && a == 1 */
969
+ /* conflict defer conflict */
970
+ return (value1 >= value2) ? RC_OVERLAP_CONFLICTING : RC_OVERLAP_DEFER;
971
+ }
972
+ break;
973
+
974
+ case RC_OPERATOR_NE:
975
+ switch (comparison1) /* comp1 comp2 comp1 comp2 comp1 comp2 */
976
+ { /* value1 = value2 value1 < value2 value1 > value2 */
977
+ case RC_OPERATOR_EQ: /* a == 1 && a != 1 | a == 1 && a != 2 | a == 2 && a != 1 */
978
+ /* conflict redundant redundant */
979
+ return (value1 == value2) ? RC_OVERLAP_CONFLICTING : RC_OVERLAP_REDUNDANT;
980
+ case RC_OPERATOR_LE: /* a <= 1 && a != 1 | a <= 1 && a != 2 | a <= 2 && a != 1 */
981
+ /* none redundant none */
982
+ return (value1 < value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_NONE;
983
+ case RC_OPERATOR_GE: /* a >= 1 && a != 1 | a >= 1 && a != 2 | a >= 2 && a != 1 */
984
+ /* none none redundant */
985
+ return (value1 > value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_NONE;
986
+ case RC_OPERATOR_NE: /* a != 1 && a != 1 | a != 1 && a != 2 | a != 2 && a != 1 */
987
+ /* redundant none none */
988
+ return (value1 == value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_NONE;
989
+ case RC_OPERATOR_LT: /* a < 1 && a != 1 | a < 1 && a != 2 | a < 2 && a != 1 */
990
+ /* redundant redundant none */
991
+ return (value1 <= value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_NONE;
992
+ case RC_OPERATOR_GT: /* a > 1 && a != 1 | a > 1 && a != 2 | a > 2 && a != 1 */
993
+ /* redundant none redundant */
994
+ return (value1 >= value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_NONE;
995
+ }
996
+ break;
997
+
998
+ case RC_OPERATOR_LT:
999
+ switch (comparison1) /* comp1 comp2 comp1 comp2 comp1 comp2 */
1000
+ { /* value1 = value2 value1 < value2 value1 > value2 */
1001
+ case RC_OPERATOR_EQ: /* a == 1 && a < 1 | a == 1 && a < 2 | a == 2 && a < 1 */
1002
+ /* conflict redundant conflict */
1003
+ return (value1 < value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_CONFLICTING;
1004
+ case RC_OPERATOR_LE: /* a <= 1 && a < 1 | a <= 1 && a < 2 | a <= 2 && a < 1 */
1005
+ /* defer redundant defer */
1006
+ return (value1 < value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_DEFER;
1007
+ case RC_OPERATOR_GE: /* a >= 1 && a < 1 | a >= 1 && a < 2 | a >= 2 && a < 1 */
1008
+ /* conflict none conflict */
1009
+ return (value1 >= value2) ? RC_OVERLAP_CONFLICTING : RC_OVERLAP_NONE;
1010
+ case RC_OPERATOR_NE: /* a != 1 && a < 1 | a != 1 && a < 2 | a != 2 && a < 1 */
1011
+ /* defer none defer */
1012
+ return (value1 >= value2) ? RC_OVERLAP_DEFER : RC_OVERLAP_NONE;
1013
+ case RC_OPERATOR_LT: /* a < 1 && a < 1 | a < 1 && a < 2 | a < 2 && a < 1 */
1014
+ /* redundant redundant defer */
1015
+ return (value1 <= value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_DEFER;
1016
+ case RC_OPERATOR_GT: /* a > 1 && a < 1 | a > 1 && a < 2 | a > 2 && a < 1 */
1017
+ /* conflict none conflict */
1018
+ return (value1 >= value2) ? RC_OVERLAP_CONFLICTING : RC_OVERLAP_NONE;
1019
+ }
1020
+ break;
1021
+
1022
+ case RC_OPERATOR_LE:
1023
+ switch (comparison1) /* comp1 comp2 comp1 comp2 comp1 comp2 */
1024
+ { /* value1 = value2 value1 < value2 value1 > value2 */
1025
+ case RC_OPERATOR_EQ: /* a == 1 && a <= 1 | a == 1 && a <= 2 | a == 2 && a <= 1 */
1026
+ /* redundant redundant conflict */
1027
+ return (value1 <= value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_CONFLICTING;
1028
+ case RC_OPERATOR_LE: /* a <= 1 && a <= 1 | a <= 1 && a <= 2 | a <= 2 && a <= 1 */
1029
+ /* redundant redundant defer */
1030
+ return (value1 <= value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_DEFER;
1031
+ case RC_OPERATOR_GE: /* a >= 1 && a <= 1 | a >= 1 && a <= 2 | a >= 2 && a <= 1 */
1032
+ /* none none conflict */
1033
+ return (value1 > value2) ? RC_OVERLAP_CONFLICTING : RC_OVERLAP_NONE;
1034
+ case RC_OPERATOR_NE: /* a != 1 && a <= 1 | a != 1 && a <= 2 | a != 2 && a <= 1 */
1035
+ /* none none defer */
1036
+ return (value1 > value2) ? RC_OVERLAP_DEFER : RC_OVERLAP_NONE;
1037
+ case RC_OPERATOR_LT: /* a < 1 && a <= 1 | a < 1 && a <= 2 | a < 2 && a <= 1 */
1038
+ /* redundant redundant defer */
1039
+ return (value1 <= value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_DEFER;
1040
+ case RC_OPERATOR_GT: /* a > 1 && a <= 1 | a > 1 && a <= 2 | a > 2 && a <= 1 */
1041
+ /* conflict none conflict */
1042
+ return (value1 >= value2) ? RC_OVERLAP_CONFLICTING : RC_OVERLAP_NONE;
1043
+ }
1044
+ break;
1045
+
1046
+ case RC_OPERATOR_GT:
1047
+ switch (comparison1) /* comp1 comp2 comp1 comp2 comp1 comp2 */
1048
+ { /* value1 = value2 value1 < value2 value1 > value2 */
1049
+ case RC_OPERATOR_EQ: /* a == 1 && a > 1 | a == 1 && a > 2 | a == 2 && a > 1 */
1050
+ /* conflict conflict redundant */
1051
+ return (value1 > value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_CONFLICTING;
1052
+ case RC_OPERATOR_LE: /* a <= 1 && a > 1 | a <= 1 && a > 2 | a <= 2 && a > 1 */
1053
+ /* conflict conflict defer */
1054
+ return (value1 <= value2) ? RC_OVERLAP_CONFLICTING : RC_OVERLAP_DEFER;
1055
+ case RC_OPERATOR_GE: /* a >= 1 && a > 1 | a >= 1 && a > 2 | a >= 2 && a > 1 */
1056
+ /* defer defer redundant */
1057
+ return (value1 > value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_DEFER;
1058
+ case RC_OPERATOR_NE: /* a != 1 && a > 1 | a != 1 && a > 2 | a != 2 && a > 1 */
1059
+ /* defer defer none */
1060
+ return (value1 <= value2) ? RC_OVERLAP_DEFER : RC_OVERLAP_NONE;
1061
+ case RC_OPERATOR_LT: /* a < 1 && a > 1 | a < 1 && a > 2 | a < 2 && a > 1 */
1062
+ /* conflict conflict none */
1063
+ return (value1 <= value2) ? RC_OVERLAP_CONFLICTING : RC_OVERLAP_NONE;
1064
+ case RC_OPERATOR_GT: /* a > 1 && a > 1 | a > 1 && a > 2 | a > 2 && a > 1 */
1065
+ /* redundant defer redundant */
1066
+ return (value1 >= value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_DEFER;
1067
+ }
1068
+ break;
1069
+
1070
+ case RC_OPERATOR_GE:
1071
+ switch (comparison1) /* comp1 comp2 comp1 comp2 comp1 comp2 */
1072
+ { /* value1 = value2 value1 < value2 value1 > value2 */
1073
+ case RC_OPERATOR_EQ: /* a == 1 && a >= 1 | a == 1 && a >= 2 | a == 2 && a >= 1 */
1074
+ /* redundant conflict redundant */
1075
+ return (value1 >= value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_CONFLICTING;
1076
+ case RC_OPERATOR_LE: /* a <= 1 && a >= 1 | a <= 1 && a >= 2 | a <= 2 && a >= 1 */
1077
+ /* none conflict none */
1078
+ return (value1 < value2) ? RC_OVERLAP_CONFLICTING : RC_OVERLAP_NONE;
1079
+ case RC_OPERATOR_GE: /* a >= 1 && a >= 1 | a >= 1 && a >= 2 | a >= 2 && a >= 1 */
1080
+ /* redundant redundant defer */
1081
+ return (value1 <= value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_DEFER;
1082
+ case RC_OPERATOR_NE: /* a != 1 && a >= 1 | a != 1 && a >= 2 | a != 2 && a >= 1 */
1083
+ /* none defer none */
1084
+ return (value1 < value2) ? RC_OVERLAP_DEFER : RC_OVERLAP_NONE;
1085
+ case RC_OPERATOR_LT: /* a < 1 && a >= 1 | a < 1 && a >= 2 | a < 2 && a >= 1 */
1086
+ /* conflict conflict none */
1087
+ return (value1 <= value2) ? RC_OVERLAP_CONFLICTING : RC_OVERLAP_NONE;
1088
+ case RC_OPERATOR_GT: /* a > 1 && a >= 1 | a > 1 && a >= 2 | a > 2 && a >= 1 */
1089
+ /* redundant defer redundant */
1090
+ return (value1 >= value2) ? RC_OVERLAP_REDUNDANT : RC_OVERLAP_DEFER;
1091
+ }
1092
+ break;
1093
+ }
1094
+
1095
+ return RC_OVERLAP_NONE;
1096
+ }
1097
+
1098
+ static int rc_validate_conflicting_conditions(const rc_condset_t* conditions, const rc_condset_t* compare_conditions,
1099
+ uint32_t group_index, rc_validation_state_t* state)
1100
+ {
1101
+ int comparison1, comparison2;
1102
+ uint32_t value1, value2;
1103
+ const rc_operand_t* operand1;
1104
+ const rc_operand_t* operand2;
1105
+ const rc_condition_t* compare_condition;
1106
+ const rc_condition_t* condition;
1107
+ const rc_condition_t* condition_chain_start;
1108
+ uint32_t errors_before = state->error_count;
1109
+ int overlap;
1110
+ int chain_matches;
1111
+
1112
+ /* empty group */
1113
+ if (conditions == NULL || compare_conditions == NULL)
1114
+ return 1;
1115
+
1116
+ /* outer loop is the source conditions */
1117
+ for (condition = conditions->conditions; condition != NULL; condition = condition->next, ++state->cond_index) {
1118
+ condition_chain_start = condition;
1119
+ while (condition && rc_condition_is_combining(condition)) {
1120
+ condition = condition->next;
1121
+ }
1122
+ if (!condition)
1123
+ break;
1124
+
1125
+ /* hits can be captured at any time, so any potential conflict will not be conflicting at another time */
1126
+ if (condition->required_hits)
1127
+ continue;
1128
+
1129
+ operand1 = rc_validate_get_comparison(condition, &comparison1, &value1);
1130
+ if (!operand1)
1131
+ continue;
1132
+
1133
+ switch (condition->type) {
1134
+ case RC_CONDITION_PAUSE_IF:
1135
+ if (conditions != compare_conditions)
1136
+ break;
1137
+ /* fallthrough */
1138
+ case RC_CONDITION_RESET_IF:
1139
+ comparison1 = rc_validate_get_opposite_comparison(comparison1);
1140
+ break;
1141
+ default:
1142
+ if (rc_validate_is_combining_condition(condition))
1143
+ continue;
1144
+ break;
1145
+ }
1146
+
1147
+ /* inner loop is the potentially conflicting conditions */
1148
+ state->cond_index = 1;
1149
+ for (compare_condition = compare_conditions->conditions; compare_condition != NULL; compare_condition = compare_condition->next, ++state->cond_index) {
1150
+ if (compare_condition == condition_chain_start) {
1151
+ /* skip condition we're already looking at */
1152
+ while (compare_condition != condition) {
1153
+ ++state->cond_index;
1154
+ compare_condition = compare_condition->next;
1155
+ }
1156
+
1157
+ continue;
1158
+ }
1159
+
1160
+ /* if combining conditions exist, make sure the same combining conditions exist in the
1161
+ * compare logic. conflicts can only occur if the combinining conditions match. */
1162
+ chain_matches = 1;
1163
+ if (condition_chain_start != condition) {
1164
+ const rc_condition_t* condition_chain_iter = condition_chain_start;
1165
+ while (condition_chain_iter != condition) {
1166
+ if (compare_condition->type != condition_chain_iter->type ||
1167
+ compare_condition->oper != condition_chain_iter->oper ||
1168
+ compare_condition->required_hits != condition_chain_iter->required_hits ||
1169
+ !rc_operands_are_equal(&compare_condition->operand1, &condition_chain_iter->operand1))
1170
+ {
1171
+ chain_matches = 0;
1172
+ break;
1173
+ }
1174
+
1175
+ if (compare_condition->oper != RC_OPERATOR_NONE &&
1176
+ !rc_operands_are_equal(&compare_condition->operand2, &condition_chain_iter->operand2))
1177
+ {
1178
+ chain_matches = 0;
1179
+ break;
1180
+ }
1181
+
1182
+ if (!compare_condition->next) {
1183
+ chain_matches = 0;
1184
+ break;
1185
+ }
1186
+
1187
+ if (compare_condition->type != RC_CONDITION_ADD_ADDRESS &&
1188
+ compare_condition->type != RC_CONDITION_ADD_SOURCE &&
1189
+ compare_condition->type != RC_CONDITION_SUB_SOURCE &&
1190
+ compare_condition->type != RC_CONDITION_AND_NEXT)
1191
+ {
1192
+ /* things like AddHits and OrNext are hard to definitively detect conflicts. ignore them. */
1193
+ chain_matches = 0;
1194
+ break;
1195
+ }
1196
+
1197
+ ++state->cond_index;
1198
+ compare_condition = compare_condition->next;
1199
+ condition_chain_iter = condition_chain_iter->next;
1200
+ }
1201
+ }
1202
+
1203
+ /* combining field didn't match, or there's more unmatched combining fields. ignore this condition */
1204
+ if (!chain_matches || rc_validate_is_combining_condition(compare_condition)) {
1205
+ while (compare_condition->next && rc_validate_is_combining_condition(compare_condition))
1206
+ compare_condition = compare_condition->next;
1207
+ continue;
1208
+ }
1209
+
1210
+ if (compare_condition->required_hits)
1211
+ continue;
1212
+
1213
+ operand2 = rc_validate_get_comparison(compare_condition, &comparison2, &value2);
1214
+ if (!operand2 || !rc_operands_are_equal(operand1, operand2))
1215
+ continue;
1216
+
1217
+ switch (compare_condition->type) {
1218
+ case RC_CONDITION_PAUSE_IF:
1219
+ if (conditions != compare_conditions) /* PauseIf only affects conditions in same group */
1220
+ break;
1221
+ /* fallthrough */
1222
+ case RC_CONDITION_RESET_IF:
1223
+ comparison2 = rc_validate_get_opposite_comparison(comparison2);
1224
+ break;
1225
+ default:
1226
+ if (rc_validate_is_combining_condition(compare_condition))
1227
+ continue;
1228
+ break;
1229
+ }
1230
+
1231
+ overlap = rc_validate_comparison_overlap(comparison1, value1, comparison2, value2);
1232
+ switch (overlap)
1233
+ {
1234
+ case RC_OVERLAP_CONFLICTING:
1235
+ if (compare_condition->type == RC_CONDITION_PAUSE_IF || condition->type == RC_CONDITION_PAUSE_IF)
1236
+ {
1237
+ /* ignore PauseIf conflicts between groups, unless both conditions are PauseIfs */
1238
+ if (conditions != compare_conditions && compare_condition->type != condition->type)
1239
+ continue;
1240
+ }
1241
+ break;
1242
+
1243
+ case RC_OVERLAP_REDUNDANT:
1244
+ if (group_index != state->group_index && state->group_index == 0)
1245
+ {
1246
+ /* if the alt condition is more restrictive than the core condition, ignore it */
1247
+ if (rc_validate_comparison_overlap(comparison2, value2, comparison1, value1) != RC_OVERLAP_REDUNDANT)
1248
+ continue;
1249
+ }
1250
+
1251
+ if (compare_condition->type == RC_CONDITION_PAUSE_IF || condition->type == RC_CONDITION_PAUSE_IF)
1252
+ {
1253
+ /* ignore PauseIf redundancies between groups */
1254
+ if (conditions != compare_conditions)
1255
+ continue;
1256
+
1257
+ /* if the PauseIf is less restrictive than the other condition, it's just a guard. ignore it */
1258
+ if (rc_validate_comparison_overlap(comparison2, value2, comparison1, value1) != RC_OVERLAP_REDUNDANT)
1259
+ continue;
1260
+
1261
+ /* PauseIf redundant with ResetIf is a conflict (both are inverted comparisons) */
1262
+ if (compare_condition->type == RC_CONDITION_RESET_IF || condition->type == RC_CONDITION_RESET_IF)
1263
+ overlap = RC_OVERLAP_CONFLICTING;
1264
+ }
1265
+ else if (compare_condition->type == RC_CONDITION_RESET_IF && condition->type != RC_CONDITION_RESET_IF)
1266
+ {
1267
+ /* only ever report the redundancy on the non-ResetIf condition. The ResetIf is allowed to
1268
+ * fire when the non-ResetIf condition is not true. */
1269
+ if (state->has_hit_targets)
1270
+ continue;
1271
+ }
1272
+ else if (condition->type == RC_CONDITION_RESET_IF && compare_condition->type != RC_CONDITION_RESET_IF)
1273
+ {
1274
+ /* if the ResetIf condition is more restrictive than the non-ResetIf condition,
1275
+ and there aren't any hits to clear, ignore it */
1276
+ if (state->has_hit_targets)
1277
+ continue;
1278
+ }
1279
+ else if (compare_condition->type == RC_CONDITION_MEASURED_IF || condition->type == RC_CONDITION_MEASURED_IF)
1280
+ {
1281
+ /* ignore MeasuredIf redundancies between groups */
1282
+ if (conditions != compare_conditions)
1283
+ continue;
1284
+
1285
+ if (compare_condition->type == RC_CONDITION_MEASURED_IF && condition->type != RC_CONDITION_MEASURED_IF)
1286
+ {
1287
+ /* only ever report the redundancy on the non-MeasuredIf condition. The MeasuredIf provides
1288
+ * additional functionality. */
1289
+ continue;
1290
+ }
1291
+ }
1292
+ else if (condition->type == RC_CONDITION_TRIGGER && compare_condition->type != RC_CONDITION_TRIGGER)
1293
+ {
1294
+ /* Trigger is allowed to be redundant with non-trigger conditions as there may be limits that start a
1295
+ * challenge that are further reduced for the completion of the challenge */
1296
+ continue;
1297
+ }
1298
+ break;
1299
+
1300
+ default:
1301
+ continue;
1302
+ }
1303
+
1304
+ /* if condition A conflicts with condition B, condition B will also conflict with
1305
+ * condition A. don't report both. */
1306
+ {
1307
+ int already_reported = 0;
1308
+ const rc_validation_error_t* error = state->errors;
1309
+ const rc_validation_error_t* stop = state->errors + state->error_count;
1310
+ for (; error < stop; ++error) {
1311
+ if (error->data2 == state->cond_index && error->data1 == state->group_index) {
1312
+ if (error->err == RC_VALIDATION_ERR_REDUNDANT_CONDITION ||
1313
+ error->err == RC_VALIDATION_ERR_CONFLICTING_CONDITION) {
1314
+ already_reported = 1;
1315
+ }
1316
+ }
1317
+ }
1318
+
1319
+ if (already_reported)
1320
+ continue;
1321
+ }
1322
+
1323
+ rc_validate_add_error(state, (overlap == RC_OVERLAP_REDUNDANT) ?
1324
+ RC_VALIDATION_ERR_REDUNDANT_CONDITION : RC_VALIDATION_ERR_CONFLICTING_CONDITION,
1325
+ group_index, rc_validate_get_condition_index(conditions, condition));
1326
+ }
1327
+ }
1328
+
1329
+ return (state->error_count == errors_before);
1330
+ }
1331
+
1332
+ static int rc_validate_trigger_internal(const rc_trigger_t* trigger, rc_validation_state_t* state)
1333
+ {
1334
+ rc_condset_t* alt;
1335
+ uint32_t index;
1336
+
1337
+ state->has_alt_groups = (trigger->alternative != NULL);
1338
+
1339
+ state->has_hit_targets = trigger->requirement && rc_condset_has_hittargets(trigger->requirement);
1340
+ if (!state->has_hit_targets) {
1341
+ for (alt = trigger->alternative; alt; alt = alt->next) {
1342
+ if (rc_condset_has_hittargets(alt)) {
1343
+ state->has_hit_targets = 1;
1344
+ break;
1345
+ }
1346
+ }
1347
+ }
1348
+
1349
+ state->group_index = 0;
1350
+ if (rc_validate_condset_internal(trigger->requirement, state)) {
1351
+ /* compare core to itself */
1352
+ rc_validate_conflicting_conditions(trigger->requirement, trigger->requirement, 0, state);
1353
+ }
1354
+
1355
+ index = 1;
1356
+ for (alt = trigger->alternative; alt; alt = alt->next, ++index) {
1357
+ state->group_index = index;
1358
+ if (rc_validate_condset_internal(alt, state)) {
1359
+ /* compare alt to itself */
1360
+ if (!rc_validate_conflicting_conditions(alt, alt, index, state))
1361
+ continue;
1362
+
1363
+ /* compare alt to core */
1364
+ if (!rc_validate_conflicting_conditions(trigger->requirement, alt, 0, state))
1365
+ continue;
1366
+
1367
+ /* compare core to alt */
1368
+ state->group_index = 0;
1369
+ if (!rc_validate_conflicting_conditions(alt, trigger->requirement, index, state))
1370
+ continue;
1371
+ }
1372
+ }
1373
+
1374
+ return (state->error_count == 0);
1375
+ }
1376
+
1377
+ int rc_validate_trigger(const rc_trigger_t* trigger, char result[], const size_t result_size, uint32_t max_address)
1378
+ {
1379
+ rc_validation_state_t state;
1380
+ memset(&state, 0, sizeof(state));
1381
+ state.max_address = max_address;
1382
+
1383
+ result[0] = '\0';
1384
+ if (!rc_validate_trigger_internal(trigger, &state)) {
1385
+ const rc_validation_error_t* most_severe_error = rc_validate_find_most_severe_error(&state);
1386
+ return rc_validate_format_error(result, result_size, &state, most_severe_error);
1387
+ }
1388
+
1389
+ return 1;
1390
+ }
1391
+
1392
+ int rc_validate_trigger_for_console(const rc_trigger_t* trigger, char result[], const size_t result_size, uint32_t console_id)
1393
+ {
1394
+ rc_validation_state_t state;
1395
+ memset(&state, 0, sizeof(state));
1396
+ state.console_id = console_id;
1397
+ state.max_address = rc_console_max_address(console_id);
1398
+
1399
+ result[0] = '\0';
1400
+ if (!rc_validate_trigger_internal(trigger, &state)) {
1401
+ const rc_validation_error_t* most_severe_error = rc_validate_find_most_severe_error(&state);
1402
+ return rc_validate_format_error(result, result_size, &state, most_severe_error);
1403
+ }
1404
+
1405
+ return 1;
1406
+ }