271 lines
6.2 KiB
C
271 lines
6.2 KiB
C
/*
|
|
* 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 <stdint.h>
|
|
|
|
#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
|
|
}
|