"Fossies" - the Fresh Open Source Software Archive

Member "free42/util/rom2raw.c" (8 Apr 2019, 38850 Bytes) of package /linux/misc/free42.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rom2raw.c" see the Fossies "Dox" file reference documentation.

    1 /*****************************************************************************
    2  * rom2raw -- extracts user code from HP-41 ROM images
    3  * Copyright (C) 2004-2019  Thomas Okken
    4  *
    5  * This program is free software; you can redistribute it and/or modify
    6  * it under the terms of the GNU General Public License, version 2,
    7  * as published by the Free Software Foundation.
    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, see http://www.gnu.org/licenses/.
   16  *****************************************************************************/
   17 
   18 #include <stdio.h>
   19 #include <string.h>
   20 #include <stdlib.h>
   21 #include <stdarg.h>
   22 #include <errno.h>
   23 
   24 /* The following is a list of all XROM numbers used by the HP-42S. Some of
   25  * these match functions that may occur in HP-41 code. When such XROM numbers
   26  * are found, rom2raw will *not* warn about them; all others are flagged as
   27  * being potentially problematic XROM calls.
   28  * NOTE: XROM 01,33 - 01,38 are hyperbolics and their inverses. They match the
   29  * corresponding XROM numbers in the Math module, but in that module, they are
   30  * implemented in user code. When rom2raw is used to convert the Math module,
   31  * these XROMs will be converted to XEQ commands, which is probably just as
   32  * well; if they are encountered in any other ROM, they will be left alone,
   33  * which means the HP-42S/Free42 machine code implementations will execute.
   34  * NOTE: XROM 29,27 - 29,32 are functions specific to the unidirectional
   35  * infrared printer interface. The IR Printer module also has these functions,
   36  * but the XROM numbers are different (see table below). I could handle this by
   37  * remapping those XROMs, but then again, why bother: I doubt that any ROM
   38  * exists that actually calls these functions. This *is* something to consider
   39  * when writing a generic HP-41-to-42S user code translator, though.
   40  *         +------------+------------+
   41  *         | IR Printer |   HP-42S   |
   42  * +-------+------------+------------+
   43  * | MAN   | XROM 29,28 | XROM 29,27 |
   44  * | NORM  | XROM 29,31 | XROM 29,28 |
   45  * | TRACE | XROM 29,38 | XROM 29,29 |
   46  * | PRON  | XROM 29,33 | XROM 29,30 |
   47  * | PROFF | XROM 29,32 | XROM 29,31 |
   48  * | DELAY | XROM 29,27 | XROM 29,32 |
   49  * +-------+------------+------------+
   50  */
   51 
   52 typedef struct {
   53     int number;
   54     int allow;
   55     char *name;
   56 } xrom_spec;
   57 
   58 xrom_spec hp42s_xroms[] = {
   59     /* XROM 01,33 */ 0x061, 1, "SINH",      /* Math (see notes, above) */
   60     /* XROM 01,34 */ 0x062, 1, "COSH",      /* Math (see notes, above) */
   61     /* XROM 01,35 */ 0x063, 1, "TANH",      /* Math (see notes, above) */
   62     /* XROM 01,36 */ 0x064, 1, "ASINH",     /* Math (see notes, above) */
   63     /* XROM 01,37 */ 0x065, 1, "ATANH",     /* Math (see notes, above) */
   64     /* XROM 01,38 */ 0x066, 1, "ACOSH",     /* Math (see notes, above) */
   65     /* XROM 01,47 */ 0x06F, 0, "COMB",
   66     /* XROM 01,48 */ 0x070, 0, "PERM",
   67     /* XROM 01,49 */ 0x071, 0, "RAN",
   68     /* XROM 01,50 */ 0x072, 0, "COMPLEX",
   69     /* XROM 01,51 */ 0x073, 0, "SEED",
   70     /* XROM 01,52 */ 0x074, 0, "GAMMA",
   71     /* XROM 02,31 */ 0x09F, 0, "BEST",
   72     /* XROM 02,32 */ 0x0A0, 0, "EXPF",
   73     /* XROM 02,33 */ 0x0A1, 0, "LINF",
   74     /* XROM 02,34 */ 0x0A2, 0, "LOGF",
   75     /* XROM 02,35 */ 0x0A3, 0, "PWRF",
   76     /* XROM 02,36 */ 0x0A4, 0, "SLOPE",
   77     /* XROM 02,37 */ 0x0A5, 0, "SUM",
   78     /* XROM 02,38 */ 0x0A6, 0, "YINT",
   79     /* XROM 02,39 */ 0x0A7, 0, "CORR",
   80     /* XROM 02,40 */ 0x0A8, 0, "FCSTX",
   81     /* XROM 02,41 */ 0x0A9, 0, "FCSTY",
   82     /* XROM 02,42 */ 0x0AA, 0, "INSR",
   83     /* XROM 02,43 */ 0x0AB, 0, "DELR",
   84     /* XROM 02,44 */ 0x0AC, 0, "WMEAN",
   85     /* XROM 02,45 */ 0x0AD, 0, "LINSigma",
   86     /* XROM 02,46 */ 0x0AE, 0, "ALLSigma",
   87     /* XROM 03,34 */ 0x0E2, 0, "HEXM",
   88     /* XROM 03,35 */ 0x0E3, 0, "DECM",
   89     /* XROM 03,36 */ 0x0E4, 0, "OCTM",
   90     /* XROM 03,37 */ 0x0E5, 0, "BINM",
   91     /* XROM 03,38 */ 0x0E6, 0, "BASE+",
   92     /* XROM 03,39 */ 0x0E7, 0, "BASE-",
   93     /* XROM 03,40 */ 0x0E8, 0, "BASE*",
   94     /* XROM 03,41 */ 0x0E9, 0, "BASE/",
   95     /* XROM 03,42 */ 0x0EA, 0, "BASE+/-",
   96     /* XROM 09,25 */ 0x259, 0, "POLAR",
   97     /* XROM 09,26 */ 0x25A, 0, "RECT",
   98     /* XROM 09,27 */ 0x25B, 0, "RDX.",
   99     /* XROM 09,28 */ 0x25C, 0, "RDX,",
  100     /* XROM 09,29 */ 0x25D, 0, "ALL",
  101     /* XROM 09,30 */ 0x25E, 0, "MENU",
  102     /* XROM 09,31 */ 0x25F, 0, "X>=0?",
  103     /* XROM 09,32 */ 0x260, 0, "X>=Y?",
  104     /* XROM 09,34 */ 0x262, 0, "CLKEYS",
  105     /* XROM 09,35 */ 0x263, 0, "KEYASN",
  106     /* XROM 09,36 */ 0x264, 0, "LCLBL",
  107     /* XROM 09,37 */ 0x265, 0, "REAL?",
  108     /* XROM 09,38 */ 0x266, 0, "MAT?",
  109     /* XROM 09,39 */ 0x267, 0, "CPX?",
  110     /* XROM 09,40 */ 0x268, 0, "STR?",
  111     /* XROM 09,42 */ 0x26A, 0, "CPXRES",
  112     /* XROM 09,43 */ 0x26B, 0, "REALRES",
  113     /* XROM 09,44 */ 0x26C, 0, "EXITALL",
  114     /* XROM 09,45 */ 0x26D, 0, "CLMENU",
  115     /* XROM 09,46 */ 0x26E, 0, "GETKEY",
  116     /* XROM 09,47 */ 0x26F, 0, "CUSTOM",
  117     /* XROM 09,48 */ 0x270, 0, "ON",
  118     /* XROM 22,07 */ 0x587, 1, "NOT",       /* Advantage */
  119     /* XROM 22,08 */ 0x588, 1, "AND",       /* Advantage */
  120     /* XROM 22,09 */ 0x589, 1, "OR",        /* Advantage */
  121     /* XROM 22,10 */ 0x58A, 1, "XOR",       /* Advantage */
  122     /* XROM 22,11 */ 0x58B, 1, "ROTXY",     /* Advantage */
  123     /* XROM 22,12 */ 0x58C, 1, "BIT?",      /* Advantage */
  124     /* XROM 24,49 */ 0x631, 1, "AIP",       /* Advantage */
  125     /* XROM 25,01 */ 0x641, 1, "ALENG",     /* Extended Functions */
  126     /* XROM 25,06 */ 0x646, 1, "AROT",      /* Extended Functions */
  127     /* XROM 25,07 */ 0x647, 1, "ATOX",      /* Extended Functions */
  128     /* XROM 25,28 */ 0x65C, 1, "POSA",      /* Extended Functions */
  129     /* XROM 25,47 */ 0x66F, 1, "XTOA",      /* Extended Functions */
  130     /* XROM 25,56 */ 0x678, 1, "SigmaREG?", /* CX Extended Functions */
  131     /* XROM 26,01 */ 0x681, 1, "ADATE",     /* Time */
  132     /* XROM 26,04 */ 0x684, 1, "ATIME",     /* Time */
  133     /* XROM 26,05 */ 0x685, 1, "ATIME24",   /* Time */
  134     /* XROM 26,06 */ 0x686, 1, "CLK12",     /* Time */
  135     /* XROM 26,07 */ 0x687, 1, "CLK24",     /* Time */
  136     /* XROM 26,12 */ 0x68C, 1, "DATE",      /* Time */
  137     /* XROM 26,13 */ 0x68D, 1, "DATE+",     /* Time */
  138     /* XROM 26,14 */ 0x68E, 1, "DDAYS",     /* Time */
  139     /* XROM 26,15 */ 0x68F, 1, "DMY",       /* Time */
  140     /* XROM 26,16 */ 0x690, 1, "DOW",       /* Time */
  141     /* XROM 26,17 */ 0x691, 1, "MDY",       /* Time */
  142     /* XROM 26,28 */ 0x69C, 1, "TIME",      /* Time */
  143     /* XROM 27,09 */ 0x6C9, 0, "TRANS",
  144     /* XROM 27,10 */ 0x6CA, 0, "CROSS",
  145     /* XROM 27,11 */ 0x6CB, 0, "DOT",
  146     /* XROM 27,12 */ 0x6CC, 0, "DET",
  147     /* XROM 27,13 */ 0x6CD, 0, "UVEC",
  148     /* XROM 27,14 */ 0x6CE, 0, "INVRT",
  149     /* XROM 27,15 */ 0x6CF, 0, "FNRM",
  150     /* XROM 27,16 */ 0x6D0, 0, "RSUM",
  151     /* XROM 27,17 */ 0x6D1, 0, "R<>R",
  152     /* XROM 27,18 */ 0x6D2, 0, "I+",
  153     /* XROM 27,19 */ 0x6D3, 0, "I-",
  154     /* XROM 27,20 */ 0x6D4, 0, "J+",
  155     /* XROM 27,21 */ 0x6D5, 0, "J-",
  156     /* XROM 27,22 */ 0x6D6, 0, "STOEL",
  157     /* XROM 27,23 */ 0x6D7, 0, "RCLEL",
  158     /* XROM 27,24 */ 0x6D8, 0, "STOIJ",
  159     /* XROM 27,25 */ 0x6D9, 0, "RCLIJ",
  160     /* XROM 27,26 */ 0x6DA, 0, "NEWMAT",
  161     /* XROM 27,27 */ 0x6DB, 0, "OLD",
  162     /* XROM 27,28 */ 0x6DC, 0, "left",
  163     /* XROM 27,29 */ 0x6DD, 0, "right",
  164     /* XROM 27,30 */ 0x6DE, 0, "up",
  165     /* XROM 27,31 */ 0x6DF, 0, "down",
  166     /* XROM 27,33 */ 0x6E1, 0, "EDIT",
  167     /* XROM 27,34 */ 0x6E2, 0, "WRAP",
  168     /* XROM 27,35 */ 0x6E3, 0, "GROW",
  169     /* XROM 27,39 */ 0x6E7, 0, "DIM?",
  170     /* XROM 27,40 */ 0x6E8, 0, "GETM",
  171     /* XROM 27,41 */ 0x6E9, 0, "PUTM",
  172     /* XROM 27,42 */ 0x6EA, 0, "[MIN]",
  173     /* XROM 27,43 */ 0x6EB, 0, "[MAX]",
  174     /* XROM 27,44 */ 0x6EC, 0, "[FIND]",
  175     /* XROM 27,45 */ 0x6ED, 0, "RNRM",
  176     /* XROM 29,08 */ 0x748, 1, "PRA",       /* Printer */
  177     /* XROM 29,18 */ 0x752, 1, "PRSigma",   /* Printer */
  178     /* XROM 29,19 */ 0x753, 1, "PRSTK",     /* Printer */
  179     /* XROM 29,20 */ 0x754, 1, "PRX",       /* Printer */
  180     /* XROM 29,27 */ 0x75B, 0, "MAN",       /* see notes, above */
  181     /* XROM 29,28 */ 0x75C, 0, "NORM",      /* see notes, above */
  182     /* XROM 29,29 */ 0x75D, 0, "TRACE",     /* see notes, above */
  183     /* XROM 29,30 */ 0x75E, 0, "PON",       /* see notes, above */
  184     /* XROM 29,31 */ 0x75F, 0, "POFF",      /* see notes, above */
  185     /* XROM 29,32 */ 0x760, 0, "DELAY",     /* see notes, above */
  186     /* XROM 29,33 */ 0x761, 0, "PRUSR",
  187     /* XROM 29,34 */ 0x762, 0, "PRLCD",
  188     /* XROM 29,35 */ 0x763, 0, "CLLCD",
  189     /* XROM 29,36 */ 0x764, 0, "AGRAPH",
  190     /* XROM 29,37 */ 0x765, 0, "PIXEL",
  191     /* XROM 31,15 */ 0x7CF, 0, "ACCEL",     /* Free42 Android/iOS extension */
  192     /* XROM 31,16 */ 0x7D0, 0, "LOCAT",     /* Free42 Android/iOS extension */
  193     /* XROM 31,17 */ 0x7D1, 0, "HEADING",   /* Free42 Android/iOS extension */
  194     /* XROM 31,18 */ 0x7D2, 0, "FPTEST",    /* Free42 Intel FP test suite */
  195     /* sentinel */      -1, 0, NULL
  196 };
  197 
  198 int entry[1024], entry_index[1024], mach_entry[1024];
  199 int rom[65536], rom_size;
  200 int pages, rom_number[16], num_func[16];
  201 int convert_strings = 1;
  202 
  203 int entry_index_compar(const void *ap, const void *bp) {
  204     int a = *((int *) ap);
  205     int b = *((int *) bp);
  206     return entry[a] - entry[b];
  207 }
  208 
  209 unsigned char chartrans[] = {
  210     31, 'x', 31, 16, 31, 31, 31, 14, 31, 31, 31, 31, 17, 23, 31, 31,
  211     31, 31, 38, 20, 20, 22, 22, 28, 28, 29, 29, 25, 25, 12, 18, 30,
  212     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
  213     48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
  214     64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
  215     80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
  216     96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
  217     112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 7, 124, 15, 5, 127
  218 };
  219 
  220 void string_convert(int len, unsigned char *s) {
  221     int i;
  222     if (!convert_strings)
  223         return;
  224     for (i = 0; i < len; i++)
  225         s[i] = chartrans[s[i] & 127];
  226 }
  227 
  228 void getname(char *dest, int src) {
  229     int c, len = 0;
  230     char k;
  231     char *d = dest;
  232     do {
  233         c = rom[--src];
  234         k = c & 127;
  235         if (k >= 0 && k <= 31)
  236             k += 64;
  237         *d++ = k;
  238     } while ((c & 128) == 0 && src > 0 && ++len < 16);
  239     *d = 0;
  240 }
  241 
  242 int xrom2index(int modnum, int funcnum) {
  243     int res = 0;
  244     int p;
  245     for (p = 0; p < pages; p++) {
  246         if (rom_number[p] == modnum)
  247             break;
  248         res += num_func[p];
  249     }
  250     return res + funcnum;
  251 }
  252 
  253 char *hp2ascii(char *src, int len) {
  254     char *esc;
  255     unsigned char c;
  256     static char dst[256];
  257     int s, d = 0;
  258     for (s = 0; s < len; s++) {
  259         c = src[s] & 127;
  260         switch (c) {
  261             /* NOTE: this code performs the following 11 translations
  262              * that are not ASCII, but seem to be widely accepted --
  263              * that is, they looked OK when I tried them in several
  264              * fonts in Windows and Linux, and in Memo Pad on the Palm:
  265              *
  266              *  19: 197 (0305) Aring
  267              *  20: 229 (0345) aring
  268              *  21: 196 (0304) Aumlaut
  269              *  22: 228 (0344) aumlaut
  270              *  23: 214 (0326) Oumlaut
  271              *  24: 246 (0366) oumlaut
  272              *  25: 220 (0334) Uumlaut
  273              *  26: 252 (0374) uumlaut
  274              *  27: 198 (0306) AE
  275              *  28: 230 (0346) ae
  276              *  29: 163 (0243) sterling
  277              */
  278             case  0:   esc = "\\diamond"; break;
  279             case  1:   esc = "x"; break;
  280             case  2:   esc = "\\mean"; break;
  281             case  3:   esc = "<-"; break;
  282             case  4:   esc = "\\alpha"; break;
  283             case  5:   esc = "\\beta"; break;
  284             case  6:   esc = "\\Gamma"; break;
  285             case  7:   esc = "v"; break;
  286             case  8:   esc = "\\Delta"; break;
  287             case  9:   esc = "\\sigma"; break;
  288             case 10:   esc = "\\LF"; break;
  289             case 11:   esc = "\\lambda"; break;
  290             case 12:   esc = "\\mu"; break;
  291             case 13:   esc = "\\angle"; break;
  292             case 14:   esc = "\\tau"; break;
  293             case 15:   esc = "\\Phi"; break;
  294             case 16:   esc = "\\Theta"; break;
  295             case 17:   esc = "\\Omega"; break;
  296             case 18:   esc = "\\delta"; break;
  297             case 19:   esc = "\305"; break;
  298             case 20:   esc = "\345"; break;
  299             case 21:   esc = "\304"; break;
  300             case 22:   esc = "\344"; break;
  301             case 23:   esc = "\326"; break;
  302             case 24:   esc = "\366"; break;
  303             case 25:   esc = "\334"; break;
  304             case 26:   esc = "\374"; break;
  305             case 27:   esc = "\306"; break;
  306             case 28:   esc = "\346"; break;
  307             case 29:   esc = "!="; break;
  308             case 30:   esc = "\243"; break;
  309             case 31:   esc = "\\gray"; break;
  310             case '\\': esc = "\\\\"; break;
  311             case 96:   esc = "\\T"; break;
  312             case 123:  esc = "\\pi"; break;
  313             case 125:  esc = "->"; break;
  314             case 126:  esc = "\\Sigma"; break;
  315             case 127:  esc = "|-"; break;
  316             default:   dst[d++] = c; continue;
  317         }
  318         while (*esc != 0)
  319             dst[d++] = *esc++;
  320     }
  321     dst[d] = 0;
  322     return dst;
  323 }
  324 
  325 char *instr_map[] = {
  326     "+", "-", "*", "/", "X<Y?", "X>Y?", "X<=Y?", "Sigma+",
  327     "Sigma-", "HMS+", "HMS-", "MOD", "%", "%CH", "P-R", "R-P",
  328     "LN", "X^2", "SQRT", "Y^X", "CHS", "E^X", "LOG", "10^X",
  329     "E^X-1", "SIN", "COS", "TAN", "ASIN", "ACOS", "ATAN", "DEC",
  330     "1/X", "ABS", "FACT", "X!=0?", "X>0?", "LN1+X", "X<0?", "X=0?",
  331     "INT", "FRC", "D-R", "R-D", "HMS", "HR", "RND", "OCT",
  332     "CLSigma", "X<>Y", "PI", "CLST", "R^", "RDN", "LASTX", "CLX",
  333     "X=Y?", "X!=Y?", "SIGN", "X<=0?", "MEAN", "SDEV", "AVIEW", "CLD",
  334     "DEG", "RAD", "GRAD", "ENTER^", "STOP", "RTN", "BEEP", "CLA",
  335     "ASHF", "PSE", "CLRG", "AOFF", "AON", "OFF", "PROMPT", "ADV",
  336     "RCL", "STO", "ST+", "ST-", "ST*", "ST/", "ISG", "DSE",
  337     "VIEW", "SigmaREG", "ASTO", "ARCL", "FIX", "SCI", "ENG", "TONE",
  338     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  339     "SF", "CF", "FS?C", "FC?C", "FS?", "FC?"
  340 };
  341 
  342 void bufprintf(char *buf, const char *fmt, ...) {
  343     int n;
  344     static char buf2[1024];
  345     va_list ap;
  346     va_start(ap, fmt);
  347     n = vsprintf(buf2, fmt, ap);
  348     va_end(ap);
  349     strcat(buf, buf2);
  350 }
  351 
  352 char *arg2str(unsigned char x, int one_digit) {
  353     static char buf[20];
  354     if (x <= 101)
  355         sprintf(buf, one_digit ? "%d" : "%02d", x);
  356     else if (x == 122)
  357         sprintf(buf, "|-");
  358     else if (x <= 127)
  359         sprintf(buf, "%c", "ABCDEFGHIJTZYXLMNOPQ.abcde"[x - 102]);
  360     else if (x <= 239)
  361         sprintf(buf, "IND %02d", x - 128);
  362     else if (x == 250)
  363         sprintf(buf, "IND |-");
  364     else
  365         sprintf(buf, "IND %c", "ABCDEFGHIJTZYXLMNOPQ.abcde"[x - 230]);
  366     return buf;
  367 }
  368 
  369 int print_line(int lineno, unsigned char *instr, int len) {
  370     int k = instr[0];
  371     static char buf[1024];
  372     buf[0] = 0;
  373     if (k == 0x00)
  374         return 0;
  375     bufprintf(buf, "%02d", lineno);
  376     if (k <= 0x0F) {
  377         bufprintf(buf, ">LBL %02d", (k & 15) - 1);
  378     } else if (k <= 0x1C) {
  379         int i;
  380         bufprintf(buf, " ");
  381         for (i = 0; i < len; i++) {
  382             k = instr[i];
  383             if (k >= 0x10 && k <= 0x19)
  384                 bufprintf(buf, "%c", '0' + k - 0x10);
  385             else if (k == 0x1A)
  386                 bufprintf(buf, ".");
  387             else if (k == 0x1B)
  388                 bufprintf(buf, " E");
  389             else if (k == 0x1C)
  390                 bufprintf(buf, "-");
  391         }
  392     } else if (k <= 0x1F) {
  393         if (k == 0x1D)
  394             bufprintf(buf, " GTO \"");
  395         else if (k == 0x1E)
  396             bufprintf(buf, " XEQ \"");
  397         else
  398             bufprintf(buf, " W \"");
  399         bufprintf(buf, "%s\"", hp2ascii(instr + 2, instr[1] & 15));
  400     } else if (k <= 0x2F) {
  401         bufprintf(buf, " RCL %02d", k & 15);
  402     } else if (k <= 0x3F) {
  403         bufprintf(buf, " STO %02d", k & 15);
  404     } else if (k <=0x8F) {
  405         bufprintf(buf, " %s", instr_map[k - 0x40]);
  406     } else if (k <= 0x9F || k >= 0xA8 && k <= 0xAE) {
  407         if (k == 0xAE) {
  408             bufprintf(buf, " %s %s", (instr[1] & 0x80) != 0 ? "XEQ" : "GTO",
  409                         arg2str(instr[1] | 0x80, 0));
  410         } else {
  411             bufprintf(buf, " %s %s", instr_map[k - 0x40],
  412                         arg2str(instr[1], k >= 0x9C && k <= 0x9F));
  413         }
  414     } else if (k <= 0xA7) {
  415         bufprintf(buf, " XROM %02d,%02d",
  416                         ((k & 7) << 2) | (instr[1] >> 6), instr[1] & 63);
  417     } else if (k == 0xAF) {
  418         bufprintf(buf, " SPARE1");
  419     } else if (k == 0xB0) {
  420         bufprintf(buf, " SPARE2");
  421     } else if (k <= 0xBF) {
  422         bufprintf(buf, " GTO %02d", (k & 15) - 1);
  423     } else if (k <= 0xCD) {
  424         if (instr[2] < 0xF1)
  425             bufprintf(buf, " END");
  426         else
  427             bufprintf(buf, ">LBL \"%s\"",
  428                                 hp2ascii(instr + 4, (instr[2] & 15) - 1));
  429     } else if (k == 0xCE) {
  430         bufprintf(buf, " X<> %s", arg2str(instr[1], 0));
  431     } else if (k == 0xCF) {
  432         /* TODO: how about IND arguments? And how does the
  433            synthetics-detecting code deal with that? */
  434         bufprintf(buf, ">LBL %s", arg2str(instr[1], 0));
  435     } else if (k <= 0xDF) {
  436         bufprintf(buf, " GTO %s", arg2str(instr[2] & 127, 0));
  437     } else if (k <= 0xEF) {
  438         bufprintf(buf, " XEQ %s", arg2str(instr[2] & 127, 0));
  439     } else {
  440         int len = k & 15;
  441         if (len > 0 && instr[1] == 127)
  442             bufprintf(buf, " |-\"%s\"", hp2ascii(instr + 2, len - 1));
  443         else
  444             bufprintf(buf, " \"%s\"", hp2ascii(instr + 1, len));
  445     }
  446     printf("%s", buf);
  447     return strlen(buf);
  448 }
  449 
  450 void spaces(int x) {
  451     do {
  452         printf(" ");
  453     } while (--x > 0);
  454 }
  455 
  456 int main(int argc, char *argv[]) {
  457     int argnum;
  458     FILE *in, *out;
  459     int pos;
  460     unsigned char rom_name[256], buf[256], outfile_name[256] = "";
  461     int f, e, i, j, p, total_func;
  462     int used_xrom[2048];
  463     int machine_code_warning = 0;
  464     int synthetic_code_warning = 0;
  465     int show_help = 0;
  466     int list = 0;
  467 
  468     /**********************/
  469     /* Parse command line */
  470     /**********************/
  471 
  472     char **argv2 = (char **) malloc(argc * sizeof(char *));
  473     int argc2 = 0;
  474 
  475     for (i = 1; i < argc; i++) {
  476         if (strcmp(argv[i], "-s") == 0)
  477             convert_strings = 0;
  478         else if (strcmp(argv[i], "-l") == 0)
  479             list = 1;
  480         else if (strcmp(argv[i], "-o") == 0) {
  481             if (i + 1 < argc)
  482                 strcpy(outfile_name, argv[++i]);
  483         } else if (strcmp(argv[i], "-h") == 0)
  484             show_help = 1;
  485         else
  486             argv2[argc2++] = argv[i];
  487     }
  488 
  489     if (show_help || argc2 == 0) {
  490         printf(
  491 "Usage: rom2raw [-o outputfile] [-s] [-l] [-h] inputfiles...\n"
  492 "    All input files are concatenated and treated as a single ROM image,\n"
  493 "     to facilitate working with multi-page ROMs. To process multiple ROMs,\n"
  494 "     you must run rom2raw once for each ROM.\n"
  495 "    If the -o option is omitted, the ROM name from the image will be used.\n"
  496 "    The -s option disables HP-41 => HP-42S character code translation.\n"
  497 "    The -l option turns on user code listings, to help you find problematic\n"
  498 "     XROMs and synthetic instructions.\n"
  499 "    The -h option shows this message.\n");
  500         exit(0);
  501     }
  502 
  503     /************************/
  504     /* Read ROM image files */
  505     /************************/
  506 
  507     rom_size = 0;
  508 
  509     printf("Input file%s:", argc2 == 1 ? "" : "s");
  510     for (argnum = 0; argnum < argc2; argnum++)
  511         printf(" %s", argv2[argnum]);
  512     printf("\n");
  513 
  514     for (argnum = 0; argnum < argc2; argnum++) {
  515         in = fopen(argv2[argnum], "rb");
  516         if (in == NULL) {
  517             int err = errno;
  518             printf("Can't open \"%s\" for reading: %s (%d)\n",
  519                                             argv2[argnum], strerror(err), err);
  520             exit(1);
  521         }
  522         while (rom_size < 65536) {
  523             int c1, c2;
  524             c1 = fgetc(in);
  525             if (c1 == EOF)
  526                 break;
  527             c2 = fgetc(in);
  528             if (c2 == EOF)
  529                 break;
  530             rom[rom_size++] = (c1 << 8) | c2;
  531         }
  532         fclose(in);
  533     }
  534 
  535     /****************************************/
  536     /* Determine ROM and output file names, */
  537     /*   and do some other preparations.    */
  538     /****************************************/
  539 
  540     num_func[0] = rom[1];
  541     if (num_func[0] == 0 || num_func[0] > 64)
  542         num_func[0] = 64;
  543 
  544     pos = ((rom[2] & 255) << 8) | (rom[3] & 255);
  545     if (pos <= num_func[0] * 2 + 2 || pos >= rom_size) {
  546         printf("Bad offset to ROM name (%d, rom size = %d)\n", pos, rom_size);
  547         strcpy(rom_name, "Unnamed");
  548     } else
  549         getname(rom_name, pos);
  550 
  551     if (outfile_name[0] == 0) {
  552         unsigned char ch;
  553         p = 0;
  554         do {
  555             ch = rom_name[p];
  556             if (ch == ' ' || ch == '/' || ch == '\\')
  557                 ch = '_';
  558             outfile_name[p] = ch;
  559             p++;
  560         } while (ch != 0);
  561         strcat(outfile_name, ".raw");
  562     }
  563     
  564     printf("Output file: %s\n", outfile_name);
  565     printf("ROM Name: %s\n", rom_name);
  566     pages = (rom_size + 4095) / 4096;
  567     printf("ROM Size: %d (0x%03X), %d page%s\n",
  568                             rom_size, rom_size, pages, pages == 1 ? "" : "s");
  569 
  570     /********************************************/
  571     /* Read page directories and compile a list */
  572     /*  of user and machine code entry points.  */
  573     /********************************************/
  574 
  575     total_func = 0;
  576 
  577     for (p = 0; p < pages; p++) {
  578         int page_base = 4096 * p;
  579         printf("--- Page %d ---\n", p);
  580         rom_number[p] = rom[page_base];
  581         if (rom_number[p] > 31) {
  582             printf("Bad ROM number (%d), using %d instead.\n",
  583                                         rom_number[p], rom_number[p] & 31);
  584             rom_number[p] &= 31;
  585         } else
  586             printf("ROM Number: %d\n", rom_number[p]);
  587         num_func[p] = rom[page_base + 1];
  588         if (num_func[p] <= 0 || num_func[p] > 64) {
  589             printf("Bad function count (%d), skipping this page.\n",
  590                                         num_func[p]);
  591             num_func[p] = 0;
  592             continue;
  593         }
  594 
  595         printf("%d functions (XROM %02d,00 - %02d,%02d)\n",
  596                 num_func[p], rom_number[p], rom_number[p], num_func[p] - 1);
  597 
  598         for (f = 0; f < num_func[p]; f++) {
  599             int mcode;
  600             e = (rom[page_base + f * 2 + 2] << 8)
  601                     | (rom[page_base + f * 2 + 3] & 255);
  602             mcode = (e & 0x20000) == 0;
  603             e &= 0xffff;
  604             if (e >= 0x8000)
  605                 e -= 0x10000;
  606             e += page_base;
  607             if (mcode) {
  608                 if (e < 0 || e >= rom_size) {
  609                     printf("Bad machine code entry point for "
  610                             "XROM %02d,%02d: 0x%03X.\n",
  611                             rom_number[p], f, e);
  612                     mach_entry[total_func] = 0;
  613                 } else {
  614                     getname(buf, e);
  615                     printf("XROM %02d,%02d: %s %s\n", rom_number[p], f,
  616                             rom[e] == 0x3E0 ? "dummy entry" : "machine code",
  617                             hp2ascii(buf, strlen(buf)));
  618                     mach_entry[total_func] = e;
  619                     if (rom[e] != 0x3E0)
  620                         machine_code_warning = 1;
  621                 }
  622                 entry[total_func] = 0;
  623             } else {
  624                 e &= 0xFFFF;
  625                 if (e >= rom_size - 5) {
  626                     printf("Bad user code entry point for "
  627                             "XROM %02d,%02d: 0x%03X, skipping.\n",
  628                             rom_number[p],
  629                             f, e);
  630                     entry[total_func] = 0;
  631                 } else if ((rom[e] & 0xF0) != 0xC0
  632                             || rom[e + 2] < 0xF2 || rom[e + 2] > 0xF8) {
  633                     printf("User code entry point (0x%03X) from "
  634                             "XROM %02d,%02d does not point to a "
  635                             "global label; skipping.\n",
  636                             e, rom_number[p], f);
  637                     entry[total_func] = 0;
  638                 } else {
  639                     entry[total_func] = e;
  640                     for (i = 0; i < (rom[e + 2] & 15) - 1; i++)
  641                         buf[i] = rom[e + 4 + i];
  642                     buf[i] = 0;
  643                     printf("XROM %02d,%02d: user code \"%s\"\n",
  644                                         rom_number[p], f, hp2ascii(buf, i));
  645                 }
  646             }
  647             entry_index[total_func] = total_func;
  648             total_func++;
  649         }
  650     }
  651 
  652     if (machine_code_warning)
  653         printf("Warning: this ROM contains machine code; "
  654                 "this code cannot be translated.\n");
  655 
  656     qsort(entry_index, total_func, sizeof(int), entry_index_compar);
  657     f = 0;
  658     while (entry[entry_index[f]] == 0 && f < total_func)
  659         f++;
  660 
  661     /****************************************/
  662     /* Open output file and write user code */
  663     /****************************************/
  664 
  665     out = fopen(outfile_name, "wb");
  666     if (out == NULL) {
  667         int err = errno;
  668         printf("Can't open \"%s\" for writing: %s (%d)\n",
  669                                             outfile_name, strerror(err), err);
  670         exit(2);
  671     }
  672 
  673     for (i = 0; i < 2048; i++)
  674         used_xrom[i] = 0;
  675 
  676     pos = 0;
  677     while (f < total_func) {
  678         unsigned char instr[16];
  679         int c, k, a;
  680         int lineno = 0;
  681         if (entry[entry_index[f]] < pos) {
  682             f++;
  683             continue;
  684         }
  685         pos = entry[entry_index[f]];
  686         if (list)
  687             printf("\n");
  688         do {
  689             int synth = 0;
  690             int conv_off, conv_len = 0;
  691             lineno++;
  692             i = 0;
  693             do {
  694                 c = rom[pos++];
  695                 instr[i++] = c & 255;
  696             } while ((c & 512) == 0 && (rom[pos] & 256) == 0);
  697             k = instr[0];
  698             a = instr[1];
  699             if (k == 0x00) {
  700                 /* NULL */
  701                 lineno--;
  702             } else if (k >= 0x1D && k <= 0x1F) {
  703                 /* GTO/XEQ/W <alpha> */
  704                 conv_off = 2;
  705                 conv_len = instr[1] & 15;
  706                 if (k == 0x1F || instr[1] < 0xF1 || instr[1] > 0xF7)
  707                     /* W instr, or bad label length */
  708                     synth = 1;
  709             } else if (k >= 0x90 && k <= 0x98 || k == 0x9A
  710                     || k == 0x9B || k == 0xAE || k == 0xCE) {
  711                 /* RCL, STO, STO+, STO-, STO*, STO/, ISG, DSE, VIEW,
  712                  * ASTO, ARCL, GTO/XEQ IND, X<>
  713                  */
  714                 a &= 127;
  715                 if (a > 99 && a < 112 || a > 116)
  716                     /* Argument is not 00-99, stack, IND 00-99, or IND stack */
  717                     synth = 1;
  718             } else if (k == 0x99) {
  719                 /* SigmaREG */
  720                 if (a > 99 && a < 128 || a > 227 && a < 240 || a > 244)
  721                     /* Argument is not 00-99, IND 00-99, or IND stack */
  722                     synth = 1;
  723             } else if (k >= 0x9C && k <= 0x9F) {
  724                 /* FIX, SCI, ENG, TONE */
  725                 if (a > 9 && a < 128 || a > 227 && a < 240 || a > 244)
  726                     /* Argument is not 0-9, IND 00-99, or IND stack */
  727                     synth = 1;
  728             } else if (k >= 0xA8 && k <= 0xAB) {
  729                 /* SF, CF, FS?C, FC?C */
  730                 if (a > 29 && a < 128 || a > 227 && a < 240 || a > 244)
  731                     /* Argument is not 00-29, IND 00-99, or IND stack */
  732                     synth = 1;
  733             } else if (k == 0xAC || k == 0xAD) {
  734                 /* FS?, FC? */
  735                 if (a > 55 && a < 128 || a > 227 && a < 240 || a > 244)
  736                     /* Argument is not 00-55, IND 00-99, or IND stack */
  737                     synth = 1;
  738             } else if (k == 0xAF || k == 0xB0) {
  739                 /* SPARE1, SPARE2 */
  740                 synth = 1;
  741             } else if (k >= 0xB1 && k <= 0xBF) {
  742                 /* Short-form GTO; wipe out offset (second byte) */
  743                 instr[1] = 0;
  744             } else if (k >= 0xC0 && k <= 0xCD) {
  745                 /* Global; wipe out offset
  746                  * (low nybble of 1st byte + all of 2nd byte)
  747                  */
  748                 instr[0] &= 0xF0;
  749                 instr[1] = 0;
  750                 if (instr[2] < 0xF1)
  751                     /* END */
  752                     instr[2] = 0x0D;
  753                 else {
  754                     conv_off = 4;
  755                     conv_len = (instr[2] & 15) - 1;
  756                     if (instr[2] > 0xF8)
  757                         /* bad label length */
  758                         synth = 1;
  759                 }
  760             } else if (k == 0xCF) {
  761                 /* LBL */
  762                 if (a > 99 && a < 102 || a > 111 && a < 123 || a > 128)
  763                     /* Argument is not 00-99, A-J, or a-e */
  764                     synth = 1;
  765             } else if (k >= 0xD0 && k <= 0xEF) {
  766                 /* Long-form GTO, and XEQ: wipe out offset
  767                  * (low nybble of 1st byte + all of 2nd byte)
  768                  * Also wipe out bit 7 of byte 2. I don't know why it
  769                  * should ever be set, but it happens.
  770                  */
  771                 instr[0] &= 0xF0;
  772                 instr[1] = 0;
  773                 instr[2] &= 0x7F;
  774                 a = instr[2];
  775                 if (a > 99 && a < 102 || a > 111 && a < 123
  776                         || a > 227 && a < 240 || a > 244)
  777                     /* Argument is not 00-99, A-J, a-e,
  778                      * IND 00-99, or IND stack */
  779                     synth = 1;
  780             } else if (k >= 0xA0 && k <= 0xA7) {
  781                 /* XROM */
  782                 int num = ((k & 7) << 8) | instr[1];
  783                 int modnum = num >> 6;
  784                 int instnum = num & 63;
  785                 int islocal = 0;
  786                 for (p = 0; p < pages; p++)
  787                     if (num_func[p] != 0 && rom_number[p] == modnum) {
  788                         islocal = 1;
  789                         break;
  790                     }
  791                 if (islocal) {
  792                     /* Local XROM */
  793                     int idx = xrom2index(modnum, instnum);
  794                     if (entry[idx] == 0) {
  795                         /* Mcode XROM, can't translate */
  796                         used_xrom[num] = 1;
  797                     } else {
  798                         /* User code XROM, translate to XEQ */
  799                         int len = (rom[entry[idx] + 2] & 15) - 1;
  800                         instr[0] = 0x1E;
  801                         instr[1] = 0xF0 + len;
  802                         for (i = 0; i < len; i++)
  803                             instr[i + 2] = rom[entry[idx] + 4 + i];
  804                         i = len + 2;
  805                         conv_off = 2;
  806                         conv_len = len;
  807                     }
  808                 } else {
  809                     /* Nonlocal XROM;
  810                      * we'll separate the HP-42S XROMs out later
  811                      */
  812                     used_xrom[num] = 2;
  813                 }
  814                 if (list) {
  815                     if (used_xrom[num] == 0) {
  816                         /* Translated to XEQ; no special action */
  817                         print_line(lineno, instr, i);
  818                         printf("\n");
  819                     } else {
  820                         int x, mistaken_identity = 0;
  821                         char linebuf[1024];
  822                         for (x = 0; hp42s_xroms[x].number != -1; x++)
  823                             if (hp42s_xroms[x].number == num)
  824                                 break;
  825                         if (hp42s_xroms[x].number != -1) {
  826                             if (hp42s_xroms[x].allow) {
  827                                 used_xrom[num] = 0;
  828                                 printf("%02d %s\n", lineno,
  829                                                     hp42s_xroms[x].name);
  830                             } else
  831                                 mistaken_identity = 1;
  832                         }
  833                         if (used_xrom[num] == 1) {
  834                             /* Mcode XROM */
  835                             int y = mach_entry[xrom2index(modnum, instnum)];
  836                             if (y == 0)
  837                                 sprintf(linebuf,
  838                                        "%02d XROM %02d,%02d (bad entry)",
  839                                        lineno, modnum, instnum);
  840                             else {
  841                                 char namebuf[30];
  842                                 getname(namebuf, y);
  843                                 sprintf(linebuf, "%02d %s", lineno,
  844                                         hp2ascii(namebuf, strlen(namebuf)));
  845                             }
  846                             printf(linebuf);
  847                             spaces(30 - strlen(linebuf));
  848                             if (mistaken_identity)
  849                                 printf("Will be mistaken for "
  850                                         "HP-42S function %s\n",
  851                                         hp42s_xroms[x].name);
  852                             else
  853                                 printf("Machine code XROM %02d,%02d\n",
  854                                                         modnum, instnum);
  855                         } else if (used_xrom[num] == 2) {
  856                             sprintf(linebuf, "%02d XROM %02d,%02d",
  857                                                     lineno, modnum, instnum);
  858                             printf(linebuf);
  859                             spaces(30 - strlen(linebuf));
  860                             if (mistaken_identity)
  861                                 printf("Will be mistaken for "
  862                                         "HP-42S function %s\n",
  863                                         hp42s_xroms[x].name);
  864                             else
  865                                 printf("Non-local XROM\n");
  866                         }
  867                     }
  868                 }
  869             } else if (k == 0xF0) {
  870                 /* zero-length string */
  871                 synth = 1;
  872             } else if (k > 0xF0) {
  873                 conv_off = 1;
  874                 conv_len = k & 15;
  875             }
  876             if (synth)
  877                 synthetic_code_warning = 1;
  878             if (list && k != 0x00 && (k < 0xA0 || k > 0xA7)) {
  879                 /* NULLs are not printed, and XROMs were handled earlier */
  880                 int x = print_line(lineno, instr, i);
  881                 if (synth) {
  882                     spaces(30 - x);
  883                     printf("Synthetic");
  884                 }
  885                 printf("\n");
  886             }
  887             if (conv_len != 0)
  888                 string_convert(conv_len, instr + conv_off);
  889             for (j = 0; j < i; j++)
  890                 fputc(instr[j], out);
  891         } while ((c & 512) == 0);
  892     }
  893 
  894     fclose(out);
  895 
  896     /*********************************************************************/
  897     /* Don't complain about XROMs that match HP-42S instructions         */
  898     /* if those are indeed the same instructions as in the corresponding */
  899     /* HP-41 ROMs; complain about all the others.                        */
  900     /*********************************************************************/
  901 
  902     for (i = 0; hp42s_xroms[i].number != -1; i++) {
  903         if (hp42s_xroms[i].allow)
  904             used_xrom[hp42s_xroms[i].number] = 0;
  905         else if (used_xrom[hp42s_xroms[i].number] != 0)
  906             used_xrom[hp42s_xroms[i].number] = 3;
  907     }
  908 
  909     /************************************************/
  910     /* Print warning about local machine code XROMs */
  911     /************************************************/
  912 
  913     j = 0;
  914     for (i = 0; i < 2048; i++) {
  915         if (used_xrom[i] == 1) {
  916             int p;
  917             if (j == 0) {
  918                 j = 1;
  919                 printf("\nThe following machine code XROMs were called "
  920                         "from user code:\n");
  921             }
  922             p = mach_entry[xrom2index(i >> 6, i & 63)];
  923             if (p == 0)
  924                 strcpy(buf, "(bad entry point)");
  925             else
  926                 getname(buf, p);
  927             printf("XROM %02d,%02d: %s\n", i >> 6, i & 63,
  928                                                 hp2ascii(buf, strlen(buf)));
  929         }
  930     }
  931 
  932     /***************************************/
  933     /* Print warning about non-local XROMs */
  934     /***************************************/
  935 
  936     for (i = 0; i < 2048; i++) {
  937         if (used_xrom[i] == 2) {
  938             if (j < 2) {
  939                 if (j == 0)
  940                     printf("\n");
  941                 j = 2;
  942                 printf("The following non-local XROMs were called "
  943                         "from user code:\n");
  944             }
  945             printf("XROM %02d,%02d\n", i >> 6, i & 63);
  946         }
  947     }
  948 
  949     /**************************************************************/
  950     /* Print warnings about XROMs that match HP-42S instructions, */
  951     /* but which have different meanings on the HP-41 than on the */
  952     /* HP-42S (these are the ones that have allow=0 in the        */
  953     /* hp42s_xroms table at the beginning of this file).          */
  954     /**************************************************************/
  955 
  956     for (i = 0; i < 2048; i++) {
  957         if (used_xrom[i] == 3) {
  958             int p;
  959             if (j < 3) {
  960                 if (j == 0)
  961                     printf("\n");
  962                 j = 3;
  963                 printf("The following XROMs were called which are "
  964                         "going to be\nmistaken for HP-42S commands:\n");
  965             }
  966             for (f = 0; hp42s_xroms[f].number != i; f++);
  967             p = mach_entry[xrom2index(i >> 6, i & 63)];
  968             if (p == 0)
  969                 strcpy(buf, "(bad entry point)");
  970             else
  971                 getname(buf, p);
  972             printf("XROM %02d,%02d: %s => %s\n", i >> 6, i & 63,
  973                             hp2ascii(buf, strlen(buf)), hp42s_xroms[f].name);
  974         }
  975     }
  976 
  977     /******************************************************/
  978     /* Print a few final words of caution, if appropriate */
  979     /******************************************************/
  980 
  981     if (j != 0)
  982         printf("Because of these XROM calls, "
  983                 "the converted user code may not work.\n");
  984     if (synthetic_code_warning)
  985         printf("\nWarning: this ROM contains synthetic code;\n"
  986                 "this code will probably fail on a HP-42S.\n");
  987     printf("\n");
  988 
  989     return 0;
  990 }