Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
rom.c
Go to the documentation of this file.
1 /* Part of the Xemu project. https://github.com/lgblgblgb/xemu
2  Copyright (C)2016-2022 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17 
18 #include "xemu/emutools.h"
19 #include "rom.h"
20 #include "xemu/emutools_files.h"
21 #include "memcontent.h"
22 
23 #define CHARACTER_SET_DEFINER_8X8 const Uint8 vga_font_8x8[2048]
24 #include "xemu/vgafonts.c"
25 
26 
27 int rom_date = 0;
29 int rom_is_stub = 0;
31 
37 static Uint8 *external_image = NULL;
38 
39 static const char _rom_name_closed[] = "Closed-ROMs";
40 static const char _rom_name_open[] = "Open-ROMs";
41 static const char _rom_name_xemu[] = "Xemu-ROMs";
42 static const char _rom_name_bad[] = "?unknown?";
43 static const char _rom_name_preboot[] = "?before-boot?";
44 
45 const char *rom_name = _rom_name_preboot;
46 
47 
48 void rom_clear_reports ( void )
49 {
50  rom_is_overriden = 0;
51  rom_is_openroms = 0;
52  rom_is_stub = 0;
53  rom_date = 0;
54  rom_name = _rom_name_preboot;
55 }
56 
57 
58 void rom_unset_requests ( void )
59 {
62  rom_load_custom(NULL); // to cancel possible already set custom ROM
63 }
64 
65 
66 static int rom_detect_try ( const Uint8 *rom, const Uint8 rom_id )
67 {
68  if (*rom != rom_id)
69  return -1;
70  int ret = 0;
71  for (int a = 0; a < 6; a++) {
72  rom++;
73  if (*rom >= '0' && *rom <= '9')
74  ret = ret * 10 + *rom - '0';
75  else
76  return -1;
77  }
78  return ret;
79 }
80 
81 
82 void rom_detect_date ( const Uint8 *rom )
83 {
84  if (!rom) {
85  DEBUGPRINT("ROM: version check is disabled (NULL pointer), previous version info: %d" NL, rom_date);
86  return;
87  }
89  DEBUGPRINT("ROM: SHA1 checksum is %s" NL, rom_hash_str);
90  const int res_open = rom_detect_try(rom + 0x10, 0x4F); // 'O' (0x4F) at ofs $10 + followed by "rom date": open-ROMs
91  const int res_closed = rom_detect_try(rom + 0x16, 0x56); // 'V' (0x56) at ofs $16 + followed by "rom date": closed-ROMs
92  rom_is_stub = 0;
93  rom_is_openroms = 0;
94  rom_date = -1;
95  rom_name = _rom_name_bad;
96  if (res_open >= 0 && res_closed < 0) {
97  rom_date = res_open;
98  rom_is_openroms = 1;
99  rom_name = _rom_name_open;
100  goto ok;
101  }
102  if (res_open < 0 && res_closed >= 0) {
103  rom_date = res_closed;
104  if (!strncmp((const char*)rom + 0x16 + 7, "Xemu", 3)) {
105  rom_is_stub = 1;
106  rom_name = _rom_name_xemu;
107  } else
108  rom_name = _rom_name_closed;
109  goto ok;
110  }
111  if (res_open < 0 && res_closed < 0)
112  DEBUGPRINT("ROM: version check failed (no leading 'V' or 'O' at ROM ofs $10/$16)" NL);
113  else
114  ERROR_WINDOW("Serious problem: ROM can be identified both as open and closed ROM?!");
115  return;
116 ok:
117  DEBUGPRINT("ROM: %s detected with version %d" NL, rom_name, rom_date);
118 }
119 
120 
121 void rom_clear_rom ( Uint8 *rom )
122 {
123  memset(rom, 0, MEMINITDATA_INITROM_SIZE);
124 }
125 
126 
127 static const Uint8 xemu_stub_rom[] = {
128 #include "rom/mega65-xemu-stub-rom.cdata"
129 };
130 
131 
132 void rom_make_xemu_stub_rom ( Uint8 *rom, const char *save_file )
133 {
134  // The message is line-wrapped by the ROM maker code itself. '\n' works as forcing into a new line,
135  // as expected, '~' toggles highlighted/normal mode. Text MUST be ended with a '\n'!
136  // The text must be larger in result than 25 lines, since the ROM code expects scrolling/etc.
137  static const char *msg =
138  "~Your emulated MEGA65 seems to work, welcome to the MEGA65 emulation of the "
139  "X-Emulators (Xemu for short) framework!~ Yes, it's ~Xemu~ and ~not~ Zemu.\n\n"
140 
141  "Use the cursor up/down keys to scroll this message.\n\n"
142 
143  "~Quick jump-start for you:~\n\n"
144 
145  "~TL;DR~ if you don't want to read all of these, you can use Xemu's menu to open "
146  "a web page with your default browser which can help to get the needed ROM. To do this "
147  "right click into the emulator window, choose \"~Help (online)~\" and \"~Xemu MEGA65 help "
148  "page~\" within that sub-menu.\n\n"
149 
150  "~The long story:~\n\n"
151 
152  "This message comes from Xemu's built-in \"stub\" ROM, ready to be replaced with "
153  "some real ROM to be able to do anything useful. The reason you see this running "
154  "now is the fact of lacking MEGA65.ROM file on your emulated SD-card. Once you "
155  "have a MEGA65.ROM file installed it will be used instead.\n\n"
156 
157  "Unfortunately, because of legal "
158  "reasons, it's not possible to include the real ROM. MEGA65 project has an "
159  "on-going effort to write an open-source free ROM called \"~open-ROMs~\" project, "
160  "however it's not yet ready for general usage at all.\n\n"
161 
162  "Thus you ~almost certainly~ "
163  "need the \"proprietary\" ROM, often called \"~closed-ROMs~\" project, it's an enhanced "
164  "and bug-fixed version of the original C65 ROM, with improved BASIC and other "
165  "MEGA65 features. However being a derivate work based on original C65 ROM, it "
166  "cannot be used without the blessing of the repspective owner of the original "
167  "Commodore(TM) rights, it's not freely distributable, and certainly cannot be "
168  "included in an open-source GNU/GPL emulator, like Xemu. That ROM on the other "
169  "hand is legally licensed to any (real) MEGA65 owners by the copyright holders.\n\n"
170 
171  "~About this ROM:~\n\n"
172 
173  "This ROM is an actual machine language code (contained by Xemu) written in "
174  "assembly. Easter egg: if you're patient enough to even read this, you may want to "
175  "try the 's' key, it won't do anything useful now (restart), but may do something "
176  "other in the future. Who knows.\n\n"
177 
178  "Thanks for your patience and understanding.\n\n"
179  "- LGB (Xemu's author)\n\n"
180  "~<END OF TEXT>~"
181  /* --- it's important to have an '\n' at the end! --- */
182  "\n"
183  ;
184  int dyn_rom = 0;
185  if (!rom) {
187  dyn_rom = 1;
188  }
190  // Make a fake closed-rom version identifier Xemu to stop complain later about its missing nature
191  strcpy((char*)rom + 0x16, "V920000XemuStubROM! Part of the Xemu project.");
192  memcpy(rom + 0xF800, vga_font_8x8, sizeof vga_font_8x8);
193  // Note: we use the "C64 kernal" port of the C65 ROM since C65/MEGA65 starts in C64 mode.
194  // Fortunately it's aligned such a way as would be the real address when used as kernal ROM in C64 mode.
195  rom[0xFFFF] = rom[0xFFFD] = rom[0xFFFB] = 0xE0; // high bytes of vectors
196  rom[0xFFFC] = 0x00; // reset vector low byte
197  rom[0xFFFA] = 0x03; // NMI vector low byte
198  rom[0xFFFE] = 0x06; // IRQ vector low byte
199  memcpy(rom + 0xE000, xemu_stub_rom, sizeof xemu_stub_rom);
200  const Uint8 normal_colour = 0xF; // light grey
201  const Uint8 hi_colour = 7; // yellow
202  memset(rom + 0x10000, 0x20, 0x8000); // default char (space)
203  memset(rom + 0x18000, normal_colour, 0x8000); // default background colour
204  // This madness wraps the text and renders into 80 column width screen size (though without height limit)
205  const char *m = msg;
206  Uint8 colour = normal_colour;
207  int pos = 0;
208  while (*m) {
209  Uint8 c = *m++;
210  if (c == '~') {
211  colour = (colour == normal_colour) ? hi_colour : normal_colour;
212  continue;
213  } else if (c == '\n') {
214  pos += 80 - (pos % 80);
215  continue;
216  }
217  if (c == ' ' && *m > ' ') {
218  const int xpos = pos % 80;
219  if (!xpos)
220  continue;
221  const char *p = m;
222  int l = 0;
223  while (*p++ > ' ')
224  l++;
225  if (l + xpos > 79)
226  pos += 79 - xpos;
227  }
228  rom[0x10000 + pos] = c;
229  rom[0x18000 + pos] = colour;
230  pos++;
231  }
232  rom[0x10000 + pos] = 0xFF; // end of text marker, should be after '\n' in the source text
233  if (save_file)
234  xemu_save_file(save_file, rom, MEMINITDATA_INITROM_SIZE, NULL);
235  if (dyn_rom)
236  free(rom);
237 }
238 
239 
240 int rom_load_custom ( const char *fn )
241 {
242  if (!fn || !*fn) {
243  DEBUGPRINT("ROM: unsetting custom ROM (clear request)" NL);
244  if (external_image) {
245  free(external_image);
246  external_image = NULL;
247  }
248  return 0;
249  } else if (xemu_load_file(fn, NULL, MEMINITDATA_INITROM_SIZE, MEMINITDATA_INITROM_SIZE, "Failed to load external ROM on user's request.\nUsing the default installed, instead.") > 0) {
250  DEBUGPRINT("ROM: custom ROM load was OK, setting custom ROM" NL);
251  if (external_image) {
252  memcpy(external_image, xemu_load_buffer_p, MEMINITDATA_INITROM_SIZE);
253  free(xemu_load_buffer_p);
254  } else {
255  external_image = xemu_load_buffer_p;
256  }
257  xemu_load_buffer_p = NULL;
260  return 1;
261  }
262  DEBUGPRINT("ROM: custom ROM setting failed, not touching custom ROM request setting (now: %s)" NL, external_image ? "SET" : "UNSET");
263  return 0;
264 }
265 
266 
267 // Called by hypervisor on exiting the first (reset) trap.
268 // Thus this is an ability to override the ROM what HICKUP loaded for us with some another one.
269 // Return value: negative: no custom ROM is needed to be loaded,
270 // otherwise, the RESET vector of the ROM (CPU PC value)
271 int rom_do_override ( Uint8 *rom )
272 {
273  rom_is_overriden = 0;
274  rom_is_external = 0;
275  if (rom_stubrom_requested) {
276  DEBUGPRINT("ROM: using stub-ROM was forced" NL);
278  goto overriden;
279  }
280  if (rom_initrom_requested) {
281  DEBUGPRINT("ROM: using init-ROM was forced" NL);
283  goto overriden;
284  }
285  if (external_image) {
286  DEBUGPRINT("ROM: using external pre-loaded ROM" NL);
287  memcpy(rom, external_image, MEMINITDATA_INITROM_SIZE);
288  rom_is_external = 1;
289  goto overriden;
290  }
292  // Special option to allow ROM to be loaded from the preferences directory as the "default" ROM:
293  // it's kind of override, but not really and handled as "default" if this option is allowed.
294  if (xemu_load_file("@MEGA65.ROM", NULL, MEMINITDATA_INITROM_SIZE, MEMINITDATA_INITROM_SIZE, NULL) > 0) {
295  DEBUGPRINT("ROM: using 'ROM from prefdir' policy for default ROM, ROM is from file %s" NL, xemu_load_filepath);
297  free(xemu_load_buffer_p);
298  xemu_load_buffer_p = NULL;
299  rom_is_external = 1;
300  goto overriden_but_lie;
301  }
302  }
303  return -1; // No override has been done
304 overriden:
305  rom_is_overriden = 1;
306 overriden_but_lie:
307  // return with the RESET vector of the ROM
308  return rom[0xFFFC] | (rom[0xFFFD] << 8);
309 }
rom_is_openroms
int rom_is_openroms
Definition: rom.c:28
rom_do_override
int rom_do_override(Uint8 *rom)
Definition: rom.c:271
rom_clear_rom
void rom_clear_rom(Uint8 *rom)
Definition: rom.c:121
rom_unset_requests
void rom_unset_requests(void)
Definition: rom.c:58
XEMU_STUB_ROM_SAVE_FILENAME
#define XEMU_STUB_ROM_SAVE_FILENAME
Definition: rom.h:21
emutools.h
sha1_hash_str
char sha1_hash_str[41]
Definition: emutools.h:237
rom_detect_date
void rom_detect_date(const Uint8 *rom)
Definition: rom.c:82
rom_hash_str
sha1_hash_str rom_hash_str
Definition: rom.c:30
colour
Uint32 colour
Definition: vera.c:67
rom_load_custom
int rom_load_custom(const char *fn)
Definition: rom.c:240
rom_is_stub
int rom_is_stub
Definition: rom.c:29
fn
const char * fn
Definition: roms.c:42
rom_date
int rom_date
Definition: rom.c:27
vga_font_8x8
const Uint8 vga_font_8x8[2048]
rom_initrom_requested
int rom_initrom_requested
Definition: rom.c:33
rom_from_prefdir_allowed
int rom_from_prefdir_allowed
Definition: rom.c:34
Uint8
uint8_t Uint8
Definition: fat32.c:51
sha1_checksum_as_string
void sha1_checksum_as_string(sha1_hash_str hash_str, const Uint8 *data, Uint32 size)
Definition: emutools.c:1853
rom_is_external
int rom_is_external
Definition: rom.c:36
emutools_files.h
xemu_malloc
void * xemu_malloc(size_t size)
Definition: emutools.c:226
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
xemu_save_file
int xemu_save_file(const char *filename_in, void *data, int size, const char *cry)
Definition: emutools_files.c:622
ERROR_WINDOW
#define ERROR_WINDOW(...)
Definition: xep128.h:116
rom_clear_reports
void rom_clear_reports(void)
Definition: rom.c:48
NL
#define NL
Definition: fat32.c:37
xemu_load_file
int xemu_load_file(const char *filename, void *store_to, int min_size, int max_size, const char *cry)
Definition: emutools_files.c:674
rom.h
xemu_load_buffer_p
void * xemu_load_buffer_p
Definition: emutools_files.c:34
rom_stubrom_requested
int rom_stubrom_requested
Definition: rom.c:32
xemu_load_filepath
char xemu_load_filepath[PATH_MAX]
Definition: emutools_files.c:35
memcontent.h
rom_is_overriden
int rom_is_overriden
Definition: rom.c:35
rom_name
const char * rom_name
Definition: rom.c:45
vgafonts.c
meminitdata_initrom
const Uint8 meminitdata_initrom[MEMINITDATA_INITROM_SIZE]
Definition: memcontent.c:2724
MEMINITDATA_INITROM_SIZE
#define MEMINITDATA_INITROM_SIZE
Definition: memcontent.h:43
rom_make_xemu_stub_rom
void rom_make_xemu_stub_rom(Uint8 *rom, const char *save_file)
Definition: rom.c:132
rom
char * rom
Definition: rc2014.c:38