First Commit of my working state
[simh.git] / Ibm1130 / utils / mkboot.c
CommitLineData
196ba1fc
PH
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
72typedef enum {R_ABSOLUTE = 0, R_RELATIVE = 1, R_LIBF = 2, R_CALL = 3} RELOC;\r
73\r
74typedef enum {B_1130, B_1800, B_CORE} BOOTMODE;\r
75\r
76BOOL verbose = FALSE;\r
77char *infile = NULL, *outfile = NULL;\r
78BOOTMODE mode = B_1130;\r
79int addr_from = 0, addr_to = 79;\r
80int outcols = 0; // columns written in using card output\r
81int maxiplcols = 80;\r
82char cardid[9]; // characters used for IPL card ID\r
83int pta = 0;\r
84int load_low = 0x7FFFFFF;\r
85int load_high = 0;\r
86unsigned 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
90void bail (char *msg);\r
91void verify_checksum(unsigned short *card);\r
92char *upcase (char *str);\r
93void unpack (unsigned short *card, unsigned short *buf);\r
94void dump (char *fname);\r
95void loaddata (char *fname);\r
96void write_1130 (void);\r
97void write_1800 (void);\r
98void write_core (void);\r
99void flushcard(void);\r
100int ascii_to_hollerith (int ch);\r
101void corecard_init (void);\r
102void corecard_writecard (char *sbrk_text);\r
103void corecard_writedata (void);\r
104void corecard_flush (void);\r
105void corecard_setorg (int neworg);\r
106void corecard_writew (int word, RELOC relative);\r
107void corecard_endcard (void);\r
108\r
109char *fname = NULL;\r
110FILE *fout;\r
111\r
112int 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
195void 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
225void 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
253void 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
278void 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
317void 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
347void 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
365void 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
426void bail (char *msg)\r
427{\r
428 fprintf(stderr, "%s\n", msg);\r
429 exit(1);\r
430}\r
431\r
432void 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
449void 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
460typedef struct {\r
461 int hollerith;\r
462 char ascii;\r
463} CPCODE;\r
464\r
465static 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
533int 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
548unsigned short corecard[54]; // the 54 data words that can fit on a binary format card\r
549int corecard_n = 0; // number of object words stored in corecard (0-45)\r
550int corecard_seq = 1; // card output sequence number\r
551int corecard_org = 0; // origin of current card-full\r
552int corecard_maxaddr = 0;\r
553BOOL 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
557void 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
567void 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
590void 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
599void 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
609void 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
617void 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
628void 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
645char *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
659int 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
684int 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