simh tools

This commit is contained in:
Bob Supnik
2003-12-28 17:18:00 -08:00
committed by Mark Pizzolato
commit abf806277d
52 changed files with 23924 additions and 0 deletions

111
config11/config11.c Normal file
View File

@@ -0,0 +1,111 @@
/* Program to configure the floating address space of a PDP-11 or VAX
Copyright (c) 2002, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <errno.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#define RANK_LNT 34
int csr, i, j;
unsigned int rank, num;
char *cp, *ocp, inp[100];
unsigned char numctl[RANK_LNT];
unsigned char modtab[RANK_LNT] = {
0X07, 0X0f, 0X07, 0X07, 0X07, 0X07, 0X07, 0X07,
0X07, 0X07, 0X07, 0X0f, 0X07, 0X07, 0X0f, 0X07,
0X07, 0X07, 0X07, 0X07, 0X07, 0X07, 0X07, 0X0f,
0X07, 0X03, 0X1f, 0X0f, 0X0f, 0X03, 0X0F, 0x0F,
0x1F, 0X1F };
unsigned int fixtab[RANK_LNT] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0774400, 0770460, 0,
0, 0777170, 0, 0772410, 0, 0, 0, 0,
0774440, 0772150, 0, 0, 0, 0774500, 0, 0,
0, 0 };
char *namtab[RANK_LNT] = {
"DJ11", "DH11", "DQ11", "DU11", "DUP11", "LK11A", "DMC11", "DZ11",
"KMC11", "LPP11", "VMV21", "VMV31", "DWR70", "RL11", "LPA11K", "KW11C",
"rsvd", "RX11", "DR11W", "DR11B", "DMP11", "DPV11", "ISB11", "DMV11",
"DEUNA", "UDA50", "DMF32", "KMS11", "VS100", "TK50", "KMV11", "DHV11",
"DMZ32", "CP132" };
int main (int argc, char *argv[])
{
for ( ;; ) {
for (i = 0; i < RANK_LNT; i++) numctl[i] = 0;
printf ("Enter configuration data\n");
for ( ;; ) {
printf ("Name:\t");
if (gets (inp) == NULL) return 0;
if (*inp == 0) break;
for (cp = inp; *cp != 0; cp++) *cp = toupper (*cp);
for (rank = 0; rank < RANK_LNT; rank++) {
if (strcmp (inp, namtab[rank]) == 0) break; }
if (rank >= RANK_LNT) {
printf ("Unknown controller, valid names are:");
for (i = 0; i < RANK_LNT; i++) {
if ((i & 07) == 0) printf ("\n");
printf (" %s", namtab[i]); }
printf ("\n");
continue; }
printf ("Number:\t");
gets (inp);
errno = 0;
num = strtoul (inp, &ocp, 10);
if (errno || (inp == ocp)) {
printf ("Input error\n");
continue; }
if (num > 8) {
printf ("Too many controllers\n");
continue; }
numctl[rank] = num;
}
printf ("\nRank\tName\tCtrl#\t CSR\n\n");
csr = 0760010;
for (i = 0; i < RANK_LNT; i++) {
if (numctl[i] == 0) {
printf (" %02d\t%s\tgap\t%06o\n", i+1, namtab[i], csr); }
else {
if (fixtab[i])
printf (" %02d\t%s\t 1\t%06o*\n", i+1, namtab[i], fixtab[i]);
else {
printf (" %02d\t%s\t 1\t%06o\n", i+1, namtab[i], csr);
csr = (csr + modtab[i] + 1) & ~modtab[i]; }
for (j = 1; j < numctl[i]; j++) {
printf ("\t\t %d\t%06o\n", j + 1, csr);
csr = (csr + modtab[i] + 1) & ~modtab[i]; }
printf (" %\t\tgap\t%06o\n", csr);
}
if ((i + 1) < RANK_LNT) csr = (csr + modtab[i+1] + 1) & ~modtab[i+1];
}
printf ("\n\n");
}
return 0;
}

17
config11/config11.txt Normal file
View File

@@ -0,0 +1,17 @@
Config11 is a program for calculating the floating address space layout of
a PDP-11 or VAX.
Config11 is an interactive program. When started, it repeatedly asks for
the names of controllers and the numbers of instances:
> config11
Name: UDA50
Number: 2
Name: DZ11
Number: 2
Name:
To end input, simply type ENTER to the NAME: prompt. Config11 will then
print out the complete floating address table for the known Unibus and
Qbus devices.

108
converters/asc.c Normal file
View File

@@ -0,0 +1,108 @@
/* This program converts <cr> delimited files to Windoze <cr><lf>
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define LAST_ANY 0
#define LAST_CR 1
#define LAST_LF 2
#define MD_WIN 0
#define MD_UNIX 1
#define MD_MAC 2
void puteol (int mode, FILE *of)
{
if (mode != MD_UNIX) putc ('\r', of);
if (mode != MD_MAC) putc ('\n', of);
return;
}
int main (int argc, char *argv[])
{
int i, k, mc, lastc;
int mode;
char *s, *ppos, oname[256];
FILE *ifile, *ofile;
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: asc -muw file [file...]\n");
exit (0); }
s = argv[1];
if ((s != NULL) && (*s++ == '-')) {
++argv; --argc;
switch (*s) {
case 'm': case 'M':
mode = MD_MAC; break;
case 'u': case 'U':
mode = MD_UNIX; break;
case 'w': case 'W':
mode = MD_WIN; break;
default:
fprintf (stderr, "Bad option %c\n", *s);
return 0; }
}
else mode = MD_WIN;
for (i = 1; i < argc; i++) {
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".new");
else strcat (oname, ".new");
ifile = fopen (argv[i], "rb");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
ofile = fopen (oname, "wb");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Processing file %s\n", argv[i]);
for (lastc = LAST_ANY;;) {
k = getc (ifile);
if (k == EOF) break;
mc = k & 0177;
if (mc && (mc != 0177)) {
if (mc == 015) {
if (lastc == LAST_CR) puteol (mode, ofile);
lastc = LAST_CR; }
else if (mc == 012) {
puteol (mode, ofile);
lastc = LAST_LF; }
else {
if (lastc == LAST_CR) puteol (mode, ofile);
putc (mc, ofile);
lastc = LAST_ANY; }
}
}
if (lastc == LAST_CR) puteol (mode, ofile);
fclose (ifile);
fclose (ofile);
}
return 0;
}

14
converters/asc.txt Normal file
View File

@@ -0,0 +1,14 @@
ASC is a simple utility for converting text files (delimited with
\r, \n, or \r\n) to Windows format (\r\n delimited), Unix format
(\n delimited) or Mac format (\r delimited).
ASC is invoked from a DOS prompt with the command:
> ASC {-m|u|w} file1 file2 ...
The optional switch specifies Mac processing (-m), Unix processing
(-u), or Windows processing (-w). If no switch is specified, Windows
processing is performed.
Each file is processed in turn. If the file is name.ext, the converted
file is name.new.

68
converters/dtos8cvt.c Normal file
View File

@@ -0,0 +1,68 @@
/* This program converts an OS8 DECtape image to simulator format
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BLKSIZ 129
int main (int argc, char *argv[])
{
int i, k;
unsigned short buf[BLKSIZ];
char *ppos, oname[256];
FILE *ifile, *ofile;
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: verb file [file...]\n");
exit (0); }
for (i = 1; i < argc; i++) {
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".dt8");
else strcat (oname, ".dt8");
ifile = fopen (argv[i], "rb");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
ofile = fopen (oname, "wb");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Processing file %s\n", argv[i]);
for (;;) {
k = fread (buf, sizeof (short), BLKSIZ - 1, ifile);
if (k == 0) break;
for ( ; k < BLKSIZ; k++) buf[k] = 0;
fwrite (buf, sizeof (short), BLKSIZ, ofile);
}
fclose (ifile);
fclose (ofile);
}
return 0;
}

13
converters/dtos8cvt.txt Normal file
View File

@@ -0,0 +1,13 @@
dtos8cvt converts a PDP-8 DECtape image from OS/8 format to simulator format.
OS/8 only uses 128 words out of 129 in a PDP-8 DECtape block. The simulator
requires all 129 words, in order to simulate the actions of the hardware, and
to deal with oddball software systems such as the PDP-8 Disk Monitor.
dtos8cvt is invoked by
dtos8cvt file1 file2 file3...
Each file in turn is converted from OS/8 format to simulator format. The
input file can have any extension; the converted file will have a .dt8
extension.

97
converters/gt7cvt.c Normal file
View File

@@ -0,0 +1,97 @@
/* This program converts a gt7 magtape dump to a SIMH magtape
Copyright (c) 2002, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define FLPSIZ 65536
unsigned char fzero[4] = { 0 };
int dump_rec (FILE *of, int bc, char *buf)
{
unsigned char buc[4];
if (((bc == 1) && (buf[0] == 0xF)) ||
((bc == 2) && (buf[0] == 0xF) && (buf[1] == 0xF))) {
fwrite (fzero, sizeof (char), 4, of);
return 1; }
buc[0] = bc & 0xFF;
buc[1] = (bc >> 8) & 0xFF;
buc[2] = (bc >> 16) & 0xFF;
buc[3] = (bc >> 24) & 0xFF;
fwrite (buc, sizeof (char), 4, of);
fwrite (buf, sizeof (char), (bc + 1) & ~1, of);
fwrite (buc, sizeof (char), 4, of);
return 0;
}
int main (int argc, char *argv[])
{
int i, ch, bc, rc, fc;
unsigned char buf[FLPSIZ];
char *ppos, oname[256];
FILE *ifile, *ofile;
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: verb file [file...]\n");
exit (0); }
for (i = 1; i < argc; i++) {
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".tap");
else strcat (oname, ".tap");
ifile = fopen (argv[i], "rb");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
ofile = fopen (oname, "wb");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Processing file %s\n", argv[i]);
for (bc = rc = fc = 0;;) {
ch = fgetc (ifile);
if (ch == EOF) break;
if (ch & 0x80) {
if (bc) {
if (dump_rec (ofile, bc, buf))
printf ("End of file %d\n", ++fc);
else printf ("Record %d size %d\n", ++rc, bc);
}
bc = 0; }
buf[bc++] = ch & 0x3F;
}
fclose (ifile);
if (bc) dump_rec (ofile, bc, buf);
fwrite (fzero, sizeof (char), 4, ofile);
printf ("End of file %d\n", ++fc);
fclose (ofile);
}
return 0;
}

69
converters/littcvt.c Normal file
View File

@@ -0,0 +1,69 @@
/* This program removes the 4 header bytes from a Litt tape
Copyright (c) 1993-1999, Robert M. Supnik, Compaq Computer Corporation
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK, OR COMPAQ COMPUTER CORPORATION, BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik, or Compaq
Computer Corporation, shall not be used in advertising or otherwise to
promote the sale, use or other dealings in this Software without prior
written authorization from both the author and Compaq Computer Corporation.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define FLPSIZ 65536
int main (int argc, char *argv[])
{
int i, k, bc;
unsigned char buf[FLPSIZ];
char *ppos, oname[256];
FILE *ifile, *ofile;
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: verb file [file...]\n");
exit (0); }
for (i = 1; i < argc; i++) {
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".new");
else strcat (oname, ".new");
ifile = fopen (argv[i], "rb");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
ofile = fopen (oname, "wb");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Processing file %s\n", argv[i]);
fread (&bc, sizeof (int), 1, ifile);
for (;;) {
k = fread (buf, sizeof (char), FLPSIZ, ifile);
if (k == 0) break;
fwrite (buf, sizeof (char), k, ofile); }
fclose (ifile);
fclose (ofile);
}
exit (0);
}

94
converters/mtcvtfix.c Normal file
View File

@@ -0,0 +1,94 @@
/* This program fixes a SIMH magtape containing a misread EOF
Copyright (c) 2003, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define FLPSIZ 65536
int main (int argc, char *argv[])
{
int i, fc, rc;
unsigned int k, tbc;
unsigned char bc[4] = { 0 };
unsigned char bceof[4] = { 0 };
unsigned char buf[FLPSIZ];
char *ppos, oname[256];
FILE *ifile, *ofile;
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: verb file [file...]\n");
exit (0); }
for (i = 1; i < argc; i++) {
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".new");
else strcat (oname, ".new");
ifile = fopen (argv[i], "rb");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
ofile = fopen (oname, "wb");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Processing file %s\n", argv[i]);
fc = 1; rc = 0;
for (;;) {
k = fread (bc, sizeof (char), 4, ifile);
if (k == 0) break;
tbc = ((unsigned int) bc[3] << 24) | ((unsigned int) bc[2] << 16) |
((unsigned int) bc[1] << 8) | (unsigned int) bc[0];
if (tbc) {
printf ("Record size = %d\n", tbc);
if (tbc > FLPSIZ) {
printf ("Record too big\n");
return 0; }
k = fread (buf, sizeof (char), tbc, ifile);
for ( ; k < tbc; k++) buf[k] = 0;
fread (bc, sizeof (char), 4, ifile);
if (tbc > 1) {
fwrite (bc, sizeof (char), 4, ofile);
fwrite (buf, sizeof (char), tbc, ofile);
fwrite (bc, sizeof (char), 4, ofile);
rc++; }
else {
printf ("Record length = 1, ignored\n");
} }
else {
fwrite (bceof, sizeof (char), 4, ofile);
if (rc) printf ("End of file %d, record count = %d\n", fc, rc);
else printf ("End of tape\n");
fc++;
rc = 0; }
}
fclose (ifile);
fclose (ofile);
}
return 0;
}

87
converters/mtcvtodd.c Normal file
View File

@@ -0,0 +1,87 @@
/* This program converts an E11 magtape (with odd record sizes) to SIMH
Copyright (c) 1993-2001, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define FLPSIZ 65536
int main (int argc, char *argv[])
{
int i, k, tbc, ebc, fc, rc;
unsigned char bc[4] = { 0 };
unsigned char buf[FLPSIZ];
char *ppos, oname[256];
FILE *ifile, *ofile;
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: verb file [file...]\n");
exit (0); }
for (i = 1; i < argc; i++) {
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".new");
else strcat (oname, ".new");
ifile = fopen (argv[i], "rb");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
ofile = fopen (oname, "wb");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Processing file %s\n", argv[i]);
fc = 1; rc = 0;
for (;;) {
k = fread (bc, sizeof (char), 4, ifile);
if (k == 0) break;
tbc = ((unsigned int) bc[3] << 24) | ((unsigned int) bc[2] << 16) |
((unsigned int) bc[1] << 8) | (unsigned int) bc[0];
ebc = (tbc + 1) & ~1;
fwrite (bc, sizeof (char), 4, ofile);
if (tbc) {
printf ("Record size = %d\n", tbc);
if (tbc > FLPSIZ) {
printf ("Record too big\n");
return 0; }
k = fread (buf, sizeof (char), tbc, ifile);
for ( ; k < ebc; k++) buf[k] = 0;
fread (bc, sizeof (char), 4, ifile);
fwrite (buf, sizeof (char), ebc, ofile);
fwrite (bc, sizeof (char), 4, ofile);
rc++; }
else { if (rc) printf ("End of file %d, record count = %d\n", fc, rc);
else printf ("End of tape\n");
fc++;
rc = 0; }
}
fclose (ifile);
fclose (ofile);
}
return 0;
}

81
converters/mtcvtv23.c Normal file
View File

@@ -0,0 +1,81 @@
/* This program converts a pre V2.3 simulated magtape to a V2.3 magtape
Copyright (c) 1993-1999, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define FLPSIZ 65536
int main (int argc, char *argv[])
{
int i, k, wc, fc, rc;
unsigned char bc[4] = { 0 };
unsigned char buf[FLPSIZ];
char *ppos, oname[256];
FILE *ifile, *ofile;
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: verb file [file...]\n");
exit (0); }
for (i = 1; i < argc; i++) {
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".tap");
else strcat (oname, ".tap");
ifile = fopen (argv[i], "rb");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
ofile = fopen (oname, "wb");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Processing file %s\n", argv[i]);
fc = 1; rc = 0;
for (;;) {
k = fread (bc, sizeof (char), 2, ifile);
if (k == 0) break;
wc = ((unsigned int) bc[1] << 8) | (unsigned int) bc[0];
wc = (wc + 1) & ~1;
fwrite (bc, sizeof (char), 4, ofile);
if (wc) {
k = fread (buf, sizeof (char), wc, ifile);
for ( ; k < wc; k++) buf[k] =0;
fwrite (buf, sizeof (char), wc, ofile);
fwrite (bc, sizeof (char), 4, ofile);
rc++; }
else { if (rc) printf ("End of file %d, record count = %d\n", fc, rc);
else printf ("End of tape\n");
fc++;
rc = 0; }
}
fclose (ifile);
fclose (ofile);
}
return 0;
}

35
converters/mtcvtv23.txt Normal file
View File

@@ -0,0 +1,35 @@
mtcvtv23 converts a tape images in .tpc format to .tap format.
.tpc format tape images have the format
2 byte record length 1
record 1
2 byte record length 2
record 2
:
2 bytes = 0000 for end of file
and so on. This is the format produced by various UNIX utilities
for dumping tape images.
.tap format tape images have the format
4 byte record length 1
record 1
repeat of 4 byte record length 1
4 byte record length 2
record 2
repeat of 4 byte record length 2
:
4 bytes = 00000000 for end of file
and so on. This is the tape format expected by simh, Tim Stark's TS10,
and John Wilson's E11.
mtcvtv23 is invoked by
mtcvtv23 file1 file2 file3...
Each file in turn is converted from .tpc format to .tap format. The
input file can have any extension; the converted file will have a .tap
extension.

116
converters/sfmtcvt.c Normal file
View File

@@ -0,0 +1,116 @@
/* This program converts a Motorola S format PROM dump to a binary file
Copyright (c) 1993-2003, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define HEX(a) ((a) >= 'A'? (a) - 'A' + 10: (a) - '0')
#define MAXA (2 << 14)
#define MAXR 4
int main (int argc, char *argv[])
{
int i, d, d1, j, k, astrt, dstrt, addr, maxaddr[MAXR];
int numr, numf;
unsigned char data[MAXR][MAXA];
char *s, *ppos, *cptr, line[256], oname[256];
FILE *ifile, *ofile;
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: verb file [file...]\n");
exit (0); }
s = argv[1];
if ((s != NULL) && (*s++ == '-')) {
++argv; --argc;
switch (*s) {
case '1':
numr = 1; break;
case '2':
numr = 2; break;
case '4':
numr = 4; break;
default:
fprintf (stderr, "Bad option %c\n", *s);
return 0; }
}
else numr = 1;
for (i = 1, numf = 0; i < argc; i++) {
ifile = fopen (argv[i], "r");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
printf ("Processing file %s\n", argv[i]);
astrt = 4;
maxaddr[numf] = 0;
for (;;) {
cptr = fgets (line, 256, ifile);
if (cptr == NULL) break;
if (line[0] != 'S') continue;
if (line[1] == '1') dstrt = 8;
else if (line[1] == '2') dstrt = 10;
else continue;
for (k = astrt, addr = 0; k < dstrt; k++) {
d = HEX (line[k]);
addr = (addr << 4) + d; }
if (addr >= MAXA) {
printf ("Address %o out of range\n", addr);
break; }
for (k = dstrt; k < (dstrt + 32); k = k + 2, addr++) {
d = HEX (line[k]);
d1 = HEX (line[k+1]);
data[numf][addr] = (d << 4) + d1; }
if (addr > maxaddr[numf]) maxaddr[numf] = addr;
}
fclose (ifile);
numf++;
if (numf >= numr) {
for (k = 0; k < numr; k++) {
if (maxaddr[k] != maxaddr[0]) {
printf ("Rom lengths don't match, file 1 = %d, file %d = %d\n",
maxaddr[0], k, maxaddr[k]);
return 0; } }
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".bin");
else strcat (oname, ".bin");
ofile = fopen (oname, "wb");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Output file: %s, ROM size is %d\n", oname, maxaddr[0]);
for (k = 0; k < maxaddr[0]; k++) {
for (j = numr - 1; j >= 0; j--) {
fwrite (&data[j][k], 1, 1, ofile); } }
fclose (ofile);
numf = 0;
}
}
if (numf) printf ("Unprocessed files\n");
return 0;
}

76
converters/tp512cvt.c Normal file
View File

@@ -0,0 +1,76 @@
/* This program converts a tp data file to a simulated 512B blocked magtape
Copyright (c) 1993-2003, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BLKSIZ 512
int main (int argc, char *argv[])
{
int i, k;
unsigned char buf[BLKSIZ];
unsigned char tef[4] = { 0, 0, 0, 0 };
unsigned char twc[4] = { 0, 2, 0, 0 };
char *ppos, oname[256];
FILE *ifile, *ofile;
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: verb file [file...]\n");
exit (0); }
for (i = 1; i < argc; i++) {
strcpy (oname, argv[i]);
if (ppos = strrchr (oname, '.')) strcpy (ppos, ".tap");
else strcat (oname, ".tap");
ifile = fopen (argv[i], "rb");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
ofile = fopen (oname, "wb");
if (ofile == NULL) {
printf ("Error opening file: %s\n", oname);
exit (0); }
printf ("Processing file %s\n", argv[i]);
for (;;) {
k = fread (buf, sizeof (char), BLKSIZ, ifile);
if (k == 0) break;
if (k != BLKSIZ) {
printf ("Short block, size = %d\n", k);
for ( ; k < BLKSIZ; k++) buf[k] = 0; }
fwrite (twc, sizeof (char), 4, ofile);
fwrite (buf, sizeof (char), BLKSIZ, ofile);
fwrite (twc, sizeof (char), 4, ofile);
}
fwrite (tef, sizeof (char), 4, ofile);
fwrite (tef, sizeof (char), 4, ofile);
fclose (ifile);
fclose (ofile);
}
return 0;
}

3068
crossassemblers/macro1.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
15-July-2001
version 0.2
removed references to snprintf from dumpobj.c and
mlb.c for portability
fixed a type cast warning in dumpobj.c compare_gsdlines
Removed strcasecmp from macro11.c for portability
Removed references to wnewmem.c from makefile (isn't needed)
makefile more compatible with non-gnu make and compiler
main prints version 0.2
14-July-2001
First release, version 0.1.

View File

View File

@@ -0,0 +1,677 @@
/* Dump and interpret an object file. */
/*
Copyright (c) 2001, Richard Krehbiel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
o Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "rad50.h"
#include "util.h"
#define WORD(cp) ((*(cp) & 0xff) + ((*((cp)+1) & 0xff) << 8))
int psectid = 0;
char *psects[256];
FILE *bin = NULL;
int badbin = 0;
int xferad = 1;
char *readrec(FILE *fp, int *len)
{
int c, i;
int chksum;
char *buf;
chksum = 0;
while(c = fgetc(fp), c != EOF && c == 0)
;
if(c == EOF)
return NULL;
if(c != 1)
{
fprintf(stderr, "Improperly formatted OBJ file (1)\n");
return NULL; // Not a properly formatted file.
}
chksum -= c;
c = fgetc(fp);
if(c != 0)
{
fprintf(stderr, "Improperly formatted OBJ file (2)\n");
return NULL; // Not properly formatted
}
chksum -= c; // even though for 0 the checksum isn't changed...
c = fgetc(fp);
if(c == EOF)
{
fprintf(stderr, "Improperly formatted OBJ file (3)\n");
return NULL;
}
*len = c;
chksum -= c;
c = fgetc(fp);
if(c == EOF)
{
fprintf(stderr, "Improperly formatted OBJ file (4)\n");
return NULL;
}
*len += (c << 8);
chksum -= c;
*len -= 4; // Subtract header and length bytes from length
if(*len < 0)
{
fprintf(stderr, "Improperly formatted OBJ file (5)\n");
return NULL;
}
buf = malloc(*len);
if(buf == NULL)
{
fprintf(stderr, "Out of memory allocating %d bytes\n", *len);
return NULL; // Bad alloc
}
i = fread(buf, 1, *len, fp);
if(i < *len)
{
free(buf);
fprintf(stderr, "Improperly formatted OBJ file (6)\n");
return NULL;
}
for(i = 0; i < *len; i++)
{
chksum -= (buf[i] & 0xff);
}
c = fgetc(fp);
c &= 0xff;
chksum &= 0xff;
if(c != chksum)
{
free(buf);
fprintf(stderr, "Bad record checksum, "
"calculated=%d, recorded=%d\n", chksum, c);
return NULL;
}
return buf;
}
void dump_bytes(char *buf, int len)
{
int i, j;
for(i = 0; i < len; i += 8)
{
printf("\t%3.3o: ", i);
for(j = i; j < len && j < i+8; j++)
{
printf("%3.3o ", buf[j] & 0xff);
}
printf("%*s", (i+8 - j) * 4, "");
for(j = i; j < len && j < i+8; j++)
{
int c = buf[j] & 0xff;
if(!isprint(c))
c = '.';
putchar(c);
}
putchar('\n');
}
}
void dump_words(unsigned addr, char *buf, int len)
{
int i, j;
for(i = 0; i < len; i += 8)
{
printf("\t%6.6o: ", addr);
for(j = i; j < len && j < i+8; j += 2)
{
if(len - j >= 2)
{
unsigned word = WORD(buf + j);
printf("%6.6o ", word);
}
else
printf("%3.3o ", buf[j] & 0xff);
}
printf("%*s", (i+8 - j) * 7 / 2, "");
for(j = i; j < len && j < i+8; j++)
{
int c = buf[j] & 0xff;
if(!isprint(c))
c = '.';
putchar(c);
}
putchar('\n');
addr += 8;
}
}
void dump_bin(unsigned addr, char *buf, int len)
{
int chksum; /* Checksum is negative sum of all
bytes including header and length */
int FBR_LEAD1 = 1, FBR_LEAD2 = 0;
int i;
unsigned hdrlen = len + 6;
for(i = 0; i < 8; i++) fputc (0, bin);
chksum = 0;
if(fputc(FBR_LEAD1, bin) == EOF) return; /* All recs begin with 1,0 */
chksum -= FBR_LEAD1;
if(fputc(FBR_LEAD2, bin) == EOF) return;
chksum -= FBR_LEAD2;
i = hdrlen & 0xff; /* length, lsb */
chksum -= i;
if(fputc(i, bin) == EOF) return;
i = (hdrlen >> 8) & 0xff; /* length, msb */
chksum -= i;
if(fputc(i, bin) == EOF) return;
i = addr & 0xff; /* origin, msb */
chksum -= i;
if(fputc(i, bin) == EOF) return;
i = (addr >> 8) & 0xff; /* origin, lsb */
chksum -= i;
if(fputc(i, bin) == EOF) return;
if ((len == 0) || (buf == NULL)) return; /* end of tape block */
i = fwrite(buf, 1, len, bin);
if(i < len) return;
while(len > 0) /* All the data bytes */
{
chksum -= *buf++ & 0xff;
len--;
}
chksum &= 0xff;
fputc(chksum, bin); /* Followed by the checksum byte */
return; /* Worked okay. */
}
void trim(char *buf)
{
char *cp;
for(cp = buf + strlen(buf); cp > buf; cp--)
{
if(cp[-1] != ' ')
break;
}
*cp = 0;
}
char **all_gsds = NULL;
int nr_gsds = 0;
int gsdsize = 0;
void add_gsdline(char *line)
{
if(nr_gsds >= gsdsize || all_gsds == NULL)
{
gsdsize += 128;
all_gsds = realloc(all_gsds, gsdsize * sizeof(char *));
if(all_gsds == NULL)
{
fprintf(stderr, "Out of memory\n");
exit(EXIT_FAILURE);
}
}
all_gsds[nr_gsds++] = line;
}
void got_gsd(char *cp, int len)
{
int i;
char *gsdline;
for(i = 2; i < len; i += 8)
{
char name[8];
unsigned value;
unsigned flags;
gsdline = malloc(256);
if(gsdline == NULL)
{
fprintf(stderr, "Out of memory\n");
exit(EXIT_FAILURE);
}
unrad50(WORD(cp+i), name);
unrad50(WORD(cp+i+2), name+3);
name[6] = 0;
value = WORD(cp+i+6);
flags = cp[i+4] & 0xff;
switch(cp[i+5] & 0xff)
{
case 0:
sprintf(gsdline,
"\tMODNAME %s=%o flags=%o\n", name, value, flags);
break;
case 1:
sprintf(gsdline,
"\tCSECT %s=%o flags=%o\n", name, value, flags);
break;
case 2:
sprintf(gsdline,
"\tISD %s=%o flags=%o\n", name, value, flags);
break;
case 3:
sprintf(gsdline,
"\tXFER %s=%o flags=%o\n", name, value, flags);
xferad = value;
break;
case 4:
sprintf(gsdline,
"\tGLOBAL %s=%o %s flags=%o\n",
name, value, cp[i+4] & 8 ? "DEF" : "REF", flags);
break;
case 5:
sprintf(gsdline,
"\tPSECT %s=%o flags=%o\n", name, value, flags);
psects[psectid] = strdup(name);
trim(psects[psectid++]);
break;
case 6:
sprintf(gsdline,
"\tIDENT %s=%o flags=%o\n", name, value, flags);
break;
case 7:
sprintf(gsdline,
"\tVSECT %s=%o flags=%o\n", name, value, flags);
break;
default:
sprintf(gsdline,
"\t***Unknown GSD entry type %d flags=%o\n",
cp[i+5] & 0xff, flags);
break;
}
gsdline = realloc(gsdline, strlen(gsdline)+1);
add_gsdline(gsdline);
}
}
int compare_gsdlines(const void *p1, const void *p2)
{
const char * const *l1 = p1, * const *l2 = p2;
return strcmp(*l1, *l2);
}
void got_endgsd(char *cp, int len)
{
int i;
qsort(all_gsds, nr_gsds, sizeof(char *), compare_gsdlines);
printf("GSD:\n");
for(i = 0; i < nr_gsds; i++)
{
fputs(all_gsds[i], stdout);
free(all_gsds[i]);
}
printf("ENDGSD\n");
free(all_gsds);
}
unsigned last_text_addr = 0;
void got_text(char *cp, int len)
{
unsigned addr = WORD(cp+2);
last_text_addr = addr;
printf("TEXT ADDR=%o LEN=%o\n", last_text_addr, len-4);
dump_words(last_text_addr, cp+4, len-4);
if (bin) dump_bin(last_text_addr, cp+4, len-4);
}
void rad50name(char *cp, char *name)
{
unrad50(WORD(cp), name);
unrad50(WORD(cp+2), name+3);
name[6] = 0;
trim(name);
}
void got_rld(char *cp, int len)
{
int i;
printf("RLD\n");
for(i = 2; i < len;)
{
unsigned addr;
unsigned word;
unsigned disp = cp[i+1] & 0xff;
char name[8];
char *byte;
addr = last_text_addr + disp - 4;
byte = "";
if(cp[i] & 0200)
byte = " byte";
switch(cp[i] & 0x7f)
{
case 01:
printf("\tInternal%s %o=%o\n", byte, addr, WORD(cp+i+2));
i += 4;
break;
case 02:
rad50name(cp+i+2, name);
printf("\tGlobal%s %o=%s\n", byte, addr, name);
i += 6;
break;
case 03:
printf("\tInternal displaced%s %o=%o\n", byte, addr, WORD(cp+i+2));
i += 4;
badbin = 1;
break;
case 04:
rad50name(cp+i+2, name);
printf("\tGlobal displaced%s %o=%s\n", byte, addr, name);
i += 6;
badbin = 1;
break;
case 05:
rad50name(cp+i+2, name);
word = WORD(cp+i+6);
printf("\tGlobal plus offset%s %o=%s+%o\n",
byte, addr, name, word);
i += 8;
badbin = 1;
break;
case 06:
rad50name(cp+i+2, name);
word = WORD(cp+i+6);
printf("\tGlobal plus offset displaced%s %o=%s+%o\n",
byte, addr, name, word);
i += 8;
badbin = 1;
break;
case 07:
rad50name(cp+i+2, name);
word = WORD(cp+i+6);
printf("\tLocation counter definition %s+%o\n",
name, word);
i += 8;
last_text_addr = word;
break;
case 010:
word = WORD(cp+i+2);
printf("\tLocation counter modification %o\n", word);
i += 4;
last_text_addr = word;
break;
case 011:
printf("\t.LIMIT %o\n", addr);
i += 2;
break;
case 012:
rad50name(cp+i+2, name);
printf("\tPSECT%s %o=%s\n", byte, addr, name);
i += 6;
badbin = 1;
break;
case 014:
rad50name(cp+i+2, name);
printf("\tPSECT displaced%s %o=%s+%o\n", byte, addr, name, word);
i += 6;
badbin = 1;
break;
case 015:
rad50name(cp+i+2, name);
word = WORD(cp+i+6);
printf("\tPSECT plus offset%s %o=%s+%o\n",
byte, addr, name, word);
i += 8;
badbin = 1;
break;
case 016:
rad50name(cp+i+2, name);
word = WORD(cp+i+6);
printf("\tPSECT plus offset displaced%s %o=%s+%o\n",
byte, addr, name, word);
i += 8;
badbin = 1;
break;
case 017:
badbin = 1;
printf("\tComplex%s %o=", byte, addr);
i += 2;
{
char *xp = cp + i;
int size;
for(;;)
{
size = 1;
switch(*xp)
{
case 000:
fputs("nop ", stdout); break;
case 001:
fputs("+ ", stdout); break;
case 002:
fputs("- ", stdout); break;
case 003:
fputs("* ", stdout); break;
case 004:
fputs("/ ", stdout); break;
case 005:
fputs("& ", stdout); break;
case 006:
fputs("! ", stdout); break;
case 010:
fputs("neg ", stdout); break;
case 011:
fputs("^C ", stdout); break;
case 012:
fputs("store ", stdout); break;
case 013:
fputs("store{disp} ", stdout); break;
case 016:
rad50name(xp+1, name);
printf("%s ", name);
size = 5;
break;
case 017:
assert((xp[1] & 0377) < psectid);
printf("%s:%o ",
psects[xp[1] & 0377],
WORD(xp+2));
size = 4;
break;
case 020:
printf("%o ", WORD(xp+1));
size = 3;
break;
default:
printf("**UNKNOWN COMPLEX CODE** %o\n", *xp & 0377);
return;
}
i += size;
if(*xp == 012 || *xp == 013)
break;
xp += size;
}
fputc('\n', stdout);
break;
}
default:
printf("\t***Unknown RLD code %o\n", cp[i] & 0xff);
return;
}
}
}
void got_isd(char *cp, int len)
{
printf("ISD len=%o\n");
}
void got_endmod(char *cp, int len)
{
printf("ENDMOD\n");
}
void got_libhdr(char *cp, int len)
{
printf("LIBHDR\n");
}
void got_libend(char *cp, int len)
{
printf("LIBEND\n");
}
int main(int argc, char *argv[])
{
int len;
FILE *fp;
char *cp;
fp = fopen(argv[1], "rb");
if(fp == NULL)
return EXIT_FAILURE;
if(argv[2])
{
bin = fopen(argv[2], "wb");
if(bin == NULL) return EXIT_FAILURE;
}
while((cp = readrec(fp, &len)) != NULL)
{
switch(cp[0] & 0xff)
{
case 1:
got_gsd(cp, len);
break;
case 2:
got_endgsd(cp, len);
break;
case 3:
got_text(cp, len);
break;
case 4:
got_rld(cp, len);
break;
case 5:
got_isd(cp, len);
break;
case 6:
got_endmod(cp, len);
break;
case 7:
got_libhdr(cp, len);
break;
case 8:
got_libend(cp, len);
break;
default:
printf("Unknown record type %d\n", cp[0] & 0xff);
break;
}
free(cp);
}
if (bin)
{ dump_bin (xferad, NULL, 0);
fclose (bin);
if (badbin) fprintf (stderr, "Probable errors in binary file\n");
}
fclose (fp);
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,114 @@
# Microsoft Developer Studio Project File - Name="dumpobj" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=dumpobj - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "dumpobj.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "dumpobj.mak" CFG="dumpobj - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "dumpobj - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "dumpobj - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""$/macro11", BAAAAAAA"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "dumpobj - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "dumpobj___Release"
# PROP Intermediate_Dir "dumpobj___Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "dumpobj - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "dumpobj___Debug"
# PROP Intermediate_Dir "dumpobj___Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "dumpobj - Win32 Release"
# Name "dumpobj - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\dumpobj.c
# End Source File
# Begin Source File
SOURCE=.\Rad50.c
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\Rad50.h
# End Source File
# Begin Source File
SOURCE=.\util.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

View File

@@ -0,0 +1,30 @@
Copyright (c) 2001, Richard Krehbiel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
o Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,180 @@
# Microsoft Developer Studio Project File - Name="macro11" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=macro11 - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "macro11.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "macro11.mak" CFG="macro11 - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "macro11 - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "macro11 - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""$/macro11", BAAAAAAA"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "macro11 - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# SUBTRACT LINK32 /profile
# Begin Special Build Tool
TargetPath=.\Release\macro11.exe
SOURCE="$(InputPath)"
PostBuild_Cmds=copy $(TargetPath) c:\bin
# End Special Build Tool
!ELSEIF "$(CFG)" == "macro11 - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "MEM_DEBUG" /FR /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# SUBTRACT LINK32 /profile
# Begin Special Build Tool
TargetPath=.\Debug\macro11.exe
SOURCE="$(InputPath)"
PostBuild_Cmds=copy $(TargetPath) c:\bin
# End Special Build Tool
!ENDIF
# Begin Target
# Name "macro11 - Win32 Release"
# Name "macro11 - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\macro11.c
# End Source File
# Begin Source File
SOURCE=.\mlb.c
# End Source File
# Begin Source File
SOURCE=.\object.c
# End Source File
# Begin Source File
SOURCE=.\rad50.c
# End Source File
# Begin Source File
SOURCE=.\stream2.c
# End Source File
# Begin Source File
SOURCE=.\util.c
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\macro11.h
# End Source File
# Begin Source File
SOURCE=.\mlb.h
# End Source File
# Begin Source File
SOURCE=.\object.h
# End Source File
# Begin Source File
SOURCE=.\Rad50.h
# End Source File
# Begin Source File
SOURCE=.\stream2.h
# End Source File
# Begin Source File
SOURCE=.\util.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# Begin Source File
SOURCE=.\Changes
# End Source File
# Begin Source File
SOURCE=.\License
# End Source File
# Begin Source File
SOURCE=.\Makefile
# End Source File
# Begin Source File
SOURCE=.\Readme
# End Source File
# Begin Source File
SOURCE=.\Todo
# End Source File
# End Target
# End Project

View File

@@ -0,0 +1,53 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "dumpobj"=.\dumpobj.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
"$/macro11", BAAAAAAA
.
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "macro11"=.\macro11.dsp - Package Owner=<4>
Package=<5>
{{{
begin source code control
"$/macro11", BAAAAAAA
.
end source code control
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
begin source code control
"$/macro11", BAAAAAAA
.
end source code control
}}}
Package=<3>
{{{
}}}
###############################################################################

View File

@@ -0,0 +1,39 @@
#ifndef MACRO11_H
#define MACRO11_H
/*
Copyright (c) 2001, Richard Krehbiel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
o Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
extern void *memcheck(void *p);
#endif

View File

@@ -0,0 +1,38 @@
CFLAGS = -O -g
MACRO11_SRCS = macro11.c mlb.c object.c stream2.c util.c rad50.c
MACRO11_OBJS = $(MACRO11_SRCS:.c=.o)
DUMPOBJ_SRCS = dumpobj.c rad50.c
DUMPOBJ_OBJS = $(DUMPOBJ_SRCS:.c=.o)
ALL_SRCS = $(MACRO11_SRCS) $(DUMPOBJ_SRCS)
all: macro11 dumpobj
tags: macro11 dumpobj
ctags *.c *.h
macro11: $(MACRO11_OBJS) makefile
$(CC) $(CFLAGS) -o macro11 $(MACRO11_OBJS) -lm
dumpobj: $(DUMPOBJ_OBJS) makefile
$(CC) $(CFLAGS) -o dumpobj $(DUMPOBJ_OBJS)
MACRO11_OBJS: makefile
DUMPOBJ_OBJS: makefile
clean:
-rm -f $(MACRO11_OBJS) $(DUMPOBJ_OBJS) macro11 dumpobj
macro11.o: macro11.c macro11.h rad50.h object.h stream2.h \
mlb.h util.h
mlb.o: mlb.c rad50.h stream2.h mlb.h macro11.h util.h
object.o: object.c rad50.h object.h
stream2.o: stream2.c macro11.h stream2.h
util.o: util.c util.h
rad50.o: rad50.c rad50.h
dumpobj.o: dumpobj.c rad50.h util.h
rad50.o: rad50.c rad50.h

View File

@@ -0,0 +1,319 @@
/* Routines for reading from an RT-11 macro library (like SYSMAC.SML) */
/*
Copyright (c) 2001, Richard Krehbiel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
o Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "rad50.h"
#include "stream2.h"
#include "mlb.h"
#include "macro11.h"
#include "util.h"
#define WORD(cp) ((*(cp) & 0xff) + ((*((cp)+1) & 0xff) << 8))
/* BYTEPOS calculates the byte position within the macro libray file.
I use this to sort the entries by their start position, in order to
be able to calculate the entries' sizes, which isn't actually
stored in the directory. */
#define BYTEPOS(rec) ((WORD((rec)+4) & 32767) * 512 + (WORD((rec)+6) & 511))
extern FILE *lstfile;
/* compare_position is the qsort callback function that compares byte
locations within the macro library */
static int compare_position(const void *arg1, const void *arg2)
{
const char *c1 = arg1, *c2 = arg2;
if(BYTEPOS(c1) < BYTEPOS(c2))
return -1;
if(BYTEPOS(c1) > BYTEPOS(c2))
return 1;
return 0;
}
/* trim removes trailing blanks from a string. */
static void trim(char *buf)
{
char *cp = buf + strlen(buf);
while(--cp >= buf && *cp == ' ')
*cp = 0;
}
/* mlb_open opens a file which is given to be a macro library. */
/* Returns NULL on failure. */
MLB *mlb_open(char *name)
{
MLB *mlb = memcheck(malloc(sizeof(MLB)));
char *buff;
unsigned entsize;
unsigned nr_entries;
unsigned start_block;
int i;
mlb->directory = NULL;
mlb->fp = fopen(name, "rb");
if(mlb->fp == NULL)
{
mlb_close(mlb);
return NULL;
}
buff = memcheck(malloc(044)); /* Size of MLB library header */
if(fread(buff, 1, 044, mlb->fp) < 044)
{
mlb_close(mlb);
free(buff);
return NULL;
}
if(WORD(buff) != 01001) /* Is this really a macro library? */
{
mlb_close(mlb); /* Nope. */
return NULL;
}
entsize = WORD(buff + 032); /* The size of each macro directory
entry */
nr_entries = WORD(buff + 036); /* The number of directory entries */
start_block = WORD(buff + 034); /* The start RT-11 block of the
directory */
free(buff); /* Done with that header. */
/* Allocate a buffer for the disk directory */
buff = memcheck(malloc(nr_entries * entsize));
fseek(mlb->fp, start_block * 512, SEEK_SET); /* Go to the directory */
/* Read the disk directory */
if(fread(buff, entsize, nr_entries, mlb->fp) < nr_entries)
{
mlb_close(mlb); /* Sorry, read error. */
free(buff);
return NULL;
}
/* Shift occupied directory entries to the front of the array
before sorting */
{
int j;
for(i = 0, j = nr_entries; i < j; i++)
{
char *ent1, *ent2;
ent1 = buff + (i * entsize);
/* Unused entries have 0177777 0177777 for the RAD50 name,
which is not legal RAD50. */
if(WORD(ent1) == 0177777 &&
WORD(ent1 + 2) == 0177777)
{
while(--j > i &&
(ent2 = buff + (j * entsize),
WORD(ent2) == 0177777 &&
WORD(ent2+2) == 0177777))
;
if(j <= i)
break; /* All done. */
memcpy(ent1, ent2, entsize); /* Move used entry
into unused entry's
space */
memset(ent2, 0377, entsize); /* Mark entry unused */
}
}
/* Now i contains the actual number of entries. */
mlb->nentries = i;
/* Sort the array by file position */
qsort(buff, i, entsize, compare_position);
/* Now, allocate my in-memory directory */
mlb->directory = memcheck(malloc(sizeof(MLBENT) * mlb->nentries));
memset(mlb->directory, 0, sizeof(MLBENT) * mlb->nentries);
/* Build in-memory directory */
for(j = 0; j < i; j++)
{
char radname[16];
char *ent;
ent = buff + (j * entsize);
unrad50(WORD(ent), radname);
unrad50(WORD(ent+2), radname+3);
radname[6] = 0;
trim(radname);
mlb->directory[j].label = memcheck(strdup(radname));
mlb->directory[j].position = BYTEPOS(ent);
if(j < i-1)
{
mlb->directory[j].length =
BYTEPOS(ent + entsize) - BYTEPOS(ent);
}
else
{
unsigned long max;
char c;
fseek(mlb->fp, 0, SEEK_END);
max = ftell(mlb->fp);
/* Look for last non-zero */
do
{
max--;
fseek(mlb->fp, max, SEEK_SET);
c = fgetc(mlb->fp);
} while(max > 0 && c == 0);
max++;
mlb->directory[j].length = max - BYTEPOS(ent);
}
}
free(buff);
}
/* Done. Return the struct that represents the opened MLB. */
return mlb;
}
/* mlb_close discards MLB and closes the file. */
void mlb_close(MLB *mlb)
{
if(mlb)
{
int i;
if(mlb->directory)
{
for(i = 0; i < mlb->nentries; i++)
{
if(mlb->directory[i].label)
free(mlb->directory[i].label);
}
free(mlb->directory);
}
if(mlb->fp)
fclose(mlb->fp);
free(mlb);
}
}
/* mlb_entry returns a BUFFER containing the specified entry from the
macro library, or NULL if not found. */
BUFFER *mlb_entry(MLB *mlb, char *name)
{
int i;
MLBENT *ent;
BUFFER *buf;
char *bp;
int c;
for(i = 0; i < mlb->nentries; i++)
{
ent = &mlb->directory[i];
if(strcmp(mlb->directory[i].label, name) == 0)
break;
}
if(i >= mlb->nentries)
return NULL;
/* Allocate a buffer to hold the text */
buf = new_buffer();
buffer_resize(buf, ent->length+1); /* Make it large enough */
bp = buf->buffer;
fseek(mlb->fp, ent->position, SEEK_SET);
for(i = 0; i < ent->length; i++)
{
c = fgetc(mlb->fp); /* Get macro byte */
if(c == '\r' || c == 0) /* If it's a carriage return or 0,
discard it. */
continue;
*bp++ = c;
}
*bp++ = 0; /* Store trailing 0 delim */
/* Now resize that buffer to the length actually read. */
buffer_resize(buf, bp - buf->buffer);
return buf;
}
/* mlb_extract - walk thru a macro library and store it's contents
into files in the current directory.
See, I had decided not to bother writing macro library maintenance
tools, since the user can call macros directly from the file
system. But if you've already got a macro library without the
sources, you can use this to extract the entries and maintain them
in the file system from thence forward.
*/
void mlb_extract(MLB *mlb)
{
int i;
FILE *fp;
BUFFER *buf;
for(i = 0; i < mlb->nentries; i++)
{
char name[32];
buf = mlb_entry(mlb, mlb->directory[i].label);
sprintf(name, "%s.MAC", mlb->directory[i].label);
fp = fopen(name, "w");
fwrite(buf->buffer, 1, buf->length, fp);
fclose(fp);
buffer_free(buf);
}
}

View File

@@ -0,0 +1,62 @@
#ifndef MLB_H
#define MLB_H
/*
Copyright (c) 2001, Richard Krehbiel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
o Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
#include "stream2.h"
/* Routines to open and read entries from a macro library */
typedef struct mlbent
{
char *label;
unsigned long position;
int length;
} MLBENT;
typedef struct mlb
{
FILE *fp;
MLBENT *directory;
int nentries;
} MLB;
extern MLB *mlb_open(char *name);
extern BUFFER *mlb_entry(MLB *mlb, char *name);
extern void mlb_close(MLB *mlb);
extern void mlb_extract(MLB *mlb);
#endif /* MLB_H */

View File

@@ -0,0 +1,861 @@
/*
object.c - writes RT-11 compatible .OBJ files.
Ref: RT-11 Software Support Manual, File Formats.
*/
/*
Copyright (c) 2001, Richard Krehbiel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
o Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "rad50.h"
#include "object.h"
#include "macro11.h"
/*
writerec writes "formatted binary records."
Each is preceeded by any number of 0 bytes, begins with a 1,0 pair,
followed by 2 byte length, followed by data, followed by 1 byte
negative checksum.
*/
static int writerec(FILE *fp, char *data, int len)
{
int chksum; /* Checksum is negative sum of all
bytes including header and length */
int i;
unsigned hdrlen = len + 4;
if(fp == NULL)
return 1; /* Silently ignore this attempt to write. */
chksum = 0;
if(fputc(FBR_LEAD1, fp) == EOF) /* All recs begin with 1,0 */
return 0;
chksum -= FBR_LEAD1;
if(fputc(FBR_LEAD2, fp) == EOF)
return 0;
chksum -= FBR_LEAD2;
i = hdrlen & 0xff; /* length, lsb */
chksum -= i;
if(fputc(i, fp) == EOF)
return 0;
i = (hdrlen >> 8) & 0xff; /* length, msb */
chksum -= i;
if(fputc(i, fp) == EOF)
return 0;
i = fwrite(data, 1, len, fp);
if(i < len)
return 0;
while(len > 0) /* All the data bytes */
{
chksum -= *data++ & 0xff;
len--;
}
chksum &= 0xff;
fputc(chksum, fp); /* Followed by the checksum byte */
return 1; /* Worked okay. */
}
/* gsd_init - prepare a GSD prior to writing GSD records */
void gsd_init(GSD *gsd, FILE *fp)
{
gsd->fp = fp;
gsd->buf[0] = OBJ_GSD; /* GSD records start with 1,0 */
gsd->buf[1] = 0;
gsd->offset = 2; /* Offset for further additions */
}
/* gsd_flush - write buffered GSD records */
int gsd_flush(GSD *gsd)
{
if(gsd->offset > 2)
{
if(!writerec(gsd->fp, gsd->buf, gsd->offset))
return 0;
gsd_init(gsd, gsd->fp);
}
return 1;
}
/* gsd_write - buffers a GSD record */
/* All GSD entries have the following 8 byte format: */
/* 4 bytes RAD50 name */
/* 1 byte flags */
/* 1 byte type */
/* 2 bytes value */
static int gsd_write(GSD *gsd, char *name, int flags,
int type, int value)
{
char *cp;
unsigned radtbl[2];
if(gsd->offset > sizeof(gsd->buf) - 8)
{
if(!gsd_flush(gsd))
return 0;
}
rad50x2(name, radtbl);
cp = gsd->buf + gsd->offset;
*cp++ = radtbl[0] & 0xff;
*cp++ = (radtbl[0] >> 8) & 0xff;
*cp++ = radtbl[1] & 0xff;
*cp++ = (radtbl[1] >> 8) & 0xff;
*cp++ = flags;
*cp++ = type;
*cp++ = value & 0xff;
*cp = (value >> 8) & 0xff;
gsd->offset += 8;
return 1;
}
/* gsd_mod - Write module name to GSD */
int gsd_mod(GSD *gsd, char *modname)
{
return gsd_write(gsd, modname, 0, GSD_MODNAME, 0);
}
/* gsd_csect - Write a control section name & size to the GSD */
int gsd_csect(GSD *gsd, char *sectname, int size)
{
return gsd_write(gsd, sectname, 0, GSD_CSECT, size);
}
/* gsd_intname - Write an internal symbol (ignored by RT-11 linker) */
int gsd_intname(GSD *gsd, char *name, unsigned value)
{
return gsd_write(gsd, name, 0, GSD_ISN, value);
}
/* gsd_xfer - Write a program transfer address to GSD */
int gsd_xfer(GSD *gsd, char *name, unsigned value)
{
return gsd_write(gsd, name, 010, GSD_XFER, value);
}
/* gsd_global - Write a global definition or reference to GSD */
/* Caller must be aware of the proper flags. */
int gsd_global(GSD *gsd, char *name, int flags, unsigned value)
{
return gsd_write(gsd, name, flags, GSD_GLOBAL, value);
}
/* Write a program section to the GSD */
/* Caller must be aware of the proper flags. */
int gsd_psect(GSD *gsd, char *name, int flags, int size)
{
return gsd_write(gsd, name, flags, GSD_PSECT, size);
}
/* Write program ident to GSD */
int gsd_ident(GSD *gsd, char *name)
{
return gsd_write(gsd, name, 0, GSD_IDENT, 0);
}
/* Write virtual array declaration to GSD */
int gsd_virt(GSD *gsd, char *name, int size)
{
return gsd_write(gsd, name, 0, GSD_VSECT, size);
}
/* Write ENDGSD record */
int gsd_end(GSD *gsd)
{
gsd->buf[0] = OBJ_ENDGSD;
gsd->buf[1] = 0;
return writerec(gsd->fp, gsd->buf, 2);
}
/* TEXT and RLD record handling */
/* TEXT records contain the plain binary of the program. An RLD
record refers to the prior TEXT record, giving relocation
information. */
/* text_init prepares a TEXT_RLD prior to writing */
void text_init(TEXT_RLD *tr, FILE *fp, unsigned addr)
{
tr->fp = fp;
tr->text[0] = OBJ_TEXT; /* text records begin with 3, 0 */
tr->text[1] = 0;
tr->text[2] = addr & 0xff; /* and are followed by load address */
tr->text[3] = (addr >> 8) & 0xff;
tr->txt_offset = 4; /* Here's where recording new text will begin */
tr->rld[0] = OBJ_RLD; /* RLD records begin with 4, 0 */
tr->rld[1] = 0;
tr->txt_addr = addr;
tr->rld_offset = 2; /* And are followed by RLD entries */
}
/* text_flush - flushes buffer TEXT and RLD records. */
int text_flush(TEXT_RLD *tr)
{
if(tr->txt_offset > 4)
{
if(!writerec(tr->fp, tr->text, tr->txt_offset))
return 0;
}
if(tr->rld_offset > 2)
{
if(!writerec(tr->fp, tr->rld, tr->rld_offset))
return 0;
}
return 1;
}
/* Used to ensure that TEXT and RLD information will be in adjacent
records. If not enough space exists in either buffer, both are
flushed. */
static int text_fit(TEXT_RLD *tr, unsigned addr,
int txtsize, int rldsize)
{
if(tr->txt_offset + txtsize <= sizeof(tr->text) &&
tr->rld_offset + rldsize <= sizeof(tr->rld) &&
(txtsize == 0 || tr->txt_addr + tr->txt_offset - 4 == addr))
return 1; /* All's well. */
if(!text_flush(tr))
return 0;
text_init(tr, tr->fp, addr);
return 1;
}
/* text_word_i - internal text_word. Used when buffer space is
already assured. */
static void text_word_i(TEXT_RLD *tr, unsigned w, int size)
{
tr->text[tr->txt_offset++] = w & 0xff;
if(size > 1)
tr->text[tr->txt_offset++] = (w >> 8) & 0xff;
}
/* text_word - write constant word to text */
int text_word(TEXT_RLD *tr, unsigned *addr, int size, unsigned word)
{
if(!text_fit(tr, *addr, size, 0))
return 0;
text_word_i(tr, word, size);
*addr += size; /* Update the caller's DOT */
return 1; /* say "ok". */
}
/* rld_word - adds a word to the RLD information. */
static void rld_word(TEXT_RLD *tr, unsigned wd)
{
tr->rld[tr->rld_offset++] = wd & 0xff;
tr->rld[tr->rld_offset++] = (wd >> 8) & 0xff;
}
/* rld_byte - adds a byte to rld information. */
static void rld_byte(TEXT_RLD *tr, unsigned byte)
{
tr->rld[tr->rld_offset++] = byte & 0xff;
}
/* rld_code - write the typical RLD first-word code. Encodes the
given address as the offset into the prior TEXT record. */
static void rld_code(TEXT_RLD *tr, unsigned code, unsigned addr, int size)
{
unsigned offset = addr - tr->txt_addr + 4;
rld_word(tr, code | offset << 8 | (size == 1 ? 0200 : 0));
}
/* rld_code_naddr - typical RLD entries refer to a text address. This
one is used when the RLD code does not. */
static void rld_code_naddr(TEXT_RLD *tr, unsigned code, int size)
{
rld_word(tr, code | (size == 1 ? 0200 : 0));
}
/* write a word with a psect-relative value */
int text_internal_word(TEXT_RLD *tr, unsigned *addr,
int size, unsigned word)
{
if(!text_fit(tr, *addr, size, 4))
return 0;
text_word_i(tr, word, size);
rld_code(tr, RLD_INT, *addr, size);
rld_word(tr, word);
*addr += size;
return 1;
}
/* write a word which is an absolute reference to a global symbol */
int text_global_word(TEXT_RLD *tr, unsigned *addr,
int size, unsigned word, char *global)
{
unsigned radtbl[2];
if(!text_fit(tr, *addr, size, 6))
return 0;
text_word_i(tr, word, size);
rld_code(tr, RLD_GLOBAL, *addr, size);
rad50x2(global, radtbl);
rld_word(tr, radtbl[0]);
rld_word(tr, radtbl[1]);
*addr += size;
return 1;
}
/* Write a word which is a PC-relative reference to an absolute address */
int text_displaced_word(TEXT_RLD *tr,
unsigned *addr, int size, unsigned word)
{
if(!text_fit(tr, *addr, size, 4))
return 0;
text_word_i(tr, word, size);
rld_code(tr, RLD_INT_DISP, *addr, size);
rld_word(tr, word);
*addr += size;
return 1;
}
/* write a word which is a PC-relative reference to a global symbol */
int text_global_displaced_word(TEXT_RLD *tr,
unsigned *addr, int size,
unsigned word, char *global)
{
unsigned radtbl[2];
if(!text_fit(tr, *addr, size, 6))
return 0;
text_word_i(tr, word, size);
rld_code(tr, RLD_GLOBAL_DISP, *addr, size);
rad50x2(global, radtbl);
rld_word(tr, radtbl[0]);
rld_word(tr, radtbl[1]);
*addr += size;
return 1;
}
/* write a word which is an absolute reference to a global symbol plus
an offset */
/* Optimizes to text_global_word when the offset is zero. */
int text_global_offset_word(TEXT_RLD *tr,
unsigned *addr, int size,
unsigned word, char *global)
{
unsigned radtbl[2];
if(word == 0)
return text_global_word(tr, addr, size, word, global);
if(!text_fit(tr, *addr, size, 8))
return 0;
text_word_i(tr, word, size);
rld_code(tr, RLD_GLOBAL_OFFSET, *addr, size);
rad50x2(global, radtbl);
rld_word(tr, radtbl[0]);
rld_word(tr, radtbl[1]);
rld_word(tr, word);
*addr += size;
return 1;
}
/* write a word which is a PC-relative reference to a global symbol
plus an offset */
/* Optimizes to text_global_displaced_word when the offset is zero. */
int text_global_displaced_offset_word(TEXT_RLD *tr,
unsigned *addr, int size,
unsigned word, char *global)
{
unsigned radtbl[2];
if(word == 0)
return text_global_displaced_word(tr, addr, size, word, global);
if(!text_fit(tr, *addr, size, 8))
return 0;
text_word_i(tr, word, size);
rld_code(tr, RLD_GLOBAL_OFFSET_DISP, *addr, size);
rad50x2(global, radtbl);
rld_word(tr, radtbl[0]);
rld_word(tr, radtbl[1]);
rld_word(tr, word);
*addr += size;
return 1;
}
/* Define current program counter, plus PSECT */
/* Different because it must be the last RLD entry in a block. That's
because TEXT records themselves contain the current text
address. */
int text_define_location(TEXT_RLD *tr, char *name, unsigned *addr)
{
unsigned radtbl[2];
if(!text_fit(tr, *addr, 0, 8)) /* No text space used */
return 0;
rld_code_naddr(tr, RLD_LOCDEF, 2); /* RLD code for "location
counter def" with no offset */
rad50x2(name, radtbl);
rld_word(tr, radtbl[0]); /* Set current section name */
rld_word(tr, radtbl[1]);
rld_word(tr, *addr); /* Set current location addr */
if(!text_flush(tr)) /* Flush that block out. */
return 0;
text_init(tr, tr->fp, *addr); /* Set new text address */
return 1;
}
/* Modify current program counter, assuming current PSECT */
/* Location counter modification is similarly weird */
/* (I wonder - why is this RLD code even here? TEXT records contain
thair own start address.) */
int text_modify_location(TEXT_RLD *tr, unsigned *addr)
{
if(!text_fit(tr, *addr, 0, 4)) /* No text space used */
return 0;
rld_code_naddr(tr, RLD_LOCMOD, 2); /* RLD code for "location
counter mod" with no offset */
rld_word(tr, *addr); /* Set current location addr */
if(!text_flush(tr)) /* Flush that block out. */
return 0;
text_init(tr, tr->fp, *addr); /* Set new text address */
return 1;
}
/* write two words containing program limits (the .LIMIT directive) */
int text_limits(TEXT_RLD *tr, unsigned *addr)
{
if(!text_fit(tr, *addr, 4, 2))
return 0;
text_word_i(tr, 0, 2);
text_word_i(tr, 0, 2);
rld_code(tr, RLD_LIMITS, *addr, 2);
*addr += 4;
return 1;
}
/* write a word which is the start address of a different PSECT */
int text_psect_word(TEXT_RLD *tr,
unsigned *addr, int size,
unsigned word, char *name)
{
unsigned radtbl[2];
if(!text_fit(tr, *addr, size, 6))
return 0;
text_word_i(tr, word, size);
rld_code(tr, RLD_PSECT, *addr, size);
rad50x2(name, radtbl);
rld_word(tr, radtbl[0]);
rld_word(tr, radtbl[1]);
*addr += size;
return 1;
}
/* write a word which is an offset from the start of a different PSECT */
/* Optimizes to text_psect_word when offset is zero */
int text_psect_offset_word(TEXT_RLD *tr,
unsigned *addr, int size,
unsigned word, char *name)
{
unsigned radtbl[2];
if(word == 0)
return text_psect_word(tr, addr, size, word, name);
if(!text_fit(tr, *addr, size, 8))
return 0;
text_word_i(tr, word, size);
rld_code(tr, RLD_PSECT_OFFSET, *addr, size);
rad50x2(name, radtbl);
rld_word(tr, radtbl[0]);
rld_word(tr, radtbl[1]);
rld_word(tr, word);
*addr += size;
return 1;
}
/* write a word which is the address of a different PSECT, PC-relative */
int text_psect_displaced_word(TEXT_RLD *tr, unsigned *addr,
int size, unsigned word, char *name)
{
unsigned radtbl[2];
if(!text_fit(tr, *addr, size, 6))
return 0;
text_word_i(tr, word, size);
rld_code(tr, RLD_PSECT_DISP, *addr, size);
rad50x2(name, radtbl);
rld_word(tr, radtbl[0]);
rld_word(tr, radtbl[1]);
*addr += size;
return 1;
}
/* write a word which is an offset from the address of a different
PSECT, PC-relative */
/* Optimizes to text_psect_displaced_word when offset is zero */
int text_psect_displaced_offset_word(TEXT_RLD *tr,
unsigned *addr, int size,
unsigned word, char *name)
{
unsigned radtbl[2];
if(word == 0)
return text_psect_displaced_word(tr, addr, size, word, name);
if(!text_fit(tr, *addr, size, 8))
return 0;
text_word_i(tr, word, size);
rld_code(tr, RLD_PSECT_OFFSET_DISP, *addr, size);
rad50x2(name, radtbl);
rld_word(tr, radtbl[0]);
rld_word(tr, radtbl[1]);
rld_word(tr, word);
*addr += size;
return 1;
}
/* complex relocation! */
/* A complex relocation expression is where a piece of code is fed to
the linker asking it to do some math for you, and store the result
in a program word. The code is a stack-based language. */
/* complex_begin initializes a TEXT_COMPLEX */
void text_complex_begin(TEXT_COMPLEX *tx)
{
tx->len = 0;
}
/* text_complex_fit checks if a complex expression will fit and
returns a pointer to it's location */
static char *text_complex_fit(TEXT_COMPLEX *tx, int size)
{
int len;
if(tx->len + size > sizeof(tx->accum))
return NULL; /* Expression has grown too complex. */
len = tx->len;
tx->len += size;
return tx->accum + len;
}
/* text_complex_byte stores a single byte. */
static int text_complex_byte(TEXT_COMPLEX *tx, unsigned byte)
{
char *cp = text_complex_fit(tx, 1);
if(!cp)
return 0;
*cp = byte;
return 1;
}
/* text_complex_add - add top two stack elements */
int text_complex_add(TEXT_COMPLEX *tx)
{
return text_complex_byte(tx, CPLX_ADD);
}
/* text_complex_sub - subtract top two stack elements. */
/* You know, I think these function labels are self-explanatory... */
int text_complex_sub(TEXT_COMPLEX *tx)
{
return text_complex_byte(tx, CPLX_SUB);
}
int text_complex_mul(TEXT_COMPLEX *tx)
{
return text_complex_byte(tx, CPLX_MUL);
}
int text_complex_div(TEXT_COMPLEX *tx)
{
return text_complex_byte(tx, CPLX_DIV);
}
int text_complex_and(TEXT_COMPLEX *tx)
{
return text_complex_byte(tx, CPLX_AND);
}
int text_complex_or(TEXT_COMPLEX *tx)
{
return text_complex_byte(tx, CPLX_OR);
}
int text_complex_xor(TEXT_COMPLEX *tx)
{
return text_complex_byte(tx, CPLX_XOR);
}
int text_complex_com(TEXT_COMPLEX *tx)
{
return text_complex_byte(tx, CPLX_COM);
}
int text_complex_neg(TEXT_COMPLEX *tx)
{
return text_complex_byte(tx, CPLX_NEG);
}
/* text_complex_lit pushes a literal value to the stack. */
int text_complex_lit(TEXT_COMPLEX *tx, unsigned word)
{
char *cp = text_complex_fit(tx, 3);
if(!cp)
return 0;
*cp++ = CPLX_CONST;
*cp++ = word & 0xff;
*cp = (word >> 8) & 0xff;
return 1;
}
/* text_complex_global pushes the value of a global variable to the
stack */
int text_complex_global(TEXT_COMPLEX *tx, char *name)
{
unsigned radtbl[2];
char *cp = text_complex_fit(tx, 5);
if(!cp)
return 0;
rad50x2(name, radtbl);
*cp++ = CPLX_GLOBAL;
*cp++ = radtbl[0] & 0xff;
*cp++ = (radtbl[0] >> 8) & 0xff;
*cp++ = radtbl[1] & 0xff;
*cp = (radtbl[1] >> 8) & 0xff;
return 1;
}
/* text_complex_psect pushes the value of an offset into a PSECT to
the stack. */
/* What was not documented in the Software Support manual is that
PSECT "sect" numbers are assigned in the order they appear in the
source program, and the order they appear in the GSD. i.e. the
first PSECT GSD is assigned sector 0 (which is always the default
absolute section so that's a bad example), the next sector 1,
etc. */
int text_complex_psect(TEXT_COMPLEX *tx, unsigned sect, unsigned offset)
{
char *cp = text_complex_fit(tx, 4);
if(!cp)
return 0;
*cp++ = CPLX_REL;
*cp++ = sect & 0xff;
*cp++ = offset & 0xff;
*cp = (offset >> 8) & 0xff;
return 1;
}
/* text_complex_commit - store the result of the complex expression
and end the RLD code. */
int text_complex_commit(TEXT_RLD *tr, unsigned *addr,
int size, TEXT_COMPLEX *tx, unsigned word)
{
int i;
text_complex_byte(tx, CPLX_STORE);
if(!text_fit(tr, *addr, size, tx->len + 2))
return 0;
rld_code(tr, RLD_COMPLEX, *addr, size);
for(i = 0; i < tx->len; i++)
rld_byte(tr, tx->accum[i]);
text_word_i(tr, word, size);
*addr += size;
return 1;
}
/* text_complex_commit_displaced - store the result of the complex
expression, relative to the current PC, and end the RLD code */
int text_complex_commit_displaced(TEXT_RLD *tr,
unsigned *addr, int size,
TEXT_COMPLEX *tx, unsigned word)
{
int i;
text_complex_byte(tx, CPLX_STORE_DISP);
if(!text_fit(tr, *addr, size, tx->len + 2))
return 0;
rld_code(tr, RLD_COMPLEX, *addr, size);
for(i = 0; i < tx->len; i++)
rld_byte(tr, tx->accum[i]);
text_word_i(tr, word, size);
*addr += size;
return 1;
}
/* Write end-of-object-module to file. */
int write_endmod(FILE *fp)
{
char endmod[2] = { OBJ_ENDMOD, 0 };
return writerec(fp, endmod, 2);
}

View File

@@ -0,0 +1,210 @@
#ifndef OBJECT_H
#define OBJECT_H
/* Object file constant definitions */
/*
Copyright (c) 2001, Richard Krehbiel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
o Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
#define FBR_LEAD1 1 /* The byte value that defines the
beginning of a formatted binary
record */
#define FBR_LEAD2 0 /* Followed by a 0 */
/* Followed by two bytes length */
/* Followed by (length-4) bytes data */
/* Followed by a 1 byte checksum */
/* which is the negative sum of all
preceeding bytes */
#define OBJ_GSD 01 /* GSD (Global symbol directory) */
#define OBJ_ENDGSD 02 /* ENDGSD */
#define OBJ_TEXT 03 /* TEXT */
#define OBJ_RLD 04 /* RLD (Relocation directory) */
#define OBJ_ISD 05 /* ISD (Internal symbol directory,
currently unused) */
#define OBJ_ENDMOD 06 /* ENDMOD (End of object module) */
#define OBJ_LIBHDR 07 /* LIBHDR (Object Library header) */
#define OBJ_LIBEND 010 /* LIBEND (Object Library header end) */
#define GSD_MODNAME 00 /* Module name */
#define GSD_CSECT 01 /* Control section name */
#define GSD_ISN 02 /* Internal symbol name */
#define GSD_XFER 03 /* Transfer address */
#define GSD_GLOBAL 04 /* Global symbol definition/reference */
#define GSD_PSECT 05 /* PSECT name */
#define GSD_IDENT 06 /* IDENT */
#define GSD_VSECT 07 /* VSECT (Virtual array declaration) */
#define GLOBAL_WEAK 01 /* GLOBAL is weak, else strong */
#define GLOBAL_DEF 010 /* GLOBAL is definition, else reference */
#define GLOBAL_REL 040 /* GLOBAL is relative, else absolute */
#define PSECT_SAV 001 /* PSECT is a root section, else overlay */
#define PSECT_COM 004 /* PSECT is merged common area, else
contatenated */
#define PSECT_RO 020 /* PSECT is read-only, else R/W */
#define PSECT_REL 040 /* PSECT is relative, else absolute
(absolute implies PSECT_COM) */
#define PSECT_GBL 0100 /* PSECT is overlay-global, else
overlay-local */
#define PSECT_DATA 0200 /* PSECT contains data, else instructions */
#define RLD_INT 01 /* "Internal relocation" */
#define RLD_GLOBAL 02 /* "Global relocation" */
#define RLD_INT_DISP 03 /* "Internal displaced" */
#define RLD_GLOBAL_DISP 04 /* "Global displaced" */
#define RLD_GLOBAL_OFFSET 05 /* "Global additive" */
#define RLD_GLOBAL_OFFSET_DISP 06 /* "Global additive displaced" */
#define RLD_LOCDEF 07 /* "Location counter definition" */
#define RLD_LOCMOD 010 /* "Location counter modification" */
#define RLD_LIMITS 011 /* ".LIMIT" */
#define RLD_PSECT 012 /* "P-sect" */
#define RLD_PSECT_DISP 014 /* "P-sect displaced" */
#define RLD_PSECT_OFFSET 015 /* "P-sect additive" */
#define RLD_PSECT_OFFSET_DISP 016 /* "P-sect additive displaced" */
#define RLD_COMPLEX 017 /* "Complex" */
#define RLD_BYTE 0200 /* RLD modifies a byte, else a word */
/* Note: complex relocation is not well documented (in particular, no effort
is made to define a section's "sector number"), but I'll just guess
it's a stack language. */
#define CPLX_NOP 00 /* NOP - used for padding */
#define CPLX_ADD 01
#define CPLX_SUB 02
#define CPLX_MUL 03
#define CPLX_DIV 04
#define CPLX_AND 05
#define CPLX_OR 06
#define CPLX_XOR 07
#define CPLX_NEG 010
#define CPLX_COM 011
#define CPLX_STORE 012 /* Store result, terminate complex string. */
#define CPLX_STORE_DISP 013 /* Store result PC-relative, terminate */
#define CPLX_GLOBAL 016 /* Followed by four bytes RAD50 global name */
#define CPLX_REL 017 /* Followed by one byte "sector
number" and two bytes offset */
#define CPLX_CONST 020 /* Followed by two bytes constant value */
typedef struct gsd
{
FILE *fp; /* The file assigned for output */
char buf[122]; /* space for 15 GSD entries */
int offset; /* Current buffer for GSD entries */
} GSD;
void gsd_init(GSD *gsd, FILE *fp);
int gsd_flush(GSD *gsd);
int gsd_mod(GSD *gsd, char *modname);
int gsd_csect(GSD *gsd, char *sectname, int size);
int gsd_intname(GSD *gsd, char *name, unsigned value);
int gsd_xfer(GSD *gsd, char *name, unsigned value);
int gsd_global(GSD *gsd, char *name, int flags, unsigned value);
int gsd_psect(GSD *gsd, char *name, int flags, int size);
int gsd_ident(GSD *gsd, char *name);
int gsd_virt(GSD *gsd, char *name, int size);
int gsd_end(GSD *gsd);
typedef struct text_rld
{
FILE *fp; /* The object file, or NULL */
char text[128]; /* text buffer */
unsigned txt_addr; /* The base text address */
int txt_offset; /* Current text offset */
char rld[128]; /* RLD buffer */
int rld_offset; /* Current RLD offset */
} TEXT_RLD;
void text_init(TEXT_RLD *tr, FILE *fp, unsigned addr);
int text_flush(TEXT_RLD *tr);
int text_word(TEXT_RLD *tr, unsigned *addr, int size, unsigned word);
int text_internal_word(TEXT_RLD *tr, unsigned *addr, int size,
unsigned word);
int text_global_word(TEXT_RLD *tr, unsigned *addr, int size,
unsigned word, char *global);
int text_displaced_word(TEXT_RLD *tr, unsigned *addr, int size,
unsigned word);
int text_global_displaced_word(TEXT_RLD *tr, unsigned *addr, int size,
unsigned word, char *global);
int text_global_offset_word(TEXT_RLD *tr, unsigned *addr, int size,
unsigned word, char *global);
int text_global_displaced_offset_word(TEXT_RLD *tr, unsigned *addr,
int size, unsigned word,
char *global);
int text_define_location(TEXT_RLD *tr, char *name,
unsigned *addr);
int text_modify_location(TEXT_RLD *tr, unsigned *addr);
int text_limits(TEXT_RLD *tr, unsigned *addr);
int text_psect_word(TEXT_RLD *tr, unsigned *addr, int size,
unsigned word, char *name);
int text_psect_offset_word(TEXT_RLD *tr, unsigned *addr,
int size, unsigned word, char *name);
int text_psect_displaced_word(TEXT_RLD *tr, unsigned *addr,
int size, unsigned word, char *name);
int text_psect_displaced_offset_word(TEXT_RLD *tr, unsigned *addr,
int size, unsigned word,
char *name);
typedef struct text_complex
{
char accum[126];
int len;
} TEXT_COMPLEX;
void text_complex_begin(TEXT_COMPLEX *tx);
int text_complex_add(TEXT_COMPLEX *tx);
int text_complex_sub(TEXT_COMPLEX *tx);
int text_complex_mul(TEXT_COMPLEX *tx);
int text_complex_div(TEXT_COMPLEX *tx);
int text_complex_and(TEXT_COMPLEX *tx);
int text_complex_or(TEXT_COMPLEX *tx);
int text_complex_xor(TEXT_COMPLEX *tx);
int text_complex_com(TEXT_COMPLEX *tx);
int text_complex_neg(TEXT_COMPLEX *tx);
int text_complex_lit(TEXT_COMPLEX *tx, unsigned word);
int text_complex_global(TEXT_COMPLEX *tx, char *name);
int text_complex_psect(TEXT_COMPLEX *tx, unsigned sect,
unsigned offset);
int text_complex_commit(TEXT_RLD *tr, unsigned *addr,
int size, TEXT_COMPLEX *tx,
unsigned word);
int text_complex_commit_displaced(TEXT_RLD *tr, unsigned *addr,
int size, TEXT_COMPLEX *tx,
unsigned word);
int write_endmod(FILE *fp);
#endif /* OBJECT_J */

