/* * VARCem Virtual ARchaeological Computer EMulator. * An emulator of (mostly) x86-based PC systems and devices, * using the ISA,EISA,VLB,MCA and PCI system buses, roughly * spanning the era between 1981 and 1995. * * This file is part of the VARCem Project. * * Implement the external ROM loader. * This loader defines a 'ROM set' to be one or more images * of ROM chip(s), where all properties of these defined in * a single 'ROM definition' (text) file. * * NOTE: This file uses a fairly generic script parser, which can * be re-used for others parts. This would mean passing the * 'parser' function a pointer to either a command handler, * or to use a generic handler, and then pass it a pointer * to a command table. For now, we don't. * * Version: @(#)rom_load.c 1.0.6 2018/03/31 * * Author: Fred N. van Kempen, * * Copyright 2018 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the * following conditions are met: * * 1. Redistributions of source code must retain the entire * above notice, this list of conditions and the following * disclaimer. * * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names * of its contributors may be used to endorse or promote * products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include "emu.h" #include "mem.h" #include "rom.h" #include "device.h" #include "plat.h" #define MAX_ARGS 16 /* max number of arguments */ /* Grab the value from a string. */ static uint32_t get_val(char *str) { long unsigned int l = 0UL; if ((strlen(str) > 1) && /* hex always is 0x... */ (sscanf(str, "0x%lx", &l) == 0)) /* no valid field found */ sscanf(str, "%i", (int *)&l); /* try decimal.. */ return(l); } /* Process a single (logical) command line. */ static int process(int ln, int argc, char **argv, romdef_t *r) { again: if (! strcmp(argv[0], "size")) { /* Total size of image. */ r->total = get_val(argv[1]); } else if (! strcmp(argv[0], "offset")) { /* Offset into the ROM area. */ r->offset = get_val(argv[1]); } else if (! strcmp(argv[0], "mode")) { /* Loading method to use for this image. */ if (! strcmp(argv[1], "linear")) r->mode = 0; else if (! strcmp(argv[1], "interleaved")) r->mode = 1; else { pclog("ROM: invalid mode '%s' on line %d.\n", argv[1], ln); return(0); } } else if (! strcmp(argv[0], "optional")) { /* * This is an optional file. * Next word is the name of the configuration * variable this depends on, for example "basic" * or "romdos". */ if (! machine_get_config_int(argv[1])) return(1); /* Skip the keyword and variable name, and re-parse. */ argv += 2; argc -= 2; goto again; } else if (! strcmp(argv[0], "file")) { /* Specify the image filename and/or additional parameters. */ mbstowcs(r->files[r->nfiles].path, argv[1], sizeof_w(r->files[r->nfiles].path)); r->files[r->nfiles].skip = 0; r->files[r->nfiles].offset = r->offset; r->files[r->nfiles].size = r->total; switch(argc) { case 5: r->files[r->nfiles].size = get_val(argv[4]); /*FALLTHROUGH*/ case 4: r->files[r->nfiles].offset = get_val(argv[3]); /*FALLTHROUGH*/ case 3: r->files[r->nfiles].skip = get_val(argv[2]); break; } r->nfiles++; } else if (! strcmp(argv[0], "font")) { /* Load a video controller font. */ r->fontnum = atoi(argv[1]); mbstowcs(r->fontfn, argv[2], sizeof_w(r->fontfn)); } else if (! strcmp(argv[0], "video")) { /* Load a video controller BIOS. */ mbstowcs(r->vidfn, argv[1], sizeof_w(r->vidfn)); sscanf(argv[2], "%i", &r->vidsz); } else { pclog("ROM: invalid command '%s' on line %d.\n", argv[0], ln); return(0); } return(1); } /* Parse a script file, and call the command handler for each command. */ static int parser(FILE *fp, romdef_t *r) { char line[1024]; char *args[MAX_ARGS]; int doskip, doquot; int skipnl, dolit; int a, c, l; char *sp; /* Initialize the parser and run. */ l = 0; for (;;) { /* Clear the per-line stuff. */ skipnl = dolit = doquot = 0; doskip = 1; for (a=0; afontnum = -1; /* Parse and process the file. */ i = parser(fp, r); (void)fclose(fp); /* Show the resulting data. */ if (! test_only) { pclog("Size : %lu\n", r->total); pclog("Offset : 0x%06lx (%lu)\n", r->offset, r->offset); pclog("Mode : %s\n", (r->mode == 1)?"interleaved":"linear"); pclog("Files : %d\n", r->nfiles); for (c=0; cnfiles; c++) { pclog(" [%d] : '%ls', %i, 0x%06lx, %i\n", c+1, r->files[c].path, r->files[c].skip, r->files[c].offset, r->files[c].size); } if (r->fontnum != -1) pclog("Font : %i, '%ls'\n", r->fontnum, r->fontfn); if (r->vidsz != 0) pclog("VideoBIOS: '%ls', %i\n", r->vidfn, r->vidsz); /* Actually perform the work. */ switch(r->mode) { case 0: /* linear file(s) */ /* We loop on all files. */ for (c=0; cnfiles; c++) { wcscpy(script, path); wcscat(script, r->files[c].path); pc_path(script, sizeof_w(script), NULL); i = rom_load_linear(script, r->files[c].offset, r->files[c].size, r->files[c].skip, rom); if (i != 1) break; } if (r->total >= 0x010000) biosmask = (r->total - 1); break; case 1: /* interleaved file(s) */ /* We loop on all files. */ for (c=0; cnfiles/2; c+=2) { wcscpy(script, path); wcscat(script, r->files[c].path); pc_path(script, sizeof_w(script), NULL); wcscpy(temp, path); wcscat(temp, r->files[c+1].path); pc_path(temp, sizeof_w(temp), NULL); i = rom_load_interleaved(script, temp, r->files[c].offset, r->files[c].size, r->files[c].skip, rom); if (i != 1) break; } if (r->total >= 0x010000) biosmask = (r->total - 1); break; } /* Create a full pathname for the video font file. */ if (r->fontnum != -1) { wcscpy(temp, path); wcscat(temp, r->fontfn); pc_path(r->fontfn, sizeof_w(r->fontfn), temp); } /* Create a full pathname for the video BIOS file. */ if (r->vidsz != 0) { wcscpy(temp, path); wcscat(temp, r->vidfn); pc_path(r->vidfn, sizeof_w(r->vidfn), temp); } pclog("ROM: status %d, tot %u, mask 0x%06lx\n", i, r->total, biosmask); } return(i); }