| 1 | /*\r |
| 2 | * (C) Copyright 2002, Brian Knittel.\r |
| 3 | * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN\r |
| 4 | * RISK basis, there is no warranty of fitness for any purpose, and the rest of the\r |
| 5 | * usual yada-yada. Please keep this notice and the copyright in any distributions\r |
| 6 | * or modifications.\r |
| 7 | *\r |
| 8 | * This is not a supported product, but I welcome bug reports and fixes.\r |
| 9 | * Mail to sim@ibm1130.org\r |
| 10 | */\r |
| 11 | \r |
| 12 | // ---------------------------------------------------------------------------------\r |
| 13 | // MKBOOT - reads card loader format cards and produces an absolute core image that\r |
| 14 | // can then be dumped out in 1130 IPL, 1800 IPL or Core Image loader formats.\r |
| 15 | //\r |
| 16 | // Usage: mkboot [-v] binfile outfile [1130|1800|core [loaddr [hiaddr [ident]]]]"\r |
| 17 | //\r |
| 18 | // Arguments:\r |
| 19 | // binfile - name of assembler output file (card loader format, absolute output)\r |
| 20 | // outfile - name of output file to create\r |
| 21 | // mode - output mode, default is 1130 IPL format\r |
| 22 | // loaddr - low address to dump. Default is lowest address loaded from binfile\r |
| 23 | // hiaddr - high address to dump. Defult is highest address loaded from binfile\r |
| 24 | // ident - ident string to write in last 8 columns. Omit when when writing an\r |
| 25 | // 1130 IPL card that requires all 80 columns of data.\r |
| 26 | //\r |
| 27 | // Examples:\r |
| 28 | // mkboot somefile.bin somefile.ipl 1130\r |
| 29 | //\r |
| 30 | // loads somefile.bin, writes object in 1130 IPL format to somefile.ipl\r |
| 31 | // Up to 80 columns will be written depending on what the object actually uses\r |
| 32 | //\r |
| 33 | // mkboot somefile.bin somefile.ipl 1130 /0 /47 SOMEF\r |
| 34 | //\r |
| 35 | // loads somefile.bin. Writes 72 columns (hex 0 to hex 47), with ident columns 73-80 = SOMEF001\r |
| 36 | //\r |
| 37 | // mkboot somefile.bin somefile.dat core 0 0 SOMEF001\r |
| 38 | //\r |
| 39 | // loads somefile.bin and writes a core image format deck with ident SOMEF001, SOMEF002, etc\r |
| 40 | //\r |
| 41 | // For other examples of usage, see MKDMS.BAT\r |
| 42 | //\r |
| 43 | // 1.00 - 2002Apr18 - first release. Tested only under Win32. The core image\r |
| 44 | // loader format is almost certainly wrong. Cannot handle\r |
| 45 | // relocatable input decks, but it works well enough to\r |
| 46 | // load DSYSLDR1 which is what we are after here.\r |
| 47 | // ---------------------------------------------------------------------------------\r |
| 48 | \r |
| 49 | #include <stdio.h>\r |
| 50 | #include <stdlib.h>\r |
| 51 | #include <string.h>\r |
| 52 | #include <ctype.h>\r |
| 53 | #include "util_io.h"\r |
| 54 | \r |
| 55 | #ifndef TRUE\r |
| 56 | #define BOOL int\r |
| 57 | #define TRUE 1\r |
| 58 | #define FALSE 0\r |
| 59 | #endif\r |
| 60 | \r |
| 61 | #ifndef _WIN32\r |
| 62 | int strnicmp (char *a, char *b, int n);\r |
| 63 | int strcmpi (char *a, char *b);\r |
| 64 | #endif\r |
| 65 | \r |
| 66 | #define BETWEEN(v,a,b) (((v) >= (a)) && ((v) <= (b)))\r |
| 67 | #define MIN(a,b) (((a) <= (b)) ? (a) : (b))\r |
| 68 | #define MAX(a,b) (((a) >= (b)) ? (a) : (b))\r |
| 69 | \r |
| 70 | #define MAXADDR 4096\r |
| 71 | \r |
| 72 | typedef enum {R_ABSOLUTE = 0, R_RELATIVE = 1, R_LIBF = 2, R_CALL = 3} RELOC;\r |
| 73 | \r |
| 74 | typedef enum {B_1130, B_1800, B_CORE} BOOTMODE;\r |
| 75 | \r |
| 76 | BOOL verbose = FALSE;\r |
| 77 | char *infile = NULL, *outfile = NULL;\r |
| 78 | BOOTMODE mode = B_1130;\r |
| 79 | int addr_from = 0, addr_to = 79;\r |
| 80 | int outcols = 0; // columns written in using card output\r |
| 81 | int maxiplcols = 80;\r |
| 82 | char cardid[9]; // characters used for IPL card ID\r |
| 83 | int pta = 0;\r |
| 84 | int load_low = 0x7FFFFFF;\r |
| 85 | int load_high = 0;\r |
| 86 | unsigned short mem[MAXADDR]; // small core!\r |
| 87 | \r |
| 88 | // mkboot - load a binary object deck into core and dump requested bytes as a boot card\r |
| 89 | \r |
| 90 | void bail (char *msg);\r |
| 91 | void verify_checksum(unsigned short *card);\r |
| 92 | char *upcase (char *str);\r |
| 93 | void unpack (unsigned short *card, unsigned short *buf);\r |
| 94 | void dump (char *fname);\r |
| 95 | void loaddata (char *fname);\r |
| 96 | void write_1130 (void);\r |
| 97 | void write_1800 (void);\r |
| 98 | void write_core (void);\r |
| 99 | void flushcard(void);\r |
| 100 | int ascii_to_hollerith (int ch);\r |
| 101 | void corecard_init (void);\r |
| 102 | void corecard_writecard (char *sbrk_text);\r |
| 103 | void corecard_writedata (void);\r |
| 104 | void corecard_flush (void);\r |
| 105 | void corecard_setorg (int neworg);\r |
| 106 | void corecard_writew (int word, RELOC relative);\r |
| 107 | void corecard_endcard (void);\r |
| 108 | \r |
| 109 | char *fname = NULL;\r |
| 110 | FILE *fout;\r |
| 111 | \r |
| 112 | int main (int argc, char **argv)\r |
| 113 | {\r |
| 114 | char *arg;\r |
| 115 | static char usestr[] = "Usage: mkboot [-v] binfile outfile [1130|1800|core [loaddr [hiaddr [ident]]]]";\r |
| 116 | int i, ano = 0, ok;\r |
| 117 | \r |
| 118 | for (i = 1; i < argc; i++) {\r |
| 119 | arg = argv[i];\r |
| 120 | if (*arg == '-') {\r |
| 121 | arg++;\r |
| 122 | while (*arg) {\r |
| 123 | switch (*arg++) {\r |
| 124 | case 'v':\r |
| 125 | verbose = TRUE;\r |
| 126 | break;\r |
| 127 | default:\r |
| 128 | bail(usestr);\r |
| 129 | }\r |
| 130 | }\r |
| 131 | }\r |
| 132 | else {\r |
| 133 | switch (ano++) {\r |
| 134 | case 0:\r |
| 135 | infile = arg;\r |
| 136 | break;\r |
| 137 | \r |
| 138 | case 1:\r |
| 139 | outfile = arg;\r |
| 140 | break;\r |
| 141 | \r |
| 142 | case 2:\r |
| 143 | if (strcmp(arg, "1130") == 0) mode = B_1130;\r |
| 144 | else if (strcmp(arg, "1800") == 0) mode = B_1800;\r |
| 145 | else if (strcmpi(arg, "core") == 0) mode = B_CORE;\r |
| 146 | else bail(usestr);\r |
| 147 | break;\r |
| 148 | \r |
| 149 | case 3:\r |
| 150 | if (strnicmp(arg, "0x", 2) == 0) ok = sscanf(arg+2, "%x", &addr_from);\r |
| 151 | else if (arg[0] == '/') ok = sscanf(arg+1, "%x", &addr_from);\r |
| 152 | else ok = sscanf(arg, "%d", &addr_from);\r |
| 153 | if (ok != 1) bail(usestr);\r |
| 154 | break;\r |
| 155 | \r |
| 156 | case 4:\r |
| 157 | if (strnicmp(arg, "0x", 2) == 0) ok = sscanf(arg+2, "%x", &addr_to);\r |
| 158 | else if (arg[0] == '/') ok = sscanf(arg+1, "%x", &addr_to);\r |
| 159 | else ok = sscanf(arg, "%d", &addr_to);\r |
| 160 | if (ok != 1) bail(usestr);\r |
| 161 | break;\r |
| 162 | \r |
| 163 | case 5:\r |
| 164 | strncpy(cardid, arg, 9);\r |
| 165 | cardid[8] = '\0';\r |
| 166 | upcase(cardid);\r |
| 167 | break;\r |
| 168 | \r |
| 169 | default:\r |
| 170 | bail(usestr);\r |
| 171 | }\r |
| 172 | }\r |
| 173 | }\r |
| 174 | \r |
| 175 | if (*cardid == '\0')\r |
| 176 | maxiplcols = (mode == B_1130) ? 80 : 72;\r |
| 177 | else {\r |
| 178 | while (strlen(cardid) < 8)\r |
| 179 | strcat(cardid, "0");\r |
| 180 | maxiplcols = 72;\r |
| 181 | }\r |
| 182 | \r |
| 183 | loaddata(infile);\r |
| 184 | \r |
| 185 | if (mode == B_1800)\r |
| 186 | write_1800();\r |
| 187 | else if (mode == B_CORE)\r |
| 188 | write_core();\r |
| 189 | else\r |
| 190 | write_1130();\r |
| 191 | \r |
| 192 | return 0;\r |
| 193 | }\r |
| 194 | \r |
| 195 | void write_1130 (void)\r |
| 196 | {\r |
| 197 | int addr;\r |
| 198 | unsigned short word;\r |
| 199 | \r |
| 200 | if ((fout = fopen(outfile, "wb")) == NULL) {\r |
| 201 | perror(outfile);\r |
| 202 | exit(1);\r |
| 203 | }\r |
| 204 | \r |
| 205 | for (addr = addr_from; addr <= addr_to; addr++) {\r |
| 206 | if (outcols >= maxiplcols)\r |
| 207 | flushcard();\r |
| 208 | \r |
| 209 | word = mem[addr];\r |
| 210 | \r |
| 211 | // if F or L bits are set, or if high 2 bits of displacement are unequal, it's bad\r |
| 212 | if ((word & 0x0700) || ! (((word & 0x00C0) == 0) || ((word & 0x00C0) == 0x00C0)))\r |
| 213 | printf("Warning: word %04x @ %04x may not IPL properly\n", word & 0xFFFF, addr);\r |
| 214 | \r |
| 215 | word = ((word & 0xF800) >> 4) | (word & 0x7F); // convert to 1130 IPL format\r |
| 216 | \r |
| 217 | putc((word & 0x000F) << 4, fout); // write the 12 bits in little-endian binary AABBCC00 as CC00 AABB\r |
| 218 | putc((word & 0x0FF0) >> 4, fout);\r |
| 219 | outcols++;\r |
| 220 | }\r |
| 221 | flushcard();\r |
| 222 | fclose(fout);\r |
| 223 | }\r |
| 224 | \r |
| 225 | void write_1800 (void)\r |
| 226 | {\r |
| 227 | int addr;\r |
| 228 | unsigned short word;\r |
| 229 | \r |
| 230 | if ((fout = fopen(outfile, "wb")) == NULL) {\r |
| 231 | perror(outfile);\r |
| 232 | exit(1);\r |
| 233 | }\r |
| 234 | \r |
| 235 | for (addr = addr_from; addr <= addr_to; addr++) {\r |
| 236 | word = mem[addr];\r |
| 237 | \r |
| 238 | if (outcols >= maxiplcols)\r |
| 239 | flushcard();\r |
| 240 | \r |
| 241 | putc(0, fout);\r |
| 242 | putc(word & 0xFF, fout); // write the low 8 bits in little-endian binary\r |
| 243 | outcols++;\r |
| 244 | \r |
| 245 | putc(0, fout);\r |
| 246 | putc((word >> 8) & 0xFF, fout); // write the high 8 bits in little-endian binary\r |
| 247 | outcols++;\r |
| 248 | }\r |
| 249 | flushcard();\r |
| 250 | fclose(fout);\r |
| 251 | }\r |
| 252 | \r |
| 253 | void write_core (void)\r |
| 254 | {\r |
| 255 | int addr;\r |
| 256 | \r |
| 257 | if ((fout = fopen(outfile, "wb")) == NULL) {\r |
| 258 | perror(outfile);\r |
| 259 | exit(1);\r |
| 260 | }\r |
| 261 | \r |
| 262 | addr_from = load_low;\r |
| 263 | addr_to = load_high;\r |
| 264 | \r |
| 265 | maxiplcols = 72;\r |
| 266 | corecard_init();\r |
| 267 | corecard_setorg(addr_from);\r |
| 268 | \r |
| 269 | for (addr = addr_from; addr <= addr_to; addr++) {\r |
| 270 | corecard_writew(mem[addr], 0);\r |
| 271 | }\r |
| 272 | \r |
| 273 | corecard_flush();\r |
| 274 | corecard_endcard();\r |
| 275 | fclose(fout);\r |
| 276 | }\r |
| 277 | \r |
| 278 | void flushcard (void)\r |
| 279 | {\r |
| 280 | int i, hol, ndig;\r |
| 281 | char fmt[20], newdig[20];\r |
| 282 | \r |
| 283 | if (outcols <= 0)\r |
| 284 | return; // nothing to flush\r |
| 285 | \r |
| 286 | while (outcols < maxiplcols) { // pad to required number of columns with blanks (no punches)\r |
| 287 | putc(0, fout);\r |
| 288 | putc(0, fout);\r |
| 289 | outcols++;\r |
| 290 | }\r |
| 291 | \r |
| 292 | if (*cardid) { // add label\r |
| 293 | for (i = 0; i < 8; i++) { // write label as specified\r |
| 294 | hol = ascii_to_hollerith(cardid[i] & 0x7F);\r |
| 295 | putc(hol & 0xFF, fout);\r |
| 296 | putc((hol >> 8) & 0xFF, fout);\r |
| 297 | }\r |
| 298 | \r |
| 299 | ndig = 0; // count trailing digits in the label\r |
| 300 | for (i = 8; --i >= 0; ndig++)\r |
| 301 | if (! isdigit(cardid[i]))\r |
| 302 | break;\r |
| 303 | \r |
| 304 | i++; // index of first digit in trailing sequence\r |
| 305 | \r |
| 306 | if (ndig > 0) { // if any, increment them\r |
| 307 | sprintf(fmt, "%%0%dd", ndig); // make, e.g. %03d\r |
| 308 | sprintf(newdig, fmt, atoi(cardid+i)+1);\r |
| 309 | newdig[ndig] = '\0'; // clip if necessary\r |
| 310 | strcpy(cardid+i, newdig); // replace for next card's sequence number\r |
| 311 | }\r |
| 312 | }\r |
| 313 | \r |
| 314 | outcols = 0;\r |
| 315 | }\r |
| 316 | \r |
| 317 | void show_data (unsigned short *buf)\r |
| 318 | {\r |
| 319 | int i, n, jrel, rflag, nout, ch, reloc;\r |
| 320 | \r |
| 321 | n = buf[2] & 0x00FF;\r |
| 322 | \r |
| 323 | printf("%04x: ", buf[0]);\r |
| 324 | \r |
| 325 | jrel = 3;\r |
| 326 | nout = 0;\r |
| 327 | rflag = buf[jrel++];\r |
| 328 | for (i = 0; i < n; i++) {\r |
| 329 | if (nout >= 8) {\r |
| 330 | rflag = buf[jrel++];\r |
| 331 | putchar('\n');\r |
| 332 | printf(" ");\r |
| 333 | nout = 0;\r |
| 334 | }\r |
| 335 | reloc = (rflag >> 14) & 0x03;\r |
| 336 | ch = (reloc == R_ABSOLUTE) ? ' ' :\r |
| 337 | (reloc == R_RELATIVE) ? 'R' :\r |
| 338 | (reloc == R_LIBF) ? 'L' : '@';\r |
| 339 | \r |
| 340 | printf("%04x%c ", buf[9+i], ch);\r |
| 341 | rflag <<= 2;\r |
| 342 | nout++;\r |
| 343 | }\r |
| 344 | putchar('\n');\r |
| 345 | }\r |
| 346 | \r |
| 347 | void loadcard (unsigned short *buf)\r |
| 348 | {\r |
| 349 | int addr, n, i;\r |
| 350 | \r |
| 351 | addr = buf[0];\r |
| 352 | n = buf[2] & 0x00FF;\r |
| 353 | \r |
| 354 | for (i = 0; i < n; i++) {\r |
| 355 | if (addr >= MAXADDR)\r |
| 356 | bail("Program doesn't fit into 4K");\r |
| 357 | mem[addr] = buf[9+i];\r |
| 358 | \r |
| 359 | load_low = MIN(addr, load_low);\r |
| 360 | load_high = MAX(addr, load_high);\r |
| 361 | addr++;\r |
| 362 | }\r |
| 363 | }\r |
| 364 | \r |
| 365 | void loaddata (char *fname)\r |
| 366 | {\r |
| 367 | FILE *fp;\r |
| 368 | BOOL first = TRUE;\r |
| 369 | unsigned short card[80], buf[54], cardtype;\r |
| 370 | \r |
| 371 | if ((fp = fopen(fname, "rb")) == NULL) {\r |
| 372 | perror(fname);\r |
| 373 | exit(1);\r |
| 374 | }\r |
| 375 | \r |
| 376 | if (verbose) \r |
| 377 | printf("\n%s:\n", fname);\r |
| 378 | \r |
| 379 | while (fxread(card, sizeof(card[0]), 80, fp) > 0) {\r |
| 380 | unpack(card, buf);\r |
| 381 | verify_checksum(card);\r |
| 382 | \r |
| 383 | cardtype = (buf[2] >> 8) & 0xFF;\r |
| 384 | \r |
| 385 | if (cardtype == 1 && ! first) { // sector break\r |
| 386 | if (verbose)\r |
| 387 | printf("*SBRK\n");\r |
| 388 | continue;\r |
| 389 | }\r |
| 390 | else {\r |
| 391 | switch (cardtype) {\r |
| 392 | case 0x01:\r |
| 393 | if (verbose)\r |
| 394 | printf("*ABS\n");\r |
| 395 | break;\r |
| 396 | case 0x02:\r |
| 397 | case 0x03:\r |
| 398 | case 0x04:\r |
| 399 | case 0x05:\r |
| 400 | case 0x06:\r |
| 401 | case 0x07:\r |
| 402 | bail("Data must be in absolute format");\r |
| 403 | break;\r |
| 404 | \r |
| 405 | case 0x0F:\r |
| 406 | pta = buf[3]; // save program transfer address\r |
| 407 | if (verbose)\r |
| 408 | printf("*END\n");\r |
| 409 | break;\r |
| 410 | \r |
| 411 | case 0x0A:\r |
| 412 | if (verbose)\r |
| 413 | show_data(buf);\r |
| 414 | loadcard(buf);\r |
| 415 | break;\r |
| 416 | default:\r |
| 417 | bail("Unexpected card type");\r |
| 418 | }\r |
| 419 | }\r |
| 420 | first = FALSE;\r |
| 421 | }\r |
| 422 | \r |
| 423 | fclose(fp);\r |
| 424 | }\r |
| 425 | \r |
| 426 | void bail (char *msg)\r |
| 427 | {\r |
| 428 | fprintf(stderr, "%s\n", msg);\r |
| 429 | exit(1);\r |
| 430 | }\r |
| 431 | \r |
| 432 | void unpack (unsigned short *card, unsigned short *buf)\r |
| 433 | {\r |
| 434 | int i, j;\r |
| 435 | unsigned short wd1, wd2, wd3, wd4;\r |
| 436 | \r |
| 437 | for (i = j = 0; i < 54; i += 3, j += 4) {\r |
| 438 | wd1 = card[j];\r |
| 439 | wd2 = card[j+1];\r |
| 440 | wd3 = card[j+2];\r |
| 441 | wd4 = card[j+3];\r |
| 442 | \r |
| 443 | buf[i ] = (wd1 & 0xFFF0) | ((wd2 >> 12) & 0x000F);\r |
| 444 | buf[i+1] = ((wd2 << 4) & 0xFF00) | ((wd3 >> 8) & 0x00FF);\r |
| 445 | buf[i+2] = ((wd3 << 8) & 0xF000) | ((wd4 >> 4) & 0x0FFF);\r |
| 446 | }\r |
| 447 | }\r |
| 448 | \r |
| 449 | void verify_checksum (unsigned short *card)\r |
| 450 | {\r |
| 451 | // unsigned short sum;\r |
| 452 | \r |
| 453 | if (card[1] == 0) // no checksum\r |
| 454 | return;\r |
| 455 | \r |
| 456 | // if (sum != card[1])\r |
| 457 | // printf("Checksum %04x doesn't match card %04x\n", sum, card[1]);\r |
| 458 | }\r |
| 459 | \r |
| 460 | typedef struct {\r |
| 461 | int hollerith;\r |
| 462 | char ascii;\r |
| 463 | } CPCODE;\r |
| 464 | \r |
| 465 | static CPCODE cardcode_029[] =\r |
| 466 | {\r |
| 467 | 0x0000, ' ',\r |
| 468 | 0x8000, '&', // + in 026 Fortran\r |
| 469 | 0x4000, '-',\r |
| 470 | 0x2000, '0',\r |
| 471 | 0x1000, '1',\r |
| 472 | 0x0800, '2',\r |
| 473 | 0x0400, '3',\r |
| 474 | 0x0200, '4',\r |
| 475 | 0x0100, '5',\r |
| 476 | 0x0080, '6',\r |
| 477 | 0x0040, '7',\r |
| 478 | 0x0020, '8',\r |
| 479 | 0x0010, '9',\r |
| 480 | 0x9000, 'A',\r |
| 481 | 0x8800, 'B',\r |
| 482 | 0x8400, 'C',\r |
| 483 | 0x8200, 'D',\r |
| 484 | 0x8100, 'E',\r |
| 485 | 0x8080, 'F',\r |
| 486 | 0x8040, 'G',\r |
| 487 | 0x8020, 'H',\r |
| 488 | 0x8010, 'I',\r |
| 489 | 0x5000, 'J',\r |
| 490 | 0x4800, 'K',\r |
| 491 | 0x4400, 'L',\r |
| 492 | 0x4200, 'M',\r |
| 493 | 0x4100, 'N',\r |
| 494 | 0x4080, 'O',\r |
| 495 | 0x4040, 'P',\r |
| 496 | 0x4020, 'Q',\r |
| 497 | 0x4010, 'R',\r |
| 498 | 0x3000, '/',\r |
| 499 | 0x2800, 'S',\r |
| 500 | 0x2400, 'T',\r |
| 501 | 0x2200, 'U',\r |
| 502 | 0x2100, 'V',\r |
| 503 | 0x2080, 'W',\r |
| 504 | 0x2040, 'X',\r |
| 505 | 0x2020, 'Y',\r |
| 506 | 0x2010, 'Z',\r |
| 507 | 0x0820, ':',\r |
| 508 | 0x0420, '#', // = in 026 Fortran\r |
| 509 | 0x0220, '@', // ' in 026 Fortran\r |
| 510 | 0x0120, '\'',\r |
| 511 | 0x00A0, '=',\r |
| 512 | 0x0060, '"',\r |
| 513 | 0x8820, 'c', // cent\r |
| 514 | 0x8420, '.',\r |
| 515 | 0x8220, '<', // ) in 026 Fortran\r |
| 516 | 0x8120, '(',\r |
| 517 | 0x80A0, '+',\r |
| 518 | 0x8060, '|',\r |
| 519 | 0x4820, '!',\r |
| 520 | 0x4420, '$',\r |
| 521 | 0x4220, '*',\r |
| 522 | 0x4120, ')',\r |
| 523 | 0x40A0, ';',\r |
| 524 | 0x4060, 'n', // not\r |
| 525 | 0x2820, 'x', // what?\r |
| 526 | 0x2420, ',',\r |
| 527 | 0x2220, '%', // ( in 026 Fortran\r |
| 528 | 0x2120, '_',\r |
| 529 | 0x20A0, '>',\r |
| 530 | 0x2060, '>',\r |
| 531 | };\r |
| 532 | \r |
| 533 | int ascii_to_hollerith (int ch)\r |
| 534 | {\r |
| 535 | int i;\r |
| 536 | \r |
| 537 | for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++)\r |
| 538 | if (cardcode_029[i].ascii == ch)\r |
| 539 | return cardcode_029[i].hollerith;\r |
| 540 | \r |
| 541 | return 0;\r |
| 542 | }\r |
| 543 | \r |
| 544 | // ---------------------------------------------------------------------------------\r |
| 545 | // corecard - routines to write IBM 1130 Card object format\r |
| 546 | // ---------------------------------------------------------------------------------\r |
| 547 | \r |
| 548 | unsigned short corecard[54]; // the 54 data words that can fit on a binary format card\r |
| 549 | int corecard_n = 0; // number of object words stored in corecard (0-45)\r |
| 550 | int corecard_seq = 1; // card output sequence number\r |
| 551 | int corecard_org = 0; // origin of current card-full\r |
| 552 | int corecard_maxaddr = 0;\r |
| 553 | BOOL corecard_first = TRUE; // TRUE when we're to write the program type card\r |
| 554 | \r |
| 555 | // corecard_init - prepare a new object data output card\r |
| 556 | \r |
| 557 | void corecard_init (void)\r |
| 558 | {\r |
| 559 | memset(corecard, 0, sizeof(corecard)); // clear card data\r |
| 560 | corecard_n = 0; // no data\r |
| 561 | corecard[0] = corecard_org; // store load address\r |
| 562 | corecard_maxaddr = MAX(corecard_maxaddr, corecard_org-1); // save highest address written-to (this may be a BSS)\r |
| 563 | }\r |
| 564 | \r |
| 565 | // binard_writecard - emit a card. sbrk_text = NULL for normal data cards, points to comment text for sbrk card\r |
| 566 | \r |
| 567 | void corecard_writecard (char *sbrk_text)\r |
| 568 | {\r |
| 569 | unsigned short binout[80];\r |
| 570 | int i, j;\r |
| 571 | \r |
| 572 | for (i = j = 0; i < 54; i += 3, j += 4) {\r |
| 573 | binout[j ] = ( corecard[i] & 0xFFF0);\r |
| 574 | binout[j+1] = ((corecard[i] << 12) & 0xF000) | ((corecard[i+1] >> 4) & 0x0FF0);\r |
| 575 | binout[j+2] = ((corecard[i+1] << 8) & 0xFF00) | ((corecard[i+2] >> 8) & 0x00F0);\r |
| 576 | binout[j+3] = ((corecard[i+2] << 4) & 0xFFF0);\r |
| 577 | }\r |
| 578 | \r |
| 579 | for (i = 0; i < 72; i++) {\r |
| 580 | putc(binout[i] & 0xFF, fout);\r |
| 581 | putc((binout[i] >> 8) & 0xFF, fout);\r |
| 582 | }\r |
| 583 | \r |
| 584 | outcols = 72; // add the ident\r |
| 585 | flushcard();\r |
| 586 | }\r |
| 587 | \r |
| 588 | // binard_writedata - emit an object data card\r |
| 589 | \r |
| 590 | void corecard_writedata (void)\r |
| 591 | {\r |
| 592 | corecard[1] = 0; // checksum\r |
| 593 | corecard[2] = 0x0000 | corecard_n; // data card type + word count\r |
| 594 | corecard_writecard(FALSE); // emit the card\r |
| 595 | }\r |
| 596 | \r |
| 597 | // corecard_flush - flush any pending binary data\r |
| 598 | \r |
| 599 | void corecard_flush (void)\r |
| 600 | {\r |
| 601 | if (corecard_n > 0)\r |
| 602 | corecard_writedata();\r |
| 603 | \r |
| 604 | corecard_init();\r |
| 605 | }\r |
| 606 | \r |
| 607 | // corecard_setorg - set the origin\r |
| 608 | \r |
| 609 | void corecard_setorg (int neworg)\r |
| 610 | {\r |
| 611 | corecard_org = neworg; // set origin for next card\r |
| 612 | corecard_flush(); // flush any current data & store origin\r |
| 613 | }\r |
| 614 | \r |
| 615 | // corecard_writew - write a word to the current output card.\r |
| 616 | \r |
| 617 | void corecard_writew (int word, RELOC relative)\r |
| 618 | {\r |
| 619 | if (corecard_n >= 50) // flush full card buffer (must be even)\r |
| 620 | corecard_flush();\r |
| 621 | \r |
| 622 | corecard[3+corecard_n++] = word;\r |
| 623 | corecard_org++;\r |
| 624 | }\r |
| 625 | \r |
| 626 | // corecard_endcard - write end of program card\r |
| 627 | \r |
| 628 | void corecard_endcard (void)\r |
| 629 | {\r |
| 630 | corecard_flush();\r |
| 631 | \r |
| 632 | corecard[0] = 0; // effective length: add 1 to max origin, then 1 more to round up\r |
| 633 | corecard[1] = 0;\r |
| 634 | corecard[2] = 0x8000; // they look for negative bit but all else must be zero\r |
| 635 | corecard[52] = 0xabcd; // index register 3 value, this is for fun\r |
| 636 | corecard[53] = pta; // hmmm\r |
| 637 | \r |
| 638 | corecard_writecard(NULL);\r |
| 639 | }\r |
| 640 | \r |
| 641 | /* ------------------------------------------------------------------------ \r |
| 642 | * upcase - force a string to uppercase (ASCII)\r |
| 643 | * ------------------------------------------------------------------------ */\r |
| 644 | \r |
| 645 | char *upcase (char *str)\r |
| 646 | {\r |
| 647 | char *s;\r |
| 648 | \r |
| 649 | for (s = str; *s; s++) {\r |
| 650 | if (*s >= 'a' && *s <= 'z')\r |
| 651 | *s -= 32;\r |
| 652 | } \r |
| 653 | \r |
| 654 | return str;\r |
| 655 | }\r |
| 656 | \r |
| 657 | #ifndef _WIN32\r |
| 658 | \r |
| 659 | int strnicmp (char *a, char *b, int n)\r |
| 660 | {\r |
| 661 | int ca, cb;\r |
| 662 | \r |
| 663 | for (;;) {\r |
| 664 | if (--n < 0) // still equal after n characters? quit now\r |
| 665 | return 0;\r |
| 666 | \r |
| 667 | if ((ca = *a) == 0) // get character, stop on null terminator\r |
| 668 | return *b ? -1 : 0;\r |
| 669 | \r |
| 670 | if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase\r |
| 671 | ca -= 32;\r |
| 672 | \r |
| 673 | cb = *b;\r |
| 674 | if (cb >= 'a' && cb <= 'z')\r |
| 675 | cb -= 32;\r |
| 676 | \r |
| 677 | if ((ca -= cb) != 0) // if different, return comparison\r |
| 678 | return ca;\r |
| 679 | \r |
| 680 | a++, b++;\r |
| 681 | }\r |
| 682 | }\r |
| 683 | \r |
| 684 | int strcmpi (char *a, char *b)\r |
| 685 | {\r |
| 686 | int ca, cb;\r |
| 687 | \r |
| 688 | for (;;) {\r |
| 689 | if ((ca = *a) == 0) // get character, stop on null terminator\r |
| 690 | return *b ? -1 : 0;\r |
| 691 | \r |
| 692 | if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase\r |
| 693 | ca -= 32;\r |
| 694 | \r |
| 695 | cb = *b;\r |
| 696 | if (cb >= 'a' && cb <= 'z')\r |
| 697 | cb -= 32;\r |
| 698 | \r |
| 699 | if ((ca -= cb) != 0) // if different, return comparison\r |
| 700 | return ca;\r |
| 701 | \r |
| 702 | a++, b++;\r |
| 703 | }\r |
| 704 | }\r |
| 705 | \r |
| 706 | #endif\r |