View File

@@ -0,0 +1,117 @@
/* Functions to convert RAD50 to or from ASCII. */
/*
Copyright (c) 2001, Richard Krehbiel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
o Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "rad50.h"
static char radtbl[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$. 0123456789";
/* rad50 converts from 0 to 3 ASCII (or EBCDIC, if your compiler is so
inclined) characters into a RAD50 word. */
unsigned rad50(char *cp, char **endp)
{
unsigned long acc = 0;
char *rp;
if(endp)
*endp = cp;
if(!*cp) /* Got to check for end-of-string
manually, because strchr will call
it a hit. :-/ */
return acc;
rp = strchr(radtbl, toupper(*cp));
if(rp == NULL) /* Not a RAD50 character */
return acc;
acc = (rp - radtbl) * 03100; /* Convert */
cp++;
/* Now, do the same thing two more times... */
if(endp)
*endp = cp;
if(!*cp)
return acc;
rp = strchr(radtbl, toupper(*cp));
if(rp == NULL)
return acc;
acc += (rp - radtbl) * 050;
cp++;
if(endp)
*endp = cp;
if(!*cp)
return acc;
rp = strchr(radtbl, toupper(*cp));
if(rp == NULL)
return acc;
acc += (rp - radtbl);
cp++;
if(endp)
*endp = cp;
return acc; /* Done. */
}
/* rad50x2 - converts from 0 to 6 characters into two words of RAD50. */
void rad50x2(char *cp, unsigned *rp)
{
*rp++ = rad50(cp, &cp);
*rp = 0;
if(*cp)
*rp = rad50(cp, &cp);
}
/* unrad50 - converts a RAD50 word to three characters of ASCII. */
void unrad50(unsigned word, char *cp)
{
if(word < 0175000) /* Is it legal RAD50? */
{
cp[0] = radtbl[word / 03100];
cp[1] = radtbl[(word / 050) % 050];
cp[2] = radtbl[word % 050];
}
else
cp[0] = cp[1] = cp[2] = ' ';
}

