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