mirror of
https://github.com/open-simh/simtools.git
synced 2026-03-06 19:21:33 +00:00
simh tools
This commit is contained in:
111
config11/config11.c
Normal file
111
config11/config11.c
Normal 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
17
config11/config11.txt
Normal 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
108
converters/asc.c
Normal 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
14
converters/asc.txt
Normal 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
68
converters/dtos8cvt.c
Normal 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
13
converters/dtos8cvt.txt
Normal 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
97
converters/gt7cvt.c
Normal 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
69
converters/littcvt.c
Normal 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
94
converters/mtcvtfix.c
Normal 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
87
converters/mtcvtodd.c
Normal 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
81
converters/mtcvtv23.c
Normal 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
35
converters/mtcvtv23.txt
Normal 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
116
converters/sfmtcvt.c
Normal 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
76
converters/tp512cvt.c
Normal 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
3068
crossassemblers/macro1.c
Normal file
File diff suppressed because it is too large
Load Diff
12
crossassemblers/macro11/changes
Normal file
12
crossassemblers/macro11/changes
Normal 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.
|
||||
0
crossassemblers/macro11/depends
Normal file
0
crossassemblers/macro11/depends
Normal file
677
crossassemblers/macro11/dumpobj.c
Normal file
677
crossassemblers/macro11/dumpobj.c
Normal 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;
|
||||
}
|
||||
114
crossassemblers/macro11/dumpobj.dsp
Normal file
114
crossassemblers/macro11/dumpobj.dsp
Normal 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
|
||||
30
crossassemblers/macro11/license
Normal file
30
crossassemblers/macro11/license
Normal 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.
|
||||
6197
crossassemblers/macro11/macro11.c
Normal file
6197
crossassemblers/macro11/macro11.c
Normal file
File diff suppressed because it is too large
Load Diff
180
crossassemblers/macro11/macro11.dsp
Normal file
180
crossassemblers/macro11/macro11.dsp
Normal 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
|
||||
53
crossassemblers/macro11/macro11.dsw
Normal file
53
crossassemblers/macro11/macro11.dsw
Normal 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>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
39
crossassemblers/macro11/macro11.h
Normal file
39
crossassemblers/macro11/macro11.h
Normal 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
|
||||
38
crossassemblers/macro11/makefile
Normal file
38
crossassemblers/macro11/makefile
Normal 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
|
||||
319
crossassemblers/macro11/mlb.c
Normal file
319
crossassemblers/macro11/mlb.c
Normal 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);
|
||||
}
|
||||
}
|
||||
62
crossassemblers/macro11/mlb.h
Normal file
62
crossassemblers/macro11/mlb.h
Normal 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 */
|
||||
861
crossassemblers/macro11/object.c
Normal file
861
crossassemblers/macro11/object.c
Normal 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);
|
||||
}
|
||||
210
crossassemblers/macro11/object.h
Normal file
210
crossassemblers/macro11/object.h
Normal 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 */
|
||||
117
crossassemblers/macro11/rad50.c
Normal file
117
crossassemblers/macro11/rad50.c
Normal 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] = ' ';
|
||||
}
|
||||
43
crossassemblers/macro11/rad50.h
Normal file
43
crossassemblers/macro11/rad50.h
Normal 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 */
|
||||
380
crossassemblers/macro11/stream2.c
Normal file
380
crossassemblers/macro11/stream2.c
Normal 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;
|
||||
}
|
||||
110
crossassemblers/macro11/stream2.h
Normal file
110
crossassemblers/macro11/stream2.h
Normal 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 */
|
||||
57
crossassemblers/macro11/todo
Normal file
57
crossassemblers/macro11/todo
Normal 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.
|
||||
|
||||
172
crossassemblers/macro11/util.c
Normal file
172
crossassemblers/macro11/util.c
Normal 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. */
|
||||
}
|
||||
56
crossassemblers/macro11/util.h
Normal file
56
crossassemblers/macro11/util.h
Normal 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
3083
crossassemblers/macro7.c
Normal file
File diff suppressed because it is too large
Load Diff
4251
crossassemblers/macro8x.c
Normal file
4251
crossassemblers/macro8x.c
Normal file
File diff suppressed because it is too large
Load Diff
636
extracters/backup/backup.c
Normal file
636
extracters/backup/backup.c
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
80
extracters/backup/backup.h
Normal file
80
extracters/backup/backup.h
Normal 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
|
||||
|
||||
91
extracters/backup/backup.txt
Normal file
91
extracters/backup/backup.txt
Normal 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
423
extracters/ckabstape.c
Normal 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
105
extracters/mmdir.c
Normal 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
130
extracters/mtdump.c
Normal 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
38
extracters/mtdump.txt
Normal 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.
|
||||
49
extracters/rawcopy/RawCopy.c
Normal file
49
extracters/rawcopy/RawCopy.c
Normal 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);
|
||||
}
|
||||
17
extracters/rawcopy/RawCopy.txt
Normal file
17
extracters/rawcopy/RawCopy.txt
Normal 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
95
extracters/sdsdump.c
Normal 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
175
ods2_readme.txt
Normal 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
BIN
putr/putr.com
Normal file
Binary file not shown.
930
putr/putr.txt
Normal file
930
putr/putr.txt
Normal 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
40
putr/readme.txt
Normal 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
|
||||
Reference in New Issue
Block a user