400 lines
16 KiB
C
400 lines
16 KiB
C
/* sim_buildROMs.c: Boot ROM / Boot program load internal support
|
|
|
|
Copyright (c) 2011, Mark Pizzolato
|
|
|
|
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
|
|
MARK PIZZOLATO 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.
|
|
|
|
Except as contained in this notice, the name of Robert M Supnik shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from Robert M Supnik.
|
|
|
|
*/
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
/*
|
|
|
|
This program builds C include files which can be used to contain the contents
|
|
of ROM or other boot code needed by simulators.
|
|
|
|
Current Internal ROM files being built:
|
|
|
|
ROM/Boot File: Include File: Size: Checksum:
|
|
=======================================================================================
|
|
*/
|
|
struct ROM_File_Descriptor {
|
|
const char *BinaryName; const char *IncludeFileName; size_t expected_size; unsigned int checksum; const char *ArrayName; const char *Comments;} ROMs[] = {
|
|
{"VAX/ka655x.bin", "VAX/vax_ka655x_bin.h", 131072, 0xFF7673B6, "vax_ka655x_bin"},
|
|
{"VAX/ka620.bin", "VAX/vax_ka620_bin.h", 65536, 0xFF7F930F, "vax_ka620_bin"},
|
|
{"VAX/ka630.bin", "VAX/vax_ka630_bin.h", 65536, 0xFF7F73EF, "vax_ka630_bin"},
|
|
{"VAX/ka610.bin", "VAX/vax_ka610_bin.h", 16384, 0xFFEF3312, "vax_ka610_bin"},
|
|
{"VAX/ka750_new.bin", "VAX/vax_ka750_bin_new.h", 1024, 0xFFFE7BE5, "vax_ka750_bin_new", "From ROM set: E40A9, E41A9, E42A9, E43A9 (Boots: A=DD, B=DB, C=DU"},
|
|
{"VAX/ka750_old.bin", "VAX/vax_ka750_bin_old.h", 1024, 0xFFFEBAA5, "vax_ka750_bin_old", "From ROM set: 990A9, 948A9, 906A9, 905A9 (Boots: A=DD, B=DM, C=DL, D=DU"},
|
|
{"VAX/vmb.exe", "VAX/vax_vmb_exe.h", 44544, 0xFFC014BB, "vax_vmb_exe"},
|
|
{"PDP11/lunar11/lunar.lda", "PDP11/pdp11_vt_lunar_rom.h", 13824 , 0xFFF15D00, "lunar_lda"},
|
|
{"swtp6800/swtp6800/swtbug.bin", "swtp6800/swtp6800/swtp_swtbug_bin.h", 1024, 0xFFFE4FBC, "swtp_swtbug_bin"},
|
|
};
|
|
|
|
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <sys/stat.h>
|
|
|
|
#if defined(_WIN32)
|
|
#include <sys/utime.h>
|
|
#define utimbuf _utimbuf
|
|
#define utime _utime
|
|
#else
|
|
#include <utime.h>
|
|
#endif
|
|
|
|
int sim_read_ROM_include(const char *include_filename,
|
|
int *psize,
|
|
unsigned char **pROMData,
|
|
unsigned int *pchecksum,
|
|
char **prom_array_name,
|
|
int *defines_found)
|
|
{
|
|
FILE *iFile;
|
|
char line[256];
|
|
size_t i;
|
|
size_t bytes_written = 0;
|
|
size_t allocated_size = 0;
|
|
int define_size_found = 0;
|
|
int define_filename_found = 0;
|
|
int define_array_found = 0;
|
|
|
|
*psize = 0;
|
|
*pchecksum = 0;
|
|
*pROMData = NULL;
|
|
*prom_array_name = NULL;
|
|
if (NULL == (iFile = fopen (include_filename, "r")))
|
|
return -1;
|
|
|
|
memset (line, 0, sizeof (line));
|
|
|
|
while (fgets (line, sizeof(line)-1, iFile)) {
|
|
unsigned int byte;
|
|
char *c;
|
|
|
|
switch (line[0]) {
|
|
case '#':
|
|
if (0 == strncmp ("#define BOOT_CODE_SIZE ", line, 23))
|
|
define_size_found = 1;
|
|
if (0 == strncmp ("#define BOOT_CODE_FILENAME ", line, 27))
|
|
define_filename_found = 1;
|
|
if (0 == strncmp ("#define BOOT_CODE_ARRAY ", line, 24))
|
|
define_array_found = 1;
|
|
break;
|
|
case ' ':
|
|
case '/':
|
|
case '*':
|
|
case '\n':
|
|
break;
|
|
case 'u': /* unsigned char {array_name}[] */
|
|
*prom_array_name = (char *)calloc(512, sizeof(char));
|
|
if (1 == sscanf (line, "unsigned char %s[]", *prom_array_name)) {
|
|
c = strchr (*prom_array_name, '[');
|
|
if (c)
|
|
*c = '\0';
|
|
}
|
|
break;
|
|
case '0': /* line containing byte data */
|
|
c = line;
|
|
while (1 == sscanf (c, "0x%2Xd,", &byte)) {
|
|
if (bytes_written >= allocated_size) {
|
|
allocated_size += 2048;
|
|
*pROMData = (unsigned char *)realloc(*pROMData, allocated_size);
|
|
}
|
|
*(*pROMData + bytes_written++) = (unsigned char)byte;
|
|
c += 5;
|
|
}
|
|
break;
|
|
}
|
|
if (strchr (line, '}'))
|
|
break;
|
|
}
|
|
fclose (iFile);
|
|
for (i=0; i<bytes_written; ++i)
|
|
*pchecksum += *(*pROMData + i);
|
|
*pchecksum = ~*pchecksum;
|
|
*psize = bytes_written;
|
|
*defines_found = (3 == (define_size_found + define_filename_found + define_array_found));
|
|
return 0;
|
|
}
|
|
|
|
int sim_make_ROMs_entry(const char *rom_filename)
|
|
{
|
|
FILE *rFile;
|
|
struct stat statb;
|
|
unsigned char *ROMData = NULL;
|
|
unsigned int checksum = 0;
|
|
char *c;
|
|
int i;
|
|
char cleaned_rom_filename[512];
|
|
char include_filename[512];
|
|
char array_name[512];
|
|
|
|
if (NULL == (rFile = fopen (rom_filename, "rb"))) {
|
|
printf ("Error Opening ROM binary file '%s' for input: %s\n", rom_filename, strerror(errno));
|
|
return -1;
|
|
}
|
|
if (stat (rom_filename, &statb)) {
|
|
printf ("Error stating '%s': %s\n", rom_filename, strerror(errno));
|
|
fclose (rFile);
|
|
return -1;
|
|
}
|
|
ROMData = (unsigned char *)malloc (statb.st_size);
|
|
if ((size_t)(statb.st_size) != fread (ROMData, sizeof(*ROMData), statb.st_size, rFile)) {
|
|
printf ("Error reading '%s': %s\n", rom_filename, strerror(errno));
|
|
fclose (rFile);
|
|
free (ROMData);
|
|
return -1;
|
|
}
|
|
fclose (rFile);
|
|
for (i=0; i<statb.st_size; ++i)
|
|
checksum += ROMData[i];
|
|
checksum = ~checksum;
|
|
strncpy (cleaned_rom_filename, rom_filename, sizeof(cleaned_rom_filename)-2);
|
|
cleaned_rom_filename[sizeof(cleaned_rom_filename)-1] = '\0';
|
|
while ((c = strchr (cleaned_rom_filename, '\\')))
|
|
*c = '/';
|
|
strcpy (array_name, cleaned_rom_filename);
|
|
for (c=array_name; *c; ++c)
|
|
if (isupper(*c))
|
|
*c = (char)tolower(*c);
|
|
if ((c = strchr (array_name, '.')))
|
|
*c = '_';
|
|
if ((c = strchr (array_name, '/')))
|
|
*c = '_';
|
|
sprintf (include_filename, "%s.h", cleaned_rom_filename);
|
|
if ((c = strrchr (include_filename, '/')))
|
|
sprintf (c+1, "%s.h", array_name);
|
|
else
|
|
sprintf (include_filename, "%s.h", array_name);
|
|
printf ("The ROMs array entry for this new ROM image file should look something like:\n");
|
|
printf ("{\"%s\", \"%s\", %d, 0x%08X, \"%s\"}\n",
|
|
rom_filename, include_filename, (int)(statb.st_size), checksum, array_name);
|
|
free (ROMData);
|
|
return 1;
|
|
}
|
|
|
|
int sim_make_ROM_include(const char *rom_filename,
|
|
int expected_size,
|
|
unsigned int expected_checksum,
|
|
const char *include_filename,
|
|
const char *rom_array_name,
|
|
const char *Comments)
|
|
{
|
|
FILE *rFile;
|
|
FILE *iFile;
|
|
time_t now;
|
|
int bytes_written = 0;
|
|
int include_bytes;
|
|
int c;
|
|
struct stat statb;
|
|
const char *load_filename;
|
|
unsigned char *ROMData = NULL;
|
|
unsigned char *include_ROMData = NULL;
|
|
char *include_array_name = NULL;
|
|
unsigned int checksum = 0;
|
|
unsigned int include_checksum;
|
|
int defines_found;
|
|
|
|
if (NULL == (rFile = fopen (rom_filename, "rb"))) {
|
|
printf ("Error Opening ROM binary file '%s' for input: %s\n", rom_filename, strerror(errno));
|
|
if (0 != sim_read_ROM_include(include_filename,
|
|
&include_bytes,
|
|
&include_ROMData,
|
|
&include_checksum,
|
|
&include_array_name,
|
|
&defines_found))
|
|
return -1;
|
|
c = ((include_checksum == expected_checksum) &&
|
|
(include_bytes == expected_size) &&
|
|
(0 == strcmp(include_array_name, rom_array_name)) &&
|
|
defines_found);
|
|
free(include_ROMData);
|
|
free(include_array_name);
|
|
if (!c)
|
|
printf ("Existing ROM include file: %s has unexpected content\n", include_filename);
|
|
else
|
|
printf ("Existing ROM include file: %s looks good\n", include_filename);
|
|
return (c ? 0 : -1);
|
|
}
|
|
if (stat (rom_filename, &statb)) {
|
|
printf ("Error stating '%s': %s\n", rom_filename, strerror(errno));
|
|
fclose (rFile);
|
|
return -1;
|
|
}
|
|
if (statb.st_size != expected_size) {
|
|
printf ("Error: ROM file '%s' has an unexpected size: %d vs %d\n", rom_filename, (int)statb.st_size, expected_size);
|
|
printf ("This can happen if the file was transferred or unpacked incorrectly\n");
|
|
printf ("and in the process tried to convert line endings rather than passing\n");
|
|
printf ("the file's contents unmodified\n");
|
|
fclose (rFile);
|
|
return -1;
|
|
}
|
|
ROMData = (unsigned char *)malloc (statb.st_size);
|
|
if ((size_t)(statb.st_size) != fread (ROMData, sizeof(*ROMData), statb.st_size, rFile)) {
|
|
printf ("Error reading '%s': %s\n", rom_filename, strerror(errno));
|
|
fclose (rFile);
|
|
free (ROMData);
|
|
return -1;
|
|
}
|
|
fclose (rFile);
|
|
for (c=0; c<statb.st_size; ++c)
|
|
checksum += ROMData[c];
|
|
checksum = ~checksum;
|
|
if ((expected_checksum != 0) && (checksum != expected_checksum)) {
|
|
printf ("Error: ROM file '%s' has an unexpected checksum: 0x%08X vs 0x%08X\n", rom_filename, checksum, expected_checksum);
|
|
printf ("This can happen if the file was transferred or unpacked incorrectly\n");
|
|
printf ("and in the process tried to convert line endings rather than passing\n");
|
|
printf ("the file's contents unmodified\n");
|
|
free (ROMData);
|
|
return -1;
|
|
}
|
|
/*
|
|
* If the target include file already exists, determine if it contains the exact
|
|
* data in the base ROM image. If so, then we are already done
|
|
*/
|
|
if (0 == sim_read_ROM_include(include_filename,
|
|
&include_bytes,
|
|
&include_ROMData,
|
|
&include_checksum,
|
|
&include_array_name,
|
|
&defines_found)) {
|
|
c = ((include_checksum == expected_checksum) &&
|
|
(include_bytes == expected_size) &&
|
|
(0 == strcmp (include_array_name, rom_array_name)) &&
|
|
(0 == memcmp (include_ROMData, ROMData, include_bytes)) &&
|
|
defines_found);
|
|
free(include_ROMData);
|
|
free(include_array_name);
|
|
if (c) {
|
|
free (ROMData);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (NULL == (iFile = fopen (include_filename, "w"))) {
|
|
printf ("Error Opening '%s' for output: %s\n", include_filename, strerror(errno));
|
|
free (ROMData);
|
|
return -1;
|
|
}
|
|
load_filename = strrchr (rom_filename, '/');
|
|
if (load_filename)
|
|
++load_filename;
|
|
else
|
|
load_filename = rom_filename;
|
|
time (&now);
|
|
fprintf (iFile, "#ifndef ROM_%s_H\n", rom_array_name);
|
|
fprintf (iFile, "#define ROM_%s_H 0\n", rom_array_name);
|
|
fprintf (iFile, "/*\n");
|
|
fprintf (iFile, " %s produced at %s", include_filename, ctime(&now));
|
|
fprintf (iFile, " from %s which was last modified at %s", rom_filename, ctime(&statb.st_mtime));
|
|
fprintf (iFile, " file size: %d (0x%X) - checksum: 0x%08X\n", (int)statb.st_size, (int)statb.st_size, checksum);
|
|
fprintf (iFile, " This file is a generated file and should NOT be edited or changed by hand.\n");
|
|
if (Comments)
|
|
fprintf (iFile, "\n %s\n\n", Comments);
|
|
fprintf (iFile, "*/\n");
|
|
fprintf (iFile, "#define BOOT_CODE_SIZE 0x%X\n", (int)statb.st_size);
|
|
fprintf (iFile, "#define BOOT_CODE_FILENAME \"%s\"\n", load_filename);
|
|
fprintf (iFile, "#define BOOT_CODE_ARRAY %s\n", rom_array_name);
|
|
fprintf (iFile, "unsigned char %s[] = {", rom_array_name);
|
|
for (bytes_written=0;bytes_written<statb.st_size; ++bytes_written) {
|
|
c = ROMData[bytes_written];
|
|
if (0 == bytes_written%16)
|
|
fprintf (iFile,"\n");
|
|
fprintf (iFile,"0x%02X,", c&0xFF);
|
|
}
|
|
free (ROMData);
|
|
fprintf (iFile,"};\n");
|
|
fprintf (iFile, "#endif /* ROM_%s_H */\n", rom_array_name);
|
|
fclose (iFile);
|
|
if (1) { /* Set Modification Time on the include file to be the modification time of the ROM file */
|
|
struct utimbuf times;
|
|
|
|
times.modtime = statb.st_mtime;
|
|
times.actime = statb.st_atime;
|
|
utime (include_filename, ×);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
Usage(void)
|
|
{
|
|
size_t i;
|
|
|
|
printf ("sim_BuildROMs Usage:\n");
|
|
printf ("sim_BuildROMs\n");
|
|
printf (" invoked with no arguments will verify and/or produce all\n");
|
|
printf (" known ROM include files\n");
|
|
printf ("sim_BuildROMs -checksum ROM-File-name\n");
|
|
printf (" computes the checksum on a ROM image file and provides a\n");
|
|
printf (" template which can be added to the ROMs array in the\n");
|
|
printf (" source file sim_BuildROMs.c\n");
|
|
printf ("sim_BuildROMs ROM-File-name\n");
|
|
printf (" if the 'ROM-File-name' specified is a file name already\n");
|
|
printf (" contained in the ROMs array, only that ROM image file's\n");
|
|
printf (" include file will be verified and/or created\n");
|
|
printf (" if the 'ROM-File-name' specified is not a file name already\n");
|
|
printf (" contained in the ROMs array, that ROM's checksum is computed\n");
|
|
printf (" and a template which can be added to the ROMs array in the\n");
|
|
printf (" source file sim_BuildROMs.c is displayed.\n");
|
|
printf ("\n");
|
|
printf ("Current ROM files:\n");
|
|
printf ("\n");
|
|
printf ("BinaryName: IncludeFileName: Size: Checksum: ROM Array Name:\n");
|
|
printf ("=============================================================================\n");
|
|
for (i=0; i<sizeof(ROMs)/sizeof(ROMs[0]); ++i)
|
|
printf("%-17s%-23s%8d 0x%08X %s\n", ROMs[i].BinaryName, ROMs[i].IncludeFileName, (int)ROMs[i].expected_size, ROMs[i].checksum, ROMs[i].ArrayName);
|
|
exit(2);
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
size_t i;
|
|
int status = 0;
|
|
|
|
if (argc == 1) { /* invoked without any arguments */
|
|
for (i=0; i<sizeof(ROMs)/sizeof(ROMs[0]); ++i)
|
|
status += sim_make_ROM_include (ROMs[i].BinaryName, ROMs[i].expected_size, ROMs[i].checksum, ROMs[i].IncludeFileName, ROMs[i].ArrayName, ROMs[i].Comments);
|
|
exit((status == 0) ? 0 : 2);
|
|
}
|
|
if ((0 == strcmp(argv[1], "/?")) ||
|
|
(0 == strcmp(argv[1], "-?")) ||
|
|
(0 == strcmp(argv[1], "/help")) ||
|
|
(0 == strcmp(argv[1], "-help")))
|
|
Usage();
|
|
if ((0 == strcmp(argv[1], "-checksum")) && (argc > 2))
|
|
status = sim_make_ROMs_entry (argv[2]);
|
|
else {
|
|
for (i=0; i<sizeof(ROMs)/sizeof(ROMs[0]); ++i)
|
|
if (0 == strcmp(argv[1], ROMs[i].BinaryName))
|
|
break;
|
|
if (i == sizeof(ROMs)/sizeof(ROMs[0]))
|
|
status = sim_make_ROMs_entry (argv[1]);
|
|
else
|
|
status = sim_make_ROM_include (ROMs[i].BinaryName, ROMs[i].expected_size, ROMs[i].checksum, ROMs[i].IncludeFileName, ROMs[i].ArrayName, ROMs[i].Comments);
|
|
}
|
|
exit((status == 0) ? 0 : 2);
|
|
}
|