View File

@@ -0,0 +1,43 @@
#ifndef RAD50_H
#define RAD50_H
/*
Copyright (c) 2001, Richard Krehbiel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
o Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
extern unsigned rad50(char *cp, char **endp);
extern void rad50x2(char *cp, unsigned *rp);
extern void unrad50(unsigned word, char *cp);
#endif /* RAD50_H */

View File

@@ -0,0 +1,380 @@
/* functions for managing a stack of file and buffer input streams. */
/*
Copyright (c) 2001, Richard Krehbiel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
o Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include "macro11.h"
#include "stream2.h"
/* BUFFER functions */
/* new_buffer allocates a new buffer */
BUFFER *new_buffer(void)
{
BUFFER *buf = memcheck(malloc(sizeof(BUFFER)));
buf->length = 0;
buf->size = 0;
buf->use = 1;
buf->buffer = NULL;
return buf;
}
/* buffer_resize makes the buffer at least the requested size. */
/* If the buffer is already larger, then it will attempt */
/* to shrink it. */
void buffer_resize(BUFFER *buff, int size)
{
buff->size = size;
buff->length = size;
if(size == 0)
{
free(buff->buffer);
buff->buffer = NULL;
}
else
{
if(buff->buffer == NULL)
buff->buffer = memcheck(malloc(buff->size));
else
buff->buffer = memcheck(realloc(buff->buffer, buff->size));
}
}
/* buffer_clone makes a copy of a buffer */
/* Basically it increases the use count */
BUFFER *buffer_clone(BUFFER *from)
{
if(from)
from->use++;
return from;
}
/* buffer_free frees a buffer */
/* It decreases the use count, and if zero, */
/* frees the memory. */
void buffer_free(BUFFER *buf)
{
if(buf)
{
if(--(buf->use) == 0)
{
free(buf->buffer);
free(buf);
}
}
}
/* Append characters to the buffer. */
void buffer_appendn(BUFFER *buf, char *str, int len)
{
int needed = buf->length + len + 1;
if(needed >= buf->size)
{
buf->size = needed + GROWBUF_INCR;
if(buf->buffer == NULL)
buf->buffer = memcheck(malloc(buf->size));
else
buf->buffer = memcheck(realloc(buf->buffer, buf->size));
}
memcpy(buf->buffer + buf->length, str, len);
buf->length += len;
buf->buffer[buf->length] = 0;
}
/* append a text line (zero or newline-delimited) */
void buffer_append_line(BUFFER *buf, char *str)
{
char *nl;
if((nl = strchr(str, '\n')) != NULL)
buffer_appendn(buf, str, nl - str + 1);
else
buffer_appendn(buf, str, strlen(str));
}
/* Base STREAM class methods */
/* stream_construct initializes a newly allocated STREAM */
void stream_construct(STREAM *str, char *name)
{
str->line = 0;
str->name = memcheck(strdup(name));
str->next = NULL;
str->vtbl = NULL;
}
/* stream_delete destroys and deletes (frees) a STREAM */
void stream_delete(STREAM *str)
{
free(str->name);
free(str);
}
/* *** class BUFFER_STREAM implementation */
/* STREAM::gets for a buffer stream */
char *buffer_stream_gets(STREAM *str)
{
char *nl;
char *cp;
BUFFER_STREAM *bstr = (BUFFER_STREAM *)str;
BUFFER *buf = bstr->buffer;
if(buf == NULL)
return NULL; /* No buffer */
if(bstr->offset >= buf->length)
return NULL;
cp = buf->buffer + bstr->offset;
/* Find the next line in preparation for the next call */
nl = memchr(cp, '\n', buf->length - bstr->offset);
if(nl)
nl++;
bstr->offset = nl - buf->buffer;
str->line++;
return cp;
}
/* STREAM::close for a buffer stream */
void buffer_stream_delete(STREAM *str)
{
BUFFER_STREAM *bstr = (BUFFER_STREAM *)str;
buffer_free(bstr->buffer);
stream_delete(str);
}
/* STREAM::rewind for a buffer stream */
void buffer_stream_rewind(STREAM *str)
{
BUFFER_STREAM *bstr = (BUFFER_STREAM *)str;
bstr->offset = 0;
str->line = 0;
}
/* BUFFER_STREAM vtbl */
STREAM_VTBL buffer_stream_vtbl = { buffer_stream_delete,
buffer_stream_gets,
buffer_stream_rewind };
void buffer_stream_construct(BUFFER_STREAM *bstr, BUFFER *buf, char *name)
{
bstr->stream.vtbl = &buffer_stream_vtbl;
bstr->stream.name = memcheck(strdup(name));
bstr->buffer = buffer_clone(buf);
bstr->offset = 0;
bstr->stream.line = 0;
}
void buffer_stream_set_buffer(BUFFER_STREAM *bstr, BUFFER *buf)
{
if(bstr->buffer)
buffer_free(bstr->buffer);
bstr->buffer = buffer_clone(buf);
bstr->offset = 0;
}
/* new_buffer_stream clones the given buffer, gives it the name, */
/* and creates a BUFFER_STREAM to reference it */
STREAM *new_buffer_stream(BUFFER *buf, char *name)
{
BUFFER_STREAM *bstr = memcheck(malloc(sizeof(BUFFER_STREAM)));
buffer_stream_construct(bstr, buf, name);
return &bstr->stream;
}
/* *** FILE_STREAM implementation */
/* Implement STREAM::gets for a file stream */
static char *file_gets(STREAM *str)
{
int i, c;
FILE_STREAM *fstr = (FILE_STREAM *)str;
if(fstr->fp == NULL)
return NULL;
if(feof(fstr->fp))
return NULL;
/* Read single characters, end of line when '\n' or '\f' hit */
i = 0;
while(c = fgetc(fstr->fp),
c != '\n' && c != '\f' && c != EOF)
{
if(c == 0)
continue; /* Don't buffer zeros */
if(c == '\r')
continue; /* Don't buffer carriage returns either */
if(i < STREAM_BUFFER_SIZE - 2)
fstr->buffer[i++] = c;
}
fstr->buffer[i++] = '\n'; /* Silently transform formfeeds
into newlines */
fstr->buffer[i] = 0;
if(c == '\n')
fstr->stream.line++; /* Count a line */
return fstr->buffer;
}
/* Implement STREAM::destroy for a file stream */
void file_destroy(STREAM *str)
{
FILE_STREAM *fstr = (FILE_STREAM *)str;
fclose(fstr->fp);
free(fstr->buffer);
stream_delete(str);
}
/* Implement STREAM::rewind for a file stream */
void file_rewind(STREAM *str)
{
FILE_STREAM *fstr = (FILE_STREAM *)str;
rewind(fstr->fp);
str->line = 0;
}
static STREAM_VTBL file_stream_vtbl = { file_destroy, file_gets,
file_rewind };
/* Prepare and open a stream from a file. */
STREAM *new_file_stream(char *filename)
{
FILE *fp;
FILE_STREAM *str;
fp = fopen(filename, "r");
if(fp == NULL)
return NULL;
str = memcheck(malloc(sizeof(FILE_STREAM)));
str->stream.vtbl = &file_stream_vtbl;
str->stream.name = memcheck(strdup(filename));
str->buffer = memcheck(malloc(STREAM_BUFFER_SIZE));
str->fp = fp;
str->stream.line = 0;
return &str->stream;
}
/* STACK functions */
/* stack_init prepares a stack */
void stack_init(STACK *stack)
{
stack->top = NULL; /* Too simple */
}
/* stack_pop removes and deletes the topmost STRAM on the stack */
void stack_pop(STACK *stack)
{
STREAM *top = stack->top;
STREAM *next = top->next;
top->vtbl->delete(top);
stack->top = next;
}
/* stack_push pushes a STREAM onto the top of the stack */
void stack_push(STACK *stack, STREAM *str)
{
str->next = stack->top;
stack->top = str;
}
/* stack_gets calls vtbl->gets for the topmost stack entry. When
topmost streams indicate they're exhausted, they are popped and
deleted, until the stack is exhausted. */
char *stack_gets(STACK *stack)
{
char *line;
if(stack->top == NULL)
return NULL;
while((line = stack->top->vtbl->gets(stack->top)) == NULL)
{
stack_pop(stack);
if(stack->top == NULL)
return NULL;
}
return line;
}

