1// MIT License
2
3// Copyright (c) 2017 Vadim Grigoruk @nesbox // grigoruk@gmail.com
4
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23#include "run.h"
24#include "console.h"
25#include "studio/fs.h"
26#include "ext/md5.h"
27#include <time.h>
28
29static void onTrace(void* data, const char* text, u8 color)
30{
31#if defined(BUILD_EDITORS)
32 Run* run = (Run*)data;
33 run->console->trace(run->console, text, color);
34#endif
35}
36
37static void onError(void* data, const char* info)
38{
39#if defined(BUILD_EDITORS)
40 Run* run = (Run*)data;
41 setStudioMode(run->studio, TIC_CONSOLE_MODE);
42 run->console->error(run->console, info);
43#endif
44}
45
46static void onExit(void* data)
47{
48 Run* run = (Run*)data;
49
50 run->exit = true;
51}
52
53static const char* data2md5(const void* data, s32 length)
54{
55 const char *str = data;
56 MD5_CTX c;
57
58 static char out[33];
59
60 MD5_Init(&c);
61
62 while (length > 0)
63 {
64 MD5_Update(&c, str, length > 512 ? 512: length);
65
66 length -= 512;
67 str += 512;
68 }
69
70 {
71 enum{Size = 16};
72 u8 digest[Size];
73 MD5_Final(digest, &c);
74
75 for (s32 n = 0; n < Size; ++n)
76 snprintf(out + n*2, sizeof("ff"), "%02x", digest[n]);
77 }
78
79 return out;
80}
81
82static void initPMemName(Run* run)
83{
84 tic_mem* tic = run->tic;
85
86 const void* data = &tic->cart.bank0;
87 s32 dataSize = sizeof(tic_bank);
88
89 if(strlen(tic->saveid))
90 {
91 data = tic->saveid;
92 dataSize = (s32)strlen(data);
93 }
94
95 const char* md5 = data2md5(data, dataSize);
96
97 strcpy(run->saveid, TIC_LOCAL);
98 strcat(run->saveid, md5);
99}
100
101static void tick(Run* run)
102{
103 if (getStudioMode(run->studio) != TIC_RUN_MODE)
104 return;
105
106 tic_mem* tic = run->tic;
107
108 tic_core_tick(tic, &run->tickData);
109
110 enum {Size = sizeof(tic_persistent)};
111
112 if(memcmp(run->pmem.data, tic->ram->persistent.data, Size))
113 {
114 tic_fs_saveroot(run->fs, run->saveid, &tic->ram->persistent, Size, true);
115 memcpy(run->pmem.data, tic->ram->persistent.data, Size);
116 }
117
118 if(run->exit)
119#if defined(BUILD_EDITORS)
120 setStudioMode(run->studio, TIC_CONSOLE_MODE);
121#else
122 studio_exit(run->studio);
123#endif
124}
125
126void initRun(Run* run, Console* console, tic_fs* fs, Studio* studio)
127{
128 *run = (Run)
129 {
130 .studio = studio,
131 .tic = getMemory(studio),
132 .console = console,
133 .fs = fs,
134 .tick = tick,
135 .exit = false,
136 .tickData = (tic_tick_data)
137 {
138 .error = onError,
139 .trace = onTrace,
140 .exit = onExit,
141 .data = run,
142 },
143 };
144
145 {
146 enum {Size = sizeof(tic_persistent)};
147 memset(&run->tic->ram->persistent, 0, Size);
148
149 initPMemName(run);
150
151 s32 size = 0;
152 void* data = tic_fs_loadroot(run->fs, run->saveid, &size);
153
154 if(data) SCOPE(free(data))
155 {
156 memset(&run->tic->ram->persistent, 0, Size);
157 memcpy(&run->tic->ram->persistent, data, MIN(size, Size));
158 }
159
160 memcpy(run->pmem.data, run->tic->ram->persistent.data, Size);
161 }
162
163 tic_sys_preseed();
164}
165
166void freeRun(Run* run)
167{
168 free(run);
169}