/* * Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include "story.h" #include "state.h" #include "opcodes.h" #include "oc_call.h" #include "oc_compare.h" #include "oc_input.h" #include "oc_math.h" #include "oc_memory.h" #include "oc_misc.h" #include "oc_object.h" #include "oc_output.h" #include "oc_save.h" #include "oc_window.h" // Macros to declare implemented opcodes. #ifdef DEBUGGING #define OP(num, name) __state.opcodes[num] = opcodes_##name; __state.opcodesName[num] = #name #define OPX(num, name) __state.extOpcodes[num] = opcodes_ext_##name; __state.extOpcodes[num] = #name #else #define OP(num, name) __state.opcodes[num] = opcodes_##name #define OPX(num, name) __state.extOpcodes[num] = opcodes_ext_##name #endif // Macros to declare un-implemented opcodes. #define mOP(num, name) #define mOPX(num, name) void opcodesBuiltInitialTable(void) { // 2-operand instructions... OP(1, je); OP(2, jl); OP(3, jg); OP(4, dec_chk); OP(5, inc_chk); OP(6, jin); OP(7, test); OP(8, or); OP(9, and); OP(10, test_attr); OP(11, set_attr); OP(12, clear_attr); OP(13, store); OP(14, insert_obj); OP(15, loadw); OP(16, loadb); OP(17, get_prop); OP(18, get_prop_addr); OP(19, get_next_prop); OP(20, add); OP(21, sub); OP(22, mul); OP(23, div); OP(24, mod); // 1-operand instructions... OP(128, jz); OP(129, get_sibling); OP(130, get_child); OP(131, get_parent); OP(132, get_prop_len); OP(133, inc); OP(134, dec); OP(135, print_addr); OP(137, remove_obj); OP(138, print_obj); OP(139, ret); OP(140, jump); OP(141, print_paddr); OP(142, load); OP(143, not); // 0-operand instructions... OP(176, rtrue); OP(177, rfalse); OP(178, print); OP(179, print_ret); OP(180, nop); OP(181, save); OP(182, restore); OP(183, restart); OP(184, ret_popped); OP(185, pop); OP(186, quit); OP(187, new_line); // variable operand instructions... OP(224, call); OP(225, storew); OP(226, storeb); OP(227, put_prop); OP(228, read); OP(229, print_char); OP(230, print_num); OP(231, random); OP(232, push); OP(233, pull); if (storyVersion() < 3) return; mOP(188, show_status); OP(189, verify); mOP(234, split_window); mOP(235, set_window); mOP(243, output_stream); mOP(244, input_stream); mOP(245, sound_effect); if (storyVersion() < 4) return; // show_status is illegal in ver4+, but a build of Wishbringer // accidentally calls it, so always treat it as NOP instead. mOP(188, opcode_nop); mOP(25, call_2s); mOP(180, save_ver4); mOP(224, call_vs); mOP(228, sread_ver4); mOP(236, call_vs2); mOP(237, erase_window); mOP(238, erase_line); mOP(239, set_cursor); mOP(240, get_cursor); mOP(241, set_text_style); mOP(242, buffer_mode); mOP(246, read_char); mOP(247, scan_table); if (storyVersion() < 5) return; mOP(26, call_2n); mOP(27, set_color); mOP(28, throw); mOP(136, call_1s); mOP(143, call_1n); mOP(185, catch); mOP(191, piracy); mOP(228, aread); mOP(243, output_stream_ver5); mOP(245, sound_effect_ver5); mOP(248, not_ver5); mOP(249, call_vn); mOP(250, call_vn2); mOP(251, tokenise); mOP(252, encode_text); mOP(253, copy_table); mOP(254, print_table); mOP(255, check_arg_count); // this is the "save" and "restore" opcodes in ver1-4; illegal in ver5+. // in ver5+, they use extended opcodes 0 and 1 for these. __state.opcodes[180] = 0; __state.opcodes[181] = 0; #ifdef DEBUGGING __state.opcodesName[180] = 0; __state.opcodesName[181] = 0; #endif // extended opcodes in ver5+ ... mOPX(0, save_ext); mOPX(1, restore_ext); mOPX(2, log_shift); mOPX(3, art_shift); mOPX(4, set_font); mOPX(9, save_undo); mOPX(10, restore_undo); mOPX(11, print_unicode); mOPX(12, check_unicode); mOPX(13, set_true_color); if (storyVersion() < 6) return; mOP(27, set_color_ver6); mOP(28, throw_ver6); mOP(185, catch_ver6); mOP(233, pull_ver6); mOP(238, erase_line_ver6); mOP(239, set_cursor_ver6); mOP(243, output_stream_ver6); mOP(248, not_ver6); mOPX(4, set_font_ver6); mOPX(5, draw_picture); mOPX(6, picture_data); mOPX(7, erase_picture); mOPX(8, set_margins); // xop# 8 mOPX(13, set_true_color_ver6); mOPX(16, move_window); mOPX(17, window_size); mOPX(18, window_style); mOPX(19, get_wind_prop); mOPX(20, scroll_window); mOPX(21, pop_stack); mOPX(22, read_mouse); mOPX(23, mouse_window); mOPX(24, push_stack); mOPX(25, put_wind_prop); mOPX(26, print_form); mOPX(27, make_menu); mOPX(28, picture_table); mOPX(29, buffer_screen); } void opcodesSetup(void) { uint8_t i; opcodesBuiltInitialTable(); // 2OP opcodes repeating with different operand forms. for (i=32; i<=127; i++) __state.opcodes[i] = __state.opcodes[i % 32]; // 1OP opcodes repeating with different operand forms. for (i=144; i<=175; i++) __state.opcodes[i] = __state.opcodes[128 + (i % 16)]; // 2OP opcodes repeating with VAR operand forms. for (i=192; i<=223; i++) __state.opcodes[i] = __state.opcodes[i % 32]; #ifdef DEBUGGING for (i=32; i<=127; i++) __state.opcodesName[i] = __state.opcodesName[i % 32]; for (i=144; i<=175; i++) __state.opcodesName[i] = __state.opcodesName[128 + (i % 16)]; for (i=192; i<=223; i++) __state.opcodesName[i] = __state.opcodesName[i % 32]; #endif }