View File

@@ -0,0 +1,110 @@
#ifndef STREAM2_H
#define STREAM2_H
/*
Copyright (c) 2001, Richard Krehbiel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
o Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
struct stream;
typedef struct stream_vtbl
{
void (*delete)(struct stream *stream); // Destructor
char *(*gets)(struct stream *stream); // "gets" function
void (*rewind)(struct stream *stream); // "rewind" function
} STREAM_VTBL;
typedef struct stream
{
STREAM_VTBL *vtbl; // Pointer to dispatch table
char *name; // Stream name
int line; // Current line number in stream
struct stream *next; // Next stream in stack
} STREAM;
typedef struct file_stream
{
STREAM stream; // Base class
FILE *fp; // File pointer
char *buffer; // Line buffer
} FILE_STREAM;
typedef struct buffer
{
char *buffer; // Pointer to text
int size; // Size of buffer
int length; // Occupied size of buffer
int use; // Number of users of buffer
} BUFFER;
#define GROWBUF_INCR 1024 // Buffers grow by leaps and bounds
typedef struct buffer_stream
{
STREAM stream; // Base class
BUFFER *buffer; // text buffer
int offset; // Current read offset
} BUFFER_STREAM;
typedef struct stack
{
STREAM *top; // Top of stacked stream pieces
} STACK;
#define STREAM_BUFFER_SIZE 1024 // This limits the max size of an input line.
BUFFER *new_buffer(void);
BUFFER *buffer_clone(BUFFER *from);
void buffer_resize(BUFFER *buff, int size);
void buffer_free(BUFFER *buf);
void buffer_appendn(BUFFER *buf, char *str, int len);
void buffer_append_line(BUFFER *buf, char *str);
STREAM *new_buffer_stream(BUFFER *buf, char *name);
void buffer_stream_set_buffer(BUFFER_STREAM *bstr, BUFFER *buf);
/* Provide these so that macro11 can derive from a BUFFER_STREAM */
extern STREAM_VTBL buffer_stream_vtbl;
void buffer_stream_construct(BUFFER_STREAM *bstr, BUFFER *buf, char *name);
char *buffer_stream_gets(STREAM *str);
void buffer_stream_delete(STREAM *str);
void buffer_stream_rewind(STREAM *str);
STREAM *new_file_stream(char *filename);
void stack_init(STACK *stack);
void stack_push(STACK *stack, STREAM *str);
void stack_pop(STACK *stack);
char *stack_gets(STACK *stack);
#endif /* STREAM2_H */

