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.
- checksums.yaml +4 -4
- data/THIRD_PARTY_NOTICES +37 -2
- data/assets/placeholder_boxart.png +0 -0
- data/bin/gemba +2 -2
- data/ext/gemba/extconf.rb +23 -1
- data/ext/gemba/gemba_ext.c +436 -2
- data/ext/gemba/gemba_ext.h +2 -0
- data/gemba.gemspec +5 -3
- data/lib/gemba/achievements/achievement.rb +23 -0
- data/lib/gemba/achievements/backend.rb +186 -0
- data/lib/gemba/achievements/cache.rb +70 -0
- data/lib/gemba/achievements/credentials_presenter.rb +142 -0
- data/lib/gemba/achievements/fake_backend.rb +205 -0
- data/lib/gemba/achievements/null_backend.rb +11 -0
- data/lib/gemba/achievements/offline_backend.rb +168 -0
- data/lib/gemba/achievements/retro_achievements/backend.rb +453 -0
- data/lib/gemba/achievements/retro_achievements/cli_sync_requester.rb +64 -0
- data/lib/gemba/achievements/retro_achievements/ping_worker.rb +27 -0
- data/lib/gemba/achievements.rb +19 -0
- data/lib/gemba/achievements_window.rb +556 -0
- data/lib/gemba/app_controller.rb +1015 -0
- data/lib/gemba/bios.rb +54 -0
- data/lib/gemba/boxart_fetcher/libretro_backend.rb +39 -0
- data/lib/gemba/boxart_fetcher/null_backend.rb +12 -0
- data/lib/gemba/boxart_fetcher.rb +79 -0
- data/lib/gemba/bus_emitter.rb +13 -0
- data/lib/gemba/child_window.rb +24 -1
- data/lib/gemba/cli/commands/config_cmd.rb +83 -0
- data/lib/gemba/cli/commands/decode.rb +154 -0
- data/lib/gemba/cli/commands/patch.rb +78 -0
- data/lib/gemba/cli/commands/play.rb +78 -0
- data/lib/gemba/cli/commands/record.rb +114 -0
- data/lib/gemba/cli/commands/replay.rb +161 -0
- data/lib/gemba/cli/commands/retro_achievements.rb +213 -0
- data/lib/gemba/cli/commands/version.rb +22 -0
- data/lib/gemba/cli.rb +52 -364
- data/lib/gemba/config.rb +134 -1
- data/lib/gemba/data/gb_games.json +1 -0
- data/lib/gemba/data/gb_md5.json +1 -0
- data/lib/gemba/data/gba_games.json +1 -0
- data/lib/gemba/data/gba_md5.json +1 -0
- data/lib/gemba/data/gbc_games.json +1 -0
- data/lib/gemba/data/gbc_md5.json +1 -0
- data/lib/gemba/emulator_frame.rb +1060 -0
- data/lib/gemba/event_bus.rb +48 -0
- data/lib/gemba/frame_stack.rb +60 -0
- data/lib/gemba/game_index.rb +84 -0
- data/lib/gemba/game_picker_frame.rb +268 -0
- data/lib/gemba/gamepad_map.rb +103 -0
- data/lib/gemba/headless.rb +6 -5
- data/lib/gemba/headless_player.rb +33 -3
- data/lib/gemba/help_window.rb +61 -0
- data/lib/gemba/hotkey_map.rb +3 -1
- data/lib/gemba/input_recorder.rb +107 -0
- data/lib/gemba/input_replayer.rb +119 -0
- data/lib/gemba/keyboard_map.rb +90 -0
- data/lib/gemba/locales/en.yml +97 -5
- data/lib/gemba/locales/ja.yml +97 -5
- data/lib/gemba/main_window.rb +56 -0
- data/lib/gemba/modal_stack.rb +81 -0
- data/lib/gemba/patcher_window.rb +223 -0
- data/lib/gemba/platform/gb.rb +21 -0
- data/lib/gemba/platform/gba.rb +21 -0
- data/lib/gemba/platform/gbc.rb +23 -0
- data/lib/gemba/platform.rb +20 -0
- data/lib/gemba/platform_open.rb +19 -0
- data/lib/gemba/recorder.rb +4 -3
- data/lib/gemba/replay_player.rb +691 -0
- data/lib/gemba/rom_info.rb +57 -0
- data/lib/gemba/rom_info_window.rb +16 -3
- data/lib/gemba/rom_library.rb +106 -0
- data/lib/gemba/rom_overrides.rb +47 -0
- data/lib/gemba/rom_patcher/bps.rb +161 -0
- data/lib/gemba/rom_patcher/ips.rb +101 -0
- data/lib/gemba/rom_patcher/ups.rb +118 -0
- data/lib/gemba/rom_patcher.rb +109 -0
- data/lib/gemba/{rom_loader.rb → rom_resolver.rb} +7 -6
- data/lib/gemba/runtime.rb +59 -26
- data/lib/gemba/save_state_manager.rb +4 -7
- data/lib/gemba/save_state_picker.rb +17 -4
- data/lib/gemba/session_logger.rb +64 -0
- data/lib/gemba/settings/audio_tab.rb +77 -0
- data/lib/gemba/settings/gamepad_tab.rb +351 -0
- data/lib/gemba/settings/hotkeys_tab.rb +259 -0
- data/lib/gemba/settings/paths.rb +11 -0
- data/lib/gemba/settings/recording_tab.rb +83 -0
- data/lib/gemba/settings/save_states_tab.rb +91 -0
- data/lib/gemba/settings/system_tab.rb +362 -0
- data/lib/gemba/settings/video_tab.rb +318 -0
- data/lib/gemba/settings_window.rb +162 -1036
- data/lib/gemba/version.rb +1 -1
- data/lib/gemba/virtual_keyboard.rb +19 -0
- data/lib/gemba.rb +2 -12
- data/test/achievements_window/test_bulk_sync.rb +218 -0
- data/test/achievements_window/test_bus_events.rb +125 -0
- data/test/achievements_window/test_close_confirmation.rb +201 -0
- data/test/achievements_window/test_initial_state.rb +164 -0
- data/test/achievements_window/test_sorting.rb +227 -0
- data/test/achievements_window/test_tree_rendering.rb +133 -0
- data/test/fixtures/fake_bios.bin +0 -0
- data/test/fixtures/pong.gba +0 -0
- data/test/fixtures/test.gb +0 -0
- data/test/fixtures/test.gbc +0 -0
- data/test/fixtures/test_quicksave.ss +0 -0
- data/test/screenshots/no_focus.png +0 -0
- data/test/shared/teek_test_worker.rb +17 -1
- data/test/shared/tk_test_helper.rb +91 -4
- data/test/support/achievements_window_helpers.rb +18 -0
- data/test/support/fake_core.rb +25 -0
- data/test/support/fake_ra_runtime.rb +74 -0
- data/test/support/fake_requester.rb +68 -0
- data/test/support/player_helpers.rb +20 -5
- data/test/test_achievement.rb +32 -0
- data/test/{test_player.rb → test_app_controller.rb} +353 -85
- data/test/test_bios.rb +123 -0
- data/test/test_boxart_fetcher.rb +150 -0
- data/test/test_cli.rb +17 -265
- data/test/test_cli_config.rb +64 -0
- data/test/test_cli_decode.rb +97 -0
- data/test/test_cli_patch.rb +58 -0
- data/test/test_cli_play.rb +213 -0
- data/test/test_cli_ra.rb +175 -0
- data/test/test_cli_record.rb +69 -0
- data/test/test_cli_replay.rb +72 -0
- data/test/test_cli_sync_requester.rb +152 -0
- data/test/test_cli_version.rb +27 -0
- data/test/test_config.rb +2 -3
- data/test/test_config_ra.rb +69 -0
- data/test/test_core.rb +62 -1
- data/test/test_credentials_presenter.rb +192 -0
- data/test/test_event_bus.rb +100 -0
- data/test/test_fake_backend_achievements.rb +130 -0
- data/test/test_fake_backend_auth.rb +68 -0
- data/test/test_game_index.rb +77 -0
- data/test/test_game_picker_frame.rb +310 -0
- data/test/test_gamepad_map.rb +1 -3
- data/test/test_headless_player.rb +17 -3
- data/test/test_help_window.rb +82 -0
- data/test/test_hotkey_map.rb +22 -1
- data/test/test_input_recorder.rb +179 -0
- data/test/test_input_replay_determinism.rb +113 -0
- data/test/test_input_replayer.rb +162 -0
- data/test/test_keyboard_map.rb +1 -3
- data/test/test_libretro_backend.rb +41 -0
- data/test/test_locale.rb +1 -1
- data/test/test_logging.rb +123 -0
- data/test/test_null_backend.rb +42 -0
- data/test/test_offline_backend.rb +116 -0
- data/test/test_overlay_renderer.rb +1 -1
- data/test/test_platform.rb +149 -0
- data/test/test_ra_backend.rb +313 -0
- data/test/test_ra_backend_unlock_gate.rb +56 -0
- data/test/test_recorder.rb +0 -3
- data/test/test_replay_player.rb +316 -0
- data/test/test_rom_info.rb +149 -0
- data/test/test_rom_overrides.rb +86 -0
- data/test/test_rom_patcher.rb +382 -0
- data/test/{test_rom_loader.rb → test_rom_resolver.rb} +25 -26
- data/test/test_save_state_manager.rb +2 -4
- data/test/test_settings_audio.rb +107 -0
- data/test/test_settings_hotkeys.rb +83 -66
- data/test/test_settings_recording.rb +49 -0
- data/test/test_settings_save_states.rb +97 -0
- data/test/test_settings_system.rb +133 -0
- data/test/test_settings_video.rb +450 -0
- data/test/test_settings_window.rb +76 -507
- data/test/test_tip_service.rb +6 -6
- data/test/test_toast_overlay.rb +1 -1
- data/test/test_virtual_events.rb +156 -0
- data/test/test_virtual_keyboard.rb +1 -1
- data/vendor/rcheevos/CHANGELOG.md +495 -0
- data/vendor/rcheevos/LICENSE +21 -0
- data/vendor/rcheevos/Package.swift +33 -0
- data/vendor/rcheevos/README.md +67 -0
- data/vendor/rcheevos/include/module.modulemap +70 -0
- data/vendor/rcheevos/include/rc_api_editor.h +296 -0
- data/vendor/rcheevos/include/rc_api_info.h +280 -0
- data/vendor/rcheevos/include/rc_api_request.h +77 -0
- data/vendor/rcheevos/include/rc_api_runtime.h +417 -0
- data/vendor/rcheevos/include/rc_api_user.h +262 -0
- data/vendor/rcheevos/include/rc_client.h +877 -0
- data/vendor/rcheevos/include/rc_client_raintegration.h +101 -0
- data/vendor/rcheevos/include/rc_consoles.h +138 -0
- data/vendor/rcheevos/include/rc_error.h +59 -0
- data/vendor/rcheevos/include/rc_export.h +100 -0
- data/vendor/rcheevos/include/rc_hash.h +200 -0
- data/vendor/rcheevos/include/rc_runtime.h +148 -0
- data/vendor/rcheevos/include/rc_runtime_types.h +452 -0
- data/vendor/rcheevos/include/rc_util.h +51 -0
- data/vendor/rcheevos/include/rcheevos.h +8 -0
- data/vendor/rcheevos/src/rapi/rc_api_common.c +1379 -0
- data/vendor/rcheevos/src/rapi/rc_api_common.h +88 -0
- data/vendor/rcheevos/src/rapi/rc_api_editor.c +625 -0
- data/vendor/rcheevos/src/rapi/rc_api_info.c +587 -0
- data/vendor/rcheevos/src/rapi/rc_api_runtime.c +901 -0
- data/vendor/rcheevos/src/rapi/rc_api_user.c +483 -0
- data/vendor/rcheevos/src/rc_client.c +6941 -0
- data/vendor/rcheevos/src/rc_client_external.c +281 -0
- data/vendor/rcheevos/src/rc_client_external.h +177 -0
- data/vendor/rcheevos/src/rc_client_external_versions.h +171 -0
- data/vendor/rcheevos/src/rc_client_internal.h +409 -0
- data/vendor/rcheevos/src/rc_client_raintegration.c +566 -0
- data/vendor/rcheevos/src/rc_client_raintegration_internal.h +61 -0
- data/vendor/rcheevos/src/rc_client_types.natvis +396 -0
- data/vendor/rcheevos/src/rc_compat.c +251 -0
- data/vendor/rcheevos/src/rc_compat.h +121 -0
- data/vendor/rcheevos/src/rc_libretro.c +915 -0
- data/vendor/rcheevos/src/rc_libretro.h +98 -0
- data/vendor/rcheevos/src/rc_util.c +199 -0
- data/vendor/rcheevos/src/rc_version.c +11 -0
- data/vendor/rcheevos/src/rc_version.h +32 -0
- data/vendor/rcheevos/src/rcheevos/alloc.c +312 -0
- data/vendor/rcheevos/src/rcheevos/condition.c +754 -0
- data/vendor/rcheevos/src/rcheevos/condset.c +777 -0
- data/vendor/rcheevos/src/rcheevos/consoleinfo.c +1215 -0
- data/vendor/rcheevos/src/rcheevos/format.c +330 -0
- data/vendor/rcheevos/src/rcheevos/lboard.c +287 -0
- data/vendor/rcheevos/src/rcheevos/memref.c +805 -0
- data/vendor/rcheevos/src/rcheevos/operand.c +607 -0
- data/vendor/rcheevos/src/rcheevos/rc_internal.h +390 -0
- data/vendor/rcheevos/src/rcheevos/rc_runtime_types.natvis +541 -0
- data/vendor/rcheevos/src/rcheevos/rc_validate.c +1406 -0
- data/vendor/rcheevos/src/rcheevos/rc_validate.h +18 -0
- data/vendor/rcheevos/src/rcheevos/richpresence.c +922 -0
- data/vendor/rcheevos/src/rcheevos/runtime.c +852 -0
- data/vendor/rcheevos/src/rcheevos/runtime_progress.c +1073 -0
- data/vendor/rcheevos/src/rcheevos/trigger.c +344 -0
- data/vendor/rcheevos/src/rcheevos/value.c +935 -0
- data/vendor/rcheevos/src/rhash/aes.c +480 -0
- data/vendor/rcheevos/src/rhash/aes.h +49 -0
- data/vendor/rcheevos/src/rhash/cdreader.c +838 -0
- data/vendor/rcheevos/src/rhash/hash.c +1402 -0
- data/vendor/rcheevos/src/rhash/hash_disc.c +1340 -0
- data/vendor/rcheevos/src/rhash/hash_encrypted.c +566 -0
- data/vendor/rcheevos/src/rhash/hash_rom.c +426 -0
- data/vendor/rcheevos/src/rhash/hash_zip.c +460 -0
- data/vendor/rcheevos/src/rhash/md5.c +382 -0
- data/vendor/rcheevos/src/rhash/md5.h +91 -0
- data/vendor/rcheevos/src/rhash/rc_hash_internal.h +116 -0
- data/vendor/rcheevos/test/libretro.h +205 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_common.c +941 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_editor.c +931 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_info.c +545 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_runtime.c +2213 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_user.c +998 -0
- data/vendor/rcheevos/test/rcheevos/mock_memory.h +32 -0
- data/vendor/rcheevos/test/rcheevos/test_condition.c +570 -0
- data/vendor/rcheevos/test/rcheevos/test_condset.c +5170 -0
- data/vendor/rcheevos/test/rcheevos/test_consoleinfo.c +203 -0
- data/vendor/rcheevos/test/rcheevos/test_format.c +112 -0
- data/vendor/rcheevos/test/rcheevos/test_lboard.c +746 -0
- data/vendor/rcheevos/test/rcheevos/test_memref.c +520 -0
- data/vendor/rcheevos/test/rcheevos/test_operand.c +692 -0
- data/vendor/rcheevos/test/rcheevos/test_rc_validate.c +502 -0
- data/vendor/rcheevos/test/rcheevos/test_richpresence.c +1564 -0
- data/vendor/rcheevos/test/rcheevos/test_runtime.c +1667 -0
- data/vendor/rcheevos/test/rcheevos/test_runtime_progress.c +1821 -0
- data/vendor/rcheevos/test/rcheevos/test_timing.c +166 -0
- data/vendor/rcheevos/test/rcheevos/test_trigger.c +2521 -0
- data/vendor/rcheevos/test/rcheevos/test_value.c +870 -0
- data/vendor/rcheevos/test/rcheevos-test.sln +46 -0
- data/vendor/rcheevos/test/rcheevos-test.vcxproj +239 -0
- data/vendor/rcheevos/test/rcheevos-test.vcxproj.filters +335 -0
- data/vendor/rcheevos/test/rhash/data.c +657 -0
- data/vendor/rcheevos/test/rhash/data.h +32 -0
- data/vendor/rcheevos/test/rhash/mock_filereader.c +236 -0
- data/vendor/rcheevos/test/rhash/mock_filereader.h +31 -0
- data/vendor/rcheevos/test/rhash/test_cdreader.c +920 -0
- data/vendor/rcheevos/test/rhash/test_hash.c +310 -0
- data/vendor/rcheevos/test/rhash/test_hash_disc.c +1450 -0
- data/vendor/rcheevos/test/rhash/test_hash_rom.c +899 -0
- data/vendor/rcheevos/test/rhash/test_hash_zip.c +551 -0
- data/vendor/rcheevos/test/test.c +113 -0
- data/vendor/rcheevos/test/test_framework.h +205 -0
- data/vendor/rcheevos/test/test_rc_client.c +10509 -0
- data/vendor/rcheevos/test/test_rc_client_external.c +2197 -0
- data/vendor/rcheevos/test/test_rc_client_raintegration.c +441 -0
- data/vendor/rcheevos/test/test_rc_libretro.c +952 -0
- data/vendor/rcheevos/test/test_types.natvis +9 -0
- data/vendor/rcheevos/validator/validator.c +658 -0
- data/vendor/rcheevos/validator/validator.vcxproj +152 -0
- data/vendor/rcheevos/validator/validator.vcxproj.filters +82 -0
- metadata +274 -11
- data/lib/gemba/input_mappings.rb +0 -214
- data/lib/gemba/player.rb +0 -1525
|
@@ -0,0 +1,754 @@
|
|
|
1
|
+
#include "rc_internal.h"
|
|
2
|
+
|
|
3
|
+
#include <stdlib.h>
|
|
4
|
+
#include <string.h>
|
|
5
|
+
#include <assert.h>
|
|
6
|
+
|
|
7
|
+
static int rc_test_condition_compare(uint32_t value1, uint32_t value2, uint8_t oper) {
|
|
8
|
+
switch (oper) {
|
|
9
|
+
case RC_OPERATOR_EQ: return value1 == value2;
|
|
10
|
+
case RC_OPERATOR_NE: return value1 != value2;
|
|
11
|
+
case RC_OPERATOR_LT: return value1 < value2;
|
|
12
|
+
case RC_OPERATOR_LE: return value1 <= value2;
|
|
13
|
+
case RC_OPERATOR_GT: return value1 > value2;
|
|
14
|
+
case RC_OPERATOR_GE: return value1 >= value2;
|
|
15
|
+
default: return 1;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static uint8_t rc_condition_determine_comparator(const rc_condition_t* self) {
|
|
20
|
+
switch (self->oper) {
|
|
21
|
+
case RC_OPERATOR_EQ:
|
|
22
|
+
case RC_OPERATOR_NE:
|
|
23
|
+
case RC_OPERATOR_LT:
|
|
24
|
+
case RC_OPERATOR_LE:
|
|
25
|
+
case RC_OPERATOR_GT:
|
|
26
|
+
case RC_OPERATOR_GE:
|
|
27
|
+
break;
|
|
28
|
+
|
|
29
|
+
default:
|
|
30
|
+
/* not a comparison. should not be getting compared. but if it is, legacy behavior was to return 1 */
|
|
31
|
+
return RC_PROCESSING_COMPARE_ALWAYS_TRUE;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if ((self->operand1.type == RC_OPERAND_ADDRESS || self->operand1.type == RC_OPERAND_DELTA) &&
|
|
35
|
+
/* TODO: allow modified memref comparisons */
|
|
36
|
+
self->operand1.value.memref->value.memref_type == RC_MEMREF_TYPE_MEMREF && !rc_operand_is_float(&self->operand1)) {
|
|
37
|
+
/* left side is an integer memory reference */
|
|
38
|
+
int needs_translate = (self->operand1.size != self->operand1.value.memref->value.size);
|
|
39
|
+
|
|
40
|
+
if (self->operand2.type == RC_OPERAND_CONST) {
|
|
41
|
+
/* right side is a constant */
|
|
42
|
+
if (self->operand1.type == RC_OPERAND_ADDRESS)
|
|
43
|
+
return needs_translate ? RC_PROCESSING_COMPARE_MEMREF_TO_CONST_TRANSFORMED : RC_PROCESSING_COMPARE_MEMREF_TO_CONST;
|
|
44
|
+
|
|
45
|
+
return needs_translate ? RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED : RC_PROCESSING_COMPARE_DELTA_TO_CONST;
|
|
46
|
+
}
|
|
47
|
+
else if ((self->operand2.type == RC_OPERAND_ADDRESS || self->operand2.type == RC_OPERAND_DELTA) &&
|
|
48
|
+
self->operand2.value.memref->value.memref_type == RC_MEMREF_TYPE_MEMREF && !rc_operand_is_float(&self->operand2)) {
|
|
49
|
+
/* right side is an integer memory reference */
|
|
50
|
+
const int is_same_memref = (self->operand1.value.memref == self->operand2.value.memref);
|
|
51
|
+
needs_translate |= (self->operand2.size != self->operand2.value.memref->value.size);
|
|
52
|
+
|
|
53
|
+
if (self->operand1.type == RC_OPERAND_ADDRESS) {
|
|
54
|
+
if (self->operand2.type == RC_OPERAND_ADDRESS) {
|
|
55
|
+
if (is_same_memref && !needs_translate) {
|
|
56
|
+
/* comparing a memref to itself, will evaluate to a constant */
|
|
57
|
+
return rc_test_condition_compare(0, 0, self->oper) ? RC_PROCESSING_COMPARE_ALWAYS_TRUE : RC_PROCESSING_COMPARE_ALWAYS_FALSE;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return needs_translate ? RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF_TRANSFORMED : RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
assert(self->operand2.type == RC_OPERAND_DELTA);
|
|
64
|
+
|
|
65
|
+
if (is_same_memref) {
|
|
66
|
+
/* delta comparison is optimized to compare with itself (for detecting change) */
|
|
67
|
+
return needs_translate ? RC_PROCESSING_COMPARE_MEMREF_TO_DELTA_TRANSFORMED : RC_PROCESSING_COMPARE_MEMREF_TO_DELTA;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
assert(self->operand1.type == RC_OPERAND_DELTA);
|
|
72
|
+
|
|
73
|
+
if (self->operand2.type == RC_OPERAND_ADDRESS) {
|
|
74
|
+
if (is_same_memref) {
|
|
75
|
+
/* delta comparison is optimized to compare with itself (for detecting change) */
|
|
76
|
+
return needs_translate ? RC_PROCESSING_COMPARE_DELTA_TO_MEMREF_TRANSFORMED : RC_PROCESSING_COMPARE_DELTA_TO_MEMREF;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (self->operand1.type == RC_OPERAND_CONST && self->operand2.type == RC_OPERAND_CONST) {
|
|
84
|
+
/* comparing constants will always generate a constant result */
|
|
85
|
+
return rc_test_condition_compare(self->operand1.value.num, self->operand2.value.num, self->oper) ?
|
|
86
|
+
RC_PROCESSING_COMPARE_ALWAYS_TRUE : RC_PROCESSING_COMPARE_ALWAYS_FALSE;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return RC_PROCESSING_COMPARE_DEFAULT;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
static int rc_parse_operator(const char** memaddr) {
|
|
93
|
+
const char* oper = *memaddr;
|
|
94
|
+
|
|
95
|
+
switch (*oper) {
|
|
96
|
+
case '=':
|
|
97
|
+
++(*memaddr);
|
|
98
|
+
(*memaddr) += (**memaddr == '=');
|
|
99
|
+
return RC_OPERATOR_EQ;
|
|
100
|
+
|
|
101
|
+
case '!':
|
|
102
|
+
if (oper[1] == '=') {
|
|
103
|
+
(*memaddr) += 2;
|
|
104
|
+
return RC_OPERATOR_NE;
|
|
105
|
+
}
|
|
106
|
+
/* fall through */
|
|
107
|
+
default:
|
|
108
|
+
return RC_INVALID_OPERATOR;
|
|
109
|
+
|
|
110
|
+
case '<':
|
|
111
|
+
if (oper[1] == '=') {
|
|
112
|
+
(*memaddr) += 2;
|
|
113
|
+
return RC_OPERATOR_LE;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
++(*memaddr);
|
|
117
|
+
return RC_OPERATOR_LT;
|
|
118
|
+
|
|
119
|
+
case '>':
|
|
120
|
+
if (oper[1] == '=') {
|
|
121
|
+
(*memaddr) += 2;
|
|
122
|
+
return RC_OPERATOR_GE;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
++(*memaddr);
|
|
126
|
+
return RC_OPERATOR_GT;
|
|
127
|
+
|
|
128
|
+
case '*':
|
|
129
|
+
++(*memaddr);
|
|
130
|
+
return RC_OPERATOR_MULT;
|
|
131
|
+
|
|
132
|
+
case '/':
|
|
133
|
+
++(*memaddr);
|
|
134
|
+
return RC_OPERATOR_DIV;
|
|
135
|
+
|
|
136
|
+
case '&':
|
|
137
|
+
++(*memaddr);
|
|
138
|
+
return RC_OPERATOR_AND;
|
|
139
|
+
|
|
140
|
+
case '^':
|
|
141
|
+
++(*memaddr);
|
|
142
|
+
return RC_OPERATOR_XOR;
|
|
143
|
+
|
|
144
|
+
case '%':
|
|
145
|
+
++(*memaddr);
|
|
146
|
+
return RC_OPERATOR_MOD;
|
|
147
|
+
|
|
148
|
+
case '+':
|
|
149
|
+
++(*memaddr);
|
|
150
|
+
return RC_OPERATOR_ADD;
|
|
151
|
+
|
|
152
|
+
case '-':
|
|
153
|
+
++(*memaddr);
|
|
154
|
+
return RC_OPERATOR_SUB;
|
|
155
|
+
|
|
156
|
+
case '\0':/* end of string */
|
|
157
|
+
case '_': /* next condition */
|
|
158
|
+
case 'S': /* next condset */
|
|
159
|
+
case ')': /* end of macro */
|
|
160
|
+
case '$': /* maximum of values */
|
|
161
|
+
/* valid condition separator, condition may not have an operator */
|
|
162
|
+
return RC_OPERATOR_NONE;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
void rc_condition_convert_to_operand(const rc_condition_t* condition, rc_operand_t* operand, rc_parse_state_t* parse) {
|
|
167
|
+
if (condition->oper == RC_OPERATOR_NONE) {
|
|
168
|
+
if (operand != &condition->operand1)
|
|
169
|
+
memcpy(operand, &condition->operand1, sizeof(*operand));
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
uint8_t new_size = RC_MEMSIZE_32_BITS;
|
|
173
|
+
if (rc_operand_is_float(&condition->operand1) || rc_operand_is_float(&condition->operand2))
|
|
174
|
+
new_size = RC_MEMSIZE_FLOAT;
|
|
175
|
+
|
|
176
|
+
/* NOTE: this makes the operand include the modification, but we have to also
|
|
177
|
+
* leave the modification in the condition so the condition reflects the actual
|
|
178
|
+
* definition. This doesn't affect the evaluation logic since this method is only
|
|
179
|
+
* called for combining conditions and Measured, and the Measured handling function
|
|
180
|
+
* ignores the operator assuming it's been handled by a modified memref chain */
|
|
181
|
+
operand->value.memref = (rc_memref_t*)rc_alloc_modified_memref(parse,
|
|
182
|
+
new_size, &condition->operand1, condition->oper, &condition->operand2);
|
|
183
|
+
|
|
184
|
+
/* not actually an address, just a non-delta memref read */
|
|
185
|
+
operand->type = operand->memref_access_type = RC_OPERAND_ADDRESS;
|
|
186
|
+
|
|
187
|
+
operand->size = new_size;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse) {
|
|
192
|
+
rc_condition_t * self = RC_ALLOC(rc_condition_t, parse);
|
|
193
|
+
rc_parse_condition_internal(self, memaddr, parse);
|
|
194
|
+
return (parse->offset < 0) ? NULL : self;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
void rc_parse_condition_internal(rc_condition_t* self, const char** memaddr, rc_parse_state_t* parse) {
|
|
198
|
+
const char* aux;
|
|
199
|
+
int result;
|
|
200
|
+
int can_modify = 0;
|
|
201
|
+
|
|
202
|
+
aux = *memaddr;
|
|
203
|
+
self->current_hits = 0;
|
|
204
|
+
self->is_true = 0;
|
|
205
|
+
self->optimized_comparator = RC_PROCESSING_COMPARE_DEFAULT;
|
|
206
|
+
|
|
207
|
+
if (*aux != 0 && aux[1] == ':') {
|
|
208
|
+
switch (*aux) {
|
|
209
|
+
case 'p': case 'P': self->type = RC_CONDITION_PAUSE_IF; break;
|
|
210
|
+
case 'r': case 'R': self->type = RC_CONDITION_RESET_IF; break;
|
|
211
|
+
case 'a': case 'A': self->type = RC_CONDITION_ADD_SOURCE; can_modify = 1; break;
|
|
212
|
+
case 'b': case 'B': self->type = RC_CONDITION_SUB_SOURCE; can_modify = 1; break;
|
|
213
|
+
case 'c': case 'C': self->type = RC_CONDITION_ADD_HITS; break;
|
|
214
|
+
case 'd': case 'D': self->type = RC_CONDITION_SUB_HITS; break;
|
|
215
|
+
case 'n': case 'N': self->type = RC_CONDITION_AND_NEXT; break;
|
|
216
|
+
case 'o': case 'O': self->type = RC_CONDITION_OR_NEXT; break;
|
|
217
|
+
case 'm': case 'M': self->type = RC_CONDITION_MEASURED; break;
|
|
218
|
+
case 'q': case 'Q': self->type = RC_CONDITION_MEASURED_IF; break;
|
|
219
|
+
case 'i': case 'I': self->type = RC_CONDITION_ADD_ADDRESS; can_modify = 1; break;
|
|
220
|
+
case 't': case 'T': self->type = RC_CONDITION_TRIGGER; break;
|
|
221
|
+
case 'k': case 'K': self->type = RC_CONDITION_REMEMBER; can_modify = 1; break;
|
|
222
|
+
case 'z': case 'Z': self->type = RC_CONDITION_RESET_NEXT_IF; break;
|
|
223
|
+
case 'g': case 'G':
|
|
224
|
+
parse->measured_as_percent = 1;
|
|
225
|
+
self->type = RC_CONDITION_MEASURED;
|
|
226
|
+
break;
|
|
227
|
+
|
|
228
|
+
/* e f h j l s u v w x y */
|
|
229
|
+
default:
|
|
230
|
+
parse->offset = RC_INVALID_CONDITION_TYPE;
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
aux += 2;
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
self->type = RC_CONDITION_STANDARD;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
result = rc_parse_operand(&self->operand1, &aux, parse);
|
|
241
|
+
if (result < 0) {
|
|
242
|
+
parse->offset = result;
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
result = rc_parse_operator(&aux);
|
|
247
|
+
if (result < 0) {
|
|
248
|
+
parse->offset = result;
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
self->oper = (uint8_t)result;
|
|
253
|
+
|
|
254
|
+
if (self->oper == RC_OPERATOR_NONE) {
|
|
255
|
+
/* non-modifying statements must have a second operand */
|
|
256
|
+
if (!can_modify) {
|
|
257
|
+
/* measured does not require a second operand when used in a value */
|
|
258
|
+
if (self->type != RC_CONDITION_MEASURED && !parse->ignore_non_parse_errors) {
|
|
259
|
+
parse->offset = RC_INVALID_OPERATOR;
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/* provide dummy operand of '1' and no required hits */
|
|
265
|
+
rc_operand_set_const(&self->operand2, 1);
|
|
266
|
+
self->required_hits = 0;
|
|
267
|
+
*memaddr = aux;
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (can_modify && !rc_operator_is_modifying(self->oper)) {
|
|
272
|
+
/* comparison operators are not valid on modifying statements */
|
|
273
|
+
switch (self->type) {
|
|
274
|
+
case RC_CONDITION_ADD_SOURCE:
|
|
275
|
+
case RC_CONDITION_SUB_SOURCE:
|
|
276
|
+
case RC_CONDITION_ADD_ADDRESS:
|
|
277
|
+
/* prevent parse errors on legacy achievements where a condition was present before changing the type */
|
|
278
|
+
self->oper = RC_OPERATOR_NONE;
|
|
279
|
+
break;
|
|
280
|
+
|
|
281
|
+
default:
|
|
282
|
+
if (!parse->ignore_non_parse_errors) {
|
|
283
|
+
parse->offset = RC_INVALID_OPERATOR;
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
result = rc_parse_operand(&self->operand2, &aux, parse);
|
|
291
|
+
if (result < 0) {
|
|
292
|
+
parse->offset = result;
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (self->oper == RC_OPERATOR_NONE) {
|
|
297
|
+
/* if operator is none, explicitly clear out the right side */
|
|
298
|
+
rc_operand_set_const(&self->operand2, 0);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (*aux == '(') {
|
|
302
|
+
char* end;
|
|
303
|
+
self->required_hits = (unsigned)strtoul(++aux, &end, 10);
|
|
304
|
+
|
|
305
|
+
if (end == aux || *end != ')') {
|
|
306
|
+
parse->offset = RC_INVALID_REQUIRED_HITS;
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/* if operator is none, explicitly clear out the required hits */
|
|
311
|
+
if (self->oper == RC_OPERATOR_NONE)
|
|
312
|
+
self->required_hits = 0;
|
|
313
|
+
else
|
|
314
|
+
parse->has_required_hits = 1;
|
|
315
|
+
|
|
316
|
+
aux = end + 1;
|
|
317
|
+
}
|
|
318
|
+
else if (*aux == '.') {
|
|
319
|
+
char* end;
|
|
320
|
+
self->required_hits = (unsigned)strtoul(++aux, &end, 10);
|
|
321
|
+
|
|
322
|
+
if (end == aux || *end != '.') {
|
|
323
|
+
parse->offset = RC_INVALID_REQUIRED_HITS;
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/* if operator is none, explicitly clear out the required hits */
|
|
328
|
+
if (self->oper == RC_OPERATOR_NONE)
|
|
329
|
+
self->required_hits = 0;
|
|
330
|
+
else
|
|
331
|
+
parse->has_required_hits = 1;
|
|
332
|
+
|
|
333
|
+
aux = end + 1;
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
self->required_hits = 0;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (parse->buffer != 0)
|
|
340
|
+
self->optimized_comparator = rc_condition_determine_comparator(self);
|
|
341
|
+
|
|
342
|
+
*memaddr = aux;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
void rc_condition_update_parse_state(rc_condition_t* condition, rc_parse_state_t* parse) {
|
|
346
|
+
/* type of values in the chain are determined by the parent.
|
|
347
|
+
* the last element of a chain is determined by the operand
|
|
348
|
+
*
|
|
349
|
+
* 1 + 1.5 + 1.75 + 1.0 => (int)1 + (int)1 + (int)1 + (float)1 = (float)4.0
|
|
350
|
+
* 1.0 + 1.5 + 1.75 + 1.0 => (float)1.0 + (float)1.5 + (float)1.75 + (float)1.0 = (float)5.25
|
|
351
|
+
* 1.0 + 1.5 + 1.75 + 1 => (float)1.0 + (float)1.5 + (float)1.75 + (int)1 = (int)5
|
|
352
|
+
*/
|
|
353
|
+
|
|
354
|
+
switch (condition->type) {
|
|
355
|
+
case RC_CONDITION_ADD_ADDRESS:
|
|
356
|
+
if (condition->oper != RC_OPERAND_NONE)
|
|
357
|
+
rc_condition_convert_to_operand(condition, &parse->indirect_parent, parse);
|
|
358
|
+
else
|
|
359
|
+
memcpy(&parse->indirect_parent, &condition->operand1, sizeof(parse->indirect_parent));
|
|
360
|
+
|
|
361
|
+
break;
|
|
362
|
+
|
|
363
|
+
case RC_CONDITION_ADD_SOURCE:
|
|
364
|
+
if (parse->addsource_parent.type == RC_OPERAND_NONE) {
|
|
365
|
+
rc_condition_convert_to_operand(condition, &parse->addsource_parent, parse);
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
rc_operand_t cond_operand;
|
|
369
|
+
/* type determined by parent */
|
|
370
|
+
const uint8_t new_size = rc_operand_is_float(&parse->addsource_parent) ? RC_MEMSIZE_FLOAT : RC_MEMSIZE_32_BITS;
|
|
371
|
+
|
|
372
|
+
rc_condition_convert_to_operand(condition, &cond_operand, parse);
|
|
373
|
+
rc_operand_addsource(&cond_operand, parse, new_size);
|
|
374
|
+
memcpy(&parse->addsource_parent, &cond_operand, sizeof(cond_operand));
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
parse->addsource_oper = RC_OPERATOR_ADD_ACCUMULATOR;
|
|
378
|
+
parse->indirect_parent.type = RC_OPERAND_NONE;
|
|
379
|
+
break;
|
|
380
|
+
|
|
381
|
+
case RC_CONDITION_SUB_SOURCE:
|
|
382
|
+
if (parse->addsource_parent.type == RC_OPERAND_NONE) {
|
|
383
|
+
rc_condition_convert_to_operand(condition, &parse->addsource_parent, parse);
|
|
384
|
+
parse->addsource_oper = RC_OPERATOR_SUB_PARENT;
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
rc_operand_t cond_operand;
|
|
388
|
+
/* type determined by parent */
|
|
389
|
+
const uint8_t new_size = rc_operand_is_float(&parse->addsource_parent) ? RC_MEMSIZE_FLOAT : RC_MEMSIZE_32_BITS;
|
|
390
|
+
|
|
391
|
+
if (parse->addsource_oper == RC_OPERATOR_ADD_ACCUMULATOR && !rc_operand_is_memref(&parse->addsource_parent)) {
|
|
392
|
+
/* if the previous element was a constant we have to turn it into a memref by adding zero */
|
|
393
|
+
rc_modified_memref_t* memref;
|
|
394
|
+
rc_operand_t zero;
|
|
395
|
+
rc_operand_set_const(&zero, 0);
|
|
396
|
+
memref = rc_alloc_modified_memref(parse,
|
|
397
|
+
parse->addsource_parent.size, &parse->addsource_parent, RC_OPERATOR_ADD_ACCUMULATOR, &zero);
|
|
398
|
+
parse->addsource_parent.value.memref = (rc_memref_t*)memref;
|
|
399
|
+
parse->addsource_parent.type = RC_OPERAND_ADDRESS;
|
|
400
|
+
}
|
|
401
|
+
else if (parse->addsource_oper == RC_OPERATOR_SUB_PARENT) {
|
|
402
|
+
/* if the previous element was also a SubSource, we have to insert a 0 and start subtracting from there */
|
|
403
|
+
rc_modified_memref_t* negate;
|
|
404
|
+
rc_operand_t zero;
|
|
405
|
+
|
|
406
|
+
if (rc_operand_is_float(&parse->addsource_parent))
|
|
407
|
+
rc_operand_set_float_const(&zero, 0.0);
|
|
408
|
+
else
|
|
409
|
+
rc_operand_set_const(&zero, 0);
|
|
410
|
+
|
|
411
|
+
negate = rc_alloc_modified_memref(parse, new_size, &parse->addsource_parent, RC_OPERATOR_SUB_PARENT, &zero);
|
|
412
|
+
parse->addsource_parent.value.memref = (rc_memref_t*)negate;
|
|
413
|
+
parse->addsource_parent.size = zero.size;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/* subtract the condition from the chain */
|
|
417
|
+
parse->addsource_oper = rc_operand_is_memref(&parse->addsource_parent) ? RC_OPERATOR_SUB_ACCUMULATOR : RC_OPERATOR_SUB_PARENT;
|
|
418
|
+
rc_condition_convert_to_operand(condition, &cond_operand, parse);
|
|
419
|
+
rc_operand_addsource(&cond_operand, parse, new_size);
|
|
420
|
+
memcpy(&parse->addsource_parent, &cond_operand, sizeof(cond_operand));
|
|
421
|
+
|
|
422
|
+
/* indicate the next value can be added to the chain */
|
|
423
|
+
parse->addsource_oper = RC_OPERATOR_ADD_ACCUMULATOR;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
parse->indirect_parent.type = RC_OPERAND_NONE;
|
|
427
|
+
break;
|
|
428
|
+
|
|
429
|
+
case RC_CONDITION_REMEMBER:
|
|
430
|
+
if (condition->operand1.type == RC_OPERAND_RECALL &&
|
|
431
|
+
condition->oper == RC_OPERATOR_NONE &&
|
|
432
|
+
parse->addsource_parent.type == RC_OPERAND_NONE &&
|
|
433
|
+
parse->indirect_parent.type == RC_OPERAND_NONE) {
|
|
434
|
+
/* Remembering {recall} without any modifications is a no-op */
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
rc_condition_convert_to_operand(condition, &condition->operand1, parse);
|
|
439
|
+
|
|
440
|
+
if (parse->addsource_parent.type != RC_OPERAND_NONE) {
|
|
441
|
+
/* type determined by leaf */
|
|
442
|
+
rc_operand_addsource(&condition->operand1, parse, condition->operand1.size);
|
|
443
|
+
condition->operand1.is_combining = 1;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
memcpy(&parse->remember, &condition->operand1, sizeof(parse->remember));
|
|
447
|
+
|
|
448
|
+
parse->addsource_parent.type = RC_OPERAND_NONE;
|
|
449
|
+
parse->indirect_parent.type = RC_OPERAND_NONE;
|
|
450
|
+
break;
|
|
451
|
+
|
|
452
|
+
case RC_CONDITION_MEASURED:
|
|
453
|
+
/* Measured condition can have modifiers in values */
|
|
454
|
+
if (parse->is_value) {
|
|
455
|
+
switch (condition->oper) {
|
|
456
|
+
case RC_OPERATOR_AND:
|
|
457
|
+
case RC_OPERATOR_XOR:
|
|
458
|
+
case RC_OPERATOR_DIV:
|
|
459
|
+
case RC_OPERATOR_MULT:
|
|
460
|
+
case RC_OPERATOR_MOD:
|
|
461
|
+
case RC_OPERATOR_ADD:
|
|
462
|
+
case RC_OPERATOR_SUB:
|
|
463
|
+
rc_condition_convert_to_operand(condition, &condition->operand1, parse);
|
|
464
|
+
break;
|
|
465
|
+
|
|
466
|
+
default:
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/* fallthrough */ /* to default */
|
|
472
|
+
|
|
473
|
+
default:
|
|
474
|
+
if (parse->addsource_parent.type != RC_OPERAND_NONE) {
|
|
475
|
+
/* type determined by leaf */
|
|
476
|
+
if (parse->addsource_oper == RC_OPERATOR_ADD_ACCUMULATOR)
|
|
477
|
+
parse->addsource_oper = RC_OPERATOR_ADD;
|
|
478
|
+
|
|
479
|
+
rc_operand_addsource(&condition->operand1, parse, condition->operand1.size);
|
|
480
|
+
condition->operand1.is_combining = 1;
|
|
481
|
+
|
|
482
|
+
if (parse->buffer)
|
|
483
|
+
condition->optimized_comparator = rc_condition_determine_comparator(condition);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
parse->addsource_parent.type = RC_OPERAND_NONE;
|
|
487
|
+
parse->indirect_parent.type = RC_OPERAND_NONE;
|
|
488
|
+
break;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
static const rc_modified_memref_t* rc_operand_get_modified_memref(const rc_operand_t* operand) {
|
|
493
|
+
if (!rc_operand_is_memref(operand))
|
|
494
|
+
return NULL;
|
|
495
|
+
|
|
496
|
+
if (operand->value.memref->value.memref_type != RC_MEMREF_TYPE_MODIFIED_MEMREF)
|
|
497
|
+
return NULL;
|
|
498
|
+
|
|
499
|
+
return (rc_modified_memref_t*)operand->value.memref;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/* rc_condition_update_parse_state will mutate the operand1 to point at the modified memref
|
|
503
|
+
* containing the accumulated result up until that point. this function returns the original
|
|
504
|
+
* unmodified operand1 from parsing the definition.
|
|
505
|
+
*/
|
|
506
|
+
const rc_operand_t* rc_condition_get_real_operand1(const rc_condition_t* self) {
|
|
507
|
+
const rc_operand_t* operand = &self->operand1;
|
|
508
|
+
const rc_modified_memref_t* modified_memref;
|
|
509
|
+
|
|
510
|
+
if (operand->is_combining) {
|
|
511
|
+
/* operand = "previous + current" - extract current */
|
|
512
|
+
const rc_modified_memref_t* combining_modified_memref = rc_operand_get_modified_memref(operand);
|
|
513
|
+
if (combining_modified_memref)
|
|
514
|
+
operand = &combining_modified_memref->modifier;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/* modifying operators are merged into an rc_modified_memref_t
|
|
518
|
+
* if operand1 is a modified memref, assume it's been merged with the right side and
|
|
519
|
+
* extract the parent which is the actual operand1. */
|
|
520
|
+
modified_memref = rc_operand_get_modified_memref(operand);
|
|
521
|
+
if (modified_memref) {
|
|
522
|
+
if (modified_memref->modifier_type == RC_OPERATOR_INDIRECT_READ) {
|
|
523
|
+
/* if the modified memref is an indirect read, the parent is the indirect
|
|
524
|
+
* address and the modifier is the offset. the actual size and address are
|
|
525
|
+
* stored in the modified memref - use it */
|
|
526
|
+
} else if (rc_operator_is_modifying(self->oper) && self->oper != RC_OPERATOR_NONE) {
|
|
527
|
+
/* operand = "parent*modifier" - extract parent.modifier will already be in operand2 */
|
|
528
|
+
operand = &modified_memref->parent;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return operand;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
int rc_condition_is_combining(const rc_condition_t* self) {
|
|
536
|
+
switch (self->type) {
|
|
537
|
+
case RC_CONDITION_STANDARD:
|
|
538
|
+
case RC_CONDITION_PAUSE_IF:
|
|
539
|
+
case RC_CONDITION_RESET_IF:
|
|
540
|
+
case RC_CONDITION_MEASURED_IF:
|
|
541
|
+
case RC_CONDITION_TRIGGER:
|
|
542
|
+
case RC_CONDITION_MEASURED:
|
|
543
|
+
return 0;
|
|
544
|
+
|
|
545
|
+
default:
|
|
546
|
+
return 1;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
static int rc_test_condition_compare_memref_to_const(rc_condition_t* self) {
|
|
551
|
+
const uint32_t value1 = self->operand1.value.memref->value.value;
|
|
552
|
+
const uint32_t value2 = self->operand2.value.num;
|
|
553
|
+
assert(self->operand1.size == self->operand1.value.memref->value.size);
|
|
554
|
+
return rc_test_condition_compare(value1, value2, self->oper);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
static int rc_test_condition_compare_delta_to_const(rc_condition_t* self) {
|
|
558
|
+
const rc_memref_value_t* memref1 = &self->operand1.value.memref->value;
|
|
559
|
+
const uint32_t value1 = (memref1->changed) ? memref1->prior : memref1->value;
|
|
560
|
+
const uint32_t value2 = self->operand2.value.num;
|
|
561
|
+
assert(self->operand1.size == self->operand1.value.memref->value.size);
|
|
562
|
+
return rc_test_condition_compare(value1, value2, self->oper);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
static int rc_test_condition_compare_memref_to_memref(rc_condition_t* self) {
|
|
566
|
+
const uint32_t value1 = self->operand1.value.memref->value.value;
|
|
567
|
+
const uint32_t value2 = self->operand2.value.memref->value.value;
|
|
568
|
+
assert(self->operand1.size == self->operand1.value.memref->value.size);
|
|
569
|
+
assert(self->operand2.size == self->operand2.value.memref->value.size);
|
|
570
|
+
return rc_test_condition_compare(value1, value2, self->oper);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
static int rc_test_condition_compare_memref_to_delta(rc_condition_t* self) {
|
|
574
|
+
const rc_memref_value_t* memref = &self->operand1.value.memref->value;
|
|
575
|
+
assert(self->operand1.value.memref == self->operand2.value.memref);
|
|
576
|
+
assert(self->operand1.size == self->operand1.value.memref->value.size);
|
|
577
|
+
assert(self->operand2.size == self->operand2.value.memref->value.size);
|
|
578
|
+
|
|
579
|
+
if (memref->changed)
|
|
580
|
+
return rc_test_condition_compare(memref->value, memref->prior, self->oper);
|
|
581
|
+
|
|
582
|
+
switch (self->oper) {
|
|
583
|
+
case RC_OPERATOR_EQ:
|
|
584
|
+
case RC_OPERATOR_GE:
|
|
585
|
+
case RC_OPERATOR_LE:
|
|
586
|
+
return 1;
|
|
587
|
+
|
|
588
|
+
default:
|
|
589
|
+
return 0;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
static int rc_test_condition_compare_delta_to_memref(rc_condition_t* self) {
|
|
594
|
+
const rc_memref_value_t* memref = &self->operand1.value.memref->value;
|
|
595
|
+
assert(self->operand1.value.memref == self->operand2.value.memref);
|
|
596
|
+
assert(self->operand1.size == self->operand1.value.memref->value.size);
|
|
597
|
+
assert(self->operand2.size == self->operand2.value.memref->value.size);
|
|
598
|
+
|
|
599
|
+
if (memref->changed)
|
|
600
|
+
return rc_test_condition_compare(memref->prior, memref->value, self->oper);
|
|
601
|
+
|
|
602
|
+
switch (self->oper) {
|
|
603
|
+
case RC_OPERATOR_EQ:
|
|
604
|
+
case RC_OPERATOR_GE:
|
|
605
|
+
case RC_OPERATOR_LE:
|
|
606
|
+
return 1;
|
|
607
|
+
|
|
608
|
+
default:
|
|
609
|
+
return 0;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
static int rc_test_condition_compare_memref_to_const_transformed(rc_condition_t* self) {
|
|
614
|
+
rc_typed_value_t value1;
|
|
615
|
+
const uint32_t value2 = self->operand2.value.num;
|
|
616
|
+
|
|
617
|
+
value1.type = RC_VALUE_TYPE_UNSIGNED;
|
|
618
|
+
value1.value.u32 = self->operand1.value.memref->value.value;
|
|
619
|
+
rc_transform_memref_value(&value1, self->operand1.size);
|
|
620
|
+
|
|
621
|
+
return rc_test_condition_compare(value1.value.u32, value2, self->oper);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
static int rc_test_condition_compare_delta_to_const_transformed(rc_condition_t* self) {
|
|
625
|
+
rc_typed_value_t value1;
|
|
626
|
+
const rc_memref_value_t* memref1 = &self->operand1.value.memref->value;
|
|
627
|
+
const uint32_t value2 = self->operand2.value.num;
|
|
628
|
+
|
|
629
|
+
value1.type = RC_VALUE_TYPE_UNSIGNED;
|
|
630
|
+
value1.value.u32 = (memref1->changed) ? memref1->prior : memref1->value;
|
|
631
|
+
rc_transform_memref_value(&value1, self->operand1.size);
|
|
632
|
+
|
|
633
|
+
return rc_test_condition_compare(value1.value.u32, value2, self->oper);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
static int rc_test_condition_compare_memref_to_memref_transformed(rc_condition_t* self) {
|
|
637
|
+
rc_typed_value_t value1, value2;
|
|
638
|
+
|
|
639
|
+
value1.type = RC_VALUE_TYPE_UNSIGNED;
|
|
640
|
+
value1.value.u32 = self->operand1.value.memref->value.value;
|
|
641
|
+
rc_transform_memref_value(&value1, self->operand1.size);
|
|
642
|
+
|
|
643
|
+
value2.type = RC_VALUE_TYPE_UNSIGNED;
|
|
644
|
+
value2.value.u32 = self->operand2.value.memref->value.value;
|
|
645
|
+
rc_transform_memref_value(&value2, self->operand2.size);
|
|
646
|
+
|
|
647
|
+
return rc_test_condition_compare(value1.value.u32, value2.value.u32, self->oper);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
static int rc_test_condition_compare_memref_to_delta_transformed(rc_condition_t* self) {
|
|
651
|
+
const rc_memref_value_t* memref = &self->operand1.value.memref->value;
|
|
652
|
+
assert(self->operand1.value.memref == self->operand2.value.memref);
|
|
653
|
+
|
|
654
|
+
if (memref->changed) {
|
|
655
|
+
rc_typed_value_t value1, value2;
|
|
656
|
+
|
|
657
|
+
value1.type = RC_VALUE_TYPE_UNSIGNED;
|
|
658
|
+
value1.value.u32 = memref->value;
|
|
659
|
+
rc_transform_memref_value(&value1, self->operand1.size);
|
|
660
|
+
|
|
661
|
+
value2.type = RC_VALUE_TYPE_UNSIGNED;
|
|
662
|
+
value2.value.u32 = memref->prior;
|
|
663
|
+
rc_transform_memref_value(&value2, self->operand2.size);
|
|
664
|
+
|
|
665
|
+
return rc_test_condition_compare(value1.value.u32, value2.value.u32, self->oper);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
switch (self->oper) {
|
|
669
|
+
case RC_OPERATOR_EQ:
|
|
670
|
+
case RC_OPERATOR_GE:
|
|
671
|
+
case RC_OPERATOR_LE:
|
|
672
|
+
return 1;
|
|
673
|
+
|
|
674
|
+
default:
|
|
675
|
+
return 0;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
static int rc_test_condition_compare_delta_to_memref_transformed(rc_condition_t* self) {
|
|
680
|
+
const rc_memref_value_t* memref = &self->operand1.value.memref->value;
|
|
681
|
+
assert(self->operand1.value.memref == self->operand2.value.memref);
|
|
682
|
+
|
|
683
|
+
if (memref->changed) {
|
|
684
|
+
rc_typed_value_t value1, value2;
|
|
685
|
+
|
|
686
|
+
value1.type = RC_VALUE_TYPE_UNSIGNED;
|
|
687
|
+
value1.value.u32 = memref->prior;
|
|
688
|
+
rc_transform_memref_value(&value1, self->operand1.size);
|
|
689
|
+
|
|
690
|
+
value2.type = RC_VALUE_TYPE_UNSIGNED;
|
|
691
|
+
value2.value.u32 = memref->value;
|
|
692
|
+
rc_transform_memref_value(&value2, self->operand2.size);
|
|
693
|
+
|
|
694
|
+
return rc_test_condition_compare(value1.value.u32, value2.value.u32, self->oper);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
switch (self->oper) {
|
|
698
|
+
case RC_OPERATOR_EQ:
|
|
699
|
+
case RC_OPERATOR_GE:
|
|
700
|
+
case RC_OPERATOR_LE:
|
|
701
|
+
return 1;
|
|
702
|
+
|
|
703
|
+
default:
|
|
704
|
+
return 0;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state) {
|
|
709
|
+
rc_typed_value_t value1, value2;
|
|
710
|
+
|
|
711
|
+
/* use an optimized comparator whenever possible */
|
|
712
|
+
switch (self->optimized_comparator) {
|
|
713
|
+
case RC_PROCESSING_COMPARE_MEMREF_TO_CONST:
|
|
714
|
+
return rc_test_condition_compare_memref_to_const(self);
|
|
715
|
+
case RC_PROCESSING_COMPARE_MEMREF_TO_DELTA:
|
|
716
|
+
return rc_test_condition_compare_memref_to_delta(self);
|
|
717
|
+
case RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF:
|
|
718
|
+
return rc_test_condition_compare_memref_to_memref(self);
|
|
719
|
+
case RC_PROCESSING_COMPARE_DELTA_TO_CONST:
|
|
720
|
+
return rc_test_condition_compare_delta_to_const(self);
|
|
721
|
+
case RC_PROCESSING_COMPARE_DELTA_TO_MEMREF:
|
|
722
|
+
return rc_test_condition_compare_delta_to_memref(self);
|
|
723
|
+
case RC_PROCESSING_COMPARE_MEMREF_TO_CONST_TRANSFORMED:
|
|
724
|
+
return rc_test_condition_compare_memref_to_const_transformed(self);
|
|
725
|
+
case RC_PROCESSING_COMPARE_MEMREF_TO_DELTA_TRANSFORMED:
|
|
726
|
+
return rc_test_condition_compare_memref_to_delta_transformed(self);
|
|
727
|
+
case RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF_TRANSFORMED:
|
|
728
|
+
return rc_test_condition_compare_memref_to_memref_transformed(self);
|
|
729
|
+
case RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED:
|
|
730
|
+
return rc_test_condition_compare_delta_to_const_transformed(self);
|
|
731
|
+
case RC_PROCESSING_COMPARE_DELTA_TO_MEMREF_TRANSFORMED:
|
|
732
|
+
return rc_test_condition_compare_delta_to_memref_transformed(self);
|
|
733
|
+
case RC_PROCESSING_COMPARE_ALWAYS_TRUE:
|
|
734
|
+
return 1;
|
|
735
|
+
case RC_PROCESSING_COMPARE_ALWAYS_FALSE:
|
|
736
|
+
return 0;
|
|
737
|
+
default:
|
|
738
|
+
rc_evaluate_operand(&value1, &self->operand1, eval_state);
|
|
739
|
+
break;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
rc_evaluate_operand(&value2, &self->operand2, eval_state);
|
|
743
|
+
|
|
744
|
+
return rc_typed_value_compare(&value1, &value2, self->oper);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
void rc_evaluate_condition_value(rc_typed_value_t* value, rc_condition_t* self, rc_eval_state_t* eval_state) {
|
|
748
|
+
rc_typed_value_t amount;
|
|
749
|
+
|
|
750
|
+
rc_evaluate_operand(value, &self->operand1, eval_state);
|
|
751
|
+
rc_evaluate_operand(&amount, &self->operand2, eval_state);
|
|
752
|
+
|
|
753
|
+
rc_typed_value_combine(value, &amount, self->oper);
|
|
754
|
+
}
|