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
8 * This is not a supported product, but I welcome bug reports and fixes.
9 * Mail to sim@ibm1130.org
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.
16 // Usage: mkboot [-v] binfile outfile [1130|1800|core [loaddr [hiaddr [ident]]]]"
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.
28 // mkboot somefile.bin somefile.ipl 1130
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
33 // mkboot somefile.bin somefile.ipl 1130 /0 /47 SOMEF
35 // loads somefile.bin. Writes 72 columns (hex 0 to hex 47), with ident columns 73-80 = SOMEF001
37 // mkboot somefile.bin somefile.dat core 0 0 SOMEF001
39 // loads somefile.bin and writes a core image format deck with ident SOMEF001, SOMEF002, etc
41 // For other examples of usage, see MKDMS.BAT
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 // ---------------------------------------------------------------------------------
62 int strnicmp (char *a
, char *b
, int n
);
63 int strcmpi (char *a
, char *b
);
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))
72 typedef enum {R_ABSOLUTE
= 0, R_RELATIVE
= 1, R_LIBF
= 2, R_CALL
= 3} RELOC
;
74 typedef enum {B_1130
, B_1800
, B_CORE
} BOOTMODE
;
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
82 char cardid
[9]; // characters used for IPL card ID
84 int load_low
= 0x7FFFFFF;
86 unsigned short mem
[MAXADDR
]; // small core!
88 // mkboot - load a binary object deck into core and dump requested bytes as a boot card
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);
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);
112 int main (int argc
, char **argv
)
115 static char usestr
[] = "Usage: mkboot [-v] binfile outfile [1130|1800|core [loaddr [hiaddr [ident]]]]";
118 for (i
= 1; i
< argc
; i
++) {
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
;
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
);
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
);
164 strncpy(cardid
, arg
, 9);
176 maxiplcols
= (mode
== B_1130
) ? 80 : 72;
178 while (strlen(cardid
) < 8)
187 else if (mode
== B_CORE
)
195 void write_1130 (void)
200 if ((fout
= fopen(outfile
, "wb")) == NULL
) {
205 for (addr
= addr_from
; addr
<= addr_to
; addr
++) {
206 if (outcols
>= maxiplcols
)
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
);
215 word
= ((word
& 0xF800) >> 4) | (word
& 0x7F); // convert to 1130 IPL format
217 putc((word
& 0x000F) << 4, fout
); // write the 12 bits in little-endian binary AABBCC00 as CC00 AABB
218 putc((word
& 0x0FF0) >> 4, fout
);
225 void write_1800 (void)
230 if ((fout
= fopen(outfile
, "wb")) == NULL
) {
235 for (addr
= addr_from
; addr
<= addr_to
; addr
++) {
238 if (outcols
>= maxiplcols
)
242 putc(word
& 0xFF, fout
); // write the low 8 bits in little-endian binary
246 putc((word
>> 8) & 0xFF, fout
); // write the high 8 bits in little-endian binary
253 void write_core (void)
257 if ((fout
= fopen(outfile
, "wb")) == NULL
) {
262 addr_from
= load_low
;
267 corecard_setorg(addr_from
);
269 for (addr
= addr_from
; addr
<= addr_to
; addr
++) {
270 corecard_writew(mem
[addr
], 0);
278 void flushcard (void)
281 char fmt
[20], newdig
[20];
284 return; // nothing to flush
286 while (outcols
< maxiplcols
) { // pad to required number of columns with blanks (no punches)
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
);
299 ndig
= 0; // count trailing digits in the label
300 for (i
= 8; --i
>= 0; ndig
++)
301 if (! isdigit(cardid
[i
]))
304 i
++; // index of first digit in trailing sequence
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
317 void show_data (unsigned short *buf
)
319 int i
, n
, jrel
, rflag
, nout
, ch
, reloc
;
323 printf("%04x: ", buf
[0]);
328 for (i
= 0; i
< n
; i
++) {
335 reloc
= (rflag
>> 14) & 0x03;
336 ch
= (reloc
== R_ABSOLUTE
) ? ' ' :
337 (reloc
== R_RELATIVE
) ? 'R' :
338 (reloc
== R_LIBF
) ? 'L' : '@';
340 printf("%04x%c ", buf
[9+i
], ch
);
347 void loadcard (unsigned short *buf
)
354 for (i
= 0; i
< n
; i
++) {
356 bail("Program doesn't fit into 4K");
357 mem
[addr
] = buf
[9+i
];
359 load_low
= MIN(addr
, load_low
);
360 load_high
= MAX(addr
, load_high
);
365 void loaddata (char *fname
)
369 unsigned short card
[80], buf
[54], cardtype
;
371 if ((fp
= fopen(fname
, "rb")) == NULL
) {
377 printf("\n%s:\n", fname
);
379 while (fxread(card
, sizeof(card
[0]), 80, fp
) > 0) {
381 verify_checksum(card
);
383 cardtype
= (buf
[2] >> 8) & 0xFF;
385 if (cardtype
== 1 && ! first
) { // sector break
402 bail("Data must be in absolute format");
406 pta
= buf
[3]; // save program transfer address
417 bail("Unexpected card type");
426 void bail (char *msg
)
428 fprintf(stderr
, "%s\n", msg
);
432 void unpack (unsigned short *card
, unsigned short *buf
)
435 unsigned short wd1
, wd2
, wd3
, wd4
;
437 for (i
= j
= 0; i
< 54; i
+= 3, j
+= 4) {
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);
449 void verify_checksum (unsigned short *card
)
451 // unsigned short sum;
453 if (card
[1] == 0) // no checksum
456 // if (sum != card[1])
457 // printf("Checksum %04x doesn't match card %04x\n", sum, card[1]);
465 static CPCODE cardcode_029
[] =
468 0x8000, '&', // + in 026 Fortran
508 0x0420, '#', // = in 026 Fortran
509 0x0220, '@', // ' in 026 Fortran
515 0x8220, '<', // ) in 026 Fortran
525 0x2820, 'x', // what?
527 0x2220, '%', // ( in 026 Fortran
533 int ascii_to_hollerith (int ch
)
537 for (i
= 0; i
< sizeof(cardcode_029
) / sizeof(CPCODE
); i
++)
538 if (cardcode_029
[i
].ascii
== ch
)
539 return cardcode_029
[i
].hollerith
;
544 // ---------------------------------------------------------------------------------
545 // corecard - routines to write IBM 1130 Card object format
546 // ---------------------------------------------------------------------------------
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
555 // corecard_init - prepare a new object data output card
557 void corecard_init (void)
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)
565 // binard_writecard - emit a card. sbrk_text = NULL for normal data cards, points to comment text for sbrk card
567 void corecard_writecard (char *sbrk_text
)
569 unsigned short binout
[80];
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);
579 for (i
= 0; i
< 72; i
++) {
580 putc(binout
[i
] & 0xFF, fout
);
581 putc((binout
[i
] >> 8) & 0xFF, fout
);
584 outcols
= 72; // add the ident
588 // binard_writedata - emit an object data card
590 void corecard_writedata (void)
592 corecard
[1] = 0; // checksum
593 corecard
[2] = 0x0000 | corecard_n
; // data card type + word count
594 corecard_writecard(FALSE
); // emit the card
597 // corecard_flush - flush any pending binary data
599 void corecard_flush (void)
602 corecard_writedata();
607 // corecard_setorg - set the origin
609 void corecard_setorg (int neworg
)
611 corecard_org
= neworg
; // set origin for next card
612 corecard_flush(); // flush any current data & store origin
615 // corecard_writew - write a word to the current output card.
617 void corecard_writew (int word
, RELOC relative
)
619 if (corecard_n
>= 50) // flush full card buffer (must be even)
622 corecard
[3+corecard_n
++] = word
;
626 // corecard_endcard - write end of program card
628 void corecard_endcard (void)
632 corecard
[0] = 0; // effective length: add 1 to max origin, then 1 more to round up
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
638 corecard_writecard(NULL
);
641 /* ------------------------------------------------------------------------
642 * upcase - force a string to uppercase (ASCII)
643 * ------------------------------------------------------------------------ */
645 char *upcase (char *str
)
649 for (s
= str
; *s
; s
++) {
650 if (*s
>= 'a' && *s
<= 'z')
659 int strnicmp (char *a
, char *b
, int n
)
664 if (--n
< 0) // still equal after n characters? quit now
667 if ((ca
= *a
) == 0) // get character, stop on null terminator
670 if (ca
>= 'a' && ca
<= 'z') // fold lowercase to uppercase
674 if (cb
>= 'a' && cb
<= 'z')
677 if ((ca
-= cb
) != 0) // if different, return comparison
684 int strcmpi (char *a
, char *b
)
689 if ((ca
= *a
) == 0) // get character, stop on null terminator
692 if (ca
>= 'a' && ca
<= 'z') // fold lowercase to uppercase
696 if (cb
>= 'a' && cb
<= 'z')
699 if ((ca
-= cb
) != 0) // if different, return comparison