View File

@@ -0,0 +1,57 @@
I was not able to locate a Macro-11 language reference manual any more
recent than for RT11 version *3*, so I used that plus my recollection
of more modern features. It was enough to get the RT11 V5.4 kernel
built, plus a significant chunk of our own code.
The biggest missing feature is full featured listings. The .LIST and
.NLIST directives are ignored, as is .SBTTL. No table of contents is
accumulated or printed. No symbol cross referencing is done (most
likely I'll just write a CTAGS file, not a cross reference listing).
Many errors still go unchecked. Off the top of my head, I recall that
object and listing file output errors are ignored.
.FLT4 format may be inaccurate in the low bits. This is because IEEE
64 bit format has two fewer mantissa bits than 64 bit PDP-11 format.
Without writing soft-float routines, there's not much I can do abbout
it.
Expression math is done in native width, almost certainly 32 bits.
Truncation to 16 bits is done only for listing and output. This may
make some output differ in the presence of 16-bit overflows and
underflows. I don't think this needs fixing.
.REM blocks containing code can screw up .MACRO, .REPT, .IRP, .IRPC.
read_body in macro11.c would need to be able to parse and ignore .REM
blocks.
Need to search a path for the .INCLUDE directive. Right now it only
takes a complete file name. And most likely, existing code will have
RT-11 style file names; I don't know what to do about that, except put
in a device name parser.
Possible enhancements:
It would be very simple to make macro11 resolve internal symbols with
more that 6 significant characters. Even so, only the first 6 would
be used for external symbols, and you have to be wary of existing code
that used (for example) .LOOKU rather than .LOOKUP, since these two
would become distinct.
SYM = 0
MOV SYM(R0),R0 ; macro11 could optimize SYM(R0) into just (R0)
I dream of automatically fixing branches out of range. Easy when the
destination is backwards, difficult when it's forwards. I have this
idea: during the first assembly pass, all branches generate a long
branch if the target symbol is undefined, otherwise an "optimized"
branch (short or long) if the target is defined. Then keep a
128-instruction FIFO of generated instructions. Each FIFO entry is
tagged with context and symbol definition as they are pushed to the
FIFO. When an instruction gets pulled from the FIFO because it's more
than 128 words away, the FIFO is searched for long branches that point
to this location; any such are shortened, and any symbols defined
following their location in the stream are adjusted. In the second
assembly pass, the FIFOs aren't used because all jump distances are
known, and the right sized branch (JMP or Bcc) can be generated.

View File

@@ -0,0 +1,172 @@
/* Some generally useful routines */
/* The majority of the non-portable code is in here. */
/*
Copyright (c) 2001, Richard Krehbiel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
o Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
#ifdef WIN32
#include <sys/types.h>
#include <sys/stat.h>
#define stat _stat
#else
#include <sys/stat.h>
#include <unistd.h>
#endif
/* Sure, the library typically provides some kind of
ultoa or _ultoa function. But since it's merely typical
and not standard, and since the function is so simple,
I'll write my own.
It's significant feature is that it'll produce representations in
any number base from 2 to 36.
*/
char *my_ultoa(unsigned long val, char *buf, unsigned int base)
{
static char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *strt = buf, *end;
do
{
*buf++ = digits[val % base];
val /= base;
} while(val != 0);
*buf = 0; /* delimit */
end = buf+1;
/* Now reverse the bytes */
while(buf > strt)
{
char temp;
temp = *--buf;
*buf = *strt;
*strt++ = temp;
}
return end;
}
/* Ditto my_ultoa. This actually emits
a signed representation in other number bases. */
char *my_ltoa(long val, char *buf, unsigned int base)
{
unsigned long uval;
if(val < 0)
uval = -val, *buf++ = '-';
else
uval = val;
return my_ultoa(uval, buf, base);
}
/*
_searchenv is a function provided by the MSVC library that finds
files which may be anywhere along a path which appears in an
environment variable. I duplicate that function for portability.
Note also that mine avoids destination buffer overruns.
Note: uses strtok. This means it'll screw you up if you
expect your strtok context to remain intact when you use
this function.
*/
void my_searchenv(char *name, char *envname, char *hitfile, int hitlen)
{
char *env;
char *envcopy;
char *cp;
*hitfile = 0; /* Default failure indication */
/* Note: If the given name is absolute, then don't search the
path, but use it as is. */
if(
#ifdef WIN32
strchr(name, ':') != NULL || /* Contain a drive spec? */
name[0] == '\\' || /* Start with absolute ref? */
#endif
name[0] == '/') /* Start with absolute ref? */
{
strncpy(hitfile, name, hitlen); /* Copy to target */
return;
}
env = getenv(envname);
if(env == NULL)
return; /* Variable not defined, no search. */
envcopy = strdup(env); /* strtok destroys it's text
argument. I don't want the return
value from getenv destroyed. */
while((cp = strtok(envcopy, PATHSEP)) != NULL)
{
struct stat info;
char *concat = malloc(strlen(cp) + strlen(name) + 2);
if(concat == NULL)
{
free(envcopy);
return;
}
strcpy(concat, cp);
if(concat[strlen(concat)-1] != '/')
strcat(concat, "/");
strcat(concat, name);
if(!stat(concat, &info))
{
/* Copy the file name to hitfile. Assure that it's really
zero-delimited. */
strncpy(hitfile, concat, hitlen-1);
hitfile[hitlen-1] = 0;
free(envcopy);
return;
}
}
/* If I fall out of that loop, then hitfile indicates no match,
and return. */
}

View File

@@ -0,0 +1,56 @@
#ifndef UTIL_H
#define UTIL_H
/*
Copyright (c) 2001, Richard Krehbiel
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
o Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
char *my_ultoa(unsigned long val, char *buf, unsigned int base);
char *my_ltoa(long val, char *buf, unsigned int base);
void my_searchenv(char *name, char *envname,
char *hitfile, int hitlen);
/* Cover a few platform-dependencies */
#ifdef WIN32
typedef unsigned __int64 ulong64;
#define strdup _strdup
#define putenv _putenv
#define PATHSEP ";"
#else
typedef unsigned long long ulong64;
#define PATHSEP ":"
#endif
#endif /* UTIL_H */

3083
crossassemblers/macro7.c Normal file

File diff suppressed because it is too large Load Diff

4251
crossassemblers/macro8x.c Normal file

File diff suppressed because it is too large Load Diff

636
extracters/backup/backup.c Normal file
View File

@@ -0,0 +1,636 @@
/* Dump contents of Tops-10 BACKUP tapes, which have been read
into a disk file. The "known good" way to do this is to use the
unix utility "dd", and a command line something like this:
dd if=/dev/rmt0 of=data ibs=2720 obs=2720 conv=block
the key thing is that this program expects a fixed block size of
2720 bytes. If the tape actually has some other format, this
program probably won't succeed. You can use the unix utility "tcopy"
to inspect the contents of the tape.
Here's the tcopy output from a good tape:
tcopy /dev/rmt0
file 0: block size 2720: 9917 records
file 0: eof after 9917 records: 26974240 bytes
eot
total length: 26974240 bytes
*/
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include "backup.h"
#define bool long
#define false 0
#define true 1
#define RAWSIZE (5*(32+512))
#define endof(s) (strchr(s, (char) 0))
FILE* source; /* Source "tape". */
bool eightbit = false; /* Status of -8 (eight-bit) flag. */
bool copytape = false; /* Status of -c (copytape fmt) flag. */
bool buildtree = false; /* Status of -d (build trees) flag. */
bool interchange = false; /* Status of -i (interchange) flag. */
bool binary = false; /* Status of -b (binary) flag. */
bool timfmt = false; /* Status of -m (mts format) flag. */
long verbose = 0; /* Status of -v (verbose) flag. */
char** argfiles; /* File spec's to extract. */
long argcount; /* Number of them. */
unsigned char rawdata[RAWSIZE]; /* Raw data for a tape block. */
long headlh[32], headrh[32]; /* Header block from tape. */
long datalh[512], datarh[512]; /* Data block from tape. */
long prevSEQ; /* SEQ number of previous block. */
long currentfilenumber;
char deferbyte; /* Defered byte for output. */
long defercount; /* Count of defered output bytes. */
bool extracting;
FILE* destination;
/* Tape information: */
char systemname[100];
char savesetname[100];
/* File information: */
long a_bsiz; /* For now. */
long a_alls;
long a_mode;
long a_leng;
char filedev[100]; /* Device: */
char filedir[100]; /* [ufd] */
char filename[100]; /* file name. */
char fileext[100]; /* extension. */
char filespec[7][100]; /* [0]: device:ufd. */
/* [1-5]: sfd's, stored directly here. */
/* [6]: file.ext */
char cname[100]; /* Canonical name. */
/* unpackheader unpacks the header block from the raw stream. */
void unpackheader() {
unsigned char* rawptr;
long i, left, right;
unsigned char c;
rawptr = &rawdata[0];
for (i = 0; i < 32; i++) {
left = *(rawptr++) << 10;
left |= *(rawptr++) << 2;
left |= (c = *(rawptr++)) >> 6;
right = (c & 077) << 12;
right |= *(rawptr++) << 4;
right |= *(rawptr++) & 017;
headlh[i] = left;
headrh[i] = right;
if(verbose>1) {printf("\n%i l=%d, r=%d",i,left,right);}
}
}
/* unpackdata unpacks the data block from the raw stream. */
void unpackdata() {
unsigned char* rawptr;
long i, left, right;
unsigned char c;
rawptr = &rawdata[32*5];
for (i = 0; i < 512; i++) {
left = *(rawptr++) << 10;
left |= *(rawptr++) << 2;
left |= (c = *(rawptr++)) >> 6;
right = (c & 077) << 12;
right |= *(rawptr++) << 4;
right |= *(rawptr++) & 017;
datalh[i] = left;
datarh[i] = right;
}
}
/* pars_36bits reads 36 bits from a machine word. */
void pars_36bits(index, store)
long index;
char *store;
{
long l, r;
l = datalh[index];
r = datarh[index];
store[0] = r & 0377;
store[1] = (r >> 8) & 0377;
store[2] = ((r >> 16) & 03) | ((l << 2) & 0374);
store[3] = (l >> 6) & 0377;
store[4] = (l >> 14) & 017;
store[5] = store[6] = store[7] = 0;
}
/* pars_5chars reads five ASCII chars from a machine word. */
void pars_5chars(index, store)
long index;
char* store;
{
long l, r;
l = datalh[index];
r = datarh[index];
store[0] = (0177 & (l >> 11));
store[1] = (0177 & (l >> 4));
store[2] = (0177 & ((l << 3) | ((r >> 15) & 017)));
store[3] = (0177 & (r >> 8));
store[4] = (0177 & (r >> 1));
}
/* pars_asciz stores asciz text from data */
void pars_asciz(index, store)
long index;
char* store;
{
long words;
words = datarh[index++];
while ((words--) > 0) {
pars_5chars(index++, store);
store += 5;
}
*store = (char) 0;
}
/* pars_o_name parses an o$name block from data. */
void pars_o_name(index)
long index;
{
long lastw;
lastw = index + datarh[index];
++index;
while (index < lastw) {
switch (datalh[index]) {
case 0: index = lastw; break;
case 1: pars_asciz(index, filedev); break;
case 2: pars_asciz(index, filename); break;
case 3: pars_asciz(index, fileext); break;
case 32: pars_asciz(index, filedir); break;
case 33: pars_asciz(index, filespec[1]); break;
case 34: pars_asciz(index, filespec[2]); break;
case 35: pars_asciz(index, filespec[3]); break;
case 36: pars_asciz(index, filespec[4]); break;
case 37: pars_asciz(index, filespec[5]); break;
}
index += datarh[index];
}
}
void pars_o_attr(index)
long index;
{
/* parse off file attribute block */
++index;
a_bsiz = datarh[index + A_BSIZ]; /* for now... */
a_alls = datarh[index + A_ALLS]; /* for now... */
a_mode = datarh[index + A_MODE]; /* for now... */
a_leng = datarh[index + A_LENG]; /* for now... */
}
void pars_o_dirt(index)
long index;
{
/* parse off directory attribute block */
}
void pars_o_sysn(index)
long index;
{
pars_asciz(index, systemname);
}
void pars_o_ssnm(index)
long index;
{
pars_asciz(index, savesetname);
}
void zerotapeinfo() {
systemname[0] = (char) 0;
savesetname[0] = (char) 0;
}
void zerofileinfo() {
filedev[0] = (char) 0;
filedir[0] = (char) 0;
filename[0] = (char) 0;
fileext[0] = (char) 0;
filespec[0][0] = (char) 0;
filespec[1][0] = (char) 0;
filespec[2][0] = (char) 0;
filespec[3][0] = (char) 0;
filespec[4][0] = (char) 0;
filespec[5][0] = (char) 0;
filespec[6][0] = (char) 0;
cname[0] = (char) 0;
}
/* unpackinfo picks non-data information from data block. */
void unpackinfo() {
long index;
unpackdata();
index = 0;
while (index < headrh[G_LND]) {
switch (datalh[index]) {
case 1: pars_o_name(index); break;
case 2: pars_o_attr(index); break;
case 3: pars_o_dirt(index); break;
case 4: pars_o_sysn(index); break;
case 5: pars_o_ssnm(index); break;
}
index += datarh[index];
}
}
void printtapeinfo() {
if (verbose) {
if (*savesetname != (char) 0) printf("Saveset name: %s\n", savesetname);
if (*systemname != (char) 0) printf("Written on: %s\n", systemname);
}
}
void downcase(s)
char* s;
{
while (*s != (char) 0) {
if (isupper(*s)) *s = tolower(*s);
s++;
}
}
void buildfilenames() {
long i;
if (*filedev != (char) 0)
sprintf(filespec[0], "%s:%s", filedev, filedir);
else
sprintf(filespec[0], "%s", filedir);
sprintf(filespec[6], "%s.%s", filename, fileext);
for(i = 0; i < 7; i++)
downcase(filespec[i]);
sprintf(cname, "%s", filespec[0]);
for(i = 1; i < 6; i++) {
if (*filespec[i] != (char) 0) sprintf(endof(cname), ".%s", filespec[i]);
}
if (*cname != (char) 0)
sprintf(endof(cname), "..%s", filespec[6]);
else
sprintf(cname, "%s", filespec[6]);
}
void printfileinfo() {
buildfilenames();
printf("%3d %s", currentfilenumber, cname);
if (verbose) {
printf(" (%d) alloc:%d, mode:%o, len:%d", a_bsiz, a_alls, a_mode, a_leng);
}
printf("\n");
}
/* readblock reads one logical block from the input stream. */
/* The header is unpacked into head{l,r}; the data is not. */
long blockn=0;
void readblock() {
long i, bytes;
unsigned char bc[4];
i = fread(bc, sizeof(char), 4, source);
if (i == 0) return;
bytes = ((long) bc[1] << 8) | (bc[0]);
if (bytes == 0) return;
if (bytes != RAWSIZE)
fprintf(stderr, "backup: incorrect block size = %d\n", bytes);
i = fread(rawdata, sizeof(char), RAWSIZE, source);
blockn++;
while (i++ < RAWSIZE) rawdata[i] = (char) 0;
fread(bc, sizeof(char), 4, source);
unpackheader();
}
/* Disk file output routines: */
void WriteBlock() {
char buffer[5*512];
char binbuf[8*512];
long bufpos, index;
for (index = 0; index < 5*512; index++) buffer[index] = 0;
for (index = 0; index < 8*512; index++) binbuf[index] = 0;
unpackdata();
if (binary) {
for (index = headrh[G_LND], bufpos = 0;
index < (headrh[G_LND] + headrh[G_SIZE]); index++) {
pars_36bits(index, &binbuf[bufpos]);
bufpos += 8;
}
(void) fwrite(binbuf, sizeof(char), bufpos, destination);
}
else {
for (index = headrh[G_LND], bufpos = 0;
index < (headrh[G_LND] + headrh[G_SIZE]); index++) {
pars_5chars(index, &buffer[bufpos]);
bufpos += 5;
}
if (headlh[G_FLAGS] & GF_EOF) {
for (index = 1; (index < (eightbit ? 4 : 5)) && (bufpos > 0); index++) {
if (buffer[bufpos - 1] == (char) 0) bufpos--;
}
}
(void) fwrite(buffer, sizeof(char), bufpos, destination);
}
}
/* OpenOutput opens the output file, according to -d and -i flags. */
bool OpenOutput() {
struct stat statbuf;
char oname[100];
long i;
defercount = 0;
if (interchange) {
destination = fopen(filespec[6], (binary? "wb": "w"));
} else if (!buildtree) {
for (i = 0; (i < sizeof (cname)) && cname[i]; i++)
if (cname[i] == ':') cname[i] = '.';
destination = fopen(cname, (binary? "wb": "w"));
} else {
/* for(i = 0, oname[0] = (char) 0; i < 6; i++) {
if (*filespec[i] == (char) 0) break;
sprintf(endof(oname), "%s", filespec[i]);
if (stat(oname, &statbuf) != 0) {
if (mkdir(oname, 0777) != 0) {
fprintf(stderr, "backup: cannot create %s/\n", oname);
return(false);
}
}
sprintf(endof(oname), "/");
}
sprintf(endof(oname), "%s", filespec[6]);
destination = fopen(oname, (binary? "wb": "w")); */
fprintf(stderr, "backup: tree mode not supported\n");
return(false);
}
return(destination != NULL);
}
void CloseOutput() {
/* Close output file after us. */
}
/* Argmatch checks if the current file matches the given argument: */
bool argmatch(arg)
char* arg;
{
long target;
char* f;
char* p;
char* s;
if (*arg == '#') {
(void) sscanf(arg, "#%d", &target);
return(target == currentfilenumber);
}
if (*arg == '*') return(1);
for (f = cname; *f != (char) 0; f++) {
for (p = f, s = arg; (*s != (char) 0) && (*p == *s); p++, s++);
if (*s == (char) 0) return (true);
}
return (false);
}
/* doextract performs the job of "backup -x ..." */
void doextract() {
long i;
currentfilenumber = 0;
extracting = false;
while (!feof(source)) {
readblock();
if (headrh[G_SEQ] == prevSEQ) continue;
if (headrh[G_TYPE] == T_FILE) {
if (headlh[G_FLAGS] & GF_SOF) {
currentfilenumber++;
zerofileinfo();
unpackinfo();
buildfilenames();
for (i = 0; i < argcount; i++) {
if (argmatch(argfiles[i])) {
if (*argfiles[i] == '#') {
/* Maybe do a pure shift here? */
argfiles[i] = argfiles[--argcount];
}
extracting = true;
break;
}
}
if (extracting) {
if (OpenOutput()) {
if (verbose) {
printf("Extracting %s", cname);
fflush(stdout);
}
} else {
fprintf(stderr, "backup: can't open %s for output\n", cname);
extracting = false;
}
}
}
if (extracting) {
WriteBlock();
if (headlh[G_FLAGS] & GF_EOF) {
(void) fclose(destination);
extracting = false;
if (verbose) printf("\n");
if (argcount == 0)
break;
}
}
}
prevSEQ = headrh[G_SEQ];
}
}
/* dodirectory performs the job of "backup -t ..." */
void dodirectory() {
currentfilenumber = 0;
while (!feof(source)) {
readblock();
if (headrh[G_SEQ] == prevSEQ) continue;
if (headrh[G_TYPE] == T_BEGIN) {
zerotapeinfo();
unpackinfo();
printtapeinfo();
}
if (headrh[G_TYPE] == T_FILE) {
if (headlh[G_FLAGS] & GF_SOF) {
++currentfilenumber;
zerofileinfo();
unpackinfo();
printfileinfo();
}
}
prevSEQ = headrh[G_SEQ];
}
}
/* command decoder and dispatcher */
bool checkarg(arg)
char* arg;
{
long i;
char c;
if (*arg == '#') {
if (sscanf(arg, "#%d%c", &i, &c) != 1) {
fprintf(stderr, "backup: bad argument: %s\n", arg);
return(true);
}
}
return(false);
}
int main(argc, argv)
long argc;
char* argv[];
{
long i;
char* s, tapetype[4];
bool namenext = false;
bool actgiven = false;
char action;
char* inputname = NULL;
if (--argc > 0) {
for (s = *(++argv); *s != (char) 0; s++)
switch(*s) {
case '-':
break;
case '8':
eightbit = true; break;
case 'b':
binary = true; break;
case 'c':
copytape = true; break;
case 'd':
buildtree = true; break;
case 'f':
namenext = true; break;
case 'i':
interchange = true; break;
case 'm':
timfmt = true; break;
case 't':
case 'x':
action = *s; actgiven = true; break;
case 'v':
verbose++; break;
default:
fprintf(stderr, "backup: bad option %c\n", *s);
return 0;
}
}
if (namenext) {
if (--argc > 0)
inputname = *(++argv);
else {
fprintf(stderr, "backup: input file name missing\n");
return 0;
}
}
argfiles = ++argv; /* Keep rest of arguments. */
argcount = --argc; /* ... and count 'em. */
for (i = 0; i < argcount; i++) {
if (checkarg(argfiles[i])) {
fprintf(stderr, "backup: error in argument %d = %s\n", i, argfiles[i]);
return 0; } }
if (inputname == NULL) {
/* Use environment var. TAPE here? */
fprintf(stderr, "backup: no input file given\n");
return 0;
}
if (strcmp(inputname, "-") != 0) {
if ((source = fopen(inputname, "rb")) == NULL) {
fprintf(stderr, "backup: can't open %s for input\n", inputname);
return 0;
}
fprintf (stderr, "backup: opening %s for input\n", inputname);
if (timfmt) fread (tapetype, sizeof(char), 4, source);
} else {
source = stdin;
}
switch (action) {
case 't': dodirectory(); break;
case 'x': doextract(); break;
default:
fprintf(stderr, "backup: internal error in program\n");
return 0;
}
}

View File

@@ -0,0 +1,80 @@
/* Record types: */
#define T_LABEL 1 /* Label. */
#define T_BEGIN 2 /* Start of SaveSet. */
#define T_END 3 /* End of SaveSet. */
#define T_FILE 4 /* File data. */
#define T_UFD 5 /* UFD data. */
#define T_EOV 6 /* End of volume. */
#define T_COMM 7 /* Comment. */
#define T_CONT 8 /* Continuation. */
/* Offsets into header block: */
#define G_TYPE 0 /* Record type. */
#define G_SEQ 1 /* Sequence #. */
#define G_RTNM 2 /* Relative tape #. */
#define G_FLAGS 3 /* Flags: */
#define GF_EOF 0400000 /* End of file. */
#define GF_RPT 0200000 /* Repeat of last record. */
#define GF_NCH 0100000 /* Ignore checksum. */
#define GF_SOF 0040000 /* Start of file. */
#define G_CHECK 4 /* Checksum. */
#define G_SIZE 5 /* Size of data in this block. */
#define G_LND 6 /* Length of non-data block. */
/* Non-data block types: */
#define O_NAME 1 /* File name. */
#define O_ATTR 2 /* File attributes. */
#define O_DIRECT 3 /* Directory attributes. */
#define O_SYSNAME 4 /* System name block. */
#define O_SAVESET 5 /* SaveSet name block. */
/* Offsets in attribute block: */
#define A_FHLN 0 /* header length word */
#define A_FLGS 1 /* flags */
#define A_WRIT 2 /* creation date/time */
#define A_ALLS 3 /* allocated size */
#define A_MODE 4 /* mode */
#define A_LENG 5 /* length */
#define A_BSIZ 6 /* byte size */
#define A_VERS 7 /* version */
#define A_PROT 8 /* protection */
#define A_ACCT 9 /* byte pointer account string */
#define A_NOTE 10 /* byte pointer to anonotation string */
#define A_CRET 11 /* creation date/time of this generation */
#define A_REDT 12 /* last read date/time of this generation */
#define A_MODT 13 /* monitor set last write date/time */
#define A_ESTS 14 /* estimated size in words */
#define A_RADR 15 /* requested disk address */
#define A_FSIZ 16 /* maximum file size in words */
#define A_MUSR 17 /* byte ptr to id of last modifier */
#define A_CUSR 18 /* byte ptr to id of creator */
#define A_BKID 19 /* byte ptr to save set of previous backup */
#define A_BKDT 20 /* date/time of last backup */
#define A_NGRT 21 /* number of generations to retain */
#define A_NRDS 22 /* nbr opens for read this generation */
#define A_NWRT 23 /* nbr opens for write this generation */
#define A_USRW 24 /* user word */
#define A_PCAW 25 /* privileged customer word */
#define A_FTYP 26 /* file type and flags */
#define A_FBSZ 27 /* byte sizes */
#define A_FRSZ 28 /* record and block sizes */
#define A_FFFB 29 /* application/customer word */
/* T_BEGIN, T_END & T_CONT header offsets: */
#define S_DATE 12
#define S_FORMAT 13
#define S_BVER 14
#define S_MONTYP 15
#define S_SVER 16
#define S_APR 17
#define S_DEVICE 18
#define S_MTCHAR 19
#define S_REELID 20
#define S_LTYPE 21

View File

@@ -0,0 +1,91 @@
Note: This program has no attribution for authorship. I modified it
to deal with binary files.
Bob Supnik
Description:
backup is a program that can list the contents of, and extract
files from a TOPS-10 backup tape. The command syntax is some-
what resembling that of tar. The command
backup -t[v][f tape]
lists the contents of 'tape'. The command
backup -x[cdimv8][f tape] file1 file2 ...
extracts all files that match either of the file arguments given.
The names used for the created files will be the canonical names
from the tape, unless -d or -i are in effect. The canonical name
is a string of the format: device.p_pn.sfd1.sfd2..file.ext
Arguments:
'tape' is the name of a tape drive, the name of a file or the
single character '-', meaning stdin. If omitted, the environment
variable TAPE will be consulted.
If the "tape" argument is actually a file, which was captured
from a tape (say, on a different machine). The "known good" way
to capture the contents of the tape is to use the unix utility
"dd", and a command line something like this:
dd if=/dev/rmt0 of=data ibs=2720 obs=2720 conv=block
the key thing is that this program expects a fixed block size of
2720 bytes. If the tape actually has some other format, this
program probably won't succeed. You can use the unix utility "tcopy"
to inspect the contents of the tape.
Here's the tcopy output from a good tape:
tcopy /dev/rmt0
file 0: block size 2720: 9917 records
file 0: eof after 9917 records: 26974240 bytes
eot
total length: 26974240 bytes
File arguments are either any substring of the canonical name
printed with 'backup -t ...', or a hash mark, and the number
of the file on the tape, or "*" to simply extract all the files.
Options:
-b Extract files in binary format. The files on tape have one
36b word stored in five 8b frames, as specified in PDP-10
"core dump" mode. The extracted files have one 36b word
stored, right justified, on one little-endian 64b word, as
expected by the simh simulators.
-c The 'tape' is a disk file, in copytape format.
-d Create a directory structure when restoring, giving files named
device:p_pn/sfd1/sfd2/file.ext, instead of the flat name space
resulting from using the canonical names.
-f The disk image file is the next argument.
-i Ignore device and directory info when building output file names.
-m The disk image file has a 4 byte header specifying density, which
must be ignored.
-v Verbose. Does the obvious. -vv does even more.
-8 Tops-10 file was in eight-bit mode.
Bugs:
We don't handle multiple tape savesets any good.
We don't check for bad format of input.
We don't handle checksums, or repeated blocks any good.

423
extracters/ckabstape.c Normal file
View File

@@ -0,0 +1,423 @@
#include <stdio.h>
static unsigned char sixlut[64] = {
'@','A','B','C','D','E','F','G',
'H','I','J','K','L','M','N','O',
'P','Q','R','S','T','U','V','W',
'X','Y','Z','[','/',']','^','_',
' ','!','"','#','$','%','&','\'',
'(',')','*','+',',','-','.','/',
'0','1','2','3','4','5','6','7',
'8','9',':',';','<','=','>','?'
};
char sixbit(char c)
{
return(sixlut[c & 0x3f]);
}
void printb(unsigned char c)
{
int i;
for(i=0; i<8; i++){
if((c & 0x80) == 0)
printf("%c",'0');
else
printf("%c",'1');
c = c << 1;
}
printf("\n");
}
/*
* read an 18 bit paper tape frame
*
* bits 6,7 packed into high part of int so we can look at them
*/
unsigned int readframe()
{
unsigned int i;
unsigned char c;
do{
c = getchar();
if(feof(stdin))
exit();
if((c & 0x80) == 0) printf("{nul}\n",c);
} while((c & 0x80) == 0);
i = ((c & 0xc0)>>6)<<27;
i = i | (c & 0x3f)<<12;
do{
c = getchar();
if(feof(stdin))
exit();
if((c & 0x80) == 0) printf("{nul}\n",c);
} while((c & 0x80) == 0);
i = i |((c & 0xc0)>>6)<<24;
i = i | (c & 0x3f)<<6;
do{
c = getchar();
if(feof(stdin))
exit();
if((c & 0x80) == 0) printf("{nul}\n",c);
} while((c & 0x80) == 0);
i = i |((c & 0xc0)>>6)<<21;
i = i | (c & 0x3f);
return i;
}
disasm(unsigned int instr)
{
char *idx;
if(instr & 0010000) idx = ",X"; else idx = " ";
if((instr & 0700000) != 0700000)
switch(instr & 0740000){
case(0000000):
printf("CAL%c %04o%s ", (instr & 0020000)?'*':' ', instr &07777, idx);
break;
case(0040000):
printf("DAC%c %04o%s ", (instr & 0020000)?'*':' ', instr &07777, idx);
break;
case(0100000):
printf("JMS%c %04o%s ", (instr & 0020000)?'*':' ', instr &07777, idx);
break;
case(0140000):
printf("DZM%c %04o%s ", (instr & 0020000)?'*':' ', instr &07777, idx);
break;
case(0200000):
printf("LAC%c %04o%s ", (instr & 0020000)?'*':' ', instr &07777, idx);
break;
case(0240000):
printf("XOR%c %04o%s ", (instr & 0020000)?'*':' ', instr &07777, idx);
break;
case(0300000):
printf("ADD%c %04o%s ", (instr & 0020000)?'*':' ', instr &07777, idx);
break;
case(0340000):
printf("TAD%c %04o%s ", (instr & 0020000)?'*':' ', instr &07777, idx);
break;
case(0400000):
printf("XCT%c %04o%s ", (instr & 0020000)?'*':' ', instr &07777, idx);
break;
case(0440000):
printf("ISZ%c %04o%s ", (instr & 0020000)?'*':' ', instr &07777, idx);
break;
case(0500000):
printf("AND%c %04o%s ", (instr & 0020000)?'*':' ', instr &07777, idx);
break;
case(0540000):
printf("SAD%c %04o%s ", (instr & 0020000)?'*':' ', instr &07777, idx);
break;
case(0600000):
printf("JMP%c %04o%s ", (instr & 0020000)?'*':' ', instr &07777, idx);
break;
default:
printf("???? ");
break;
}
/*
*/
if((instr & 0700000) == 0700000)
switch(instr){
case(0700000):
printf("IOT ");
break;
case(0700002):
printf("IOF ");
break;
case(0700004):
printf("CLOF ");
break;
case(0700042):
printf("ION ");
break;
case(0700101):
printf("RSF (hsrdr)");
break;
case(0700102):
printf("RCF (hsrdr)");
break;
case(0700104):
printf("RSA (hsrdr)");
break;
case(0700112):
printf("RRB (hsrdr)");
break;
case(0700144):
printf("RSB (hsrdr)");
break;
case(0700201):
printf("PSF (hsptp)");
break;
case(0700202):
printf("PCF (hsptp)");
break;
case(0700204):
printf("PSA (hsptp)");
break;
case(0700244):
printf("PSB (hsptp)");
break;
case(0700301):
printf("KSF (ttykb)");
break;
case(0700312):
printf("KRB (ttyrd)");
break;
case(0700314):
printf("IORS ");
break;
case(0700322):
printf("KRS (ttykb)");
break;
case(0700401):
printf("TSF (ttyout)");
break;
case(0700402):
printf("TCF (ttyout)");
break;
case(0700406):
printf("TLS (ttyout)");
break;
case(0703302):
printf("CAF ");
break;
case(0707721):
printf("SBA ");
break;
case(0707722):
case(0707762):
printf("DBA ");
break;
case(0707724):
case(0707764):
printf("EBA ");
break;
/*
*/
case(0720000):
printf("AAS ");
break;
case(0723000):
printf("AAC ");
break;
case(0725000):
printf("AXS ");
break;
case(0736000):
printf("CLLR ");
break;
case(0735000):
printf("CLX ");
break;
case(0722000):
printf("PAL ");
break;
case(0721000):
printf("PAX ");
break;
case(0730000):
printf("PLA ");
break;
case(0731000):
printf("PLX ");
break;
case(0724000):
printf("PXA ");
break;
case(0726000):
printf("PXL ");
break;
/*
* operate instructions
*/
case(0740000):
printf("NOP ");
break;
case(0740001): // CMA compliment AC
printf("CMA ");
break;
case(0740002):
printf("CML ");
break;
case(0740004):
printf("OAS ");
break;
case(0740010):
printf("RAL ");
break;
case(0740020):
printf("RAR ");
break;
case(0740030):
printf("IAC ");
break;
case(0740031):
printf("TCA ");
break;
case(0740040):
printf("HLT ");
break;
case(0740100):
printf("SMA ");
break;
case(0740200):
printf("SZA ");
break;
case(0740400):
printf("SNL ");
break;
case(0741000):
printf("SKP ");
break;
case(0741100):
printf("SPA ");
break;
case(0741200):
printf("SNA ");
break;
case(0741400):
printf("SZL ");
break;
case(0742010):
printf("RTL ");
break;
case(0742020):
printf("RTR ");
break;
case(0742030):
printf("SWHA ");
break;
case(0744000):
printf("CLL ");
break;
case(0744002):
printf("STL ");
break;
case(0744010):
printf("CCL ");
break;
case(0744020):
printf("RCL ");
break;
case(0750000):
printf("CLA ");
break;
case(0750001):
printf("LAS ");
break;
case(0750004):
printf("LAT ");
break;
case(0750010):
printf("GLK ");
break;
case(0760000):
printf("LAW ");
break;
default:
printf("??? ");
break;
}
}
main()
{
int totalblks = 0;
int badblks = 0;
unsigned int fullwd = 0;
unsigned int currentwd = 0;
int wds = 0;
int bytecnt = 0;
int col = 0;
int framecount;
unsigned int cksum;
unsigned int adr;
unsigned char c;
/*
* read 3 chars and pack them in a word
*/
do {
currentwd = readframe();
printf("%010o ", currentwd);
printf("%c %c %c ",sixbit((currentwd & 0770000) >>12),
sixbit((currentwd & 007700) >>6),
sixbit(currentwd & 077) );
col++;
if(col == 4){
printf("\n");
col = 0;
}
if(currentwd & 00010000000) {
printf("\n loader end ----\n");
/*
* start looking for binary data frames
*/
while(1){
/*
* frames start at the first 0x80 punched
* (check is in readframe..)
*/
adr = readframe() & 0777777; // staring adr
cksum = adr;
printf("ADR: %010o\n", adr);
framecount = readframe() & 0777777; // word count
cksum += framecount;
framecount = -(0xfffe0000 | framecount); // sign extend
printf("CNT: %010o (%d)\n", framecount, framecount);
if((adr & 0700000) != 0){
printf("FRAMECOUNT == 0 START ADR == %06o\n", adr);
printf("TOTAL BLKS %d TOTAL ERRS %d\n", totalblks, badblks);
exit();
}
currentwd = readframe() & 0777777; // checksum
cksum += currentwd;
printf("CKS: %06o\n", currentwd);
/*
* read all the data words
*/
while(framecount > 0){
currentwd = readframe();
cksum += currentwd & 0777777;
printf("%05o: %06o ",adr++, currentwd & 0777777);
disasm(currentwd & 0777777);
printf(" ; %c%c%c ",sixbit((currentwd & 0770000) >>12),
sixbit((currentwd & 007700) >>6),
sixbit(currentwd & 077) );
printf("\n");
framecount--;
}
if(cksum&0777777){
printf("****BAD CKSUM**** %06o\n",cksum&0777777);
badblks++;
}
totalblks++;
}
}
} while(!feof(stdin));
if(bytecnt > 0){
printf("%d chrs left\n", bytecnt);
}
}

105
extracters/mmdir.c Normal file
View File

@@ -0,0 +1,105 @@
/* This program dumps the directory of a simulated Interdata MDM tape
Copyright (c) 1993-2002, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
int main (int argc, char *argv[])
{
int obj, i, k, fc, rc, tpos, sa, ea, fr, fq;
unsigned char b[53];
unsigned char bca[4];
unsigned int bc;
int preveof;
FILE *ifile;
#define MAXRLNT 65536
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: verb file [file...]\n");
exit (0); }
for (i = 1; i < argc; i++) {
ifile = fopen (argv[i], "rb");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
return 0; }
printf ("Processing input file %s\n", argv[i]);
tpos = 0; rc = 1; fc = 0; preveof = 0;
for (;;) {
fseek (ifile, tpos, SEEK_SET);
k = fread (bca, 1, 4, ifile);
bc = (((unsigned int) bca[3]) << 24) | (((unsigned int) bca[2]) << 16) |
(((unsigned int) bca[1]) << 8) | ((unsigned int) bca[0]);
if ((k == 0) || (bc == 0xFFFFFFFF)) {
printf ("End of physical tape\n");
break; }
if (bc & 0x80000000) {
printf ("Error marker at record %d\n", rc);
bc = bc & ~0x80000000; }
if (bc == 0) {
if (preveof) {
printf ("End of logical tape\n");
break; }
preveof = 1;
fc++; obj++;
rc = 1;
tpos = tpos + 4; }
else if (bc > MAXRLNT) {
printf ("Invalid record length %d, terminating\n", bc);
break; }
else {
tpos = tpos + 8 + ((bc + 1) & ~1);
preveof = 0;
if (fc && (rc == 1)) {
if (bc != 52) {
printf ("Invalid record length %d, terminating\n", bc);
break; }
fread (b, 1, 52, ifile);
sa = (((unsigned int) b[18]) << 16) |
(((unsigned int) b[19]) << 8) | ((unsigned int) b[20]);
ea = (((unsigned int) b[21]) << 16) |
(((unsigned int) b[22]) << 8) | ((unsigned int) b[23]);
fr = b[27] >> 4;
fq = b[27] & 0xF;
printf ("%3d %c%c%c 06-%c%c%c", fc,
b[0], b[1], b[2], b[3], b[4], b[5]);
if (fr) printf ("F0%X", fr);
else printf (" ");
printf ("R%c%c%c%c %c%c ",
b[6], b[7], b[25], b[26], b[28], b[29]);
b[18] = b[51] = b[52] = 0;
printf ("%s%s %06X %06X %X\n",
&b[8], &b[30], sa, ea, fq);
}
rc++; }
}
fclose (ifile);
}
return 0;
}

130
extracters/mtdump.c Normal file
View File

@@ -0,0 +1,130 @@
/* This program dumps the format of a simulated magtape
Copyright (c) 1993-2003, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#define F_STD 0
#define F_E11 1
#define F_TPC 2
#define F_TPF 3
int main (int argc, char *argv[])
{
int obj, i, k, fc, rc, tpos;
unsigned int bc, fmt, rlntsiz;
unsigned char *s, bca[4];
int preveof;
FILE *ifile;
#define MAXRLNT 65536
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: mtdump {-secf} file [file...]\n");
exit (0); }
s = argv[1];
if ((s != NULL) && (*s++ == '-')) {
++argv; --argc;
switch (*s) {
case 'S': case 's':
fmt = F_STD; rlntsiz = 4; break;
case 'E': case 'e':
fmt = F_E11; rlntsiz = 4; break;
case 'C': case 'c':
fmt = F_TPC; rlntsiz = 2; break;
/* case 'F': case 'f':
/* fmt = F_TPF; break; */
default:
fprintf (stderr, "Bad option %c\n", *s);
return 0;
}
}
else { fmt = F_STD;
rlntsiz = 4; }
for (i = 1; i < argc; i++) {
ifile = fopen (argv[i], "rb");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
printf ("Processing input file %s\n", argv[i]);
tpos = 0; rc = 1; fc = 1; preveof = 0;
printf ("Processing tape file %d\n", fc);
for (obj = 1;;) {
fseek (ifile, tpos, SEEK_SET);
k = fread (bca, 1, rlntsiz, ifile);
switch (fmt) {
case F_STD: case F_E11:
bc = (((unsigned int) bca[3]) << 24) | (((unsigned int) bca[2]) << 16) |
(((unsigned int) bca[1]) << 8) | ((unsigned int) bca[0]);
break;
case F_TPC:
bc = (((unsigned int) bca[1]) << 8) | ((unsigned int) bca[0]);
break;
}
if ((k == 0) || (bc == 0xFFFFFFFF)) {
printf ("End of physical tape\n");
break; }
if (bc & 0x80000000) {
printf ("Error marker at record %d\n", rc);
bc = bc & ~0x80000000; }
if (bc == 0) {
if (preveof) {
printf ("Obj %d, position %d, end of logical tape\n", obj, tpos);
break; }
preveof = 1;
printf ("Obj %d, position %d, end of tape file %d\n", obj, tpos, fc);
fc++; obj++;
rc = 1;
tpos = tpos + rlntsiz; }
else if (bc > MAXRLNT) {
printf ("Invalid record length %d, terminating dump\n", bc);
break; }
else {
if (preveof) printf ("Processing tape file %d\n", fc);
preveof = 0;
printf ("Obj %d, position %d, record %d, length = %d (0x%X)\n",
obj, tpos, rc, bc, bc);
rc++; obj++;
switch (fmt) {
case F_STD:
tpos = tpos + 8 + ((bc + 1) & ~1); break;
case F_E11:
tpos = tpos + 8 + bc; break;
case F_TPC:
tpos = tpos + 2 + ((bc + 1) & ~1); break;
}
}
}
fclose (ifile);
}
return 0;
}

