|
|
@ -0,0 +1,578 @@
|
|
|
|
|
|
|
|
From 3e565f7d35e842e246db3371776adae74d02ae62 Mon Sep 17 00:00:00 2001
|
|
|
|
|
|
|
|
From: Bananymous <bananymousosq@gmail.com>
|
|
|
|
|
|
|
|
Date: Wed, 23 Apr 2025 13:10:38 +0300
|
|
|
|
|
|
|
|
Subject: [PATCH] Add support for banan-os
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
Makefile.banan_os | 28 +++
|
|
|
|
|
|
|
|
src/platform/banan-os/main.cpp | 365 +++++++++++++++++++++++++++++++
|
|
|
|
|
|
|
|
src/platform/banan-os/main.cpp.o | Bin 0 -> 23536 bytes
|
|
|
|
|
|
|
|
3 files changed, 393 insertions(+)
|
|
|
|
|
|
|
|
create mode 100644 Makefile.banan_os
|
|
|
|
|
|
|
|
create mode 100644 src/platform/banan-os/main.cpp
|
|
|
|
|
|
|
|
create mode 100644 src/platform/banan-os/main.cpp.o
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
diff --git a/Makefile.banan_os b/Makefile.banan_os
|
|
|
|
|
|
|
|
new file mode 100644
|
|
|
|
|
|
|
|
index 0000000..22e191e
|
|
|
|
|
|
|
|
--- /dev/null
|
|
|
|
|
|
|
|
+++ b/Makefile.banan_os
|
|
|
|
|
|
|
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
+CC = $(BANAN_ARCH)-banan_os-gcc
|
|
|
|
|
|
|
|
+CXX = $(BANAN_ARCH)-banan_os-g++
|
|
|
|
|
|
|
|
+LD = $(BANAN_ARCH)-banan_os-gcc
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+CFLAGS = -c -O2 -Isrc/include -Wall
|
|
|
|
|
|
|
|
+CXXFLAGS = --std=c++20
|
|
|
|
|
|
|
|
+LDFLAGS = -O2 -lgui -linput
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+SRC := $(shell find src -name "*.c" -not -path 'src/platform/*') $(shell find src/platform/banan-os -name "*.c" -or -name "*.cpp")
|
|
|
|
|
|
|
|
+OBJ := $(addsuffix .o,$(SRC))
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+all: tinygb
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+clean:
|
|
|
|
|
|
|
|
+ @rm -f $(OBJ)
|
|
|
|
|
|
|
|
+ @rm -f tinygb
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+%.c.o: %.c
|
|
|
|
|
|
|
|
+ @echo -e "\x1B[0;1;35m [ CC ]\x1B[0m $@"
|
|
|
|
|
|
|
|
+ $(CC) -o $@ $(CFLAGS) $<
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+%.cpp.o: %.cpp
|
|
|
|
|
|
|
|
+ @echo -e "\x1B[0;1;35m [ CC ]\x1B[0m $@"
|
|
|
|
|
|
|
|
+ $(CXX) -o $@ $(CFLAGS) $(CXXFLAGS) $<
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+tinygb: $(OBJ)
|
|
|
|
|
|
|
|
+ @echo -e "\x1B[0;1;36m [ LD ]\x1B[0m tinygb"
|
|
|
|
|
|
|
|
+ $(LD) $(OBJ) -o tinygb $(LDFLAGS)
|
|
|
|
|
|
|
|
diff --git a/src/platform/banan-os/main.cpp b/src/platform/banan-os/main.cpp
|
|
|
|
|
|
|
|
new file mode 100644
|
|
|
|
|
|
|
|
index 0000000..e9c6a02
|
|
|
|
|
|
|
|
--- /dev/null
|
|
|
|
|
|
|
|
+++ b/src/platform/banan-os/main.cpp
|
|
|
|
|
|
|
|
@@ -0,0 +1,365 @@
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+/* tinygb - a tiny gameboy emulator
|
|
|
|
|
|
|
|
+ (c) 2022 by jewel */
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+extern "C" {
|
|
|
|
|
|
|
|
+#include <tinygb.h>
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+#include <LibGUI/Window.h>
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+#include <stdio.h>
|
|
|
|
|
|
|
|
+#include <stdlib.h>
|
|
|
|
|
|
|
|
+#include <time.h>
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+long rom_size;
|
|
|
|
|
|
|
|
+int scaling = 4;
|
|
|
|
|
|
|
|
+int frameskip = 0; // no skip
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+timing_t timing;
|
|
|
|
|
|
|
|
+char *rom_filename;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+BAN::UniqPtr<LibGUI::Window> s_window;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+// Key Config
|
|
|
|
|
|
|
|
+LibInput::Key key_a;
|
|
|
|
|
|
|
|
+LibInput::Key key_b;
|
|
|
|
|
|
|
|
+LibInput::Key key_start;
|
|
|
|
|
|
|
|
+LibInput::Key key_select;
|
|
|
|
|
|
|
|
+LibInput::Key key_up;
|
|
|
|
|
|
|
|
+LibInput::Key key_down;
|
|
|
|
|
|
|
|
+LibInput::Key key_left;
|
|
|
|
|
|
|
|
+LibInput::Key key_right;
|
|
|
|
|
|
|
|
+LibInput::Key key_throttle;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+LibInput::Key get_key(const char* keyname)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ if (keyname == nullptr);
|
|
|
|
|
|
|
|
+ else if (!strcmp("a", keyname)) return LibInput::Key::A;
|
|
|
|
|
|
|
|
+ else if (!strcmp("b", keyname)) return LibInput::Key::B;
|
|
|
|
|
|
|
|
+ else if (!strcmp("c", keyname)) return LibInput::Key::C;
|
|
|
|
|
|
|
|
+ else if (!strcmp("d", keyname)) return LibInput::Key::D;
|
|
|
|
|
|
|
|
+ else if (!strcmp("e", keyname)) return LibInput::Key::E;
|
|
|
|
|
|
|
|
+ else if (!strcmp("f", keyname)) return LibInput::Key::F;
|
|
|
|
|
|
|
|
+ else if (!strcmp("g", keyname)) return LibInput::Key::G;
|
|
|
|
|
|
|
|
+ else if (!strcmp("h", keyname)) return LibInput::Key::H;
|
|
|
|
|
|
|
|
+ else if (!strcmp("i", keyname)) return LibInput::Key::I;
|
|
|
|
|
|
|
|
+ else if (!strcmp("j", keyname)) return LibInput::Key::J;
|
|
|
|
|
|
|
|
+ else if (!strcmp("k", keyname)) return LibInput::Key::K;
|
|
|
|
|
|
|
|
+ else if (!strcmp("l", keyname)) return LibInput::Key::L;
|
|
|
|
|
|
|
|
+ else if (!strcmp("m", keyname)) return LibInput::Key::M;
|
|
|
|
|
|
|
|
+ else if (!strcmp("n", keyname)) return LibInput::Key::N;
|
|
|
|
|
|
|
|
+ else if (!strcmp("o", keyname)) return LibInput::Key::O;
|
|
|
|
|
|
|
|
+ else if (!strcmp("p", keyname)) return LibInput::Key::P;
|
|
|
|
|
|
|
|
+ else if (!strcmp("q", keyname)) return LibInput::Key::Q;
|
|
|
|
|
|
|
|
+ else if (!strcmp("r", keyname)) return LibInput::Key::R;
|
|
|
|
|
|
|
|
+ else if (!strcmp("s", keyname)) return LibInput::Key::S;
|
|
|
|
|
|
|
|
+ else if (!strcmp("t", keyname)) return LibInput::Key::T;
|
|
|
|
|
|
|
|
+ else if (!strcmp("u", keyname)) return LibInput::Key::U;
|
|
|
|
|
|
|
|
+ else if (!strcmp("v", keyname)) return LibInput::Key::V;
|
|
|
|
|
|
|
|
+ else if (!strcmp("w", keyname)) return LibInput::Key::W;
|
|
|
|
|
|
|
|
+ else if (!strcmp("x", keyname)) return LibInput::Key::X;
|
|
|
|
|
|
|
|
+ else if (!strcmp("y", keyname)) return LibInput::Key::Y;
|
|
|
|
|
|
|
|
+ else if (!strcmp("z", keyname)) return LibInput::Key::Z;
|
|
|
|
|
|
|
|
+ else if (!strcmp("0", keyname)) return LibInput::Key::_0;
|
|
|
|
|
|
|
|
+ else if (!strcmp("1", keyname)) return LibInput::Key::_1;
|
|
|
|
|
|
|
|
+ else if (!strcmp("2", keyname)) return LibInput::Key::_2;
|
|
|
|
|
|
|
|
+ else if (!strcmp("3", keyname)) return LibInput::Key::_3;
|
|
|
|
|
|
|
|
+ else if (!strcmp("4", keyname)) return LibInput::Key::_4;
|
|
|
|
|
|
|
|
+ else if (!strcmp("5", keyname)) return LibInput::Key::_5;
|
|
|
|
|
|
|
|
+ else if (!strcmp("6", keyname)) return LibInput::Key::_6;
|
|
|
|
|
|
|
|
+ else if (!strcmp("7", keyname)) return LibInput::Key::_7;
|
|
|
|
|
|
|
|
+ else if (!strcmp("8", keyname)) return LibInput::Key::_8;
|
|
|
|
|
|
|
|
+ else if (!strcmp("9", keyname)) return LibInput::Key::_9;
|
|
|
|
|
|
|
|
+ else if (!strcmp("up", keyname)) return LibInput::Key::ArrowUp;
|
|
|
|
|
|
|
|
+ else if (!strcmp("down", keyname)) return LibInput::Key::ArrowDown;
|
|
|
|
|
|
|
|
+ else if (!strcmp("left", keyname)) return LibInput::Key::ArrowLeft;
|
|
|
|
|
|
|
|
+ else if (!strcmp("right", keyname)) return LibInput::Key::ArrowRight;
|
|
|
|
|
|
|
|
+ else if (!strcmp("space", keyname)) return LibInput::Key::Space;
|
|
|
|
|
|
|
|
+ else if (!strcmp("rshift", keyname)) return LibInput::Key::RightShift;
|
|
|
|
|
|
|
|
+ else if (!strcmp("lshift", keyname)) return LibInput::Key::LeftShift;
|
|
|
|
|
|
|
|
+ else if (!strcmp("backspace", keyname)) return LibInput::Key::Backspace;
|
|
|
|
|
|
|
|
+ else if (!strcmp("delete", keyname)) return LibInput::Key::Delete;
|
|
|
|
|
|
|
|
+ else if (!strcmp("tab", keyname)) return LibInput::Key::Tab;
|
|
|
|
|
|
|
|
+ else if (!strcmp("escape", keyname)) return LibInput::Key::Escape;
|
|
|
|
|
|
|
|
+ else if (!strcmp("exclamation", keyname)) return LibInput::Key::ExclamationMark;
|
|
|
|
|
|
|
|
+ else if (!strcmp("at", keyname)) return LibInput::Key::AtSign;
|
|
|
|
|
|
|
|
+ else if (!strcmp("hash", keyname)) return LibInput::Key::Hashtag;
|
|
|
|
|
|
|
|
+ else if (!strcmp("dollar", keyname)) return LibInput::Key::Dollar;
|
|
|
|
|
|
|
|
+ else if (!strcmp("percent", keyname)) return LibInput::Key::Percent;
|
|
|
|
|
|
|
|
+ else if (!strcmp("caret", keyname)) return LibInput::Key::Caret;
|
|
|
|
|
|
|
|
+ else if (!strcmp("ampersand", keyname)) return LibInput::Key::Ampersand;
|
|
|
|
|
|
|
|
+ else if (!strcmp("asterisk", keyname)) return LibInput::Key::Asterix;
|
|
|
|
|
|
|
|
+ else if (!strcmp("leftparenthesis", keyname)) return LibInput::Key::OpenParenthesis;
|
|
|
|
|
|
|
|
+ else if (!strcmp("rightparenthesis", keyname)) return LibInput::Key::CloseParenthesis;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ return LibInput::Key::None;
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+static void load_keys()
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ key_a = get_key(config_file.a);
|
|
|
|
|
|
|
|
+ if (key_a == LibInput::Key::None)
|
|
|
|
|
|
|
|
+ key_a = LibInput::Key::Z;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ key_b = get_key(config_file.b);
|
|
|
|
|
|
|
|
+ if (key_b == LibInput::Key::None)
|
|
|
|
|
|
|
|
+ key_b = LibInput::Key::X;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ key_start = get_key(config_file.start);
|
|
|
|
|
|
|
|
+ if (key_start == LibInput::Key::None)
|
|
|
|
|
|
|
|
+ key_start = LibInput::Key::Enter;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ key_select = get_key(config_file.select);
|
|
|
|
|
|
|
|
+ if (key_select == LibInput::Key::None)
|
|
|
|
|
|
|
|
+ key_select = LibInput::Key::RightShift;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ key_up = get_key(config_file.up);
|
|
|
|
|
|
|
|
+ if (key_up == LibInput::Key::None)
|
|
|
|
|
|
|
|
+ key_up = LibInput::Key::ArrowUp;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ key_down = get_key(config_file.down);
|
|
|
|
|
|
|
|
+ if (key_down == LibInput::Key::None)
|
|
|
|
|
|
|
|
+ key_down = LibInput::Key::ArrowDown;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ key_left = get_key(config_file.left);
|
|
|
|
|
|
|
|
+ if (key_left == LibInput::Key::None)
|
|
|
|
|
|
|
|
+ key_left = LibInput::Key::ArrowLeft;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ key_right = get_key(config_file.right);
|
|
|
|
|
|
|
|
+ if (key_right == LibInput::Key::None)
|
|
|
|
|
|
|
|
+ key_right = LibInput::Key::ArrowRight;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ key_throttle = get_key(config_file.throttle);
|
|
|
|
|
|
|
|
+ if (key_throttle == LibInput::Key::None)
|
|
|
|
|
|
|
|
+ key_throttle = LibInput::Key::Space;
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+void delay(int ms)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ const timespec ts {
|
|
|
|
|
|
|
|
+ .tv_sec = static_cast<time_t>(ms / 1000),
|
|
|
|
|
|
|
|
+ .tv_nsec = (ms % 1000) * 1000000
|
|
|
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
+ nanosleep(&ts, nullptr);
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+void destroy_window()
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ s_window.clear();
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+void update_window(uint32_t *framebuffer)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ for (int i = 0; i < scaled_h; i++)
|
|
|
|
|
|
|
|
+ {
|
|
|
|
|
|
|
|
+ uint32_t* src = &framebuffer[i * scaled_w];
|
|
|
|
|
|
|
|
+ uint32_t* dst = using_sgb_border
|
|
|
|
|
|
|
|
+ ? &s_window->pixels()[(i + gb_y) * s_window->width() + gb_x]
|
|
|
|
|
|
|
|
+ : &s_window->pixels()[i * s_window->width()];
|
|
|
|
|
|
|
|
+ memcpy(dst, src, scaled_w * 4);
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ if (framecount > frameskip)
|
|
|
|
|
|
|
|
+ {
|
|
|
|
|
|
|
|
+ s_window->invalidate();
|
|
|
|
|
|
|
|
+ framecount = 0;
|
|
|
|
|
|
|
|
+ drawn_frames++;
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+void update_border(uint32_t *framebuffer)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ for (int i = 0; i < sgb_scaled_h; i++)
|
|
|
|
|
|
|
|
+ {
|
|
|
|
|
|
|
|
+ uint32_t* src = &framebuffer[i * sgb_scaled_w];
|
|
|
|
|
|
|
|
+ uint32_t* dst = &s_window->pixels()[i * s_window->width()];
|
|
|
|
|
|
|
|
+ memcpy(dst, src, sgb_scaled_w*4);
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+void resize_sgb_window()
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ s_window->request_resize(SGB_WIDTH * scaling, SGB_HEIGHT * scaling);
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ bool resized { false };
|
|
|
|
|
|
|
|
+ s_window->set_resize_window_event_callback([&]() { resized = true; });
|
|
|
|
|
|
|
|
+ while (!resized)
|
|
|
|
|
|
|
|
+ s_window->poll_events();
|
|
|
|
|
|
|
|
+ s_window->set_resize_window_event_callback({});
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ ASSERT(s_window->width() == static_cast<uint32_t>(SGB_WIDTH * scaling));
|
|
|
|
|
|
|
|
+ ASSERT(s_window->height() == static_cast<uint32_t>(SGB_HEIGHT * scaling));
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+int main(int argc, char **argv)
|
|
|
|
|
|
|
|
+{
|
|
|
|
|
|
|
|
+ if(argc != 2)
|
|
|
|
|
|
|
|
+ {
|
|
|
|
|
|
|
|
+ fprintf(stdout, "usage: %s rom_name\n", argv[0]);
|
|
|
|
|
|
|
|
+ return 1;
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ rom_filename = argv[1];
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ open_log();
|
|
|
|
|
|
|
|
+ open_config();
|
|
|
|
|
|
|
|
+ load_keys();
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ // open the rom
|
|
|
|
|
|
|
|
+ FILE* rom_file = fopen(rom_filename, "r");
|
|
|
|
|
|
|
|
+ if (rom_file == nullptr)
|
|
|
|
|
|
|
|
+ {
|
|
|
|
|
|
|
|
+ write_log("unable to open %s for reading: %s\n", rom_filename, strerror(errno));
|
|
|
|
|
|
|
|
+ return 1;
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ fseek(rom_file, 0L, SEEK_END);
|
|
|
|
|
|
|
|
+ rom_size = ftell(rom_file);
|
|
|
|
|
|
|
|
+ fseek(rom_file, 0L, SEEK_SET);
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ write_log("loading rom from file %s, %d KiB\n", rom_filename, rom_size / 1024);
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ rom = malloc(rom_size);
|
|
|
|
|
|
|
|
+ if (rom == nullptr)
|
|
|
|
|
|
|
|
+ {
|
|
|
|
|
|
|
|
+ write_log("unable to allocate memory\n");
|
|
|
|
|
|
|
|
+ fclose(rom_file);
|
|
|
|
|
|
|
|
+ return 1;
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ if (fread(rom, 1, rom_size, rom_file) <= 0)
|
|
|
|
|
|
|
|
+ {
|
|
|
|
|
|
|
|
+ write_log("an error occured while reading from rom file: %s\n", strerror(errno));
|
|
|
|
|
|
|
|
+ fclose(rom_file);
|
|
|
|
|
|
|
|
+ free(rom);
|
|
|
|
|
|
|
|
+ return 1;
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ fclose(rom_file);
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ if (auto ret = LibGUI::Window::create(GB_WIDTH * scaling, GB_HEIGHT * scaling, "tinygb"_sv); !ret.is_error())
|
|
|
|
|
|
|
|
+ s_window = ret.release_value();
|
|
|
|
|
|
|
|
+ else
|
|
|
|
|
|
|
|
+ {
|
|
|
|
|
|
|
|
+ write_log("couldn't create SDL window: %s\n", ret.error().get_message());
|
|
|
|
|
|
|
|
+ free(rom);
|
|
|
|
|
|
|
|
+ return 1;
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ s_window->set_key_event_callback([](LibGUI::EventPacket::KeyEvent::event_t event) {
|
|
|
|
|
|
|
|
+ int key = 0;
|
|
|
|
|
|
|
|
+ if (event.key == key_left)
|
|
|
|
|
|
|
|
+ key = JOYPAD_LEFT;
|
|
|
|
|
|
|
|
+ else if (event.key == key_right)
|
|
|
|
|
|
|
|
+ key = JOYPAD_RIGHT;
|
|
|
|
|
|
|
|
+ else if (event.key == key_up)
|
|
|
|
|
|
|
|
+ key = JOYPAD_UP;
|
|
|
|
|
|
|
|
+ else if (event.key == key_down)
|
|
|
|
|
|
|
|
+ key = JOYPAD_DOWN;
|
|
|
|
|
|
|
|
+ else if (event.key == key_a)
|
|
|
|
|
|
|
|
+ key = JOYPAD_A;
|
|
|
|
|
|
|
|
+ else if (event.key == key_b)
|
|
|
|
|
|
|
|
+ key = JOYPAD_B;
|
|
|
|
|
|
|
|
+ else if (event.key == key_start)
|
|
|
|
|
|
|
|
+ key = JOYPAD_START;
|
|
|
|
|
|
|
|
+ else if (event.key == key_select)
|
|
|
|
|
|
|
|
+ key = JOYPAD_SELECT;
|
|
|
|
|
|
|
|
+ else if (event.key == key_throttle)
|
|
|
|
|
|
|
|
+ throttle_enabled = event.released();
|
|
|
|
|
|
|
|
+ else if (event.pressed() && (event.key == LibInput::Key::Plus || event.key == LibInput::Key::Equals))
|
|
|
|
|
|
|
|
+ next_palette();
|
|
|
|
|
|
|
|
+ else if (event.pressed() && (event.key == LibInput::Key::Hyphen))
|
|
|
|
|
|
|
|
+ prev_palette();
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ if (key)
|
|
|
|
|
|
|
|
+ joypad_handle(event.pressed(), key);
|
|
|
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ // start emulation
|
|
|
|
|
|
|
|
+ memory_start();
|
|
|
|
|
|
|
|
+ cpu_start();
|
|
|
|
|
|
|
|
+ display_start();
|
|
|
|
|
|
|
|
+ timer_start();
|
|
|
|
|
|
|
|
+ sound_start();
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ time_t rawtime;
|
|
|
|
|
|
|
|
+ struct tm *timeinfo;
|
|
|
|
|
|
|
|
+ int sec = 500; // any invalid number
|
|
|
|
|
|
|
|
+ int percentage;
|
|
|
|
|
|
|
|
+ int throttle_underflow = 0;
|
|
|
|
|
|
|
|
+ int throttle_target = throttle_lo + SPEED_ALLOWANCE;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ for (;;)
|
|
|
|
|
|
|
|
+ {
|
|
|
|
|
|
|
|
+ s_window->poll_events();
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ for (timing.current_cycles = 0; timing.current_cycles < timing.main_cycles;)
|
|
|
|
|
|
|
|
+ {
|
|
|
|
|
|
|
|
+ cpu_cycle();
|
|
|
|
|
|
|
|
+ display_cycle();
|
|
|
|
|
|
|
|
+ timer_cycle();
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ time(&rawtime);
|
|
|
|
|
|
|
|
+ timeinfo = localtime(&rawtime);
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ if (sec != timeinfo->tm_sec)
|
|
|
|
|
|
|
|
+ {
|
|
|
|
|
|
|
|
+ sec = timeinfo->tm_sec;
|
|
|
|
|
|
|
|
+ percentage = (drawn_frames * 1000) / 597;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ // adjust cpu throttle according to acceptable fps (98%-102%)
|
|
|
|
|
|
|
|
+ if (throttle_enabled){
|
|
|
|
|
|
|
|
+ if(percentage < throttle_lo) {
|
|
|
|
|
|
|
|
+ // emulation is too slow
|
|
|
|
|
|
|
|
+ if(!throttle_time) {
|
|
|
|
|
|
|
|
+ // throttle_time--;
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ if(!throttle_underflow) {
|
|
|
|
|
|
|
|
+ throttle_underflow = 1;
|
|
|
|
|
|
|
|
+ write_log("WARNING: CPU throttle interval has underflown, emulation may be too slow\n");
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ } else {
|
|
|
|
|
|
|
|
+ //write_log("too slow; decreasing throttle time: %d\n", throttle_time);
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ // this will speed up the speed adjustments for a more natural feel
|
|
|
|
|
|
|
|
+ if(percentage < (throttle_target/3)) throttle_time /= 3;
|
|
|
|
|
|
|
|
+ else if(percentage < (throttle_target/2)) throttle_time /= 2;
|
|
|
|
|
|
|
|
+ else throttle_time--;
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ // prevent this from going too low
|
|
|
|
|
|
|
|
+ if(throttle_time <= (THROTTLE_THRESHOLD/3)) {
|
|
|
|
|
|
|
|
+ cycles_per_throttle += (cycles_per_throttle/5); // delay 20% less often
|
|
|
|
|
|
|
|
+ throttle_time = (THROTTLE_THRESHOLD/3);
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ } else if(percentage > throttle_hi) {
|
|
|
|
|
|
|
|
+ // emulation is too fast
|
|
|
|
|
|
|
|
+ //write_log("too fast; increasing throttle time: %d\n", throttle_time);
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ if(throttle_time) {
|
|
|
|
|
|
|
|
+ // to make sure we're not multiplying zero
|
|
|
|
|
|
|
|
+ if(percentage > (throttle_target*3)) throttle_time *= 3;
|
|
|
|
|
|
|
|
+ else if(percentage > (throttle_target*2)) throttle_time *= 2;
|
|
|
|
|
|
|
|
+ else throttle_time++;
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ else {
|
|
|
|
|
|
|
|
+ throttle_time++;
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ // prevent unnecessary lag
|
|
|
|
|
|
|
|
+ if(throttle_time > THROTTLE_THRESHOLD) {
|
|
|
|
|
|
|
|
+ cycles_per_throttle -= (cycles_per_throttle/5); // delay 20% more often
|
|
|
|
|
|
|
|
+ throttle_time = THROTTLE_THRESHOLD;
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ drawn_frames = 0;
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+ die(0, "");
|
|
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
diff --git a/src/platform/banan-os/main.cpp.o b/src/platform/banan-os/main.cpp.o
|
|
|
|
|
|
|
|
new file mode 100644
|
|
|
|
|
|
|
|
index 0000000000000000000000000000000000000000..3774a9abb35f0e1c899e550571c8755c90296733
|
|
|
|
|
|
|
|
GIT binary patch
|
|
|
|
|
|
|
|
literal 23536
|
|
|
|
|
|
|
|
zcmb_k3wTu3wcbe(5Tpb6ew9H{KqX|5rw>dZ0}}~|K$NO<m`qN{z+`5a2P9e*O|Z_5
|
|
|
|
|
|
|
|
z!St<dzh2vZ_ty5dYOPiDS`A`R+TMPsx7OBsD|)RpSKH!euZ_>#_3yJ*vT`!VS6v@x
|
|
|
|
|
|
|
|
z_S*kmd#$zK`<%VWwc+|@<z;0?sLU)jLoq>($y_|dS6jB)oMC2K*&`@Efga?WOwW<b
|
|
|
|
|
|
|
|
zpUB}!6rRldr#YNLVUYP#DHPh<)7)Gcn9^zEfhootk8~{`yU&#E6_JM~l4KvGn*&p7
|
|
|
|
|
|
|
|
zjq%1K#Y4^4y=2NGd-{Xt9tOEUXAk|ld_E)Cmj|&x=k1F3!|zctw<!LH#5eDJBY$M^
|
|
|
|
|
|
|
|
zk&YMM?RaaYtFEIzlfR0bHoM_NXn;hD`>F$9dCa;_cxYhvXg4d+;y#6sDTVJwWxsN7
|
|
|
|
|
|
|
|
z59J$MGQAw>U+vjF3gIqRS8aAzP`vM|fq?<HzCyj^O5n@AMO!y}-I^R~fu09oC$e)O
|
|
|
|
|
|
|
|
z(0L_kYKRp7xHeLJJJRv$*ucGGI{IVzPj~b;=0hF*@j~s6tIEs+uvb_V>Dtg=Jg|Rn
|
|
|
|
|
|
|
|
z&yH&egD-{O3TE5M%EFhzqr>oy{-!|Zv81G<-wAY{Zkgsl=RC`7DvY=JP~!YIJNjEV
|
|
|
|
|
|
|
|
zemLScb@V3!oztw~=0NA!me~^MTw<AIAz-tjp9VTNQ29IhTN(S5#p*1UVk}^>c@|4E
|
|
|
|
|
|
|
|
zhOQRqoNBQQW0Nd4!D3q(!x#v3zWE+(WEsPl2z36@VmZc+ve*+A%QJSg#eQb70%ONm
|
|
|
|
|
|
|
|
z?E4nm#@MkI`-;W3Gj^QCuCrJhW5-*p)ne_8onW!gSnNv1FjfPdVT)BUhA|rG3=tM7
|
|
|
|
|
|
|
|
z{^4PYn3wUhvp3K=o|<k1_$syY2=M<(flrqLpDP9SmI9wD1>RE%+*-=dHKo9_OMyp~
|
|
|
|
|
|
|
|
z0zZ6-?knZeEv3NrQs8B!z;jE1CzS%<rJ*~bIsQ-ze7F>NTPg6mQea~#aA_%US}E`~
|
|
|
|
|
|
|
|
z>Qlq~?C38${>hFPmUlc-*7uXQ2L=LDs!j0#&7QT!*g=fBD$scgCH4J=(=Cn}G|;&N
|
|
|
|
|
|
|
|
z_&$we1`Tw!0KZS;<1D@!_~RNMZ}Ek|@7FjMx<F?T_z&pkfvFVln*=ThZVb3n!M*zy
|
|
|
|
|
|
|
|
zai@TL9o%W)`oK*C_Z+z8;C=&cI=EkgJ008}a1OZpz%2#$BXG^&z6)*%xLd)k2X`~L
|
|
|
|
|
|
|
|
zYH&NjT>|bZaErlh1$P;^P2esEw*lM&aBIOefU5(y0o(=P;^5|iJ0IMc;I@F93T`vF
|
|
|
|
|
|
|
|
zW5FfBO#s&dt^(W)aBsdzYfMih{#fy?hR_?4MDJ588z=60YYHtPw0umY1^M)u2O{wU
|
|
|
|
|
|
|
|
ziQbp(C~G)0^RdK0^^$;z#A(90x<Ar=^&vaq?B6@IAh|0LEkBViY$<4IdNzM_r1+c_
|
|
|
|
|
|
|
|
ze5l{{FE<i-%r0qGh*qQhZvScMnrD&XA8XcyLoZ@6+xf;di7w2$rVFbBb+wwnosULt
|
|
|
|
|
|
|
|
ziFD8Hh;&&cJNE}VucxF4=Du$aN=CZcCf1fcAGkA8RbjJ6&W!|f**!0mN4n3uxu)aM
|
|
|
|
|
|
|
|
zvPk?%>sjq0^Z|42*Ia#ztk!F0MY>SASYPw2x-P1!?OHxJ^knD_o2A3blns^Q@|r6)
|
|
|
|
|
|
|
|
z>?IHKr`8sqhiTY_#q6$!pk-)=ru~Emp~b!vGKS038`y>Npf(5V!L5T5rH9Q09-F!O
|
|
|
|
|
|
|
|
z?^DX3T36lu7>o{i*5mQ3XYa7>UbShs9~qh>fz*DtqimEq>JC2)_&{?Y`3qFo=iHVI
|
|
|
|
|
|
|
|
z%v^a};^~8wY0pbzZN+hhec^{~#ja}(q*vb79QbQ*U}pFLJqPJIMA>=+lWyKk`2v$Z
|
|
|
|
|
|
|
|
z|F|1G;|9<o^<_2gxcXsJI87YcIZ){H6l17=a)&{cJ?mDewLEDDEES&!Oxoev+5ua8
|
|
|
|
|
|
|
|
zo*zp9Oq?63Dx8#f@*vpNa|`AB_j)XNqJ}m#mehEdg0Voui@SgEIc%)#kl4@LKbk**
|
|
|
|
|
|
|
|
z?cW<RbIjRhu9;`%n+0Z}S!4<s)0EzxGD)X7Z?cI^EqRm6#Nv+0=2{X2CEcJg7T@CH
|
|
|
|
|
|
|
|
zO-|CuJ0>4%G)^ua%Q(hqizj2Pv3w$(GO@gAiRD^IXEGVfnv9c;JE^>h$Ffe|#9Aqy
|
|
|
|
|
|
|
|
zi=~=OESGn(iQE=zHbaT2e2bGy<XjIlP_uSzc+I*Qt<g+6k)lj9gUzu-(rGfBkVrK-
|
|
|
|
|
|
|
|
zZNc+`t<hZKN@p;&A+;q%#R@vvY&vTSx!5M>oZxA>U^d+vO~qQBafZ-TtTE{X^XXtL
|
|
|
|
|
|
|
|
znM}uHc_-NFw5GG|<4iu0YTwi-HmF4Bty?@}=Ad?Jf!QtTR%doPw<VTM%x-eF&2EgP
|
|
|
|
|
|
|
|
zVyRi_-0a3eBH1)M*PhF!)A`wjTy}OM6;BqLoY_liR?TimCAO~4XDeIISx|+B{J477
|
|
|
|
|
|
|
|
zW@0H)GJn494MtqeMYmIpq_@vnygkvBZ<#SOc>ejpT%H;y9*tA2pI4w-JbO+wzj(&l
|
|
|
|
|
|
|
|
z<x8TM*43_y1kVUkLnafcO{#>sY<zYm8Ot}Pv#mpAYmFsRmGMmGoY10>YnYp1$Zm^+
|
|
|
|
|
|
|
|
zPV_;BBjLK`k#!|4yLvy+{v20ss1ef{Cxs>^kAqn!)<oq&lVhzXN~SG>4iId%Kh%pT
|
|
|
|
|
|
|
|
z`K;h+O~Dn3B`juQ+-HL6c)XBxnu6O~Ajk^ctdd=+|Jdz#3H6^?Do;&0XZ~FBGoCIa
|
|
|
|
|
|
|
|
zn^M#B!8n<u9=W!*KIk^7YwgmSHLL1YEk7r?bag{8-;zz|^W>f#8rx#YAa&JXfrdo3
|
|
|
|
|
|
|
|
zIZ56Btf13cphl#T8ElQU2OH7b)4?32jpH5@U3JmA=$dfN(nz?L8jXy`TWEBB0_B-^
|
|
|
|
|
|
|
|
zwyk*nq4)QRk&gcI{3Y(%W8Wrs_7;wfJhpUVISJXNL(QkO87!Px-!*;Z&KL8~)))U|
|
|
|
|
|
|
|
|
zCu9ok#AYMIa(d@YnGPkVwR&mIB{dB->(<gfB+@ZZo<Aefbqvq$cAgFOx{5m<jo9~W
|
|
|
|
|
|
|
|
z@~LJ+&1Y+(wElK28yj(7maU8{=q}@yCw~K-i>M^5P|4b)8U9Jf`X`O{Px?RXd0Yp)
|
|
|
|
|
|
|
|
zwqEp4ddffP5&xtg4<*@(QU)VM>`iD_P9pY&pZ0vk$K2}SB?(&_Y7bp~_hTWm+XGoR
|
|
|
|
|
|
|
|
zd4G0m<nM1rijQzh)OXqKlQbf0ApO?l38W)Z{9S$Vg@?$v`;uxC?nSMU!R`$`))C$@
|
|
|
|
|
|
|
|
z+-rAMcB2uv*KYi31NYkfTaEn)6WMccY~nq9C5jw=fF%-d+(z-bJ<kUtdtR6rIsB1;
|
|
|
|
|
|
|
|
ztA%8bBdOwBWT)=%J=`6_x556-pFl-d;g$$}V(CnhGq$ACyHux<UfNfDcVJ*Q-o^WV
|
|
|
|
|
|
|
|
z1`coUeZK~G9=PYg*^T)ja4o>f==FTJ-GomDXE)}jg0q|Tx!~*u9<TOpB`jno?MB$G
|
|
|
|
|
|
|
|
z`@xFt8%v5K9WR#!cFre%x!yzj>$_TeBE^+G7==emGuR<05h_A`aTa;R_3v(eB0HZ9
|
|
|
|
|
|
|
|
zbjGPwLcO$|zx95+bI`lq>p!?3A5+4iH)<aI8~RlD1N}&OER0$=um6j6vDA;df359q
|
|
|
|
|
|
|
|
z8RdSz8rqZvI^U+OHc#lu4!f^5Mcca9Odpz0JUaDu{B!>!%^+cI*TV3kKjpu{+VY=C
|
|
|
|
|
|
|
|
z*q(#;m4_OrdT#yud+tuYxF@jd2V~vtVAR?>$55%lX!eVVao;N*LS}b6j~CVA<CMMZ
|
|
|
|
|
|
|
|
zad!xXdc(zcT()l}eN3`$cDXIZO|(z?jco8#|LMD!UOhcq#ICE|P9G`mvz>7VwX7BC
|
|
|
|
|
|
|
|
z+eV!0_tl?wn+dISEBUmvySCLVdOXm5Cq=qPt#Li-=${<ebs2fZ<se%FZaMI!Ygjq@
|
|
|
|
|
|
|
|
z&ZabvBelhsAEp|k+8S8&__dXYQr#h1Q|#?tHc&(8acs#p+vvc}uTpRA`#Jp-50Ts}
|
|
|
|
|
|
|
|
z&%5TRDor20m+?5N85-}eJi4?yKg)D4DO>dGKzA*9(LHK%-+2@c8*^ND_9eEi_^90%
|
|
|
|
|
|
|
|
zt2dD5o(IT;dU>(}0|RBJO#c~8GCL1Dtm_E#?qR1G^Sv>9sStlY{Dv|@o*GYU97&BD
|
|
|
|
|
|
|
|
zZ~F&S2(3Dsc6$q#6;g4mzIDsCZ3~A(bC%Lh6PwN@v78eY(URea{Hqq$CmQQgnL>Wy
|
|
|
|
|
|
|
|
z3a351jke6;kEXJu9Y64l5e}dLbEN?FvDU_>Slwlz1zFm+U+F}1n;LoR8E!~!3rEB6
|
|
|
|
|
|
|
|
zUpzBXzfS>2n4F7EC>dEhC;Gu={EGL1co~r~%a<-aCpcsIs)m`t(45LSl~o4cZb4;N
|
|
|
|
|
|
|
|
zt}$h86U$CKV$9eclEk!z^9~TYD+pMX<%VOmjE&_Ga_gCweJHSG32X;rbJ@r=ihr3g
|
|
|
|
|
|
|
|
z`z}!Psfjm~FP$(t+)=S%965L4_%QvNYLa=7<rZTax`^d!Ix4n6ZprvH2$o4uaoi}1
|
|
|
|
|
|
|
|
z?%fwTV)Vq0iW@L;ZTZ;lGU!?c9T!a)oq+{6J;>?jB3=2il|<lcHK+f5FuiWV=p{E*
|
|
|
|
|
|
|
|
z)OL(2zY`ABj5lXdS_{j40dnFi%dw*yt$)8VCP*UKet@PUw02ic7+wArYc%xEOXX*o
|
|
|
|
|
|
|
|
z3<Otj`Ip{Q(J^Wr<W`JN!~WiVzp6o*N8M0<Q^io5Ub(v7w)hxKX{JKj9loMmpd+bX
|
|
|
|
|
|
|
|
zM}d)Yue`Zp*QoBpZW`S&CdHlvDR~`ah|tDX9_Gf7xzXK+?HYA+1@IPBIFa->H#YJY
|
|
|
|
|
|
|
|
zMH*#Z8yJ~FP8#W9L#gOr<qGF2vHh<U{;w<#pFkr2XW}96#nCT;2O&%(9?)@+#j9M{
|
|
|
|
|
|
|
|
zNI&1lc(n&Vipmc?s~MO6j%bBBg3;kYg~5r=NUAV6)frBx-!e1R9AJ2cO0F0zl>&*a
|
|
|
|
|
|
|
|
zFq4J@9ILRWpCgkhd|I!<;ACew-NF7~I|Lf;&v7oOe&4qBGt@hz9S)=JSx)+c7~@1k
|
|
|
|
|
|
|
|
z67YYj3##9fNgnkeB$ncg2RUIWhu>$sh2tXs2ID&zzmUVFwu4h6dniG;_^gw*5<ba{
|
|
|
|
|
|
|
|
zAM7_aI|<+v61c=A>||VY3EsuH^c2Cr%y^KE3jTG*WeykoHpZo#g8zVVsb9f=%D9wC
|
|
|
|
|
|
|
|
z@JEOdA0-Xp0U!Loeel2d;BOOtiW(R4U1%!pOiI~ZKzJ$n4TMjo+Q*s(vTFr}TYU6n
|
|
|
|
|
|
|
|
zS^fadT8QkrKw+DY{Pip!<cYzq6D0oy!qL9c?>X6go#i(&VAl<jUqb!6RJktl!Eg8R
|
|
|
|
|
|
|
|
z=YAg?oAy%r_xj+!ARPW*LB4^gIV}CBkNk5!c)5@N0Ux}IaJ1LP!(DrJy(AXxR?7bs
|
|
|
|
|
|
|
|
zKKOdpBNMY-M@i3S!Y2txaVb~UN6*)MaJ*ojqUOnr>#li+@X2aE#2N}JqyALN|6_dc
|
|
|
|
|
|
|
|
zDL(jg!qF~Ou3D-om*)D&pYMa$`QQyc_~kx$%m>GbGyL4>@pF@p{8k^l%?JOS4}QH5
|
|
|
|
|
|
|
|
zUL<^~IhDOJhPtbzyL{x|@xjZe!b`Q|WFP!QAAE)nKF0^I_QC6Y@bx};6X9r=YA(O5
|
|
|
|
|
|
|
|
z4_kcX3qE*<5B?n={AM5gRv-L(KKQ@;;J@_2f9r$41f2F9UV7a}-q3tB)!>VkOVc=<
|
|
|
|
|
|
|
|
zVR5O&p}w)2@KXI`o0b2xsG(CUmws&VDTBD=ebq;gk)sO}y==s*?Z<odteq3y_6ceW
|
|
|
|
|
|
|
|
zmDctVU%UOB`lxEyn-!%#V~ltu_x}nomkySapG?83N~`&pZO7V1l<(uIbBjq|B&a{E
|
|
|
|
|
|
|
|
zyJSTF`iPYuF0JL`xfbT0pH4QJ=<@oDmekZoqq#z3v@VLnP<*_Bxw=op>9wDTmXW@E
|
|
|
|
|
|
|
|
z+@e##M!NLzmD$oQ;3M3+RrBeK-13IH`Ip)w*KoLYp6#Md$<^Ch%@(IUY7f=HxCiUt
|
|
|
|
|
|
|
|
z=)4_)J#z;Wv(ZNTOXsxNyvxxcd)#H^jL&RNw`XEa(H1&CPdX-(b+$z_F*=LKVLYD$
|
|
|
|
|
|
|
|
zMjd;k-DFZuTYfN=C%pIZn<uj2<*8K@();9fr50>*@=+?!>J@R5%V*=QbgjTi#@Y=X
|
|
|
|
|
|
|
|
zil=i)$3dJD((U|}(8!4~-9TufgHC}9IXbtsUlSYCSvtow^j)zXKW&B%=i`}n)10OA
|
|
|
|
|
|
|
|
z``ng9#^vb1lr9)h8Halxs!F8jKr{i};Y4EdX4907ZBIqr+$29|PBcnq_R&}_=VbAX
|
|
|
|
|
|
|
|
zHtJq1pc1UDii%h41io(KjNGC6H!8B-jQIR%_$<AIOLMc%)&kW+)Xfwor$+i6%Fxw`
|
|
|
|
|
|
|
|
zsDtmjxuF?v0iP4sUASs(bY2*@8p6c+w+nq6o)=F#u`KDp(r2R4O>J#aT);@Ds9y5z
|
|
|
|
|
|
|
|
z(QQ=(=JHMHLf$lIvUG;rY%nD>(}6ecNEn=`N0aGIE)!3uniHGofEs}nGR=@M%{j-}
|
|
|
|
|
|
|
|
zVw&?#GHJGF6V#T-(`qkOKq0jg9mkvIcru;CT;px2g-uR#tdPt{WBGhG(OAekIn00_
|
|
|
|
|
|
|
|
zvH9+SI8~Y*g`ujoB%IoGNy6EVnh4EtN8xI^sN&>9RW(W%*(bYEx(kv@lW%m>16Nh3
|
|
|
|
|
|
|
|
zH@de&+)E!+6BvE*Oo6$kM2;>%v~w(<Xmzs8=cvmy2`)n~nWkGKt>lqa5pSo;H=@Fg
|
|
|
|
|
|
|
|
zxhh;9UL*kwja?hFsW~)LR0j2+qcnix(NtzAM@zy)8&bF(5MATs3ZyI=ZOWx(iik$z
|
|
|
|
|
|
|
|
zZ854;r!9d2Qeq~=y5u>N@LdW<%3ZQ5R0SJtvBt!<P-p@1Ng7Sje0#=;CQ{95v|<UX
|
|
|
|
|
|
|
|
zKJ)KL10Q-F7@2jrZ*$1cTw<hqw0rz4?;x?Y#cuK)IynMuR(Me1S%u@PnaE$G@KY52
|
|
|
|
|
|
|
|
zPYTD|l*oTo;n*7s{vCy%rtmuye!9Z#xfR9X|8#|4$=`2)pP}%t(|aap96j=F4Do+v
|
|
|
|
|
|
|
|
z9PjsdR~CQn^vFXW=pG;WM?LcLy<oqO{O>&S{Q7VH;3NMRk37A8SbE(@zJeW)@*)I{
|
|
|
|
|
|
|
|
zW!zid<2>?GM<@Hp&+^F27w9=Y^7vl~An`}uTbBFCU+R&^$t&mzANiz5-X4ULJie=f
|
|
|
|
|
|
|
|
z5a{;3&LfZiBLKR=NB*lGd3gi-hL8NedF0WjL3jDc_j=^dbj8ijedK@Rk>_h+=J!7G
|
|
|
|
|
|
|
|
z|Lc)o#QOj0BR}AgU&`{M_=5<Nb$uSixU}zuEPuR@{7jGhDwePGkzeeQZ(#YQKJsfl
|
|
|
|
|
|
|
|
z@-dcQ?<3#hk#A!8Rv-DRJ@N^b$9G<kw|>6pk<Ykd=4(Fk-}A_~vHTBx<RA3N%e=hD
|
|
|
|
|
|
|
|
zNB#+q{Ee*tX&?EQJo56r^%Woaw>|RTX8ndII&b|<<OvNp`m)T!XEBcXcdo)0DS6z&
|
|
|
|
|
|
|
|
z5&2~b$JZ0VS9<jHyUX1`T;Vu75czh6<J*hi*D8FW!oR3+?dSIujxi^C9#Hr>3V(`m
|
|
|
|
|
|
|
|
z)C0~4ME>_mUi<li!p~FkFDo3EOhnIX3fF#)rte1}*j-GI$REKt>i+_Ia2E!2q{5+J
|
|
|
|
|
|
|
|
z>T?0(G7tQc(m>}a99PdG7NsL&#$mUb9<f`e<gpgrO%G_5!l6fKt&g5Y#^L`GdPM)#
|
|
|
|
|
|
|
|
z3dh_gc#pz${oJqg>vri?@>>5Bj7vR;|4%Di`~R%cU#<LkUdf{#q&{C#xUSDveDsvV
|
|
|
|
|
|
|
|
z5h4UQ(>q8H=xD}KKf1iL6dtBDsh<lNM|&+(_%bE0^?X6eFIV#4@{zxtaRj>Ef243-
|
|
|
|
|
|
|
|
zZ+A29?LT`N_m=C|3fJWtH=Ya<AsPC|@;)-)!8bB~6ysjI$9v>^pp@v-9{iw1jXBjv
|
|
|
|
|
|
|
|
zkDOydzn;fX=O8csnhRTe2JzBfhqJ$s*Z5Q)yv7G#uke{l{|<$psc_kU!R{=DW3LYK
|
|
|
|
|
|
|
|
z`j4>#^2%T2!XxAx8Ap5RTMnBPK9P9@N#>!ynjWbi#6bu#Ckc+e2Lhg^M{xOqkAAg6
|
|
|
|
|
|
|
|
z;ZunR!5`$6^IFt72zu)25j_|SAm~|1kKm92K^}V|!7m0#1RQlD_<Ddu(6gEz!8ZUT
|
|
|
|
|
|
|
|
zg8XcH1aAdMB=SfH<=nvHrxGvnvhVQfxlzf(uGH5qg-=s@zQnj!&v%tP^c=<U?<@Q?
|
|
|
|
|
|
|
|
z;>Djk829RVNXbKww9}&sKb?5dv!8LVp5G~X=$Xdx=M;{%7CkRA?$z@*B@aDkar`ZX
|
|
|
|
|
|
|
|
zpF+Io8DQM2C&1%N+6!|l=xBxGT}1Spz_?e>8A=}hV6OnGQh1Q!qGz6up0JYF{q{n}
|
|
|
|
|
|
|
|
zrT>rT_-ZAOu`l`?7>A$e+k$5lzDD6~3SX=68<hTa3hz?#TF+M)mwEm!j(^if&vzBB
|
|
|
|
|
|
|
|
z%X>HD@E`9Y;{W|hUi-60$zP)6A6N31Djffn0R;UR<D&mfg?~oj14@rx*YF=HKnO0Q
|
|
|
|
|
|
|
|
zhps|f8qc`2*9^`-*&{D@Pw?Q-37YG{>9Vq=dJoR<z(&SVuFL5W{ns)s?XsTZ_5vo!
|
|
|
|
|
|
|
|
zdF#1b>DTr4MWz1=rT^;+*Yo^)3dfu&{@^|t2zEb9kKjizj%>O=Ok!O8zme<nM5Raf
|
|
|
|
|
|
|
|
zlaSJbF)jKdN`98Y8x*eh15qD6O-f#ucZ-kww;9KF1p7nT|J<(hM3p~3Qus!N->vYN
|
|
|
|
|
|
|
|
z!tYafqrx9lcwFI+Fphd|QutE}*Y)<i(u1{C>a$PDJA}(#;gAQH^{WgGPK2PD9?>&e
|
|
|
|
|
|
|
|
z;n-scK3?H13ZKL{{D<9%^nmcEK0tzt-Kk1Xg3?9*OoeY&_yVQp48rBTtXkn05H9a!
|
|
|
|
|
|
|
|
zYZTt3^lVi47KLwDcv9ilD;)Bo|4Rzj^50T8{E>3q&Nu=+?(S5$9(VUJF5~MN9$ybB
|
|
|
|
|
|
|
|
zc|E@NDO}H!|G_xwU(Xv)DtSF`{1@Y}i?)*YxaSo<fpDRhl%8q=rM$Sm2tv?GkKo?#
|
|
|
|
|
|
|
|
zY<&<S8h4l*!p{^vB0pK-y1lA=@Cy{K+vP%q>vp_c;ac8dT<T#q*Z*dPqaNh0Oqy|&
|
|
|
|
|
|
|
|
zw_5p+dyOEJOZ$JD2bcbgdx{{Dm;UDd2brPwwKfP4;ocz#c6EPvopJGh0{j1#k38-p
|
|
|
|
|
|
|
|
zf}ltDpQ(&PPX+=^rz;%ulF*q7uN06%+-n5E?aA~=`{G_B2zIy9BRDV++&+>Xx#tWF
|
|
|
|
|
|
|
|
z1UyfV%rj#F5&_RzZurmp$rpx;+8E@w(^E=6){7uLAW4V3yi)+j+z9gOkvaqpJv-<D
|
|
|
|
|
|
|
|
zwYh<n-^M(GXA};3p@Ymo59(C>c-ezjar}@64|3cZBwqXxzhylX{USaQ0FmI;Hb!Of
|
|
|
|
|
|
|
|
z;Hw!AatI%}%UVSGjNsyb#3LW%IOZsj$V<60E<A`=bG*}oi$Aw0d_40AdYKpfJzSnq
|
|
|
|
|
|
|
|
z911S?pYfM&K!OLyy75{MzLD{y7eCyU*ZXkjvM<yW^eXvDuBiR3utKibg$h58aReAI
|
|
|
|
|
|
|
|
zLQ|Fe(E?H!QSum%LKl1FPv->u?^Y0kVdJqf*WQXh5>ZL#>~7d1T$XNzRMN3@-c-`{
|
|
|
|
|
|
|
|
zjF_ox%;ikwAX-Uh|G0MMf4RY4a;wayksJC$l_AQnq6-J3qU#^HKjF3TiK&E_QWb-R
|
|
|
|
|
|
|
|
z{s$b@>I$i3VvCb(*O<NGKo^iIH^t*o`l}sICLg7yp^FNxABj|gE@5P|bZtj!v*ZDO
|
|
|
|
|
|
|
|
ziE9I{0&ap2dxzkCjeNLU0v~Mmqw7(H_uN4VmAtA_8Be#i;;)>z&NwaZB_pclY?^BO
|
|
|
|
|
|
|
|
zlc5UQr|a=9TC17Co(zO<3n$ZqbrU3^U;cVmZ1B4k@?)-*d=mQQU(fk@I<xk%&PqNB
|
|
|
|
|
|
|
|
z{qk?*{Mvu4my%CHzx>#nfwX<B+mcU0zx>!MfV6$Avyx9jzx+FpnMm8m_XWu(VURFP
|
|
|
|
|
|
|
|
z-Mp<K&ZQm>r|U(Bu!)RIfSc6NRV@IAV?!>pkqdzKgD>Kb><utq!#=<65$Dowwkv)L
|
|
|
|
|
|
|
|
z?v0;C3DD`y-^=-1BqN7j|M4B)mY>%P5tsZ(*W}HQV%qY1^0%Dt=Bnb%C_k#gTmDAE
|
|
|
|
|
|
|
|
zV1Euhn%-dlmm^V;L?zrxX{GX4^GnYo9>2uC<lo_wznlw-F{?@PN%#~cma-q@{9&D$
|
|
|
|
|
|
|
|
zc(464DKqlRcQ6spaQ=({95OtJo=%xd)&DJA|7|RZ`p3RO>`VW{eI#ptP@~HnWJ6wi
|
|
|
|
|
|
|
|
zkkwQW`x+#E;$j!5VjT95qQ`50myi8JY<R9`V0!&2`q-~#`)z9c9aF+S_H*>l?vp4O
|
|
|
|
|
|
|
|
zq-n>xtbQi~0$EKzA>dO4c*oy*&M)PaJQA1i4$5!aPXsvJ&6`DOC)D5Z^hiFz@uwo;
|
|
|
|
|
|
|
|
zQ@N*~Z)E$^Sf2zzVK~HJ`zV$FM$Yf8Z?P|G{z{ok^}hq`zi$7ND3jzD|EH1PrR?9v
|
|
|
|
|
|
|
|
z_7{jD4uhUJ_PM3<Kl35|-$eOK`EL);$d>jW=NMl9@mEf*eUD%EWs$HT5)}m%5B5&6
|
|
|
|
|
|
|
|
z@4>59xWH=8kM^HRkJtW#VxK}yL39=({(Rs@=-1<pd4=;!IYsa^&adB1kS6&hd{gX8
|
|
|
|
|
|
|
|
zMh+Kpe);Yp$>P7n|3>*s_5U69uEaq$gz}$8kK~vBgJe(9ZN|H>FcVetIx>TJe3$m-
|
|
|
|
|
|
|
|
m$7`K;>=I-S@r#t)KL7@ja=S5i?^i1S##OGwI8UNC|NjH~pc5<r
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
literal 0
|
|
|
|
|
|
|
|
HcmV?d00001
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
--
|
|
|
|
|
|
|
|
2.49.0
|
|
|
|
|
|
|
|
|