campctf2023-chall-tis256

Zachtronics TIS100-inspired reversing challenge for CampCTF 2023
git clone https://git.sinitax.com/sinitax/campctf2023-chall-tis256
Log | Files | Refs | Submodules | README | sfeed.txt

tis256-gui.c (5974B)


      1#include "asm.h"
      2#include "util.h"
      3
      4#include "raylib.h"
      5#include "raymath.h"
      6#include "tpu.h"
      7
      8#include <math.h>
      9#include <string.h>
     10
     11#define TPU_PAD 15
     12#define TPU_SIZE 160
     13#define TPU_DIST (TPU_SIZE + 2 * TPU_PAD)
     14
     15struct tpu_info {
     16	int inst_off;
     17};
     18
     19static uint16_t window_width = 0;
     20static uint16_t window_height = 0;
     21
     22static bool drag = false;
     23static Vector2 drag_mouse = { 0 };
     24static Vector2 drag_target = { 0 };
     25
     26static float mouse_scroll = 0;
     27static Vector2 mouse = { 0 };
     28
     29static Camera2D camera = { 0 };
     30
     31static struct tis tis = { 0 };
     32
     33int (*cleanup)(void) = NULL;
     34const char *progname = "tis256-gui";
     35
     36static void
     37draw_rect(float x, float y, float w, float h, Color c)
     38{
     39	DrawRectangle((int) x, (int) y, (int) w, (int) h, c);
     40}
     41
     42static void
     43draw_text(float x, float y, const char *str, int size, Color c)
     44{
     45	DrawText(str, (int) x, (int) y, size, c);
     46}
     47
     48static void
     49draw_tpu(struct tpu *tpu)
     50{
     51	const int max_h = (TPU_SIZE - 8) / 8;
     52	const int max_w = (TPU_SIZE - 8) / 5;
     53	struct tpu_info *info;
     54	char linebuf[32];
     55	int inst, off;
     56	float sx, sy;
     57	size_t len;
     58	Vector2 v;
     59
     60	sx = (float) tpu->x * TPU_DIST;
     61	sy = (float) tpu->y * TPU_DIST;
     62
     63	v = Vector2Transform((Vector2) { sx, sy }, GetCameraMatrix2D(camera));
     64	if (v.x >= window_width || v.y >= window_height) return;
     65
     66	v = Vector2Transform((Vector2) { sx + TPU_SIZE, sy + TPU_SIZE },
     67		GetCameraMatrix2D(camera));
     68	if (v.x < 0 || v.y < 0) return;
     69
     70	draw_rect(sx, sy, TPU_SIZE, TPU_SIZE,
     71		tpu->status == STATUS_RUN ? GREEN : WHITE);
     72	if (camera.zoom >= 1) {
     73		draw_rect(sx + 2, sy + 2, TPU_SIZE - 4, TPU_SIZE - 4, BLACK);
     74		info = tpu->user;
     75		inst = info->inst_off;
     76		for (off = 0; inst < TPU_MAX_INST; inst++) {
     77			if (tpu->labels[inst]) {
     78				len = strlen(tpu->labels[inst]);
     79				snprintf(linebuf, 32, "%.*s:", max_w - 1,
     80					tpu->labels[inst]);
     81				draw_text(sx + 4, sy + 4 + (float) off * 8,
     82					linebuf, 6, WHITE);
     83				if (++off >= max_h) break;
     84			}
     85			if (inst < tpu->inst_cnt) {
     86				asm_print_inst(linebuf, 32, &tpu->insts[inst]);
     87				draw_text(sx + 4, sy + 4 + (float) off * 8,
     88					linebuf, 6, WHITE);
     89				if (++off >= max_h) break;
     90			}
     91		}
     92	}
     93	if (tpu->ports[DIR_LEFT].type != 0)
     94		draw_rect(sx - TPU_PAD, sy + TPU_SIZE / 2.f, TPU_PAD, 4,
     95			tpu->ports[DIR_LEFT].attached ? WHITE : RED);
     96	if (tpu->ports[DIR_RIGHT].type != 0)
     97		draw_rect(sx + TPU_SIZE, sy + TPU_SIZE / 2.f, TPU_PAD, 4,
     98			tpu->ports[DIR_RIGHT].attached ? WHITE : RED);
     99	if (tpu->ports[DIR_UP].type != 0)
    100		draw_rect(sx + TPU_SIZE / 2.f, sy - TPU_PAD, 4, TPU_PAD,
    101			tpu->ports[DIR_UP].attached ? WHITE : RED);
    102	if (tpu->ports[DIR_DOWN].type != 0)
    103		draw_rect(sx + TPU_SIZE / 2.f, sy + TPU_SIZE, 4, TPU_PAD,
    104			tpu->ports[DIR_DOWN].attached ? WHITE : RED);
    105}
    106
    107static struct tpu *
    108in_tpu(Vector2 pos)
    109{
    110	struct tpu *tpu;
    111	float x, y;
    112	size_t i;
    113
    114	for (tpu = tis.tpu_vec.tpus, i = 0; i < tis.tpu_vec.cnt; i++, tpu++) {
    115		x = (float) tpu->x * TPU_DIST;
    116		y = (float) tpu->y * TPU_DIST;
    117		if (pos.x >= x && pos.x < x + TPU_SIZE
    118				&& pos.y >= y && pos.y < y + TPU_SIZE)
    119			return tpu;
    120	}
    121
    122	return NULL;
    123}
    124
    125int
    126main(int argc, const char **argv)
    127{
    128	Vector2 wpos_prev, wpos;
    129	struct tpu *tpu;
    130	struct tpu_info *info;
    131	float min_x, min_y;
    132	float max_x, max_y;
    133	double last_step;
    134	FILE *tis_stdin, *tis_stdout;
    135	float x, y;
    136	size_t i;
    137
    138	if (argc < 2 || argc > 4) {
    139		fprintf(stderr, "Usage: tis256-gui FILE [STDIN] [STDOUT]\n");
    140		exit(1);
    141	}
    142
    143	tis_stdin = NULL;
    144	if (argc >= 3) {
    145		tis_stdin = fopen(argv[2], "r");
    146		if (!tis_stdin) die("fopen '%s':", argv[2]);
    147	}
    148
    149	tis_stdout = NULL;
    150	if (argc >= 4) {
    151		tis_stdout = fopen(argv[3], "r");
    152		if (!tis_stdout) die("fopen '%s':", argv[3]);
    153	}
    154
    155	tis_load(&tis, argv[1], tis_stdin, tis_stdout);
    156
    157	min_x = min_y = INFINITY;
    158	max_x = max_y = -INFINITY;
    159	for (tpu = tis.tpu_vec.tpus, i = 0; i < tis.tpu_vec.cnt; i++, tpu++) {
    160		tpu->user = calloc(1, sizeof(struct tpu_info));
    161		if (!tpu->user) die("calloc:");
    162		x = (float) tpu->x * TPU_DIST;
    163		y = (float) tpu->y * TPU_DIST;
    164		min_x = MIN(min_x, x);
    165		min_y = MIN(min_y, y);
    166		max_x = MAX(max_x, x + TPU_SIZE);
    167		max_y = MAX(max_y, y + TPU_SIZE);
    168	}
    169	if (min_x == INFINITY) min_x = min_y = max_x = max_y = 0;
    170
    171	SetConfigFlags(FLAG_WINDOW_RESIZABLE);
    172	InitWindow(800, 600, "tis256-gui");
    173	SetTargetFPS(60);
    174
    175	camera.target.x = (min_x + max_x) / 2;
    176	camera.target.y = (min_y + max_y) / 2;
    177	camera.zoom = 1.f;
    178
    179	while (!WindowShouldClose()) {
    180		if (IsWindowResized() || !window_width || !window_height) {
    181			window_width = (uint16_t) GetScreenWidth();
    182			window_height = (uint16_t) GetScreenHeight();
    183			camera.offset.x = (float) window_width / 2;
    184			camera.offset.y = (float) window_height / 2;
    185		}
    186
    187		mouse = GetMousePosition();
    188		if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
    189			drag_mouse = mouse;
    190			drag_target = camera.target;
    191			drag = true;
    192		} else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) {
    193			drag = false;
    194		}
    195
    196		mouse_scroll = GetMouseWheelMove();
    197		if (mouse_scroll != 0) {
    198			wpos_prev = Vector2Transform(mouse,
    199				MatrixInvert(GetCameraMatrix2D(camera)));
    200			if (IsKeyDown(KEY_LEFT_SHIFT) && (tpu = in_tpu(wpos_prev))) {
    201				info = tpu->user;
    202				info->inst_off += mouse_scroll > 0 ? -1 : 1;
    203				info->inst_off = MAX(0, MIN(info->inst_off,
    204					(int) tpu->inst_cnt-1));
    205			} else {
    206				camera.zoom *= mouse_scroll > 0 ? 2.f : 0.5f;
    207				wpos = Vector2Transform(mouse,
    208					MatrixInvert(GetCameraMatrix2D(camera)));
    209				camera.target.x += wpos_prev.x - wpos.x;
    210				camera.target.y += wpos_prev.y - wpos.y;
    211			}
    212		}
    213
    214		if (IsKeyDown(KEY_S) && GetTime() > last_step + 0.05) {
    215			last_step = GetTime();
    216			tis_step(&tis);
    217		}
    218
    219		if (drag) {
    220			camera.target.x = drag_target.x
    221				- (mouse.x - drag_mouse.x) / camera.zoom;
    222			camera.target.y = drag_target.y
    223				- (mouse.y - drag_mouse.y) / camera.zoom;
    224		}
    225
    226		BeginDrawing();
    227
    228		ClearBackground(BLACK);
    229
    230		BeginMode2D(camera);
    231
    232		for (tpu = tis.tpu_vec.tpus, i = 0; i < tis.tpu_vec.cnt; i++, tpu++)
    233			draw_tpu(tpu);
    234
    235		EndMode2D();
    236
    237		EndDrawing();
    238	}
    239
    240	tis_deinit(&tis);
    241}