38
extracters/mtdump.txt Normal file
View File

@@ -0,0 +1,38 @@
mtdump dumps the record structure of a tape image file in SIMH, E11, or
TPC format. mtdump is invoked by
mtdump {-sec} file1 file2 file3...
where -s specifies SIMH format, -e E11 format, and -c TPC format. The
default is SIMH format. Output is to stdout, unless redirected.
SIMH format is as follows:
4 byte record length 1
record 1
repeat of 4 byte record length 1
4 byte record length 2
record 2
repeat of 4 byte record length 2
:
4 bytes = 00000000 for end of file
and so on. Records are padded to even byte length.
E11 format is similar to SIMH format, but odd length records are not padded
to even length.
TPC format is as follows:
2 byte record length 1
record 1
2 byte record length 2
record 2
:
2 bytes = 0000 for end of file
and so on. Records are padded to even byte length.
mmdir is a variant of mtdump that dumps the directory structure of an
Interdata MMD (multimedia diagnostic) tape. The tape must be in SMIH
format.

View File

@@ -0,0 +1,49 @@
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
static
char buf[1024*1024];
int main(int argc, char **argv)
{
FILE *fin, *fout;
size_t bytesread, readsize = sizeof(buf), totalbytes = 0;
if (argc < 3)
{
fprintf(stderr, "Usage: RawCopy <infile> <outfile>\n");
fprintf(stderr, "On Win32 environments, RAW devices have names for the format:\n");
fprintf(stderr," CD Drives \\\\.\\CdRom0\n");
fprintf(stderr," Hard Drives \\\\.\\PhysicalDrive0\n");
exit(0);
}
if (NULL == (fin = fopen(argv[1], "rb")))
{
fprintf(stderr, "Error Opening '%s' for input: %s\n", argv[1], strerror(errno));
exit(errno);
}
if (NULL == (fout = fopen(argv[2], "wb")))
{
fprintf(stderr, "Error Opening '%s' for output: %s\n", argv[2], strerror(errno));
exit(errno);
}
fprintf(stderr, "Copying '%s' to '%s'\n", argv[1], argv[2]);
while (0 != (bytesread = fread(buf, 1, readsize, fin)))
{
if (bytesread != fwrite(buf, 1, bytesread, fout))
{
fprintf(stderr, "Error Writing '%s': %s\n", strerror(errno));
break;
}
else
totalbytes += bytesread;
if (0 == (totalbytes%(1024*1024)))
fprintf(stderr, "%6dMB Copied...\r", totalbytes/(1024*1024));
}
fprintf(stderr, "\n");
fprintf(stderr, "Total Data: %6.2f MBytes (%d bytes)\n", totalbytes/(1024.0*1024.0), totalbytes);
fclose(fin);
fclose(fout);
}

View File

@@ -0,0 +1,17 @@
The attached program will make an ISO compatible CD Image on both Intel
Linux and Windows XP systems.
It works with the VMS Hobbyist CD, and the result is bootable. It works
with all the other data CD's that I tried as well.
The same exe works on Windows 2000, with one odd exception. It will
simply copy a CD image from any CD which has an ISO9660 file system on it,
but it fails to recognize a non-zero size for the \\.\CdRom0 device on these
systems when the Hobbist CD is installed.
Meanwhile, this raw data copy operation is the "right" thing for this problem.
The raw copy result provides a disk image that the simulator can access.
On many platforms, the simulator could access the device directly just as
this program does.
- Mark Pizzolato

95
extracters/sdsdump.c Normal file
View File

@@ -0,0 +1,95 @@
/* This program dumps the format of an SDS paper tape
Copyright (c) 2002, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Robert M Supnik shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
int getfc (FILE *ifile)
{
int k;
unsigned char by;
k = fread (&by, sizeof (char), 1, ifile);
if (k == 0) {
printf ("End of physical tape\n");
return -1; }
return by;
}
int main (int argc, char *argv[])
{
int i, k, wc, pos, cc, inrec, wd, op, tag, addr;
FILE *ifile;
char *opstr[] = {
"HLT", "BRU", "EOM", NULL, NULL, NULL, "EOD", NULL,
"MIY", "BRI", "MIW", "POT", "ETR", NULL, "MRG", "EOR",
"NOP", NULL, "OVF", "EXU", NULL, NULL, NULL, NULL,
"YIM", NULL, "WIM", "PIN", NULL, "STA", "STB", "STX",
"SKS", "BRX", NULL, "BRM", NULL, NULL, "CPY", NULL,
"SKE", "BRR", "SKB", "SKN", "SUB", "ADD", "SUC", "ADC",
"SKR", "MIN", "XMA", "ADM", "MUL", "DIV", "RSH", "LSH",
"SKM", "LDX", "SKA", "SKG", "SKD", "LDB", "LDA", "EAX" };
if ((argc < 2) || (argv[0] == NULL)) {
printf ("Usage is: verb file [file...]\n");
exit (0); }
for (i = 1; i < argc; i++) {
ifile = fopen (argv[i], "rb");
if (ifile == NULL) {
printf ("Error opening file: %s\n", argv[i]);
exit (0); }
printf ("Processing input file %s\n", argv[i]);
inrec = 0; wc = 1;
for (pos = wd = cc = 0; ;pos++) {
if ((k = getfc (ifile)) < 0) {
if (inrec) printf ("Format error\n");
break; }
if (k == 0) {
if (inrec && cc) printf ("Incomplete word\n");
inrec = 0;
continue; }
wd = (wd << 6) | (k & 077);
cc++;
if (cc >= 4) {
printf ("Pos = %d, cnt = %d: %08o", pos, wc, wd);
tag = (wd >> 21) & 07;
op = (wd >> 15) & 077;
addr = wd & 037777;
if (opstr[op] && ((op != 0) || (wd == 0))) {
if (wd & 040000) printf (" [%s* %o", opstr[op], addr);
else printf (" [%s %o", opstr[op], addr);
if (tag) printf (",%o", tag);
printf ("]"); }
printf ("\n");
cc = wd = 0;
wc++; }
}
fclose (ifile);
}
return 0;
}

175
ods2_readme.txt Normal file
View File

@@ -0,0 +1,175 @@
ODS2 June '98
A Program to Read ODS2 Disk Volumes
Say, what is this?
ODS2 is a program to read VMS disk volumes written in VMS
ODS2 format.
Why bother?
Well sometimes it is convenient to see what is on a VMS CD,
or copy files from VMS disk on another platform. Maybe in
future it could be used as a basis for a PC Bookreader
program, or possibly other software?
What other platforms?
ODS2 is written in 'Standard C' with the intent that it can
be compiled and run on non-VMS systems. However this requires
a C compiler which has 32 bit 'int' types, 16 bit 'short'
types, and 8 bit 'char'. The current version does no special
'endian' handling so it can only be run on systems which are
little-endian like the VAX. Fortunately that inludes Intel...
Could it be made to run on big-endian systems?
Yes it could! This would probably best be done by defining
C macros or functions to extract words or long words from the
disk structures as appropriate. On a little-endian system these
would be simply pass-through, while on a big-endian system they
would reverse the byte order. I have not attempted this because
I don't have a suitable test system!!
What else is needed?
Some operating system support is also required to read an
absolute disk sector from the target disk. This is NOT as
easy as it sounds. I do not currently have sufficient
documentation to set this up for as many platforms as I
would like!! However I do have modules to read disks under
VMS (easy!) and floppies and CD under OS2, Windows 95 and
Windows NT.
How do I build it?
On a VMS system ODS2 can be compiled by executing the
procedure BUILD.COM. On other platforms you need to compile
Ods2.c, Rms.c, Direct.c, Access.c, Device.c, Cache.c, Vmstime.c,
and the appropriate Phy*.c routine for your system. On OS/2 I
compile using the gcc command:-
gcc -fdollars-in-identifiers ods2.c,rms.c,direct.c,
access.c,device.c,cache.c,phyos2.c,vmstime.c
What can it do?
Basically ODS2 provides cut down DIRECTORY, COPY and
SEARCH commands for VMS volumes on non-VMS systems. These
can be used to find out what is on a VMS volume, and copy
files onto the local file sytem.
What file types?
Basically ODS2 can only deal with sequential files. I do not
have information on how indexed file types are constructed,
and relative files are of limited interest.
What about volume sets?
ODS2 does contain support for multi-volume sets. However there
is no checking that the correct volumes have been specified and
error handling is very fragile. You should ensure that you
specify volume set mount commands very carefully!
What about ODS5?
Sorry, but I have no idea! I have not seen any ODS5 information
or specifications. Most likely this program will fall in a heap
when presented with an ODS5 disk volume.
What about bugs?
There are plenty!! This code has been tested for several hours
by a single developer/user on one workstation (absolutely no
testing or input from any other person up to this point!).
Contrast this to the VMS filesystem which has had hundreds of
developers, millions of users, and has run on about 500,000
systems over the last 20 years!! I would hope to fix some of
the more severe limitations and provide better error handling
fairly soon, perhaps even put some comments into the code?
Maybe the next release might have fewer bugs?
It is free?
Yeap! It is provided 'as is' to help people in the VMS
community. However there is NO SUPPORT! I will try to fix
any reported problems, but as I really only get to work on
it while the kids are at Scouts on Monday nights, fixes
happen slowly! But if you have comments or suggestions then
please feel free to mail me!
Can I use the code?
Yeap! You can use and modify the code provided that you
acknowledge the author in the source of any modules which use
any part of this code. I would also appreciate, where possible,
being sent any enhancements for my own use.
Can I call the routines from my program?
You should be able to. Many of the modules follow an 'RMS'
sort of standard, and programs which only ever read RMS files
from C might be converted to read VMS volumes on another platform
without too much effort. In addition to the RMSish interface,
it would not be difficult to package up an $ASSIGN/$QIOW interface
for common file operations...
What is the status of ODS2?
This is the first release - actually more like a prototype
than an real release! But it may generate useful feedback and
possibly be useful to others the way it is? However if you are
tempted to use this version for real file transfers, DO YOUR OWN
TESTING first! This program may not have encountered volumes and
files like yours and could easily generate garbage results!!!
Is more work happening?
Yes! I find the program very useful moving stuff from my
VAXstation to my PC. I would like to be able to write ODS2 volumes
so that I can move files in the other direction! And yes I hope
to generally improve the code - particularly in the area of error
handling!
Can I make a suggestion?
You sure can! If you see something which needs improvement then
let me know. It may be more interesting than whatever I am doing now!
In fact if I don't hear from anyone then I might even loose interest!
Can I see a command sample?
Sure:-
C:> ODS2
ODS2 v1.2
$> mount E:,F:
%MOUNT-I-MOUNTED, Volume FOX1 mounted on E:
%MOUNT-I-MOUNTED, Volume FOX2 mounted on F:
$> direct/file E:[*...]
Directory E:[PNANKERVIS]
3MONTH.LOWUSE;1 (51,20,2)
ACCTEST.COM;1 (137,4,1)
ACCTEST.EXE;1 (53,4,2)
.....
$> set default E:[sys0.sysmgr]
$> dir [-.sys*...].%
.....
$> copy *.c *.*
%COPY-S-COPIED, E:[SYS0.SYSMGR]ACCESS.C;1 copied to ACCESS.C (3 records)
....
$> show time
24-MAR-1998 20:15:23.5
$> dismount E:
$> exit
What commands are supported?
A summary is:-
mount DRIVE:[,DRIVE:...]
directory [/file|/size|/date] [FILE-SPEC]
copy FILE-SPEC OUTPUT-FILE
dismount DRIVE:
search FILE-SPEC STRING
set default DIR-SPEC
show default
show time
exit
Note - DRIVE: is normally the native system drive name,
for example D: might be a CD on a PC - xxx: might be
/dev/xxx on a Unix system.
- when a list of drives is specified on the mount command
they are assumed to contain a single valid volume set
(this is not validated!!)
- file-spec is in the usual VMS syntax and may contain
wildcards (for example A:[-.*obj%%...]*abc*.obj;-2)
Who would write this?
Me! Maybe it will become the basis of something more? If you
have suggestions or want to know more then please mail me at
paulnank@au1.ibm.com
Thanks for listening!
Paul Nankervis

BIN
putr/putr.com Normal file

Binary file not shown.

930
putr/putr.txt Normal file
View File

@@ -0,0 +1,930 @@
PUTR V2.01
FILE TRANSFER PROGRAM
Copyright (C) 1995-2001 by John Wilson
All rights reserved
Release date: 05-Sep-2001
PUTR is a copyrighted but freely distributable utility for
transferring files between various file systems and various
media. It is named after PUTR.SAV (Peripheral Utility Transfer
Routines), the utility which performs the same function under
the DEC TSS/8.24 operating system for the PDP-8.
This program is a companion to the D Bit "Ersatz-11" PDP-11
emulation package, which emulates a broad range of PDP-11 CPU
and peripheral models at greatly increased speed. A demo
version (with reduced features) is available for free download,
it may be used for 30-day commercial evaluation or unlimited
hobby use. See www.dbit.com for information. PUTR is generally
compatible with other emulators and coprocessors as well, and
can transfer files between PCs and real PDP-11s and PDP-8s using
a variety of media. Multiple foreign volumes can be mounted at
once, and files can be copied directly between them (or within a
single foreign volume) in one step without having to do separate
extract and insert operations using the PC disk as intermediate
storage.
The file systems currently fully supported are RT-11,
RSTS/E, DOS/BATCH, XXDP+, OS/8 (and OS/78 etc.), PUTR (TSS/8
DECtape utility), and PC-DOS. PUTR can also read Files-11 ODS-1
file systems (i.e. disks from RSX-11M, RSX-11M-PLUS, IAS, and
P/OS) and TSS/8.24 file systems. COS-310 disks have the same
structure as OS/8 disks, however the text file format is
different and is currently not supported by PUTR. COS-310
binary files may be transferred the same as OS/8 binary files.
All file systems other than PC-DOS must be logically
mounted and assigned a logical device name before use. This is
done with the MOUNT command. PUTR is mainly intended to work on
logical devices contained in disk image files (normally a
block-by-block copy of the foreign disk), but it also supports
raw SCSI disks (through an ASPI driver), DEC TU58 tape drives
(plugged into a COM port), RX50 (including a double-sided
variant) and RX33 floppy disks or RX01/02/03 26-sector workalike
disks mounted on a 1.2 MB drive, and RX24, RX23, and RX26 720
KB/1.44 MB/2.88 MB disks on an appropriate 3.5" drive (even
though none of these was supported by standard DEC controllers
on machines using these file systems).
PUTR can format any of these types of floppy disks. Note
that most PC floppy controllers don't work correctly in single
density mode, but some chips made by SMC, WD, Goldstar, Intel
(but not the 82078), and National Semiconductor are known to
work. On a controller with a working single density mode, the
RX01 format is exactly compatible with genuine RX01 disks
(i.e. IBM 3740 format) mounted in an 8" drive connected in place
of a 1.2 MB one, using an adapter such as D Bit's "FDADAP" board
(see http://www.dbit.com/fdadap.html for information). The
"RX02" format used by PUTR is actually IBM System 34 format,
since DEC's 8" DD disks use a strange combination of SD headers
with non-standard ID marks, and DD data fields, that can't be
accessed with a standard PC FDC regardless of the software used.
The 26-sector 5.25" disk formats are compatible with those used
by Ersatz-11.
FILENAMES
=========
[ldevu:][dir][filename]
As much as possible, the filename syntax is intended to look
similar to that of the host operating system for the volume on
which the file is located.
The ldevu: parameter is the logical device and unit number where
the file is located. The device name is one or two letters with
an optional unit number in the range 0-255, so that DOS-style
drive names like "X:" or DEC-style drive names like "SY:" or
"DL0:" are possible. Logical devices are mounted using the
MOUNT command, or they may be PC-DOS drives (which are all
implicitly mounted under the native file system (i.e. PC-DOS)).
The device name syntax is intended to mimic that of the DEC
PDP-11 OSes for convenience only, at the moment no significance
is attached to the device name (different units of the same
device name have nothing to do with each other, and for example
DL0: need not be an RL01/02 image). This may change. If the
ldevu: parameter is omitted, the current logged-in logical
device is assumed (you log into a device by typing the device
name and a colon at the prompt, just like in PC-DOS).
The dir parameter is the directory in which the file is located
(by default, the current working directory on that logical
device). With PC-DOS drives this is the usual sequence of
directory names separated by \ (or / if that isn't your
SWITCHAR). RT-11 drives use the same syntax as PC-DOS, to refer
to nested logical disk files (LD:); the default extension is
".DSK". "." and ".." are fake directory names and have the same
meanings as under PC-DOS. Note that PUTR doesn't assume that it
can tell the difference between a directory and an ordinary file
(because under RT-11 there is no difference), so all pathname
elements must end in \ (except the final one in a CD command).
So if you want to list the parent directory, type "DIR ..\"
instead of "DIR ..".
RSTS drives use directory names of the form [proj,prog], with
the project and programmer numbers in decimal. The
one-character logical names !, #, $, %, and & also work.
DOS/BATCH uses "[proj,prog]" directory names too but the numbers
are octal instead of decimal, and the directory name comes after
the filename instead of before it.
Files-11 drives (RSX etc.) use either numeric directory names of
the form [proj,prog], with the project and programmer numbers in
octal, or named directories with names like [USER]. PUTR
supports tree-structured directories, with names like
[USER.FILES.OLD]. P/OS is currently the only DEC PDP-11
operating system which implements tree-structured Files-11 ODS-1
disks.
The filename syntax depends on the file structure of the drive;
under all supported file structures it is of the form
"filename.ext", where the length of the filename and extension
have fixed limits for each OS. Note that the parsing and
wildcard matching routines make no assumptions about filename
syntax (except for adding default "*"s depending on whether they
see a "." anywhere in the filespec), so it is possible to fool
them. For example, typing "DIR ????????A.*" on a PC-DOS disk
will not give an error message, but it's impossible for anything
to match this spec. The wildcard parser is smarter than the one
in PC-DOS -- '*' and '?' really work the way they should (in
PC-DOS a '*' is equivalent to filling out the rest of the field
with '?'s instead of really matching 0 or more characters, and
in PC-DOS '?' will match a blank, which isn't true of most other
systems).
Note that each filename on an ODS-1 disk contains a version
number, which PUTR interprets as a decimal number. Some systems
use octal but that's a function of the operating system and not
the disk structure itself, so there's no way for PUTR to
auto-detect this. PUTR's wildcard lookup code is currently
operating system independent and does not give special treatment
to version numbers, they are regarded as simply being part of
the filename string. So in order to access a file on an ODS-1
disk, you must either use a wildcard that matches the ";n" on
the end of the filename, or explicitly specify a version number
(preceded by a semicolon). Otherwise PUTR's file search code
will not recognize it as a match against the file on the ODS-1
disk.
This also may cause trouble in output filenames. If X: is an
ODS-1 disk and C: is a DOS disk, the command "copy
x:[200,200]foo.txt;1 c:" will attempt to create a file named
"FOO.TXT;1" on the DOS C: drive. Most versions of DOS will
ignore everything after the first three letters of the filename
extension, however DR-DOS treats the semicolon character
specially, and considers everything after the semicolon to be a
password, which is used to lock the file. So on DR-DOS, the
above command will create a file which appears as "FOO.TXT" in a
directory listing, but you must use the name "FOO.TXT;1" to
access that file (or delete it). This can be worked around by
specifying the output filename explicitly, as in "copy
x:[200,200]foo.txt;1 c:foo.txt".
COMMANDS
========
PUTR is an interactive program with a simple command line
interface. Many of the basic file-related commands which work
at a DOS command prompt, such as DIR or TYPE or COPY, will also
work when typed at PUTR's command prompt. PUTR extends these
commands by allowing any mixture of real DOS drive letters, and
PUTR's own logical device names, to be used in file
specifications. There are also additional commands which allow
special file operations to be performed, which have no
equivalent in the DOS command language. In many cases, the
syntax follows that of the equivalent commands in DEC operating
systems.
A typical PUTR session starts with a MOUNT command for each
foreign volume which will be accessed, possibly preceded by
FORMAT and/or INITIALIZE commands to create these volumes if
they do not already exist. Then the user can use the familiar
CD, DIR, TYPE, COPY, COPY/B, and DELETE commands to manipulate
files. Finally, QUIT exits to DOS.
When PUTR is run, it looks for an indirect command file named
"PUTR.INI", first in the current directory, then in the
directory where the executable is located (for PC-DOS 3.0 and
later only). If found, this file is opened as an indirect
command file before the first command prompt. This is a
convenient place to put SET commands, and MOUNT commands for the
disk image file(s) that you usually use.
------------------------------------------------------------
ldevu:
Simply typing a logical device name (with the colon) on a line
by itself, switches the "logged-in" drive to that device, just
as in PC-DOS or CP/M. This drive (and its current working
directory) will now appear in PUTR's prompt, and it will be used
as the default for all file specifications which do not include
an explicit drive name.
------------------------------------------------------------
@ filename[.CMD]
Redirects input so that commands come from the specified
indirect command file (with default extension ".CMD"). Indirect
files chain rather than nesting, so if an "@" command appears
inside an indirect file the file is closed and new input comes
from the specified file. At end of file input reverts to the
keyboard.
------------------------------------------------------------
BOOT ldevu:
On RT-11 volumes only, makes a volume bootable. The volume must
contain the needed .SYS files (monitor, system device handler,
TT: device handler), there are prompts that let you choose which
monitor to boot and which device handler the bootstrap should be
for. At each prompt you may enter a blank line to display a
list of all .SYS files on the volume, or a filename (default
extension ".SYS") to use. The action performed is exactly
equivalent to COPY/BOOT under RT-11.
------------------------------------------------------------
CD ldevu:dir
Changes the current working directory on the specified drive
(default is the current logged-in drive). If no directory is
given the current working directory is displayed. For RT-11
drives, logical disks (*.DSK) are made to look like
subdirectories so you can CD into them too (and use CD .. to get
out).
------------------------------------------------------------
CLS
Clears the screen.
------------------------------------------------------------
COPY[/BINARY][/OVERRIDE] ldevu:inspec ldevu:outspec
Copies the specified file(s), converting between file systems if
necessary. Files are assumed to be ASCII (NULs are squeezed
out, two 12-bit words are unpacked to three 8-bit characters,
etc.) unless the /BINARY switch is given; this default may be
changed with the SET COPY command. If an output file has the
same name as an existing file in the same directory, then the
existing file is deleted, unless it is protected; the /OVERRIDE
switch overrides this protection. Not all file systems support
protection. In a binary copy between 12- and 16-bit media, the
12-bit words are considered to be right-justified in 16-bit
words (PDP-11 byte order); the remaining four bits are ignored
on input and written as 0 on output.
Additional COPY switches are useful when writing into a RSTS/E
file system. /CLUSTERSIZE:n writes the output file with the
specified cluster size, instead of the pack cluster size. This
value is ignored unless it is a power of two, between the pack
cluster size and 256, inclusive. Also the /CONTIGUOUS switch
writes the output file as a contiguous file. Ideally this
switch would work with DOS/BATCH volumes too, but it is not yet
implemented.
Note that unlike the COPY commands in DOS or RT-11, this command
cannot concatenate multiple input files into one output file.
------------------------------------------------------------
COPY/DEVICE[/FILES][/BINARY] ldevu:[inspec] ldevu:[outspec]
Does an image copy from one device to another, or between a
device and a file. By default the copy is done in logical block
order, which is to say the 512-byte blocks are copied in order
starting at block 0. If you're copying a floppy disk (or an
image of one) then adding a /BINARY switch tells PUTR to copy in
physical sector order, starting with cylinder 0 head 0 sector 1,
and proceeding in sequential sector order, copying both surfaces
of each cylinder (if double sided) before proceeding to the next
cylinder. This copies all sectors of the disk, even those not
used by the DEC interleave schemes (on RX01, RX02, and RX03
disks, DEC leaves out track 0), and the resulting image files
are more likely to be in the right order if they aren't really
DEC disks. This use of /BINARY is not affected by the SET COPY
command.
------------------------------------------------------------
DELETE[/NOQUERY][/OVERRIDE] ldevu:filespec
Deletes the specified file(s), prompting before each unless
/NOQUERY is specified. If a file is protected, it is not
deleted unless the /OVERRIDE switch is given.
------------------------------------------------------------
DIRECTORY ldevu:wildcard [/FULL]
Displays a directory of the indicated file(s). /FULL gives the
starting block numbers of files as well on OS/8 or RT-11
volumes.
------------------------------------------------------------
DISMOUNT ldevu: [/UNLOAD]
Undoes the effect of a MOUNT command (q.v.). Closes any image
file associated with the logical device, or releases the COM
port or floppy drive or SCSI device, and deletes the logical
name definition. /UNLOAD ejects the disk on SCSI drives that
support this.
------------------------------------------------------------
EXIT
Returns to PC-DOS.
------------------------------------------------------------
FORMAT d: /devtype /ostype
Formats the disk in PC-DOS floppy drive d: to the type specified
by /devtype (/RX01, /RX02, /RX03, /RX23, /RX24, /RX26, /RX33,
/RX50, /RX52 -- default depends on drive type and is /RX50 for
1.2 MB drives or if the drive type is unknown). The /ostype
switch is optional and tells PUTR to write a blank directory
structure for the specified OS (see the INITIALIZE command). It
may also affect the interleave and skew used for formating, if
appropriate for that OS.
Note that for RX50 format, double density disks (e.g. PC 360 KB
disks) should be used rather than the PC high density 1.2 MB
disks. Opinion is divided as to whether the hub rings should be
peeled off before use -- as they age they may slide slightly out
of place so that the disk doesn't center properly, but then
again they're there to protect the disk and without them it's
more likely to get damaged. In any case the 1.2 MB disks don't
erase/rewrite properly in double density mode (RX50s are double
density disks), even if they appear to format OK (which might
happen if they were bulk erased first) they can't be trusted as
RX50s.
------------------------------------------------------------
FORMAT dev:filename /devtype /ostype
Creates an image file of the specified device type. The file is
initialized to zeros and an empty bad sector file is written if
appropriate (you will be prompted for a pack serial number for
device types that have them). As above, if /ostype is specified
then a blank directory is written.
If no device type is given then PUTR assumes nothing and just
prompts for the file size and creates a zeroed file of that
size. The value entered for the size should be a decimal
integer, optionally followed by the units the size represents;
if no unit is specified then the number is assumed to be the
number of bytes. Examples of the possibilities are, "100" means
100 bytes, "100 BLOCKS" means 100 blocks (512 bytes each), "100
KB" means 100 KB, "100 MB" means 100 MB (1 MB = 2**20 bytes),
and "100 GB" would mean 100 GB (1 GB = 2**30 bytes) except that
that exceeds the 2 GB limit on the size of a single DOS file.
Note that only integers may be used, so you can't say "1.44 MB"
or "2.1 GB". Those might not mean what you intend anyway, note
that 2.1 GB is not equal to 2100 MB (unless you're talking about
"marketing" numbers where MB/GB mean 10**6/10**9 instead of the
usual 2**20/2**30), so it's probably better to spell it out in
smaller units.
------------------------------------------------------------
INITIALIZE vol /devtype /ostype
Writes a blank directory on the specified volume or image file
(only /OS8, /PUTR, and /RT11 are allowed as /ostype switches at
this time). Prompts for any needed information. "vol" is a
file, floppy drive, SCSI device, or COM port name the same as in
FORMAT and MOUNT. For initializing RT-11 volumes, there is a
"/SEGMENTS:n" switch which overrides the default number of
directory segments created. The default depends on size of
volume, using the same rules as with RT-11's own DUP.SAV (which
implements its INITIALIZE command).
------------------------------------------------------------
MOUNT ldevu: image /devtype /ostype
Mounts a disk image, and attaches it to logical device name for
later use in other PUTR commands. "ldevu:" is a logical device
name (1 or 2 letters) and optional unit number. The device name
is arbitrary, but future versions of PUTR may change so that the
device name dictates the emulation (i.e. "DL1:" must be an RL01
or RL02) since that will make it possible to have useful
defaults for /devtype in case file size alone isn't enough to
tell.
"image" is the location of the disk image. Possibilities are as
follows:
[d:][path\]filename[.DSK] (name of a PC file)
The specified file contains a raw image of the disk.
This is known as an "image file" or "container file",
and is commonly obtained by downloading a disk from a
live machine over a serial or network connection, or
taking a snapshot of a SCSI disk, although PUTR can
also create image files from scratch itself (see
FORMAT).
d: (name of a PC floppy drive)
The raw floppy disk is used to hold the volume. This
should not be confused with an image file on a DOS
diskette, the disk uses the foreign file system and in
most cases will interchange with the foreign machine.
In a MOUNT command, if the "ldevu:" logical device
name is omitted, the floppy name will be used. For
example you may "MOUNT B: /RT11 /RX50" and then "DIR
B:".
SCSIhtl: (SCSI disk)
This form allows a raw SCSI disk to be mounted using a
foreign file system. The "SCSIhtl:" device name
specifies a SCSI disk (accessed through an ASPI
manager) at host adapter "h" (A=0, B=1, etc.), target
"t", and LUN "l", where h, t, and l (as well as the
underscore character) are all optional (the defaults
are "SCSIA00:"). On most systems there will be only
one SCSI host adapter, and most disks have only one
logical unit, so in most cases the device name may be
something like "SCSI5:", which specifies SCSI target
#5.
Note that some DOS ASPI drivers exist which make
non-SCSI devices look like SCSI drives. These should
work fine with PUTR, just pretend it's a SCSI drive.
An example is the ASPIATAP.SYS used with IDE/ATAPI
versions of the Iomega Zip drive, which makes the
drive look as if it's SCSI target 1, so
"SCSI1:" refers to the raw Zip drive in this case.
CDROMx: (raw CD-ROM drive)
This name can be used to open a raw CD-ROM, using the
usual MSCDEX.EXE interface (or NWCDEX.EXE under
DR-DOS). "x" is the CD-ROM drive's DOS drive letter.
Note that the MSCDEX emulation provided in Windows 95
and Windows 98 does not allow access to the first
sixteen sectors of the disk, which will not allow
PDP-11 format disks to work, except for non-zero RT-11
partitions. The workaround is to use plain DOS, or
else use a SCSI CD-ROM drive with the SCSI: device
type.
COMn:bbbbb/DRIVE:u (TU58 tape drive)
This specifies an actual DEC TU58 drive connected to
COM port "n", at baud rate "bbbbb" (default is 38400),
unit u (0 or 1, default is 0).
The /devtype switch specifies the device type of the image; the
defaults are auto-sensed except for TU58 drives where obviously
the default is always /TU58. With image files the default
device type depends on the file size, and is the largest defined
device less than or equal to the file in length. With floppies
various reads are attempted to detect the disk type. Raw
CD-ROMs and SCSI disks always default to /MSCP since their size
probably has more to do with the physical drive than with
whatever DEC drive it's supposed to replace.
Possible switches are as follows:
/RX01 = RX01 disk, 5.25" RX01 workalike
/RX02 = 5.25" RX02 workalike
/RX03 = DS 5.25" RX02 workalike
NOTE: for image files of the above devices, the file
size is used to determine which disk type it is and
whether the file is a block-by-block image (as
obtained by a "COPY/DEVICE/FILES DY0: FLOPPY.IMG"
command under RT-11, for example) which has had
interleave and skew applied to it by the PDP-11 device
driver that read it, or a sector-by-sector image (as
might be obtained by any simple program that reads the
sectors off sequentially and puts them in order into a
file). Block-by-block image files of 8" disks are
slightly smaller because the DEC interleave/skew
scheme skips track 0.
/RX23 = 1.44 MB 3.5" disk
/RX24 = 720 KB 3.5" disk
/RX26 = 2.88 MB 3.5" disk
/RX33 = 1.2 MB 5.25" disk
/RX50 = 400 KB 5.25" disk
NOTE: RX50 image files are the same size whether they
have interleave or not, so PUTR tries it both ways
while trying to guess the OS type.
/RX52 = DS RX50, 800 KB 5.25" disk (PUTR's own name)
The following switches are also supported: /MSCP, /RA60, /RA70,
/RA71, /RA72, /RA73, /RA80, /RA81, /RA82, /RA90, /RA92, /RD32,
/RD51, /RD52, /RD53, /RD54, /RK02, /RK05, /RK06, /RK07, /RL01,
/RL02, /RM02, /RM03, /RM05, /RM80, /RP02, /RP03, /RP04, /RP05,
/RP06, /RP07, /RS03, /RS04, /RS08, /TU56, /TU58. These switches
set the device type to the indicated DEC drive model. Since
there is no way to connect most of these devices directly to a
PC (unlike floppies), the effect of these switches is to specify
the exact size of the volume. Also, for the FORMAT command,
there is special handling of RL01, RL02, RK06, and RK07 drives
for building a blank bad sector track and (in the case of RT-11)
deducting the correct amount from the volume size to allow for
driver-implemented replacement blocks. The /MSCP switch means
that the image is a generic disk device whose actual size should
be used, instead of assuming the size matches some particular
model of DEC disk drive.
The /ostype switch specifies the file structure on the device;
one of the switches below may be given. If none is specified
then PUTR performs tests to guess the disk format. If the
volume appears to have no known directory, or seems to be valid
for more than one of the supported file structures, then a
message is displayed and the volume is not mounted. Mounting a
disk with /FOREIGN would seem pointless (since no directory
operations are allowed), except that it makes it usable with the
COPY/DEVICE command so it can be used to transfer an image of
the disk to or from a file (or another identical disk).
File structure switches:
/FILES11 = Files-11 ODS-1, used by RSX-11M, RSX-11M-PLUS,
IAS, and P/OS. Support is currently read-only.
/RSTSE = RSTS/E disk structure (RDS 0.0, 1.1, or 1.2).
/RT11 = RT-11 disk structure (/PARTITION:n switch selects
MSCP partition number, default is 0).
/OS8 = OS/8, OS/78, OS/278, COS-310 disk structure
(/PARTITION:n switch selects RK05 partition number,
default is 0).
/PUTR = TSS/8 PUTR.SAV DECtape format, similar to OS/8
format but with software 11:1 block interleave,
encoded 3-letter filename extensions, and a different
way of packing 7-bit ASCII characters into 12-bit
words.
Note: even though the regular OS/8 format uses 128
words of each 129-word DECtape block, the PUTR.SAV
format needs all 129 words (so a full 1474-block
DECtape image is 190,146 words or 380,292 bytes)
because some of the blocks are recorded in reverse, so
that the last 128 words of those blocks are used
rather than the first.
/TSS8 = TSS/8.24 system disk format (DS32 or RS08).
Currently read-only. Works only with disks built with
256-word segments, which is the most common size.
Probably not compatible with disks written by older
versions of the TSS/8 monitor, but nothing else was
available for testing. Filename extensions (chosen
from a fixed list of eleven) were a late addition, and
the base year for file dates was changed from 1964 to
1974 somewhere along the way (the new format ran out
in 1984).
The location of the MFD depends on the value of the
JOBMAX build parameter. This value may be specified
using the "/PARTITION:n" switch (where n is between 1
and 25 decimal). If this switch is omitted, PUTR will
search every 4 K words until it finds what looks like
a valid MFD.
/DOSBATCH = DOS/BATCH file structure.
/XXDP = XXDP+ file structure, a variant of DOS/BATCH format
used in late versions of the XXDP+ diagnostic package
(earlier versions of XXDP used exactly the DOS/BATCH
format, so they should be mounted with /DOSBATCH).
/FOREIGN = some other file structure, device is accessed in
16-bit mode and the only possible operations are COPY
/DEV and COPY /FILE /DEV.
There are a few miscellaneous MOUNT switches. /INTERLEAVE and
/NOINTERLEAVE tell whether an image file is interleaved (i.e. a
block-by-block copy of a floppy disk so the data are in block
order, not sector order) or non-interleaved (i.e. a
sector-by-sector copy so the data are in sector order). The
default is to guess based on the image file size (or prompt in
the case of FORMAT, which takes the same switches).
/PARTITION:n specifies the partition number for RT-11 MSCP disks
or OS/8 RK05 disks (default is 0). /RONLY and /RW tell whether
the device should be mounted for read-only or read/write access.
The default is read/write.
All of the above switches may be given in any order.
------------------------------------------------------------
QUIT
Returns to PC-DOS.
------------------------------------------------------------
SET x: type
Sets the drive type for one of the four possible PC floppy
drives A:-D: (note that actual PCs rarely have more than one or
two floppy drives). The type must be RX01, RX02, RX03, RX50,
RX33, RX24, RX23, or RX26. The default value for each drive is
whatever was stored in CMOS memory by the ROM BIOS setup
utility.
This command may be useful when the drive types stored in CMOS
RAM are incorrect for some reason. It's also helpful when an 8"
drive, or a real DEC RX50 drive, has been attached to the PC
using a D Bit "FDADAP" adapter, or something equivalent. There
is no standard for representing these drive types in CMOS RAM.
Using real RX50 drives (or other 300 RPM quad-density drives
such as the Tandon TM100-3 and TM100-4) is different from RX33s
(which is what PUTR calls regular PC 1.2 MB drives) because the
motor speed is slower, so the FDC chip must be programmed for a
lower data rate to match.
------------------------------------------------------------
SET COPY {ASCII | BINARY}
Sets the default transfer mode for the COPY command (initially
ASCII). Intended mainly for use in the PUTR.INI command file.
------------------------------------------------------------
SET DISMOUNT {NOUNLOAD | UNLOAD}
Sets the default unload action of DISMOUNTs, both explicit, and
implied by QUITting, or reMOUNTing the pseudo-device as
something else. Default is NOUNLOAD. Intended for use in
PUTR.INI with drive models where the disk shouldn't be left in
the drive when it's powered off.
------------------------------------------------------------
SET FDC {COMPATICARD | GENERIC}
Tells PUTR whether your floppy disk controller is a Micro
Solutions CompatiCard IV, or just a generic PC floppy
controller. If it is a CompatiCard, PUTR maintains the TG43
signal (for 8" drives) by writing to port 3F0h; normal FDCs
have no writable port at that address and don't do anything when
it gets written so the default is COMPATICARD to cover
everything, but if your FDC does strange things when that port
is written you should SET FDC GENERIC to disable the writes.
This setting doesn't matter if you're using the D Bit "FDADAP"
floppy disk adapter board (see http://www.dbit.com/fdadap.html)
to connect to an 8" drive. The board has an on-board
microcontroller which transparently monitors the drive bus and
drives the TG43 signal correctly for each drive without any
software help.
------------------------------------------------------------
SET MORE {OFF | ON}
Turns **MORE** processing on or off; the default is on, so
output pauses at the end of every screen. As above, intended
mainly for use in PUTR.INI.
------------------------------------------------------------
SHOW ldevu:
Shows the medium and file system types for the specified logical
device.
------------------------------------------------------------
TYPE ldevu:wildcard
Types the specified file(s) on the terminal, printing the
filename(s) first.
------------------------------------------------------------
WIPEOUT ldevu:dir
Writes zeros over all "< UNUSED >" areas so that disk image
files will compress smaller with GZIP (etc.) and/or transfer
faster with Kermit (etc.). Supported only for OS/8, PUTR, and
RT-11 volumes.
Example Operations
======= ==========
This section gives sample commands to accomplish common
operations. In these examples the PUTR prompt is shown as
"(C:\)>", whereas on your system it will show the actual
logged-in drive and current working directory.
------------------------------------------------------------
Formating RX50 disks (assuming B: is a 1.2 MB drive):
(C:\)>format b: /rx50
Press ENTER when ready...
(status is displayed during the format operation)
Format more disks (Y/N)? N
(or type Y to format more RX50s)
(C:\)>quit
------------------------------------------------------------
Copying PDP-11 image files to RX50s (B: is the 1.2 MB drive):
(C:\)>mount b: /rx50 /foreign
(C:\)>copy/file/dev disk1.dsk b:
(if you have more than one disk to copy, you may swap disks
and issue more COPY commands without having to repeat the
MOUNT command)
(C:\)>quit
------------------------------------------------------------
Creating blank container files:
Example 1 -- MSCP disk (user-selected size):
(C:\)>format du0.dsk /mscp
Are you sure (Y/N)? Y
File size (bytes): 10000 blocks
(C:\)>quit
Example 2 -- RL02 (size known by PUTR, has pack serial number):
(C:\)>format dl0.dsk /rl02
Are you sure (Y/N)? Y
Serial # [1234512345]: 666
(C:\)>quit
------------------------------------------------------------
Create a bootable RT-11 disk image from its component files:
All of the RT-11 files have been downloaded in binary mode, from
the PDP-11 into a PC directory named "C:\RT11".
(C:\)>format du0.dsk /mscp /rt11
Are you sure (Y/N)? Y
File size (bytes): 32 mb
Volume ID <RT11A>:
Owner name:
(C:\)>mount x: du0 /mscp
(C:\)>set more off
(avoids having to press space bar during the copy)
(C:\)>copy/b c:\rt11\*.* x:
(... lists all files being copied ...)
(C:\)>boot x:
Writing bootstrap on X:\
Monitor file [.SYS]: rt11xm
Device handler file [.SYS]: dlx
(substitute actual monitor and device handler filenames,
being careful to append "X" to the handler name when using
an XM monitor)
(C:\)>quit
File Formats
==== =======
Generally, the disk image files used by PUTR (typically with a
".DSK" extension) simply contain a byte-by-byte snapshot of the
entire disk, in physical sector order. For 12-bit images
(PDP-8, DECmate series), each 12-bit word is stored
right-justified in a 16-bit word in PDP-11 byte order.
There are several exceptions:
RX01, RX02, "RX03":
These may be accessed either as "block" images or as
"sector" images. Block images contain a snapshot of
the disk as seen through a PDP-8/PDP-11 device driver,
so there's no interleave, and track 0 does not appear
in the image file. Block images generally work the
same as images of any other type of drive, since DEC
used most styles of disks directly, without any kind
of soft interleave. Sector images are a snapshot of
the disk in raw sector order, including track 0, and
the data are in physical order, so soft interleave is
required to sort out the "cooked" blocks seen through
the host operating system.
Note that these disks have the same low-level format,
and thus the same sector image file format, in both
PDP-8 and PDP-11 systems. PDP-11s simply treat the
bytes as bytes, while PDP-8s perform packing and
unpacking of the 12-bit words so that (typically) 64
or 128 words are packed into the first 3/4 of the
sector, with the remainder ignored.
RX50, "RX52":
These disks have similar issues to the 8" disks, but
the details are different. The interleave schemes
wrap around the end of the disk to track 0, so track 0
is used in both the "block" and "sector" image file
formats, and the image file size is the same either
way. On 12-bit systems, the words are not packed
together in the first 3/4 of the sector, they're
individually right-justified in a PDP-11 word, so four
bits of each word are wasted but the data go all the
way to the end of the sector.
RK05 disk packs:
RK05 drives were used on both 12- and 16-bit systems.
The same drives work with both formats, but the packs
are different. 12-bit packs have 16 sectors per track
(1.6 MW total), and 16-bit packs have 12 sectors per
track (1.2 MW total). In both cases the sectors are
256 words each. Because of the 4 bits of padding for
every word in a 12-bit image, PUTR uses 3,276,800
bytes to store a 12-bit RK05 image, vs. only 2,457,600
bytes for a 16-bit RK05 image.
555, TU55, TU56 DECtape:
DECtapes were used on a wide variety of machines with
different word sizes. PUTR stores DECtape image files
in three different formats.
PDP-11s use DECtapes formatted in 18-bit mode (the
high 2 bits are ignored), giving 578 blocks of 256
words each. PUTR stores those as byte-for-byte images
with an image file size of 295,936 bytes.
PDP-8 DECtapes have 1474 blocks of 129 words each.
Most file systems actually use only 128 words per
block, but the DECtape hardware doesn't allow that
block size because it uses 6-bit mark codes which are
recorded in a single track alongside three data
tracks, so a block's data field must be a multiple of
18 bits. OS/8 always uses only the first 128 words of
each sector, so the 129th word can be safely omitted
from an image file. With PUTR's usual packing (each
12-bit word is right-justified in a 16-bit PDP-11
word), this gives an image file size of 377,344 bytes.
However, you may wish to include the 129th word just
to be safe. This is definitely required for TSS/8
PUTR.SAV format tapes. Even though they use only 128
words per block, they are recorded using an interleave
scheme in which 45% of the blocks are recorded
backwards, so the first 128 words of the block become
the last 128 words of the block when read forwards.
Therefore all 129 words must be preserved, because the
image file is considered to be accessed in the forward
direction (i.e. that's what you should do when taking
a snapshot of a tape). This gives a file size of
380,292 bytes.
PUTR tests the file size when opening an existing
image, and chooses the most appropriate size when
creating a new image file with the FORMAT command, so
generally it will do the right thing with all three
file sizes.
Note:
"D Bit", "Ersatz", and "E11" are trademarks of Digby's Bitpile,
Inc. All other trademarks are used for identification purposes
only and are the property of their respective owners.
John Wilson
Digby's Bitpile, Inc. DBA D Bit
11 Bank Street
Troy, NY 12180
USA
+1 (518) 271-6824
+1 (518) 272-3853 fax (call above number first)
<wilson@dbit.com>
www.dbit.com

40
putr/readme.txt Normal file
View File

@@ -0,0 +1,40 @@
This directory contains PUTR.COM V2.01, a program for accessing DEC file
systems from DOS PCs.
Supported file systems:
DOS/BATCH (both disks and DECtapes)
Files-11 (read only)
OS/8
RSTS/E
RT-11
TSS/8.24 DECtape (PUTR.SAV format)
TSS/8.24 system disk (read only)
XXDP+
Supported media:
disk image files (can apply/remove interleave for floppy image files)
RX33, RX50 floppies in 1.2MB drive
RX01/02/03 workalike floppies in 1.2MB drive
RX23, RX24, RX26 disks in 3.5" 720KB/1.44MB/2.88MB drive
RX01 real floppies in 8" drive with appropriate controller
TU58 drives plugged into PC COM port
SCSI disks through ASPI driver
CD-ROM
(Catweasel/ISA driver is unfinished and therefore undocumented)
The program accepts a subset of the usual DOS commands, but allows you to
MOUNT non-DOS disks (with a fake drive letter or "ddu:" style name). Once
you've mounted a foreign disk, you can "log in" to it just like a DOS disk,
and TYPE, COPY (including COPY /B), DIR etc. will work (no RENAME yet, sorry).
The program's basic point of pride is the fact that you can mount more than
one foreign disk at once, and they may be from different operating systems,
so you can copy file between foreign file systems w/o the intermediate step
of copying them into a DOS directory and back out again (especially handy if
space is tight and/or your files have dates before 01/01/1980).
By the way, whatever your stinking web browser may tell you, "putr.doc" is
a plain ASCII file! This shouldn't be a problem when accessing this server
via HTTP, because the server's MIME types file has this set up properly.
John Wilson wilson@dbit.com 05-Sep-2001