# Conflicts:
#	.gitignore
#	extracters/ods2/Makefile
This commit is contained in:
Timothe Litt
2022-10-10 12:03:53 -04:00
295 changed files with 88385 additions and 8170 deletions

2
.gitignore vendored
View File

@@ -1,6 +1,8 @@
\#*
*~
*.bak
*.d
*.dep
*.o
*.orig
*.vhd

View File

@@ -5,29 +5,17 @@ BIN=/usr/local/bin
INSTALL=install
CC=gcc
SUBDIRS=config11 converters crossassemblers extracters
.PHONY: all clean install uninstall
# Omitted: putr: has no sources.
all:
cd config11 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd converters && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd crossassemblers && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd extracters && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
for subdir in $(SUBDIRS); do \
$(MAKE) -C $$subdir CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"; \
done
clean:
cd config11 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd converters && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd crossassemblers && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd extracters && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
install:
cd config11 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd converters && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd crossassemblers && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd extracters && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
uninstall:
cd config11 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd converters && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd crossassemblers && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd extracters && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
clean install uninstall:
for subdir in $(SUBDIRS); do \
$(MAKE) -C $$subdir CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" $@; \
done

View File

@@ -50,7 +50,7 @@ hpasm | Assembler for the HP2100
macro1 | Assembler for the PDP-1
macro7 | Assembler for the PDP-7
macro8x | Assembler for the PDP-8
macro11 | Assembler for the PDP-11
macro11 | Assembler for the PDP-11. Synchronized from git `https://gitlab.com/Rhialto/macro11.git`; most recently from tag `macro11-v0.7.2`.
## Extracters
@@ -66,6 +66,7 @@ mmdir | List directory of Interdata MDM tape
mtdump | Dump the record structure of a SIMH, E11, TPC, or P7B
ods2 | Directory, Copy & Search commands for VMS ODS2 disk images
rawcopy | Create SIMH disk image from physical media on RAW device.
rstsflx | Manipulate PDP11 RSTS file systems.
sdsdump | Disassemble SDS SDS paper tape
tpdump | Dump files on IBM 1401 tape

View File

@@ -1,92 +1,22 @@
# all of these can be over-ridden on the "make" command line if they don't suit your environment.
CFLAGS="-O2 -Wall -Wshadow -Wextra -pedantic -Woverflow -Wstrict-overflow"
CFLAGS=-O2 -Wall -Wshadow -Wextra -pedantic -Woverflow -Wstrict-overflow
BIN=/usr/local/bin
INSTALL=install
CC=gcc
SUBDIRS=asc cosy decsys dtos8cvt fsio gt7cvt hpconvert indent littcvt m8376 \
mksimtape mt2tpc mtcvt23 mtcvtfix mtcvtodd noff sfmtcvt strrem strsub \
tar2mt tp512cvt tpc2mt
.PHONY: all clean install uninstall
all:
cd asc && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd dtos8cvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd hpconvert && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd littcvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd mt2tpc && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd mtcvtfix && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd noff && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd strrem && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd tar2mt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd tpc2mt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd decsys && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd gt7cvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd indent && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd m8376 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd mtcvt23 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd mtcvtodd && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd sfmtcvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd strsub && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd tp512cvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
for subdir in $(SUBDIRS); do \
$(MAKE) -C $$subdir CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"; \
done
clean:
cd asc && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd dtos8cvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd hpconvert && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd littcvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd mt2tpc && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd mtcvtfix && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd noff && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd strrem && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd tar2mt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd tpc2mt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd decsys && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd gt7cvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd indent && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd m8376 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd mtcvt23 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd mtcvtodd && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd sfmtcvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd strsub && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd tp512cvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
install:
cd asc && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd dtos8cvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd hpconvert && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd littcvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd mt2tpc && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd mtcvtfix && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd noff && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd strrem && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd tar2mt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd tpc2mt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd decsys && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd gt7cvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd indent && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd m8376 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd mtcvt23 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd mtcvtodd && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd sfmtcvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd strsub && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd tp512cvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
uninstall:
cd asc && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd dtos8cvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd hpconvert && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd littcvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd mt2tpc && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd mtcvtfix && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd noff && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd strrem && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd tar2mt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd tpc2mt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd decsys && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd gt7cvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd indent && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd m8376 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd mtcvt23 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd mtcvtodd && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd sfmtcvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd strsub && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd tp512cvt && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
clean install uninstall:
for subdir in $(SUBDIRS); do \
$(MAKE) -C $$subdir CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" $@; \
done

21
converters/cosy/Makefile Normal file
View File

@@ -0,0 +1,21 @@
# all of these can be over-ridden on the "make" command line if don't suit
# your environment
TOOL=cosy
CFLAGS=-O2 -Wall -Wshadow -Wextra -pedantic -Woverflow -Wstrict-overflow
BIN=/usr/local/bin
INSTALL=install
CC=gcc
$(TOOL): $(TOOL).c
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $(TOOL) $(TOOL).c $(LDLIBS)
.PHONY: clean install uninstall
clean:
rm -f $(TOOL)
install: $(TOOL)
$(INSTALL) -p -m u=rx,g=rx,o=rx $(TOOL) $(BIN)
uninstall:
rm -f $(BIN)/$(TOOL)

590
converters/cosy/cosy.c Normal file
View File

@@ -0,0 +1,590 @@
/* cosy.c: compress/decompress CDC1700 COSY format files
Copyright (c) 2015-2017, John Forecast
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
JOHN FORECAST 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 John Forecast shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from John Forecast.
*/
/*
* The CDC1700 COSY format is well documented with respect to the compression
* algorithm (Run length encoding of 3 - 62 consecutive blanks) but less so
* for the higher level COSY constructs. This program is written to handle
* COSY format files found on bitsavers.org. It operates in one of 2 modes:
*
* 1. Decompress a sequence of one or more COSY compressed decks. Each deck
* will start with a CSY/ card and end with a END/ card. If the input
* consists of a single compressed deck, the CSY/ and END/ cards may be
* omitted. If a deck name (e.g. "xxx") is provided on the CSY/ card,
* the output file will be named "deck_xxx", if an empty deck name is
* provided or the CSY/ card is missing, the output file will be named
* "nnnnn.deck" where nnnnn is the number of the deck within the input
* file. The CSY/ and END/ cards will not be passed through to the
* output file.
*
* 2. Compress a series of input decks, generating a single compressed COSY
* file. A CSY/ card will be prepended to each input file and a END/
* card will be appended. If the input file name is "deck_yyy" the deck
* name on the CSY/ card will be yyy. Any other input file name will leave
* the deck name empty on the CSY/ card. The output file will be padded
* to a multiple of 192 words (384 bytes).
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define PREFIX 0x5F
/*
* Record lengths.
*/
#define RECLEN 384
#define CARDLEN 80
char card[CARDLEN + 1], pad[RECLEN];
int idx = 0, outcount = 0;
int compress = 0;
#define VALID(c) ((c >= 0x20) && (c <= 0x5E) && (c != 0x26))
/*
* Pre-defined strings to start and end a COSY deck.
*/
char *csy = " CSY/";
char *end = " END/";
/*
* Compression table
*/
#define MAXSPACES 62
char *compr[MAXSPACES+1] = {
NULL, " ", " ",
"\x5F\x21", "\x5F\x22", "\x5F\x23", "\x5F\x24", "\x5F\x25",
"\x5F\x27", "\x5F\x28", "\x5F\x29", "\x5F\x2A",
"\x5F\x2B", "\x5F\x2C", "\x5F\x2D", "\x5F\x2E",
"\x5F\x2F", "\x5F\x30", "\x5F\x31", "\x5F\x32",
"\x5F\x33", "\x5F\x34", "\x5F\x35", "\x5F\x36",
"\x5F\x37", "\x5F\x38", "\x5F\x39", "\x5F\x3A",
"\x5F\x3B", "\x5F\x3C", "\x5F\x3D", "\x5F\x3E",
"\x5F\x3F", "\x5F\x40", "\x5F\x41", "\x5F\x42",
"\x5F\x43", "\x5F\x44", "\x5F\x45", "\x5F\x46",
"\x5F\x47", "\x5F\x48", "\x5F\x49", "\x5F\x4A",
"\x5F\x4B", "\x5F\x4C", "\x5F\x4D", "\x5F\x4E",
"\x5F\x4F", "\x5F\x50", "\x5F\x51", "\x5F\x52",
"\x5F\x53", "\x5F\x54", "\x5F\x55", "\x5F\x56",
"\x5F\x57", "\x5F\x58", "\x5F\x59", "\x5F\x5A",
"\x5F\x5B", "\x5F\x5C", "\x5F\x5D"
};
int doCompress(FILE *, int, char **), doDecompress(FILE *);
/*++
* compressCard
*
* Write the current card, in COSY compressed format, to the destination
* COSY file.
*
* Inputs:
*
* dest - Destination COSY file
*
* Outputs:
*
* ...
*
* Returns:
*
* Exit status:
* 0 - Success
* 3 - File write error
* 4 - Invalid input character
*
--*/
int compressCard(
FILE *dest
)
{
int i, spcount = 0, len = strlen(card);
for (i = 0; i < len; i++) {
if (!VALID(card[i]))
return 4;
if (card[i] != ' ') {
if (spcount != 0) {
size_t l = strlen(compr[spcount]);
if (fwrite(compr[spcount], sizeof(char), l, dest) != l)
return 3;
outcount += l;
spcount = 0;
}
if (fputc(card[i], dest) == EOF)
return 3;
outcount++;
} else {
if (++spcount == MAXSPACES) {
size_t l = strlen(compr[spcount]);
if (fwrite(compr[spcount], sizeof(char), l, dest) != l)
return 3;
outcount += l;
spcount = 0;
}
}
}
/*
* Terminate the card image.
*/
fwrite("\x5F\x5E", sizeof(char), 2, dest);
outcount += 2;
return 0;
}
/*++
* decompressCard
*
* Read the next card image from a source file while performing COSY
* decompression. The card image will be null terminated.
*
* Inputs:
*
* src - Source COSY file
*
* Outputs:
*
* ...
*
* Returns:
*
* 0 - Card image successfully read
* -1 - EOF read
* -2 - End of deck read
*
--*/
int decompressCard(
FILE *src
)
{
int ch, i, spcount;
idx = 0;
while ((ch = fgetc(src)) != -1) {
if (ch == 0)
continue;
if (ch == PREFIX) {
if ((ch = fgetc(src)) == -1)
break;
switch (ch) {
case 0x21: case 0x22: case 0x23: case 0x24: case 0x25:
spcount = ch - 0x21 + 3;
goto fill;
case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B:
case 0x2C: case 0x2D: case 0x2E: case 0x2F: case 0x30:
case 0x31: case 0x32: case 0x33: case 0x34: case 0x35:
case 0x36: case 0x37: case 0x38: case 0x39: case 0x3A:
case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F:
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44:
case 0x45: case 0x46: case 0x47: case 0x48: case 0x49:
case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E:
case 0x4F: case 0x50: case 0x51: case 0x52: case 0x53:
case 0x54: case 0x55: case 0x56: case 0x57: case 0x58:
case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D:
spcount = ch - 0x27 + 8;
fill:
for (i = 0; i< spcount; i++) {
if (idx != CARDLEN)
card[idx++] = ' ';
}
break;
case 0x5E:
card[idx] = '\0';
return 0;
case 0x5F:
card[idx] = '\0';
return -2;
}
} else {
if (idx != CARDLEN)
card[idx++] = ch;
}
}
card[idx] = '\0';
return -1;
}
/*++
* writeCard
*
* Remove trailing spaces from the card image and write the resulting line
* to the destination file with a terminating newline character.
*
* Inputs:
*
* dest - Destination file
*
* Outputs:
*
* ...
*
* Returns:
*
* 0 - write was successful
* -1 - error on write
*
--*/
int writeCard(
FILE *dest
)
{
/*
* Remove trailing spaces.
*/
while (idx && (card[idx - 1] == ' '))
card[--idx] = '\0';
if (fprintf(dest, "%s\n", card) < 0)
return -1;
return 0;
}
/*++
* usage
*
* Display a usage message on stderr and exit.
*
* Inputs:
*
* None
*
* Outputs:
*
* None
*
* Returns:
*
* Never returns
*
--*/
void usage(void)
{
fprintf(stderr,
"Usage: cosy [-cd] <cosyfile> [file ...]\n");
fprintf(stderr,
" Compress/decompress a COSY file\n");
fprintf(stderr, "\nSwitches:\n\n");
fprintf(stderr, " -c Perform COSY compression\n");
fprintf(stderr, " -d Perform COSY decompression (the default)\n");
exit(1);
}
/*++
* main
*
* Entry point for cosy program.
*
* Inputs:
*
* argc - # of supplied arguments
* argv - Array of argument strings
*
* Outputs:
*
* None
*
* Returns:
*
* Exit status
*
--*/
int main(
int argc,
char *argv[]
)
{
int ch;
FILE *cosy;
while ((ch = getopt(argc, argv, "cd")) != -1) {
switch (ch) {
case 'c':
compress = 1;
break;
case 'd':
compress = 0;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc < (compress ? 2 : 1))
usage();
/*
* Open the COSY file.
*/
if ((cosy = fopen(argv[0], compress ? "w" : "r")) == NULL) {
fprintf(stderr, "Failed to open COSY file - %s\n", argv[0]);
return 2;
}
argc--, argv++;
if (compress) {
return doCompress(cosy, argc, argv);
}
return doDecompress(cosy);
}
/*++
* doCompress
*
* Compress a sequence of 1 or more files into a single COSY file.
*
* Inputs:
*
* dest - Destination cosy file
* argc - # of source files to compress
* argv - Pointer to array of file names
*
* Outputs:
*
* ...
*
* Returns:
*
* Exit status:
* 0 - Success
* 2 - File open error
* 3 - File write error
* 4 - Invalid input character
*
--*/
int doCompress(
FILE *dest,
int argc,
char *argv[]
)
{
int status = 0;
unsigned int i;
char *filename;
FILE *src;
while (argc != 0) {
filename = argv[0];
if ((src = fopen(filename, "r")) == NULL) {
status = 2;
break;
}
/*
* Build a leading CSY/ card.
*/
strcpy(card, csy);
if (strncmp(filename, "deck_", 5) == 0) {
/*
* Possible deck name derived from filename.
*/
if (strlen(filename) <= 11) {
for (i = 5; i < strlen(filename); i++)
if (!VALID(filename[i]))
goto noname;
strncpy(card, &filename[5], strlen(filename) - 5);
goto named;
}
noname:
fprintf(stderr, "Unable to use filename (%s) for deck name\n", filename);
}
named:
if ((status = compressCard(dest)) != 0)
break;
/*
* Copy the source file to the destination while compressing.
*/
while (fgets(card, sizeof(card), src) != NULL) {
int len = strlen(card);
if (card[len - 1] == '\n')
card[len - 1] = '\0';
if ((status = compressCard(dest)) != 0)
goto error;
}
/*
* Build a trailing END/ card.
*/
strcpy(card, end);
if ((status = compressCard(dest)) != 0)
break;
fclose(src);
argc--, argv++;
}
error:
/*
* Report possible error.
*/
switch (status) {
case 0:
if ((outcount % RECLEN) != 0)
fwrite(pad, sizeof(char), outcount % RECLEN, dest);
break;
case 2:
fprintf(stderr, "Failed to open file - %s\n", filename);
break;
case 3:
fprintf(stderr, "Error writing COSY file\n");
break;
case 4:
fprintf(stderr, "Invalid character in file - %s\n", filename);
break;
default:
fprintf(stderr, "Unknown exit status - %u\n", status);
break;
}
fclose(dest);
return status;
}
/*++
* doDecompress
*
* Decompress a COSY file.
*
* Inputs:
*
* src - Source COSY file
*
* Outputs:
*
* ...
*
* Returns:
*
* Exit status:
* 0 - Success
* 2 - File open error
* 3 - File write error
*
--*/
int doDecompress(
FILE *src
)
{
int seqno = 0, valid;
char filename[32], *eofn;
FILE *dest = NULL;
while (decompressCard(src) == 0) {
/*
* First card of next deck has been read - is is a CSY/ card?
*/
sprintf(filename, "%05u.deck", seqno);
valid = 1;
if (strncmp("CSY/", &card[7], 4) == 0) {
if (card[0] != ' ') {
if ((eofn = strchr(card, ' ')) != NULL) {
int len = eofn - card;
if (len <= 6) {
*eofn = '\0';
sprintf(filename, "deck_%s", card);
}
}
}
valid = 0;
}
if ((dest = fopen(filename, "w")) == 0) {
fprintf(stderr, "Failed to create file - %s\n", filename);
return 2;
}
/*
* If the first line was not a CSY/ card, write to the destination file
*/
if (valid) {
if (writeCard(dest) == -1) {
fprintf(stderr, "Error writing to file - %s\n", filename);
fclose(dest);
return 3;
}
}
/*
* Now process the rest of this file.
*/
while (dest != NULL) {
switch (decompressCard(src)) {
case 0:
if (strncmp("END/", &card[7], 4) == 0) {
fclose(dest);
dest = NULL;
break;
}
if (writeCard(dest) == -1) {
fprintf(stderr, "Error writing to file%s\n", filename);
fclose(dest);
return 3;
}
break;
case -1:
fclose(dest);
return 0;
case -2:
fclose(dest);
dest = NULL;
break;
}
}
seqno++;
}
return 0;
}

24
converters/cosy/cosy.txt Normal file
View File

@@ -0,0 +1,24 @@
cosy manipulates files in the CDC1700 COSY format (note this is different from
the CDC3000 series COSY format). COSY is a format used for containing card
images as ASCII files using run length encoding of 3 or more spaces to reduce
the amount of space required. Multiple card decks may be present in a single
COSY file. File naming in the host environment makes use of the deck name
which is optionally present in the CSY/ cards. For decompression, if a deck
name is present, the host file will be named "deck_<deckname>" otherwise it
will be named "nnnnn.deck" where nnnnn is the position number of the deck
within the COSY file. On compression, source files named "deck_<deckname>"
will result in the CSY/ deckname being filled in otherwise an empty name wil
be used.
To compress a COSY format file:
cosy -c <cosyFile> file ...
To decompress a COSY format file:
cosy -d <cosyFile>
When decompressing a COSY format file, CSY/ and END/ card images are removed
from the output. On compression, a CSY/ card image is inserted at the start
of the output and a END/ card is appended to the output. The resulting
compressed file will be padded, with NULLs, to be a multiple of 384 bytes.

35
converters/fsio/Changes Normal file
View File

@@ -0,0 +1,35 @@
Changes Since Alpha Release:
1. mount: Fix memory leak when file system verification fails
2. dos11: Fix hang when parsing wildcard programmer number
3. Migrate to using GNU readline library for command line editing etc
4. local: Fix buffering so that local "type" command works
5. Add DOS-11 magtape support using file system type "dosmt"
6. newfs: Remove -a switch. Replace with "-t type" switch to allow more
flexibility. The equivalent of "-a" is now "-t rl02".
12-Jun-19
- Added support for sector interleave on RX01/RX02 drives
- Now supports creating RX01-sized container files
- Now works with RTFLX on TOPS-10 with RX02-sized container files
(documentation updated)
25-Jun-19
- Added support for OS/8 file systems on RX01, RX02 and RK05 drives using
file system type "os8"
- Added support for creating RT-11 file systems with additional space
allocated to each directory entry
9-Jan-20
- Merged change from tvrusso to fix compilation on FreeBSD

55
converters/fsio/Makefile Normal file
View File

@@ -0,0 +1,55 @@
CFLAGS=-O2 -Wall -Wshadow -Wextra -pedantic -Woverflow -Wstrict-overflow
#CFLAGS=-g -Wall -Wshadow -Wextra -pedantic -Woverflow -Wstrict-overflow
DEFINES=-DDEBUG
BIN=/usr/local/bin
MAN=/usr/local/man/man1
INSTALL=install
CC=gcc
EXECUTABLE=fsio
SOURCES=fsio.c declib.c tape.c dos11.c rt11.c dosmt.c local.c os8.c
INCLUDES=fsio.h declib.h tape.h dos11.h rt11.h dosmt.h os8.h
LIBS=-lreadline
MANPAGE=fsio.1
MANPAGE_DOS=fsio-dos11.1
MANPAGE_RT=fsio-rt11.1
MANPAGE_DOSMT=fsio-dosmt.1
MANPAGE_OS8=fsio-os8.1
ARCHIVE=fsio.tgz
RELEASEFILES=$(BIN)/$(EXECUTABLE)
RELEASEFILES+=$(MAN)/$(MANPAGE)
RELEASEFILES+=$(MAN)/$(MANPAGE_DOS)
RELEASEFILES+=$(MAN)/$(MANPAGE_RT)
RELEASEFILES+=$(MAN)/$(MANPAGE_DOSMT)
RELEASEFILES+=$(MAN)/$(MANPAGE_OS8)
RELEASEFILES+=./fsio.txt ./fsioSimh.txt
$(EXECUTABLE): $(SOURCES) $(INCLUDES) Makefile
$(CC) $(CFLAGS) $(DEFINES) -o $(EXECUTABLE) $(SOURCES) $(LIBS)
.phony: clean install uninstall
clean:
rm -f $(EXECUTABLE)
install: $(EXECUTABLE) $(MANPAGE) $(MANPAGE_DOS) $(MANPAGE_RT)
$(INSTALL) -p -m u=rx,g=rx,o=rx $(EXECUTABLE) $(BIN)
mkdir -p $(MAN)
$(INSTALL) -p -m u=r,g=r,o=r $(MANPAGE) $(MAN)
$(INSTALL) -p -m u=r,g=r,o=r $(MANPAGE_DOS) $(MAN)
$(INSTALL) -p -m u=r,g=r,o=r $(MANPAGE_RT) $(MAN)
$(INSTALL) -p -m u=r,g=r,o=r $(MANPAGE_DOSMT) $(MAN)
$(INSTALL) -p -m u=r,g=r,o=r $(MANPAGE_OS8) $(MAN)
uninstall:
rm -f $(BIN)/$(EXECUTABLE)
rm -f $(MAN)/$(MANPAGE)
rm -f $(MAN)/$(MANPAGE_DOS)
rm -f $(MAN)/$(MANPAGE_RT)
rm -f $(MAN)/$(MANPAGE_DOSMT)
rm -f $(MAN)/$(MANPAGE_OS8)
# This assumes that fsio has been "installed" on the current system
archive: $(RELEASEFILES)
tar czvPf $(ARCHIVE) $(RELEASEFILES)

242
converters/fsio/declib.c Normal file
View File

@@ -0,0 +1,242 @@
/*
* Copyright (C) 2018 John Forecast. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "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 AUTHOR 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.
*/
/*
* Routines/data which are common to multiple DEC file systems.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <sys/stat.h>
#include "fsio.h"
char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$.%0123456789";
char *month[12] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
/*
* Table of days/month for both normal and leap years.
*/
unsigned short mnth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
unsigned short mnthl[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
/*
* ASCII character set
*/
char *Ascii[128] = {
"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
" BS", " HT", " LF", " VT", " FF", " CR", " SO", " SI",
"DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
"CAN", " EM", "SUB", "ESC", " FS", " GS", " RS", " US",
" ", " ! ", " \" ", " # ", " $ ", " % ", " & ", " \' ",
" ( ", " ) ", " * ", " + ", " , ", " - ", " . ", " / ",
" 0 ", " 1 ", " 2 ", " 3 ", " 4 ", " 5 ", " 6 ", " 7 ",
" 8 ", " 9 ", " : ", " ; ", " < ", " = ", " > ", " ? ",
" @ ", " 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 ", " [ ", " \\ ", " ] ", " ^ ", " _ ",
" ` ", " 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 ", " { ", " | ", " } ", " ~ ", "DEL"
};
/*++
* r 5 0 A s c
*
* Convert a 16-bit rad50 value into 3 ASCII characters.
*
* Inputs:
*
* value - rad50 value to be converted
* outbuf - pointer to 3 character buffer to receive the
* converted output
*
* Outputs:
*
* None
*
* Returns:
*
* None
*
--*/
void r50Asc(
uint16_t value,
char *outbuf
)
{
outbuf[2] = rad50[value % 050];
value /= 050;
outbuf[1] = rad50[value % 050];
outbuf[0] = rad50[value / 050];
}
/*++
* r 5 0 A s c N o S p a c e
*
* Convert a 16-bit rad50 value into up to 3 ASCII characters. Spaces are
* dropped from the conversion.
*
* Inputs:
*
* value - rad50 value to be converted
* outbuf - pointer to 3 character buffer to receive the
* converted output
*
* Outputs:
*
* None
*
* Returns:
*
* None
*
--*/
void r50AscNoSpace(
uint16_t value,
char *outbuf
)
{
uint16_t value2 = value / 050;
/*
* The rad50 representation of ' ' is zero.
*/
if ((value2 / 050) != 0)
*outbuf++ = rad50[value2 / 050];
if ((value2 % 050) != 0)
*outbuf++ = rad50[value2 % 050];
if ((value % 050) != 0)
*outbuf++ = rad50[value % 050];
}
/*++
* a s c R 5 0
*
* Convert 3 ASCII characters into a single 16-bit rad50 value. If an input
* character is not in the rad50 character set it is quietly converted to '%'.
*
* Inputs:
*
* inbuf - pointer to the buffer with the 3 characters
*
* Outputs:
*
* None
*
* Returns:
*
* rad50 value for the 3 characters
*
--*/
uint16_t ascR50(
char *inbuf
)
{
uint16_t value;
char *ptr;
if ((ptr = strchr(rad50, toupper(*inbuf++))) == NULL)
ptr = strchr(rad50, '%');
value = (ptr - rad50) * 03100;
if ((ptr = strchr(rad50, toupper(*inbuf++))) == NULL)
ptr = strchr(rad50, '%');
value += (ptr - rad50) * 050;
if ((ptr = strchr(rad50, toupper(*inbuf++))) == NULL)
ptr = strchr(rad50, '%');
value += ptr - rad50;
return value;
}
/*++
* d o s 1 1 D a t e
*
* Convert a DOS/BATCH-11 date value into an ASCII string.
*
* Inputs:
*
* value - DOS/BATCH-11 date value
* buf - buffer to receive the string (requires 12 bytes)
*
* Outputs:
*
* None
*
* Returns:
*
* Pointer to the date string
*
--*/
char *dos11Date(
uint16_t value,
char *buf
)
{
unsigned short year, doyr, leapyr;
unsigned short *table;
/*
* The DOS/BATCH-11 date format is documented as having 3 reserved bit.
* Version 9.20C (and later?) makes use of these bits to allow dates up
* to 2035. Unfortunately, the date input routine only allows up to 1999!
*/
year = 1970 + value / 1000;
doyr = value % 1000;
leapyr = ((year % 4) == 0) && (year != 2000);
table = leapyr ? mnthl : mnth;
/*
* Check for valid day of year.
*/
if (doyr < (leapyr ? 366 : 365)) {
int i = 0;
while (doyr > table[i])
doyr -= table[i++];
sprintf(buf, "%2d-%s-%4d", doyr, month[i], year);
} else strcpy(buf, "xx-yyy-xxxx");
return buf;
}

40
converters/fsio/declib.h Normal file
View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2018 John Forecast. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "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 AUTHOR 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.
*/
#ifndef __DECLIB_H__
#define __DECLIB_H__
extern char rad50[];
extern char *month[];
extern char *Ascii[];
extern void r50Asc(uint16_t, char *);
extern void r50AscNoSpace(uint16_t, char *);
extern uint16_t ascR50(char *);
extern char *dos11Date(uint16_t, char *);
#endif

2490
converters/fsio/dos11.c Normal file

File diff suppressed because it is too large Load Diff

292
converters/fsio/dos11.h Normal file
View File

@@ -0,0 +1,292 @@
/*
* Copyright (C) 2018 John Forecast. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "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 AUTHOR 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.
*/
#ifndef __DOS11_H__
#define __DOS11_H__
/*
* General disk layout:
*
* Block
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0 | Reserved for Bootstrap |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 1 | MFD Block #1 |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 2 | UFD Block #1 |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* ... | |
* | User linked files |
* | & |
* | other UFD blocks |
* | |
* |-- --|
* | User contiguous files |
* | |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* X-n | MFD Block #2 |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* X-n-1 | Bitmap Block #1 |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* ... | |
* | |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* X | Bitmap Block #n |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
*
* MFD Block 1:
*
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Block # of MFD Block 2 |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Interleave factor |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Bitmap start block # |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Bitmap #1 block # |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Bitmap #2 block # |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | |
* | ... |
* | |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Bitmap #N block # |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | 0 |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | |
*
* MFD Block 2 - N:
*
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Link to next MFD block or 0 |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Group code | User code |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | UFD start block # |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | # of words in UFD entry |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | 0 |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Repeat above 4 words |
* | for each UFD |
* | |
*
* UFD Block:
*
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Link to next UFD block or 0 |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | File |
* +- -+
* | name |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Extension |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* |Typ| Rsvd | Creation Date |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Next free byte |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Start block # |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Length (in # of blocks) |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Last block written |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* |LCK| Usage count | Protection code |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
*
* Bitmap Block:
*
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Link to next bitmap block |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Map # |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | # of words of map |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Link to first bitmap block |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Map for blocks 0 - 17 |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Map for blocks 20 - 37 |
* | ... |
* | |
*/
/*
* The MFD and UFD directories can be treated as an array of 16-bit values.
* The following offsets describe each structure.
*/
#define BOOT_BLOCK 0 /* Reserved for bootstrap */
#define MFD1_BLOCK 1 /* MFD always at block 1*/
#define MFD1_MFD2BLOCK 0
#define MFD1_INTERLEAVE 1
#define MFD1_BMSTART 2
#define MFD1_BM1 3
#define MFD2_LINK 0
#define MFD2_HEADER 1
#define MFD2_UFDUIC 0
#define MFD2_UFDSTART 1
#define MFD2_UFDSIZE 2
#define MFD2_UFDZERO 3
#define MFD2_SIZE 4
#define UFD_LINK 0
#define UFD_HEADER 1
#define UFD_FILENAME 0
#define UFD_EXTENSION 2
#define UFD_CREATION 3
#define UFD_TYPE 0100000
#define UFD_TYPELINKED 0000000
#define UFD_TYPECONTIGUOUS 0100000
#define UFD_DATE 0077777
#define UFD_NEXTFREEBYTE 4
#define UFD_FILESTART 5
#define UFD_FILELENGTH 6
#define UFD_LASTBLOCKWRITTEN 7
#define UFD_LUP 8
#define UFD_LOCK 0100000
#define UFD_USAGE 0077400
#define UFD_PROT 0000377
#define UFD_LEN 9 /* 9 word in each entry */
#define MAP_LINK 0
#define MAP_MAP 1
#define MAP_WORDS 2
#define MAP_FIRST 3
#define MAP_BMSTART 4
#define MAP_LEN 60 /* 60 words in each entry */
#define MAP_BLOCKS (MAP_LEN * 16)
#define FILE_LINK 0
/*
* Block sizes for each supported disk drive
*/
#define BLOCKSIZE_RC11 64
#define BLOCKSIZE_RF11 64
#define BLOCKSIZE_RK11 256
#define BLOCKSIZE_RP03 512
/*
* Max # of UIC's (UFDs) for each supported disk drive
*/
#define UICCOUNT_RC11 15
#define UICCOUNT_RF11 15
#define UICCOUNT_RK11 63
#define UICCOUNT_RP03 127
/*
* Compute end of directory block, given the size of each directory entry.
* This macro is good for both MFDs and UFDs.
*/
#define EODIR(m, sz) ((m->blocksz / 2) - (sz - 1))
/*
* The logical block size will depend on the type of the disks. Disks smaller
* than a RK05 (RS11/RS64) will use 64 word blocks while disks larger than
* a RK05 (RP03) will use 512 word blocks. The default will be for an 256
* word blocks for a RK05.
*/
#define DISKSIZE_RK05 4800
/*
* Structure to describe a filename and associated UIC. Asterisks may be used
* as wild card characters for the 4 components of a filename; name, extension,
* group number and user number.
*/
struct dos11FileSpec {
uint8_t flags; /* Wild card indicators */
uint16_t name[2]; /* File name */
uint16_t ext; /* Extension */
unsigned char user; /* User number */
unsigned char group; /* Group number */
};
#define DOS11_WC_NAME 0001 /* Wild card name */
#define DOS11_WC_EXT 0002 /* Wild card extension */
#define DOS11_WC_GROUP 0004 /* Wild card group number */
#define DOS11_WC_USER 0010 /* Wild card user number */
#define DOS11_M_NONE 0000 /* Wild cards not allowed */
#define DOS11_M_ALLOW 0001 /* Wild cards allowed */
#define DOS11_M_NONAME 0002 /* Wild cards allowed */
/* If no filename + extension */
/* present, default to *.* */
/*
* Structure to define an open file. This is a DOS-11 UFD entry along with
* sufficient information to be able to write the directory entry back
* to disk.
*/
struct dos11OpenFile {
uint16_t name[2]; /* File name */
uint16_t ext; /* Extension */
uint16_t creation; /* Type + creation date */
uint16_t nfb; /* Next free byte */
uint16_t start; /* Start block # */
uint16_t length; /* Length in blocks */
uint16_t last; /* Last block written */
uint16_t lup; /* Lock, usage + protection */
/* End of directory entry */
uint16_t ufdblk; /* UFD block # */
uint16_t ufdoffset; /* Offset within UFD */
/* Start of read/write info */
enum openMode mode; /* Open mode (read/write) */
struct mountedFS *mount; /* Mounted file system descriptor */
char *buffer; /* Private buffer for file I/O */
uint16_t current; /* Current block */
uint16_t nab; /* Next available byte */
uint16_t eob; /* End of buffer */
};
/*
* DOS-11 specific data area. Some fields are sized for the worst case -
* RP03 disk pack with 65535 blocks of 1024 bytes each.
*/
struct DOS11data {
unsigned int blocks; /* # of blocks in file system */
uint16_t bitmaps; /* # of bitmaps */
uint16_t bmblk[128]; /* Bitmap block addresses */
uint16_t bmindex; /* Current bitmap in buffer */
uint16_t bmscan; /* Start bitmap scans here */
uint8_t bmdirty; /* 0 => clean, 1 => dirty */
uint16_t bmbuf[512]; /* Buffer for bitmap access */
uint16_t buf[512]; /* Disk buffer */
/*
* Settable parameters
*/
uint8_t group; /* Default group # */
uint8_t user; /* Default user # */
};
#endif

1321
converters/fsio/dosmt.c Normal file

File diff suppressed because it is too large Load Diff

101
converters/fsio/dosmt.h Normal file
View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2018 John Forecast. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "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 AUTHOR 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.
*/
#ifndef __DOSMT_H__
#define __DOSMT_H__
#include "tape.h"
/*
* DOS-11 magtapes contain data records of 512 bytes each.
*/
#define DOSMTRCLNT 512
/*
* DOS/BATCH-11 magtape file header.
*/
struct dosmthdr {
uint16_t fname[2]; /* first 6 chars of filename (RAD50) */
uint16_t ext; /* 3 char file extension (RAD50) */
uint8_t prog; /* programmer # (octal) */
uint8_t proj; /* project # (octal) */
uint16_t prot; /* protection code (octal) */
uint16_t date; /* (year-1970) * 1000 + day of year */
uint16_t fname3; /* optional, char 7 - 9 of name */
};
/*
* Structure to describe a filename and associated UIC. Asterisks may be used
* as wild card characters for the 4 components of a filename; name, extension,
* group number and user number.
*/
struct dosmtFileSpec {
uint8_t flags; /* Wild card indicators */
uint16_t name[3]; /* File name */
uint16_t ext; /* Extension */
unsigned char proj; /* Project number */
unsigned char prog; /* Programmer number */
};
#define DOSMT_WC_NAME 0001 /* Wild card name */
#define DOSMT_WC_EXT 0002 /* Wild card extension */
#define DOSMT_WC_PROJ 0004 /* Wild card project number */
#define DOSMT_WC_PROG 0010 /* Wild card programmer number */
#define DOSMT_M_NONE 0000 /* Wild cards not allowed */
#define DOSMT_M_ALLOW 0001 /* Wild cards allowed */
#define DOSMT_M_NONAME 0002 /* Wild cards allowed */
/* If no filename + extension */
/* present, default to *.*[*,*] */
/*
* Structure to define an open file.
*/
struct dosmtOpenFile {
enum openMode mode; /* Open mode (read/write) */
struct mountedFS *mount; /* Mounted file system descriptor */
char buf[DOSMTRCLNT];/* Private buffer for file I/O */
uint16_t nextb; /* Next byte to use */
uint8_t tm; /* Tape mark has been read */
uint8_t error; /* Error has been detected */
};
/*
* DOS-11 magtape specific data area.
*/
struct DOSMTdata {
uint8_t buf[DOSMTRCLNT];
off_t eot; /* Logical end-of-tape */
/*
* Settable parameters
*/
uint8_t proj; /* project # */
uint8_t prog; /* programmer # */
uint8_t prot; /* protection code */
#define FS_DOSMTEXT 0x0100 /* Write extended file headers */
};
#endif

View File

@@ -0,0 +1,51 @@
.TH FSIO-DOS11 1 "Jun 21,2019" "FFS I/O - DOS-11"
.SH NAME
fsio-dos11 \- Foreign File System I/O - DOS-11
.br
.SH DESCRIPTION
\fBfsio\fP allows access to DOS-11 file systems using the file system type
"\fIdos11\fP"
.br
.SH WILDCARD CHARACTERS
The wildcard character \fI'*'\fP may be used to match filename, extension,
group number and user number. Wildcard characters are only valid with the
\fIdir\fP command.
.br
.SH NEWFS OPERATION
\fInewfs\fP creates a blank RK05 image (2.5MB, 4800 blocks) with no UFD
entries.
.SH SET OPERATION
The following \fIset\fP commands are supported:
.br
.TP
.B "\fIuic\fP [group,user]"
Sets the default UIC for file access (was [1,1] after mount).
.br
.RS
.RS
.B "\fIgroup\fP \- Group number (octal 1 - 377)"
.br
.B "\fIuser\fP \- User number (octal 1 - 377)"
.br
.RE
.RE
.TP
.B "\fIufd\fP [group,user]"
Creates an empty UFD and sets default UIC for file access.
.br
.RS
.RS
.B "\fIgroup\fP \- Group number (octal 1 - 377)"
.br
.B "\fIuser\fP \- User number (octal 1 - 377)"
.br
.RE
.RE
.SH SEE ALSO
.BR fsio (1),
.BR fsio-rt11 (1)
.BR fsio-dosmt (1)
.BR fsio-os8 (1)
.SH AUTHOR
John Forecast, <john@forecast.name>
.br

View File

@@ -0,0 +1,111 @@
.TH FSIO-DOSMT 1 "Jun 25,2019" "FFS I/O - DOS-11 magtape"
.SH NAME
fsio-dosmt \- Foreign File System I/O - DOS-11 magtape
.br
.SH DESCRIPTION
\fBfsio\fP allows access to DOS-11 magtapes using the file system type
"\fIdosmt\fP"
.br
.SH WILDCARD CHARACTERS
The wildcard character \fI'*'\fP may be used to match filename, extension,
group number and user number. Wildcard characters may be used with the
\fIdir\fP command to limit the number of files being displayed. They may also
be used with commands to read files; \fIdump\fP, \fItype\fP and \fIcopy\fP
(only the source file for \fIcopy\fP), in which case the next file which
matches the wildcard character(s) will be used for input. As a consequence
of this, the empty filename may be used to select the next file on the tape,
so:
.RS
fsio> type mt:
.RE
will type the next file on the tape.
.br
.SH MOUNT OPERATION
DOS/BATCH-11 defined magtape headers to be 14 bytes long with 2 bytes unused.
Some tapes use these unused bytes to add an additional 3 characters to the
filename (e.g. ABCDEFGHI.EXT rather than ABCDEF.EXT). By default, fsio will
ignore these unused bytes. If the \fI-x\fP switch is used on the \fImount\fP
command, fsio will make use of the extra 3 characters on file lookup,
directory listing and file creation.
.SH NEWFS OPERATION
\fInewfs\fP creates an empty (zero length) file.
.SH SET OPERATION
The following \fIset\fP commands are supported:
.br
.TP
.B "\fIuic\fP [proj,prog]"
Sets the default UIC for file access (was [1,1] after mount).
.br
.RS
.RS
.B "\fIproj\fP \- Project number (octal 1 - 377)"
.br
.B "\fIprog\fP \- Programmer number (octal 1 - 377)"
.br
.RE
.RE
.TP
.B "\fIprot\fP <code>"
Set the default protection code when writing new files to magtape.
.br
.RS
.RS
.B "\fIprot\fP \- Protection code (octal 0 - 377)"
.br
.RE
.RE
.SH INFO OPERATION
\fIinfo\fP displays where the tape is currently positioned. If the tape is
not positioned at the end and it is not an empty tape, the name of the next
file after the current position will be displayed.
.SH NOTES
DOS-11 magtapes differ from disk-based file systems in a number of ways:
.br
.RS
1. Filenames are not unique on a magtape.
.br
2. The tape has to be positioned before writing a new file to
avoid over-writing an existing file.
.br
.RE
Assuming a magtape is mounted on mt: and has 5 files on it:
.br
The sequence:
.br
.RS
fsio> rewind mt:
.br
fsio> copy -a a.b mt:c.d
.br
.RE
will result in the tape containing a single file (c.d), while the sequence:
.br
.RS
fsio> eom mt:
.br
fsio> copy -a a.b mt:c.d
.br
.RE
will result in the tape containing 6 files (the original 5 followed by c.d).
.br
By using skipf/skipr commands it is possible to position the tape just past
the end of any specific file (see info command for more details on how to
determine the current tape position).
.br
.SH SEE ALSO
.BR fsio (1)
.BR fsio-dos11 (1)
.BR fsio-rt11 (1)
.BR fsio-os8 (1)
.SH AUTHOR
John Forecast, <john@forecast.name>
.br

View File

@@ -0,0 +1,80 @@
.TH FSIO-OS8 1 "Sep 218,2019" "FFS I/O - OS/8"
.SH NAME
fsio-os8 \- Foreign File System I/O - OS/8
.br
.SH DESCRIPTION
\fBfsio\fP allows access to OS/8 file systems using the file system type
"\fIos8\fP"
.br
.SH OS/8 PHYSICAL DISKS
OS/8 uses a file system block size of 256 words and OS/8 devices are limited
to 4095 blocks. Blocks 0 through 6 are reserved so the largest possible file
is 4088 blocks long (1046528 words). Larger devices, for example the RK05,
place multiple file systems on each physical device.
.br
OS/8 does not write any type of signature on the device and each device type
has it's own partitioning scheme so the \fImount\fP command must use the
"\fI-f type\fP switch so that \fBfsio\fP can determine the file system
layout. \fBfsio\fP uses a set of heuristics to verify the integrity of
the OS/8 file system(s) but it is quite possible for a random disk to pass
these tests and later crash \fBfsio\fP.
.SH MOUNT OPERATION
\fImount\fP requires the "\fI-f type\fP" switch so that it can determine the
type of the underlying disk (See NEWFS OPERATION below for details).
.SH NEWFS OPERATION
\fInewfs\fP creates an RK05 disk image with 2 file systems. If the
"\fI-f type\fP" switch is present a different container file will be created
depending on the type of the device specified:
.br
.RS
.TP
\fIrk05\fP \- RK05 image (2 file systems, 3248 blocks each)
.br
.TP
\fIrx01\fP \- RX01 image (single file system, 494 blocks)
.br
.TP
\fIrx02\fP \- RX02 image (single file system, 988 blocks)
.br
.RE
Note that in order to use RX02 media the OS/8 system must have the device
extensions kit installed.
.br
The "\fI-e extra\fP" switch, where "extra" is a number in the range 0 - 63,
may be used to create file systems with "extra" additional information words
available to each directory entry. By default, \fInewfs\fP will create file
systems with 1 additional information word which will be used to hold the
file creation date. If you do not want any additional information words
use "\fI-e 0\fP".
.br
.SH SET OPERATION
The following \fIset\fP commands are supported:
.br
.TP
.B "\fIyear\fP n"
.br
All subsequent OS/8 file creations will include a creation date (if the file
system was created with at least 1 additional information word). The date used
will be the month and day of the month for today with the year "n" (where "n"
is in the range 0 - 7).
.br
.TP
.B "\fIyear\fP none"
.br
All subsequent OS/8 file creations will include a zero creation date (if the
file system was created with at least 1 additional information word). This is
the default state after mount.
.br
.SH SEE ALSO
.BR fsio (1)
.BR fsio-dos11 (1)
.BR fsio-dosmt (1)
.BR fsio-rt11 (1)
.SH AUTHOR
John Forecast, <john@forecast.name>
.br

View File

@@ -0,0 +1,89 @@
.TH FSIO-RT11 1 "Jun 25,2019" "FFS I/O - RT-11"
.SH NAME
fsio-rt11 \- Foreign File System I/O - RT-11
.br
.SH DESCRIPTION
\fBfsio\fP allows access to RT-11 file systems using the file system type
"\fIrt11\fP"
.br
.SH RT-11 VERSIONS
There were 5 major versions of RT-11 released. Versions 1 and 2 did not use
the home block (block 1) to indicate that the on-disk file structure was RT-11
format. The remaining 3 versions wrote a signature on the home block
including the file system version in use. In order to access a version 1 or
version 2 container file, the \fI"-f"\fP switch must be used on the
\fI"mount"\fP command to force \fBfsio\fP
to bypass the home block checks. While \fBfsio\fP will use a set of
heuristics to verify the integrity of the RT-11 file structure it is possible
that an invalid file structure will satisfy the checks and cause \fBfsio\fP to
fail. Do not use the \fI"-f"\fP switch other than to mount version 1 or
version 2 file systems.
.br
The VMS exchange utility may be used to initialize an RT-11 volume but writes
it's own unique signature in the home block. \fBfsio\fP is able to correctly
handle this signature.
.br
.SH RT-11 PHYSICAL DISKS
RT-11 uses a file system block size of 512 bytes and most disk type either
have a block size of 512 bytes or use 2 contiguous blocks or 256 bytes each.
Floppy diskettes, RX01 and RX02 drives, use small sectors size and for
performance reason, adjacent logical sectors are interleaved within the same
track. When mounting a floppy diskette, the \fI"-f type"\fP must be used so
that \fIfsio\fP can determine the interleaving used. In this case "type"
should be either "rx01" or "rx02".
.SH LOGICAL DISKS
\fBfsio\fP can be used to access an RT-11 logical disk if the file has been
copied to the host file system.
.SH WILDCARD CHARACTERS
The wildcard character \fI'%'\fP may be used to match a single character in a
filename or type. The wildcard character \fI'*'\fP may be used to match
zero or more characters in a filename or type. Wildcard characters are only
valid with the \fIdir\fP command.
.br
.SH NEWFS OPERATION
\fInewfs\fP creates a blank MSCP image (32MB, 65535 blocks) with a single
partition which can be accessed via the DU device (rq in SIMH). If the
\fI"-t type"\fP switch is present, a smaller container file will be created
depending on the type of device specified:
.br
.RS
.TP
\fIrk05\fP \- RK05 image (2.5MB, 4800 blocks)
.br
.TP
\fIrl01\fP \- RL01 image (5MB, 10240 blocks)
.br
.TP
\fIrl02\fP \- RL02 image (10MB, 20480 blocks)
.br
.TP
\fIrx01\fP \- RX01 floopy image (256KB, 2002 sectors of 128 bytes)
.br
.TP
\fIrx02\fP \- RX02 floopy image (512KB, 2002 sectors of 256 bytes)
.br
.RE
The "\fI-e extra\fP" switch, where "extra" is a number in the range 0 - 63,
may be used to create file systems with "extra" additional bytes available to
each directory entry. \fIfsio\fP will silently round up the value to make it
an even number required by RT-11. By default, \fInewfs\fP will create file
systems with no additional bytes for each directory entry.
.SH COPY OPERATION
When copying in ASCII mode, \fBfsio\fP will normally write ^Z (octal 032) to
indicate the end-of-file. Some utilities, such as FLX on RSX-11, cannot
handle ^Z in the middle of a formatted ASCII file. The \fI"-p"\fP switch
may be used on a copy operation to skip writing the ^Z and pad the file with
NULLs up to the next block boundary if this occurs.
.br
.SH SET OPERATION
No \fIset\fP commands are currently supported.
.SH SEE ALSO
.BR fsio (1)
.BR fsio-dos11 (1)
.BR fsio-dosmt (1)
.BR fsio-os8 (1)
.SH AUTHOR
John Forecast, <john@forecast.name>
.br

343
converters/fsio/fsio.1 Normal file
View File

@@ -0,0 +1,343 @@
.TH FSIO 1 "Sep 17,2019" "Foreign File System I/O"
.SH NAME
fsio \- Foreign File System I/O
.SH SYNOPSIS
.B fsio
[
.B \-qv
]
[
.I cmdfile
]
.br
.SH DESCRIPTION
\fBfsio\fP is a utility for manipulating foreign file systems within container
files used by various emulators such as
.B SIMH.
If cmdfile is given, commands will be read and executed from the command file
otherwise it will prompt the user for commands with \fBfsio> \fP
.br
.TP
\fB-q\fP - Be quiet, do not output unsolicited text during processing
.TP
\fB-v\fP - Echo each command as it is read from a command file
.br
.TP
Each command occupies one line and has a common format:
.br
.RS
.TP
verb [switches] args ...
.RE
.TP
The following verbs are supported:
.br
.B "\fImount\fP \- make a container file available to fsio"
.br
.B "\fIumount\fP \- remove knowledge of a container file from fsio"
.br
.B "\fInewfs\fP \- create and new container and empty file system"
.br
.B "\fIset\fP \- set parameters on a mounted file system"
.br
.B "\fIinfo\fP \- display information about the container file system"
.br
.B "\fIdir\fP \- list a directory"
.br
.B "\fIdump\fP \- dump a file in hex or octal"
.br
.B "\fIcopy\fP \- copy a single file"
.br
.B "\fItype\fP \- type a file on the terminal"
.br
.B "\fIdelete\fP \- delete a file"
.br
.B "\fIstatus\fP \- display currently mounted file systems"
.br
.B "\fIdo\fP \- echo and execute commands from a file"
.br
.B "\fIhelp\fP \- display help on using fsio"
.br
.B "\fIexit\fP \- terminate fsio (quit is an alias for exit)"
.br
.TP
The following commands are only accepted by file systems which are on magtape devices:
.br
.B "\fIrewind\fP \- position the tape to the start of the data stream"
.br
.B "\fIeom\fP \- position the tape to the end of the data stream"
.br
.B "\fIskipf\fP \- position the tape by skipping forward over files"
.br
.B "\fIskipr\fP \- position the tape by skipping backward over files"
.br
.SH COMMANDS
.TP
.B "\fImount\fP [-dfrx] [-t type] dev[:] file type"
Make the container file available to fsio.
.br
.RS
.RS
.B "\fI\-d\fP \- generate debug output on stdout"
.br
.B " Use environment variable \fIFSioDebugLog\fP to"
.br
.B " override stdout"
.br
.B " Only available if built with DEBUG enabled"
.br
.B "\fI\-f\fP \- bypass home block validation (RT-11 only)"
.br
.B "\fI\-r\fP \- mount file system read-only"
.br
.B "\fI\-t type\fP \- specify optional disk type"
.br
.B "\fI\-x\fP \- dosmt will use extended filenames when writing"
.br
.B "\fIdev[:]\fP \- user supplied name for the mount"
.br
.B "\fIfile\fP \- name of the container file"
.br
.B "\fItype\fP \- type of container file system"
.br
.RE
.RE
.TP
.B "\fIumount\fP dev[:]"
Remove knowledge of the container file from fsio.
.br
.RS
.RS
.B "\fIdev[:]\fP \- name supplied on a previous mount"
.RE
.RE
.TP
.B "\fInewfs\fP [-t type] [-e count] file type"
Create an new container with an empty file system.
.br
.RS
.RS
.B "\fI\-t type\fP \- use alternate, file-system dependent size"
.br
.B "\fI\-e n\fP \- Specify extra space for directory entries (RT11, OS/8)"
.br
.B "\fIfile\fP \- name of the container file"
.br
.B "\fItype\fP \- type of container file system"
.br
.RE
.RE
.TP
.B "\fIset\fP dev: args ..."
Set parameters on a mounted file system.
.br
.RS
.RS
.B "\fIdev:\fP \- name supplied on a previous mount"
.br
.B "\fIargs ...\fP\- arguments are passed on to the file system"
.br
.RE
.RE
.TP
.B "\fIinfo\fP dev:"
Display information about the file system(s) within the container file.
.br
.RS
.RS
.B "\fIdev:\fP \- name supplied on a previous mount"
.RE
.RE
.TP
.B "\fIdir\fP [-fn] dev:dirspec"
List the contents of a specific directory.
.br
.RS
.RS
.B "\fI\-f\fP \- display a full (vs. brief) directory"
.br
.B "\fI\-n\fP \- don't rewind tape before listing directory"
.br
.B "\fIdev:\fP \- name supplied on a previous mount"
.br
.B "\fIdirspec\fP \- filespec to display, may include wildcards"
.br
.RE
.RE
.TP
.B "\fIdump\fP [-bcdnwx] dev:filespec"
Dump the contents of the file in octal, hex or characters.
.br
.RS
.RS
.B "\fI\-b\fP \- dump byte (8-bits) at a time"
.br
.B "\fI\-c\fP \- dump in character format"
.br
.B "\fI\-d\fP \- dump double-word (32-bits) at a time"
.br
.B "\fI\-w\fP \- dump word (16-bits) at a time"
.br
.B "\fI\-x\fP \- dump in hex format (default is octal)"
.br
.B "\fI\-n\fP \- don't rewind magtape before looking for file"
.br
.B "\fIdev:\fP \- name supplied on a previous mount"
.br
.B "\fIdirspec\fP \- filespec to dump"
.br
.RE
.RE
.TP
.B "\fIcopy\fP [-anpc blks] dev1:srcfile dev2:dstfile"
Copy a file.
.br
.RS
.RS
.B "\fI\-a\fP \- copy in ASCII mode (translates line endings)"
.br
.B "\fI\-p\fP \- pad the file with NULLs"
.br
.B "\fI\-n\fP \- don't rewind magtape before looking for input file"
.br
.B "\fI\-c blks\fP \- make contiguous file of specified size"
.br
.B "\fIdev1:\fP \- name supplied on a previous mount"
.br
.B "\fIsrcfile\fP \- source file to copy"
.br
.B "\fIdev2:\fP \- name supplied on a previous mount"
.br
.B "\fIdstfile\fP \- destination file to copy"
.br
.RE
.RE
.TP
.B "\fItype\fP [-n] dev:filespec"
Types the contents of the file on stdout.
.br
.RS
.RS
.B "\fI\-n\fP \- don't rewind magtape before looking for file"
.br
.B "\fIdev:\fP \- name supplied on a previous mount"
.br
.B "\fIfilespec\fP\- filespec to type"
.br
.RE
.RE
.TP
.B "\fIdelete\fP dev:filespec"
Deletes the specified file.
.br
.RS
.RS
.B "\fIdev:\fP \- name supplied on a previous mount"
.br
.B "\fIfilespec\fP\- filespec to delete"
.br
.RE
.RE
.TP
.B "\fIstatus\fP"
Displays the currently mounted file system(s).
.br
.TP
.B "\fIdo\fP [-q] cmdFile"
Echo and execute commands from a file.
.br
.RS
.RS
.B "\fI\-q\fP \- don't echo commands as they are read"
.br
.B "\fIcmdFile\fP \- file containing fsio commands"
.br
.RE
.RE
.TP
.B "\fIhelp\fP"
Displays help text on stdout.
.br
.TP
.B "\fIexit\fP"
Causes fsio to exit (the quit command has the same effect).
.br
.TP
.B "\fIrewind\fP dev:"
Positions the device to the start of the tape.
.br
.RS
.RS
.B "\fIdev:\fP \- name supplied on a previous mount"
.br
.RE
.RE
.TP
.B "\fIeom\fP dev:"
Positions the device to the end of the tape.
.br
.RS
.RS
.B "\fIdev:\fP \- name supplied on a previous mount"
.br
.RE
.RE
.TP
.B "\fIskipf\fP dev: n"
Positions the device by skipping forward over files.
.br
.RS
.RS
.B "\fIdev:\fP \- name supplied on a previous mount"
.br
.B "\fIn\fP \- # of files to skip (must be > 0)"
.br
.RE
.RE
.TP
.B "\fIskipr\fP dev: n"
Positions the device by skipping backward over files.
.br
.RS
.RS
.B "\fIdev:\fP \- name supplied on a previous mount"
.br
.B "\fIn\fP \- # of files to skip (must be > 0)"
.br
.RE
.RE
.SH NOTES
If the "\fIdev:\fP" prefix is not present on a file specification, a file in
the host file system is used. It is also possible to use the "\fIlocal:\fP"
prefix to reference local files.
.br
The -c switch on the copy command is used to determine the number of
contiguous blocks allocated to the destination file before starting the copy.
This function depends on the value of blks:
.br
.B "\fI0\fP \- Use size of source file, if 0 then default to 1 block"
.br
.B "\fI!=0\fP \- Use larger of blks and size of the source file"
.br
.SH SUPPORTED FILESYSTEMS
.B "\fIdos11\fP \- DOS/BATCH-11 on RF11, RK05 or RP03"
.br
.B "\fIrt11\fP \- RT-11 including large drives with multiple partitions"
.br
.B "\fIdosmt\fP \- container file in DOS-11 magtape format"
.br
.B "\fIos8\fP \- OS/8 on RX01, RX01 or RK05"
.br
.SH SEE ALSO
.BR fsio-dos11 (1),
.BR fsio-rt11 (1)
.BR fsio-dosmt (1)
.BR fsio-os8 (1)
.SH AUTHOR
John Forecast, <john@forecast.name>
.br

2187
converters/fsio/fsio.c Normal file

File diff suppressed because it is too large Load Diff

174
converters/fsio/fsio.h Normal file
View File

@@ -0,0 +1,174 @@
/*
* Copyright (C) 2018 John Forecast. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "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 AUTHOR 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.
*/
#ifndef __FSIO_H__
#define __FSIO_H__
#include <stdio.h>
#include <stdint.h>
#include "declib.h"
/*
* Mode for open files
*/
enum openMode { M_RD, M_WR };
#include "dos11.h"
#include "rt11.h"
#include "dosmt.h"
#include "os8.h"
/*
* All of the supported file systems are natively little endian so we only
* need a subset of the endian support macros/routines.
*/
#if defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define htole16(x) OSSwapHostToLittleInt16(x)
#define le16toh(x) OSSwapLittleToHostInt16(x)
#define htole32(x) OSSwapHostToLittleInt32(x)
#define le32toh(x) OSSwapLittleToHostInt32(x)
#elif defined(__linux__)
#include <endian.h>
#elif defined(__NetBSD__)
#include <sys/endian.h>
#define le16toh(x) letoh16(x)
#define le32toh(x) letoh32(x)
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
#include <sys/endian.h>
#endif
#ifdef __GNUC__
#define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
#else
#define UNUSED(x) UNUSED_ ## x
#endif
#define MAX_DEVLEN 16
#if defined(__linux__)
#define OPTIONS(s) "+" s
#else
#define OPTIONS(s) s
#endif
extern uint32_t swPresent;
extern char *swValue[];
#define SWISSET(c) ((swPresent & (1 << (c - 'a'))) != 0)
#define SWSET(c) swPresent |= (1 << (c - 'a'))
#define SWGETVAL(c) (swValue[c - 'a'])
#define SWSETVAL(c, v) swValue[c - 'a'] = v
#ifdef DEBUG
extern FILE *DEBUGout;
#define ERROR(...) { \
fprintf(stderr, __VA_ARGS__); \
if ((DEBUGout != NULL) && (DEBUGout != stdout)) \
fprintf(DEBUGout, __VA_ARGS__); \
}
#else
#define ERROR(...) fprintf(stderr, __VA_ARGS__)
#endif
struct mountedFS;
/*
* File system definition
*/
struct FSdef {
struct FSdef *next; /* Pointer to next file system */
char *fstype; /* File system type name */
char *descr; /* File system description */
uint16_t flags; /* Flags */
size_t blocksz; /* Default block size */
int (*mount)(struct mountedFS *);
void (*umount)(struct mountedFS *);
size_t (*size)(void);
int (*newfs)(struct mountedFS *, size_t);
void (*set)(struct mountedFS *, uint8_t, uint8_t);
void (*info)(struct mountedFS *, uint8_t, uint8_t);
void (*dir)(struct mountedFS *, uint8_t, char *);
void *(*openFileR)(struct mountedFS *, uint8_t, char *);
void *(*openFileW)(struct mountedFS *, uint8_t, char *, off_t);
off_t (*fileSize)(void *);
void (*closeFile)(void *);
size_t (*readFile)(void *, void *, size_t);
size_t (*writeFile)(void *, void *, size_t);
void (*deleteFile)(void *, char *);
/*
* The following functions are only supported by magtape file systems.
*/
void (*rewind)(struct mountedFS *);
void (*eom)(struct mountedFS *);
void (*skipforw)(struct mountedFS *, unsigned long);
void (*skiprev)(struct mountedFS *, unsigned long);
};
#define FS_UNITVALID 0x0001 /* Unit # valid in device name */
#define FS_TAPE 0x0002 /* File system for magtapes */
#define FS_EMPTYFILE 0x0004 /* Empty file is OK */
#define FS_1OPENFILE 0x0008 /* Only support a single open file */
/*
* Mounted file system descriptor
*/
struct mountedFS {
struct mountedFS *next; /* Pointer to next mounted file sys */
char name[MAX_DEVLEN + 1];
struct FSdef *filesys; /* File system */
size_t blocksz; /* Active block size */
uint16_t flags;
#define FS_READONLY 0x0001 /* Mounted read-only */
#define FS_DEBUG 0x0002 /* Debug output */
/* Bits after 0x0080 reserved for */
/* file system use */
FILE *container; /* Container file access */
off_t skip; /* Data to skip in container file */
union {
struct DOS11data _dos11;
struct RT11data _rt11;
struct DOSMTdata _dosmt;
struct OS8data _os8;
} FSdata;
#define dos11data FSdata._dos11
#define rt11data FSdata._rt11
#define dosmtdata FSdata._dosmt
#define os8data FSdata._os8
};
extern int FSioReadBlob(struct mountedFS *, off_t, unsigned int, void *);
extern int FSioWriteBlob(struct mountedFS *, off_t, unsigned int, void *);
extern int FSioReadBlock(struct mountedFS *, unsigned int, void *);
extern int FSioWriteBlock(struct mountedFS *, unsigned int, void *);
extern int FSioReadSector(struct mountedFS *, unsigned int, unsigned int, void *);
extern int FSioWriteSector(struct mountedFS *, unsigned int, unsigned int, void *);
#endif

332
converters/fsio/fsio.txt Normal file
View File

@@ -0,0 +1,332 @@
fsio is a utility for manipulating files within file system container files
supported by by various emulators such as SIMH. fsio is designed for Unix and
Unix-like operating systems.
fsio is executed by the command:
fsio [-qv] [cmdfile]
If cmdfile is present, fsio will read commands from the command file and
echoing each command to stdout if -v . present. If the -q switch is present,
no unsolicited output will be generated by fsio. If the command file is not
present fsio will prompt for input:
fsio>
Commands to fsio have the following general syntax:
verb [switches] args...
The following verbs are supported:
mount - makes a container file available to fsio and specifies the file
system it contains.
umount - removes knowledge of a container file from fsio
newfs - create a new container with an empty file system
set - set file system parameters
info - display information about the file system
dir - list a directory
dump - Dump the contents of a file in a human readable format
copy - copies a single file
type - types the contents of a file on the terminal
delete - deletes a file
status - displays the currently mounted file systems
do - execute commands from a file
help - display help on using fsio
exit - terminate fsio
The following commands are only accepted by file systems which are on magtape
devices:
rewind - position the tape to the start of the data stream
eom - position the tape to the end of the data stream
skipf - position the tape by skipping forward over a number of files
skipr - position the tape by skipping backwards over a number of files
fsio will accept shorter versions of each verb as long as they are unique
within the command set, so c, co and cop are all synonyms for copy.
The generic form of the "dev" argument is "DDnn:" where the ":" is optional
in some commands. DD is a sequence of upper and lower case letters and nn is
an octal number in the range 0 - 377. The length of "DDnn" must not exceed 16
characters. In most cases the number field should not be present and will be
flagged as an error if it is. Some container file formats, e.g. RT-11, allow
multiple file systems within a single container and the number is used to
specify which file system to use. For these types of containers the following
rules apply:
- For "mount" and "umount" commands always use "DD:"
- For file access commands (e.g. "dir", "type" etc) use "DDnn:" ("DD:"
is treated the same as "DD0:")
- The "info" command use the presence/absence of the number to control
what information is display. If "DD:" is used, it will display
information abount all file systems within the container. If "DDnn:"
is used, it will only display information about the specific file
system.
Full command syntax:
1. mount
mount [-dfr] [-t type] dev[:] container type
Make the specified container file available to fsio for I/O.
-d Generate debug output if fsio is built with the DEBUG symbol
defined
-f Force the mount to happen even if we are unable to completely
validate the container file format
-r If present, the file system is only available for read access
-t type Specify the type of the container file. This is only required
for OS/8 file systems where type should be one of "rx01",
"rx02" or "rk05".
dev[:] User supplied name to be used for accessing files within the
container file. Files within the container are named by using
the syntax dev:filespec where filespec uses the native syntax
of the container file system. Files within the host file
system can be named directly without any prefix. If such a
file includes ':' in its filename, the reserved prefix local:
may be used to provide access. If you want to disallow default
access to the local filesystem, creating an environment
variable with the name "FSioForceLocal" (the value does not
matter) will require use of the "local:" prefix.
container The name of the file containing the file system
type The type of the file system in the container
2. umount
umount dev[:]
Removes all knowledge of the container file from fsio
dev[:] The name of a previously mounted file system
3. newfs
newfs [-t type] container type
Create a new container file with an empty file system. The container
will be a fixed size (depending on file system type) and may not exist
prior to issuing this command. This command does not support all features
of container files and will build a fixed size container known to work
on the target O/S:
dos11 RK05 image (2.5MB, 4800 blocks)
rt11 MSCP image (32MB, 65535 blocks)
dosmt An empty file suitable for use with any magtape controller
os8 An OS/8 file system
-t type Use a different size for the container file. The size used
will be file system dependent.
For rt11, the following disk types are valid:
rl02 RL02 image (10MB, 20480 blocks)
rx20 RX20 image (512KB, 1024 blocks)
For os8, the following disk types are valid:
rk05 RK05 image (3248 blocks)
rx01 RX01 image (2002 sectors of 128 bytes each)
rx02 RX02 imgae (2002 sectors of 256 bytes each)
container The name of the file to create
type The type of the file system to create in the container
4. set
set dev: args ...
Set parameters on a mounted file system. The arguments are file system
dependent.
dev: The name of a previously mounted file system
5. info
info dev:
Display internal information about the file system within the container
file
dev: The name of a previously mounted file system
6. dir
dir [-fn] dev:dirspec
List the contents of a specific directory.
-f If present, display full directory information.
-n If present, don't rewind the magtape before listing
dev: The name of a previosly mounted file system
dirspec Specification of the directory to list using the dev: syntax.
7. dump
dump [-bcdnwx] dev:src
Dump the contents of a specified file in some human readable format (e.g
hex, octal etc). If no switches are present, the output will be in octal
word format. If multiple size switches are set, the first in alphabetical
order will take precedence.
-b Output byte at a time
-d Output double word (4 bytes) at a type
-c Output ASCII characters
-w Output word (2 bytes) at a time
-x Output the data in hex
-n Don't rewind the magtape before looking for the input file
dev: The name of a previosly mounted file system
src The name of the source file (e.g. dp:input.dat)
8. copy
copy [-anpc blocks] dev1:src dev2:dest
Copy a file. The copy may be between file systems or within a single
filesystem including the host filesystem.
-a Copy in ASCII mode. This performs any necessary translation
of end-of-line characters.
-n Don't rewind the magtape before looking for the input file
-p Pad the file with NULLs. This is target file system
dependent.
-c blocks If the file system for the destination file supports
contiguous files, "blocks" is the number of file system
contiguous files to be allocated before starting to write
the file. This function depends on the value of "blocks":
0 - Use the size of the source file for the allocation,
if that is 0 (e.g. input from a keyboard) use 1.
!= 0 - Use the larger of "blocks" and the size of the
source file.
dev1: The name of a previosly mounted file system
src The name of the source file (e.g. dk:source.file)
dev2: The name of a previously mounted file system
dest The name of the desination file (e.g. dm:dest.file)
Note that wildcard naming is not supported and the source and destination
file names must be fully specified.
9. type
type [-n] dev:src
Copies the specified file to the terminal. This is equivalent to
copy -a dev:src /dev/tty
-n Don't rewind the magtape before looking for the input file
dev: The name of a previously mounted file system
src The name of the source file (e.g. dp:input.txt)
10. delete
delete dev:file
Deletes the specified file from the file system.
dev: The name of a previously mounted file system
file The name of the file to be deleted
11. status
status
Displays the currently mounted file systems.
12. do
do [-q] cmdFile
Executes commands from the specified file
-q By default, command lines are echoed. Use -q to not echo.
13. help
help
Display help text on the terminal.
14. exit
exit
Terminates the fsio application.
15. rewind
rewind dev:
Positions a magtape device to the start of the tape.
dev: The name of a previously mounted file system
16. eom
eom dev:
Positions a magtape device past the end of the last file already on the
tape. A subsequent copy to the device will append a new file to the tape.
dev: The name of a previously mounted file system
17. skipf
skipf dev: n
Changes the current position of the magtape device by skipping forwards
over a number of files. If end of tape is reached before the file count is
complete, the skip operation will terminate early.
dev: The name of a previously mounted file system
n Number of files to skip (must be > 0)
18. skipr
skipr dev: n
Changes the current position of the magtape device by skipping backwards
over a number of files. If beginning of tape is reached before the file
count is complete, the skip operation will terminate early.
dev: The name of a previously mounted file system
n Number of files to skip (must be > 0)

View File

@@ -0,0 +1,317 @@
How to use fsio to transfer files in/out of SIMH emulators
----------------------------------------------------------
The examples below assume a basic knowlegde of fsio (see the man pages - fsio.1
fsio-dos11.1 and fsio-rt11.1). The following examples assume that we want to
move an ASCII formatted file "file.txt" into the target operating system. If
fsio understands the target file system (DOS-11 and RT-11 right now), we can
copy the file directly into the SIMH container file used for booting the
operating system. For other target file systems we need to transfer into a
file system that the target operating system understands, even if it is not
the native file system for that operation system. In the DEC world, this is
typically RT-11.
Note: all of these examples assume that we are running on a Linux or Unix-like
operating system (in my case Raspbian on a Raspberry Pi).
Native File System Support
--------------------------
DOS-11
------
For DOS-11, fsio understands the native disk format so we can transfer
directly into the bootable SIMH disk ("system.dsk" in the examples).
pi@host:~ $ fsio
fsio> mount dk: system.dsk dos11
dk: successfully mounted
Total blocks: 4800, Free blocks: 3591, Interleave: 1
fsio> copy -a file.txt dk:file.txt
fsio> quit
pi@host:~ $
This will copy file.txt into the default UFD ([1,1]) on the target file system.
The copy will be in ASCII mode meaning that line endings will be translated
into the character pair <cr><lf> which DOS/BATCH-11 requires. If you wish to
transfer the file into another (existing) UFD (e.g. [200,200]) you can use
either of the following 2 options:
fsio> copy -a file.txt dk:file.txt[200,200]
or
fsio> set dk: uic [200,200]
fsio> copy -a file.txt dk:file.txt
If the destination UFD does not already exist on the target file system use
the following to create the UFD:
fsio> set dk: ufd [200,200]
fsio> copy -a file.txt dk:file.txt
RT-11
-----
For RT-11, fsio understands the native disk format so we can transfer
directly into the bootable SIMH disk ("rt11sys.dsk" in the examples). Note
that RT-11 disk images can hold multiple partitions, each having a maximum
size of 32MB. Partitions are named by appending an octal number to the device
name - xx0: will be the first partition, xx1: the second etc. fsio will only
allow access to partitions which have been initialized with an RT-11 file
system. The example below shows a disk with 3 partitions but only the first
and last have been initialized.
pi@host:~ $ fsio
fsio> mount dk: rt11sys.dsk rt11
dk: successfully mounted (2 partitions)
dk0:
Total blocks: 65536, Free blocks: 24279
Directory segments: 31 (Highest 4)
Extra bytes/directory entry: 0
dk2:
Total blocks: 65536, Free blocks: 65422
Directory segments: 31 (Highest 1)
Extra bytes/directory entry: 0
fsio> copy -a file.txt dk:file.txt
fsio> quit
pi@host:~ $
This will copy file.txt into the target file system. The copy will be in
ASCII mode meaning that line endings will be translated into the character
pair <cr><lf> which RT-11 requires. In addition, unless the file ends
exactly on a block (512 bytes) boundary, a ^Z (octal 32) will be appended
to the file indicating end-of-file.
Foreign File System Support
---------------------------
For other target operating systems we will use an RT-11 format RL02 disk as an
intermediary for performing the transfer:
pi@host:~ $ fsio
fsio> newfs -a xfer.dsk rt11
fsio> mount dk: xfer.dsk rt11
fsio> copy -a file.txt dk:file.txt
fsio> quit
pi@host:~ $
This will create a maximum sized, single partition RT-11 file system in a
container file called "xfer.dsk" which may be copied to the target system
running SIMH.
Once on the target system, the commands to copy the file into the emulated
operating system will depend on that operating system and, possible, its age.
RSX-11M/RSX-11M+
----------------
Use the FLX utility to copy the file over to the Files-11 file system:
>set /uic=[1,2]
>^E
Simulation stopped, PC: 017460 (BR 17426)
sim> att rq2 xfer.dsk
sim> c
>all du2:
>mou du2:/for
>ins $flx
>flx [200,200]/fa=du2:file.txt/rt
>pip [200,200]file.txt/fu
Directory DU0:[200,200]
2019-01-10 18:10
FILE.TXT;1 (6400,15) 1./1. 2019-01-10 18:09
[1,2] [RWED,RWED,RWED,R]
Total of 1./1. blocks in 1. file
>dmo du2:
18:10:28 *** DU2: -- Dismount complete
DMO -- TT0: dismounted from DU2: *** Final dismount initiated ***
>dea du2:
>^E
Simulation stopped, PC: 017460 (BR 17426)
sim> det rq2
sim> c
>
Note that RSX FLX cannot handle formatted ASCII input files with an embedded
^Z character indicating end-of-file. Use the "-p" switch during the copy to
pad the file with NULLs.
IAS
---
The following example assumes that you are logged into a non-console
terminal. You will still need to break in on the cosole with ^E and attach
the RT-11 transfer disk as in all the other examples.
PDS> ALLOC DL0:
PDS> MOU/FOR DL0:
MOUNT-**Volume Information**
Device =DL0
Class =Foreign
UIC =[201,201]
Access =[RWED,RWED,RWED,RWED]
Charac =[FOR,ATCH,DCF]
PDS> DIR DL0:/RT
DIRECTORY DL0:
31-JAN-99
FILE .TXT 1. 12-87
< UNUSED > 20411.
20411. FREE BLOCKS
TOTAL OF 1. BLOCKS IN 1. FILES
PDS> COPY DL:FILE.TXT/RT *.*
PDS> DIR
Directory DU0:[201,201]
31-JAN-99 15:56
FILE.TXT;1 1. 31-JAN-99 15:56
Total of 1./1. blocks in 1. file
PDS> DISM DL0:
DMO -- DL00: ** DISMOUNT COMPLETE **
Note that in order to use the RL02 drive from timesharing, the following
changes will need to be made to the IAS startup scripts of the PiDP-11
distribution:
1. [1,1]STARTUP.CMD
Add the following lines at the start of the file:
INS [11,1]DL
LOA DL
2. [1,1]IASSTART.CMD
Add the following lines after the one containing "DU0/S":
DL0
DL1
After making these changes, reboot the system and users will be able to access
the 2 RL02 drives.
RSTS/E
------
For this example I have used the "-a" on the fsio "newfs" command to create an
empty RL02 disk image. Use the "-p" switch on the fsio "copy" command to pad
the file with NULLs, otherwise the ^Z will be copied into the RSTS/E file. Use
the FIT utility to copy the file over to the RSTS/E file system:
$ ^E
Simulation stopped, PC: 065640 (BR 65630)
sim> att rl0 xfer.dsk
sim> c
$ run auxlib$:fit
FIT V10.1-A RSTS V10.1-L RSTS/E V10.1
FIT>sy:=dl0:file.txt/rt11
FIT>^Z
$ dir file.txt/fu
Name .Typ Size Prot Access Date Time Clu RTS Pos Op/rr SY:[1,2]
FILE .TXT 1 < 60> 12-Jan-19 12-Jan-87 04:23 PM 8 RT11 214 0/0
Total of 1 block in 1 file in SY:[1,2]
$ ^E
Simulation stopped, PC: 065640 (BR 65630)
sim> det rl0
sim> c
$
VMS
---
Use the exchange utility to copy the file over to the VMS file system:
$^E
Simulation stopped, PC: 80B90B8D (BBC #3,26C(R3),80B90BE1)
sim> att rq1 xfer.dsk
sim> c
$ mou/for dua1:
%MOUNT-I-MOUNTED, mounted on _ROUTER$DUA1:
$ exchange copy dua1:file.txt/volume=rt11/record=stream file.txt
%EXCHANGE-S-MOUNTED, the RT-11 volume _ROUTER$DUA1: has been mounted
$ dism dua1:
$^E
Simulation stopped, PC: 80B90936 (ASHL #1,R3,R0)
sim> det rq1
sim> c
$ dir file.txt
Directory SYS$SYSROOT:[SYSMGR]
FILE.TXT;1
Total of 1 file.
$
This can be especially useful for getting the Hobbyist licences into VMS
before you have any network running.
TOPS-10
-------
The RTFLX utility is available on TOPS-10 reading/writing files on an RX20
drive (combination of RX02 drive and controller) attached to a DECsystem-2020
(KS10). In order to access the RX20, a new system generation must be
performed. There is a help file on Tops-10 for RTFLX but no other
documentation.
.
Simulation stopped, PC: 000001 (SOJG 6,1)
sim> att ry0 xfer.dsk
RY: buffering file in memory
sim> c
.assign rxa0: rt:
RXA000 assigned
.r rtflx
RTFLX>dir
FILE TXT 1 11-Jun-87
Total of 1 block in 1 file
973 blocks free on RT:
RTFLX>copy rt:file.txt
FILE.TXT=RT:FILE.TXT
RTFLX>exit
.dir *.txt
FILE TXT 1 <057> 11-Jun-87 DSKB: [1,2]
.deassign rxa0:
.
If you use the RTFLX "ZERO" command to initialize an RT-11 file system it
will create an RT-11 V2 format file system and you will need to use the "-f"
switch to force fsio to see the file system.

377
converters/fsio/local.c Normal file
View File

@@ -0,0 +1,377 @@
/*
* Copyright (C) 2018 John Forecast. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "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 AUTHOR 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.
*/
/*
* Support routines for local file access under fsio.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#include "fsio.h"
/*++
* l o c a l I n f o
*
* Display information about the local file system. This is not supported
* by the "local" device.
*
* Inputs:
*
* mount - pointer to the mounted file system descriptor
* unit - device unit number (unused)
* present - device unit number present (unused)
*
* Outputs:
*
* None
*
* Returns:
*
* None
*
--*/
static void localInfo(
struct mountedFS *UNUSED(mount),
uint8_t UNUSED(unit),
uint8_t UNUSED(present)
)
{
fprintf(stderr, "info: The \"local:\" device does not support this command\n");
}
/*++
* l o c a l D i r
*
* Produce a full or brief directory listing.
*
* Inputs:
*
* mount - pointer to the mounted file system descriptor
* unit - device unit number
* fname - pointer to filename string
*
* Outputs:
*
* None
*
* Returns:
*
* None
*
--*/
static void localDir(
struct mountedFS *UNUSED(mount),
uint8_t UNUSED(unit),
char *fname
)
{
char cmd[64];
sprintf(cmd, "/bin/ls %s%s\n",
SWISSET('f') ? "-l " : "", fname);
system(cmd);
}
/*++
* l o c a l O p e n F i l e R
*
* Open a local file for reading.
*
* Inputs:
*
* mount - pointer to the mounted file system descriptor
* unit - device unit number
* fname - pointer to filename string
*
* Outputs:
*
* None
*
* Returns:
*
* Pointer to open file descriptor, NULL if open fails
*
--*/
static void *localOpenFileR(
struct mountedFS *UNUSED(mount),
uint8_t UNUSED(unit),
char *fname
)
{
return fopen(fname, "r");
}
/*++
* l o c a l O p e n F i l e W
*
* Open a local file for writing.
*
* Inputs:
*
* mount - pointer to the mounted file system descriptor
* unit - device unit number
* fname - pointer to filename string
* size - estimated file size (in bytes)
*
* Outputs:
*
* None
*
* Returns:
*
* Pointer to open file descriptor, NULL if open fails
*
--*/
static void *localOpenFileW(
struct mountedFS *UNUSED(mount),
uint8_t UNUSED(unit),
char *fname,
off_t UNUSED(size)
)
{
return fopen(fname, "w");
}
/*++
* l o c a l F i l e S i z e
*
* Return the size of a currently open file. If the file is open in ASCII
* mode we do not know how many lines are present in the file and so cannot
* calculate how much additional space will be needed for a possible <LF>
* to <CRLF> translation. In this case we return 0.
*
* Inputs:
*
* filep - pointer to open file descriptor
*
* Outputs:
*
* None
*
* Returns:
*
* Current size of the file, 0 on error
*
--*/
static off_t localFileSize(
void *filep
)
{
FILE *file = filep;
struct stat stat;
if (!SWISSET('a'))
if (fstat(fileno(file), &stat) == 0)
return stat.st_size;
return 0;
}
/*++
* l o c a l D e l e t e F i l e
*
* Delete a local file.
*
* Inputs:
*
* file - pointer to open file descriptor
* fname - pointer to filename string
*
* Outputs:
*
* None
*
* Returns:
*
* None
*
--*/
static void localDeleteFile(
void *file,
char *fname
)
{
fclose(file);
if (unlink(fname) != 0)
fprintf(stderr, "delete: failed to delete \"%s\"\n", fname);
}
/*++
* l o c a l C l o s e F i l e
*
* Close an open local file.
*
* Inputs:
*
* file - pointer to open file descriptor
*
* Outputs:
*
* None
*
* Returns:
*
* None
*
--*/
static void localCloseFile(
void *file
)
{
fclose(file);
}
/*++
* l o c a l R e a d F i l e
*
* Read from a local file into a supplied buffer. If ASCII mode is active,
* each read will return at most 1 line of data and any terminating <LF> will
* be translated into <CRLF>.
*
* Inputs:
*
* file - pointer to open file descriptor
* buf - pointer to buffer
* buflen - length of the supplied buffer
*
* Outputs:
*
* None
*
* Returns:
*
* # of bytes of data read, 0 means EOF or error
*
--*/
static size_t localReadFile(
void *file,
void *buf,
size_t buflen
)
{
if (SWISSET('a')) {
char *bufr = buf;
int readlen;
if (fgets(bufr, buflen - 1, file) == NULL)
return 0;
/*
* Translate terminating \n into \r\n unless it is already there
*/
if ((readlen = strlen(bufr)) != 0) {
if (bufr[readlen - 1] == '\n') {
if ((readlen == 1) || (bufr[readlen - 2] != '\r'))
strcpy(&bufr[readlen - 1], "\r\n");
}
}
return strlen(bufr);
}
return fread(buf, sizeof(char), buflen, file);
}
/*++
* l o c a l W r i t e F i l e
*
* Write to a local file from a supplied buffer. If ASCII mode is active,
* if the buffer is terminated with <CRLF> translate it into <LF>.
*
* Inputs:
*
* file - pointer to open file descriptor
* buf - pointer to buffer
* buflen - length of the supplied buffer
*
* Outputs:
*
* None
*
* Returns:
*
* # of bytes of data written, 0 means error
*
--*/
static size_t localWriteFile(
void *file,
void *buf,
size_t buflen
)
{
if (SWISSET('a')) {
char *bufw = buf;
if (buflen >= 2)
if ((bufw[buflen - 2] == '\r') && (bufw[buflen - 1] == '\n')) {
bufw[buflen - 2] = '\n';
buflen--;
}
}
return fwrite(buf, sizeof(char), buflen, file);
}
/*++
* l o c a l F S
*
* Descriptor for accessing local files. Note that none of command routines
* are present since this device never appears to be mounted.
--*/
struct FSdef localFS = {
NULL,
"local",
"local Local file access\n",
0,
0,
NULL,
NULL,
NULL,
NULL,
NULL,
localInfo,
localDir,
localOpenFileR,
localOpenFileW,
localFileSize,
localCloseFile,
localReadFile,
localWriteFile,
localDeleteFile,
NULL, /* No tape support functions */
NULL,
NULL,
NULL
};
/*
* Statically allocated mounted file system for local file access
*/
struct mountedFS localMount;

3014
converters/fsio/os8.c Normal file

File diff suppressed because it is too large Load Diff

248
converters/fsio/os8.h Normal file
View File

@@ -0,0 +1,248 @@
/*
* Copyright (C) 2019 John Forecast. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "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 AUTHOR 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.
*/
#ifndef __OS8_H__
#define __OS8_H__
/*
* General disk layout (each block is 256 12-bit words).
*
* Block
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 0 | Reserved |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 1-6 | Directory segments |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 7-12 | Keyboard Monitor | **
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 13-15 | User Service Routine | **
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 16-25 | Device Handlers | **
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 26 | Enter Processor For USR | **
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 27-50 | System Scratch Blocks | **
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 51-53 | Command Decoder | **
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 54-55 | SAVE And DATE Overlays | **
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 56 | Monitor Error Routine | **
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 57 | CHAIN Processor For USR | **
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 60-63 | System ODT | **
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 64 | Reserved For System Expansion | **
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 65 | CCL Reminiscences | **
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 66 | 12K TD8E Resident Code | **
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 67 | CCL Overlay | **
* +---+---+---+---+---+---+---+---+---+---+---+---+
* Files | ... |
* | ... |
* | ... |
* | ... |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* End Of Volume
*
* Blocks marked "**" are only reserved on System Devices, on non-System
* Devices, file storage starts at block 7.
*
* Directory Segment Header:
*
* Word
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 0 | Minus # of entries in this segment |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 1 | Starting block # of first file in this segment|
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 2 | Link to next directory segment |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 3 | Flag Word |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 4 | Minus # of additional information words |
* +---+---+---+---+---+---+---+---+---+---+---+---+
*
* Directory Entry:
*
* Word
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 0 | Sixbit ASCII File Name (chars 1 - 2) |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 1 | Sixbit ASCII File Name (chars 3 - 4) |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 2 | Sixbit ASCII File Name (chars 5 - 6) |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* 3 | Sixbit ASCII File Extension (chars 1 - 2) |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* | N additional information words |
* | ... |
* | ... |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* N + 4 | Minus file length in blocks |
* +---+---+---+---+---+---+---+---+---+---+---+---+
*
* If there are additional informations words in the directory, the file
* creation time is stored in word 4 (zero means not available):
*
* +---+---+---+---+---+---+---+---+---+---+---+---+
* | | | |
* +---+---+---+---+---+---+---+---+---+---+---+---+
* | | | | | |
* | | | | +-------+
* | | +---------------+ |
* +-----------+ | Year - 1970
* | Day of Month (1 - 31)
* Month (1 - 12)
*/
#define OS8_BLOCKSIZE 256 /* Size of a block on disk (words) */
#define OS8_DSSTART 1 /* Start of directory segments */
#define OS8_DSLAST 6 /* Last directory segment */
#define OS8_DATA 7 /* Start of data (non-system device) */
#define OS8_DH_ENTRIES 0 /* -(# of entries in segment) */
#define OS8_DH_START 1 /* Block # for segment start */
#define OS8_DH_NEXT 2 /* Next directory segment */
#define OS8_DH_FLAGWD 3 /* Flag word */
#define OS8_DH_EXTRA 4 /* -(# of additional info. words) */
#define OS8_DH_SIZE 5 /* Size of directory header */
#define OS8_DI_FNAME1 0 /* File name (chars 1 - 2) */
#define OS8_DI_FNAME2 1 /* File name (chars 3 - 4) */
#define OS8_DI_FNAME3 2 /* File name (chars 5 - 6) */
#define OS8_DI_EXT 3 /* File extension (1 - 2 chars) */
/* Additional words go here */
#define OS8_DI_DATE 4 /* Optional creation date */
#define OS8_DI_LENGTH 4 /* -(File length in blocks) */
#define OS8_DI_SIZE 5 /* Default entry size */
#define OS8_ED_IND 0 /* Empty directory entry */
#define OS8_ED_LENGTH 1 /* -(Empty file length in blocks) */
#define OS8_ED_SIZE 2 /* Entry size */
/*
* Device specific definitions
*/
#define OS8_RK05FS_BLKS 3248 /* Blocks in an RK05 file system */
#define OS8_RX01SS 128 /* Byte sector size of RX01 floppy */
#define OS8_RX02SS 256 /* Byte sector size of RX02 floppy */
#define OS8_RX01SS_W 64 /* Word sector size of RX01 floppy */
#define OS8_RX02SS_W 128 /* Word sector size of RX02 floppy */
#define OS8_RX0xNSECT 26 /* Sectors/track on RX01/RX02 */
#define OS8_RX0xSZ 2002 /* Sectors on an RX01/RX02 */
/*
* Structure to describe a filename. Asterisks may be used as wild card
* characters for the 2 components of a filename; namd and extension
*/
struct os8FileSpec {
uint8_t flags; /* Wild card indicators */
uint16_t name[3]; /* File name (sixbit) */
uint16_t ext; /* File extension (sixbit) */
char fname[6]; /* File name (ASCII) */
char fext[2]; /* File extension (ASCII) */
};
#define OS8_WC_NAME 001 /* Wild card in name */
#define OS8_WC_EXT 002 /* Wild card in extension */
#define OS8_M_NONE 0000 /* Wild cards not allowed */
#define OS8_M_ALLOW 0001 /* Wild cards allowed */
#define OS8_M_NONAME 0002 /* Wild cards allowed */
/* If no filename + extension */
/* present, default to *.* */
/*
* OS/8 files pack 3 bytes into a pair of 12-bit words. The following states
* are used to pack/unpack bytes.
*/
#define OS8_BYTE0 0 /* Pack/unpack byte 0 */
#define OS8_BYTE1 1 /* Pack/unpack byte 1 */
#define OS8_BYTE2 2 /* Pack/unpack byte 2 */
#define OS8_CHECK 3 /* Check for end of block/EOF */
/*
* Structure to define an open file. This is an OS/8 directory entry along
* with sufficient information to be able to write the directory entry back
* to disk.
*/
struct os8OpenFile {
uint16_t name[3]; /* File name */
uint16_t ext; /* File extension */
uint16_t creation; /* Creation date */
uint16_t length; /* File length (blocks) */
/* End of directory entry */
uint8_t segment; /* Directory segment */
uint16_t offset; /* Directory offset */
uint16_t entrysz; /* Size of directory entries */
uint16_t extra; /* Extra words in directory entries */
uint16_t remain; /* Remaining directory entries */
/* Start of read/write info */
enum openMode mode; /* Open mode (read/write) */
struct mountedFS *mount; /* Mounted file system descriptor */
uint8_t unit; /* File system # */
uint16_t *buffer; /* Private buffer for file I/O */
uint16_t start; /* Starting block # */
uint16_t current; /* Current block # */
uint16_t last; /* Last block # */
uint16_t wordpos; /* Current word offset */
uint8_t bytepos; /* Current byte position */
off_t written; /* # of bytes written to the file */
};
/*
* Device descriptor
*/
struct OS8device {
char *name; /* Device name */
uint8_t filesys; /* # of file systems on device */
size_t diskSize; /* # of blocks on device */
off_t skip; /* Reserved space at start of disk */
uint16_t blocks[8]; /* File system sizes */
int (*blockPresent)(struct mountedFS *, uint8_t, unsigned int);
int (*readBlock)(struct mountedFS *, uint8_t, unsigned int, void *);
int (*writeBlock)(struct mountedFS *, uint8_t, unsigned int, void *);
};
/*
* OS/8 specific data area
*/
struct OS8data {
unsigned int blocks; /* Size of container */
struct OS8device *device; /* Device type */
uint8_t devices; /* # of "devices" present */
uint8_t valid; /* Bitmap of valid devices */
uint16_t date; /* Date for creating files */
uint16_t buf[OS8_BLOCKSIZE]; /* Disk buffer */
};
#endif

2586
converters/fsio/rt11.c Normal file

File diff suppressed because it is too large Load Diff

306
converters/fsio/rt11.h Normal file
View File

@@ -0,0 +1,306 @@
/*
* Copyright (C) 2018 John Forecast. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "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 AUTHOR 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.
*/
#ifndef __RT11_H__
#define __RT11_H__
/*
* General disk layout:
*
* Block
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0 | Reserved |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 1 | Home Block (Reserved) |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 2 | Reserved |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 3 | Reserved |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 4 | Reserved |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 5 | Reserved |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 6 | Directory Segment 1 |
* 7 | |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 10 | Directory Segment 2 |
* 11 | |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | ... |
* | ... |
* | ... |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* x | Directory Segment n |
* x+1 | |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* Files | ... |
* | ... |
* | ... |
* | ... |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* End of Volume
*
* Home Block:
*
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0000 | Bad block replacement table |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0202 | Unused |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0204 | INITIALIZE/RESTORE data area |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0252 | BUP Information area |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0274 | Unused |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0700 | Reserved for Digital - 000000 |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0702 | Reserved for Digital - 000000 |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0704 | Unused |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0722 | Pack cluster size - 000001 |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0724 | Block # of first directory segment - 000006 |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0726 | System version - Radix-50 "V3A"? |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0730 | Volume identification - "RT11A " |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0744 | Owner name - " " |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0760 | System identification - "DECRT11A " |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* 0776 | Checksum |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
*
* Directory Segment Header:
*
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Total # of directory segments (1 - 31) |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Next logical directory segment # |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Highest directory segment in use |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Extra bytes per directory entry |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Block # for start of this segment |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
*
* Directory Entry:
*
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Status Word |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Radix-50 File Name (chars 1 - 3) |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Radix-50 File Name (chars 4 - 6) |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Radix-50 File Type (1 - 3 chars) |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Job # | Channel # |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Creation Date |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | Optional Extra Words |
* | ... |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
*
* Status Word:
*
* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | | | | | | | | | | | | | | | | |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | | | | | | |
* | | | | | | - Prefix block indicator
* | | | | | - Tentative file
* | | | | - Empty area
* | | | - Permanent file
* | | - End of segment marker
* | - Protected from .WRITE requests
* - Protected permanent file
*
* Date Word:
*
* 15 14 13 10 9 5 4 0
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | | | | |
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | | | | | | | |
* +---+ +-----------+ +---------------+ +---------------+
* | | | |
* | | | Year - 1972
* | | | - 32 x Age
* | | - Day (1 - 31)
* | - Month (1 - 12)
* - Age (0 - 3)
*/
#define RT11_HOME 1 /* Home block is always 1 */
#define RT11_DSSTART 6 /* Start of directory segs */
#define RT11_BLOCKSIZE 512 /* Size of a data block on disk */
#define RT11_RX01SS 128 /* Sector size of RX01 floppy */
#define RT11_RX02SS 256 /* Sector size of RX02 floppy */
#define RT11_RX0xNSECT 26 /* Sectors/track on RX01/RX02 */
#define RT11_SYSVER_V3A 36521
#define RT11_SYSVER_V04 36434
#define RT11_SYSVER_V05 36435
#define RT11_NOPART 0 /* Not a valid partition */
#define RT11_SINGLE 1 /* Single partition per disk */
#define RT11_MULTI 2 /* Multiple partitions per disk */
#define RT11_VOLID "RT11A "
#define RT11_OWNER " "
#define RT11_SYSID "DECRT11A "
#define RT11_VMSSYSID "DECVMSEXCHNG" /* VMS exchange created volume */
/*
* Partition sizes. The last block of a maximum sized partition (32MB) is
* unused. The minimum size is based on a file system having 1 directory
* segment and 1 data block! Is this reasonable?
*/
#define RT11_MAXPARTSZ 0200000 /* Max partition size */
#define RT11_MINPARTSZ 0000010 /* Min partition size */
#define RT11_RK05SZ 4800 /* Blocks on an RK05 drive */
#define RT11_RL01SZ 10240 /* Blocks on an RL01 drive */
#define RT11_RL02SZ 20480 /* Blocks on an RL02 drive */
#define RT11_RX0xSZ 2002 /* Sectors on an RX01/RX02 */
#define RT11_HB_BBLOCK 0000 /* Bad block replacement tbl */
#define RT11_HB_RESTORE 0102 /* INIT/RESTORE data area */
#define RT11_HB_BUP 0125 /* BUP info area */
#define RT11_HB_PCS 0351 /* Pack cluster size */
#define RT11_HB_FIRST 0352 /* First directory segment */
#define RT11_HB_SYSVER 0353 /* System version */
#define RT11_HB_VOLID 0354 /* Volume identification */
#define RT11_HB_OWNER 0362 /* Owner name */
#define RT11_HB_SYSID 0370 /* System identification */
#define RT11_HB_CHKSUM 0377 /* Checksum */
#define RT11_DH_COUNT 0000 /* # of directory segments */
#define RT11_DH_NEXT 0001 /* Next logical segment # */
#define RT11_DH_HIGHEST 0002 /* Highest segment # in use */
#define RT11_DH_EXTRA 0003 /* Extra bytes/dir. entry */
#define RT11_DH_START 0004 /* Block # for segment start */
#define RT11_DH_SIZE 0005 /* Size of header */
#define RT11_DS_SIZE 512 /* Directory segment size */
#define RT11_DS_DISPACE (RT11_DS_SIZE - RT11_DH_SIZE)
#define RT11_DS_MAX 31 /* Max # of directory segments */
#define RT11_DI_STATUS 0000 /* Status word */
#define RT11_DI_FNAME1 0001 /* File name (chars 1 - 3) */
#define RT11_DI_FNAME2 0002 /* File name (chars 4 - 6) */
#define RT11_DI_FTYPE 0003 /* File type (1 - 3 chars) */
#define RT11_DI_LENGTH 0004 /* Total file length */
#define RT11_DI_JOB_CHN 0005 /* Channel # */
#define RT11_DI_CREATE 0006 /* Date of creation */
#define RT11_DI_SIZE 0007 /* Default entry size */
#define RT11_E_PRE 000020 /* Prefix block indicator */
#define RT11_E_TENT 000400 /* Tentative file */
#define RT11_E_MPTY 001000 /* Empty area */
#define RT11_E_PERM 002000 /* Permanent file */
#define RT11_E_EOS 004000 /* End of segment marker */
#define RT11_E_READ 040000 /* Protected from .WRITE */
#define RT11_E_PROT 100000 /* Protected permanent file */
#define RT11EOS(v) (((v) & RT11_E_EOS) != 0)
#define RT11_DW_YEAR 0000037 /* Year */
#define RT11_DW_DAY 0001740 /* Day */
#define RT11_DW_MONTH 0036000 /* Month */
#define RT11_DW_AGE 0140000 /* Age */
/*
* Structure to describe a filename. Asterisks may be used as wild card
* characters for the 2 components of a filename; name and type.
*/
struct rt11FileSpec {
uint8_t flags; /* Wild card indicators */
uint16_t name[2]; /* File name (RAD50) */
uint16_t type; /* File type (RAD50) */
char fname[6]; /* File name (ASCII) */
char ftype[3]; /* File type (ASCII) */
};
#define RT11_WC_NAME 0001 /* Wild card in name */
#define RT11_WC_TYPE 0002 /* Wild card in type */
#define RT11_M_NONE 0000 /* Wild cards not allowed */
#define RT11_M_ALLOW 0001 /* Wild cards allowed */
#define RT11_M_NONAME 0002 /* Wild cards allowed */
/* If no filename + extension */
/* present, default to *.* */
/*
* Structure to define an open file. This is an RT-11 directory entry along
* with sufficient information to be able to write the directory entry back
* to disk. Some of the directory information can be created on-the-fly so
* will not be stored here.
*/
struct rt11OpenFile {
uint16_t status; /* File status */
uint16_t name[2]; /* File name */
uint16_t type; /* File type */
uint16_t length; /* Blocks written */
uint16_t creation; /* Creation date */
/* End of directory entry */
uint8_t segment; /* Directory segment # */
uint16_t offset; /* Directory offset */
/* Start of read/write info */
enum openMode mode; /* Open mode (read/write) */
struct mountedFS *mount; /* Mounted file system descriptor */
uint8_t unit; /* Partition number */
char *buffer; /* Private buffer for file I/O */
uint16_t current; /* Current working block # */
uint16_t last; /* Last usable block */
uint16_t count; /* Bytes used in current block */
uint16_t start; /* Starting block # */
};
/*
* RT-11 specific data area.
*/
struct RT11data {
unsigned int blocks; /* Size of container */
unsigned int sectorsz; /* Interleave sector size */
/* 0 if no interleave */
uint16_t filesystems; /* Max # of filesystems */
uint16_t valid[16]; /* Valid partitions */
uint16_t maxblk[256]; /* Max block address */
uint16_t first[256]; /* First directory block */
uint16_t buf[512]; /* Disk buffer - enough for a */
/* directory segment */
};
#define RT11_PARTITIONVALID(d, u) ((d->valid[u / 16] & (1 << (u % 16))) != 0)
#endif

816
converters/fsio/tape.c Normal file
View File

@@ -0,0 +1,816 @@
/*
* Copyright (C) 2018 John Forecast. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "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 AUTHOR 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.
*/
/*
* Support routines for reading/writing SIMH tape container files.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <sys/stat.h>
#include "fsio.h"
/*++
* t a p e V e r i f y
*
* Verify that the container format is valid, leaving the tape positioned
* at beginning-of-tape.
*
* Inputs:
*
* container - pointer open container file
* eot - return end-of-tape info here, NUL if not needed
*
* Outputs:
*
* None
*
* Returns:
*
* 1 if format is valid, 0 otherwise
*
--*/
int tapeVerify(
FILE *container,
off_t *eot
)
{
int errorCount = 0, tmSeen = 0;
uint32_t meta, header, bc;
off_t position;
struct stat stat;
/*
* Determine the size of the file.
*/
fstat(fileno(container), &stat);
for (;;) {
position = ftello(container);
/*
* If we are positioned at the end-of-file, there is a tape mark or
* end-of-media marker missing. Treat it as though one is present.
*/
if (position == stat.st_size)
break;
if (fread(&meta, sizeof(meta), 1, container) != 1)
return 0;
bc = le32toh(meta);
switch (bc) {
case ST_TM:
if (++tmSeen <= 1)
break;
/* Treat second TM in a row as end of medium */
/* FALLTHROUGH */
case ST_EOM:
if (fseeko(container, -sizeof(meta), SEEK_CUR) != 0)
return 0;
if (errorCount)
printf("mount: Tape contains error records\n");
goto done;
case ST_GAP:
break;
default:
/*
* Record descriptor
*/
tmSeen = 0;
header = bc;
if ((bc & ST_ERROR) != 0)
errorCount++;
if ((bc & ST_MBZ) != 0)
return 0;
bc = RECLEN(bc & ST_LENGTH);
/*
* Check if we are seeking ouside of the file. If so, this is not
* a .tap container file.
*/
if ((position + bc + (2 * sizeof(meta))) > (unsigned long long)stat.st_size)
return 0;
if (fseeko(container, bc, SEEK_CUR) != 0)
return 0;
if (fread(&meta, sizeof(meta), 1, container) != 1)
return 0;
bc = le32toh(meta);
if (header != bc)
return 0;
}
}
done:
if (eot != NULL)
*eot = ftello(container);
/*
* Position at beginning-of-tape.
*/
if (fseeko(container, 0, SEEK_SET) == 0)
return 1;
return 0;
}
/*++
* t a p e G e t P o s i t i o n
*
* Get the current position of the tape.
*
* Inputs:
*
* container - pointer open container file
*
* Outputs:
*
* None
*
* Returns:
*
* Current position of the tape
*
--*/
off_t tapeGetPosition(
FILE *container
)
{
return ftello(container);
}
/*++
* t a p e S e t P o s i t i o n
*
* Position the tape to a position previously obtained by tapeGetPosition().
*
* Inputs:
*
* container - pointer open container file
* pos - requested position
*
* Outputs:
*
* None
*
* Returns:
*
* 1 if successfully positioned, 0 if error
*
--*/
int tapeSetPosition(
FILE *container,
off_t pos
)
{
return fseeko(container, pos, SEEK_SET) == 0 ? 1 : 0;
}
/*++
* t a p e S k i p R e c o r d F
*
* Skip over the next record in the forward direction.
*
* Inputs:
*
* container - pointer open container file
*
* Outputs:
*
* None
*
* Returns:
*
* ST_FAIL - error accessing container file
* ST_EOM - end of media detected
* ST_TM - tape mark detected
* Other - record length (including error flag)
*
--*/
uint32_t tapeSkipRecordF(
FILE *container
)
{
return tapeReadRecordLength(container);
}
/*++
* t a p e S k i p R e c o r d R
*
* Skip over the next record in the reverse direction.
*
* Inputs:
*
* container - pointer open container file
*
* Outputs:
*
* None
*
* Returns:
*
* ST_FAIL - error accessing container file
* ST_EOM - end of media detected
* ST_TM - tape mark detected
* Other - record length (including error flag)
*
--*/
uint32_t tapeSkipRecordR(
FILE *container
)
{
return tapeReadRecordLengthReverse(container);
}
/*++
* t a p e P e e k R e c o r d L e n g t h
*
* Get the length of the next record on the tape without actually reading
* the data or changing the current position of the tape.
*
* Inputs:
*
* container - pointer open container file
*
* Outputs:
*
* None
*
* Returns:
*
* ST_FAIL - error accessing the container file
* ST_EOM - end of media detected
* ST_TM - tape mark detected
* Other - record length (including error flag)
*
--*/
uint32_t tapePeekRecordLength(
FILE *container
)
{
off_t pos = ftello(container);
uint32_t meta;
if ((fread(&meta, sizeof(meta), 1, container) != 1) ||
(fseeko(container, pos, SEEK_SET) != 0))
return ST_FAIL;
return le32toh(meta);
}
/*++
* t a p e R e a d R e c o r d
*
* Read the next record from the tape into the specified buffer. If the
* buffer is smaller than the record, the entire record will be consumed,
* losing data.
*
* Inputs:
*
* container - pointer open container file
* buf - pointer to the buffer to receive the data
* len - length of the buffer
*
* Outputs:
*
* None
*
* Returns:
*
* ST_FAIL - error accessing the container file
* ST_EOM - end of media detected
* ST_TM - tape mark detected
* Other - record length (including error flag)
* if the buffer is smaller than the record, the
* length returned will be that of the buffer
*
--*/
uint32_t tapeReadRecord(
FILE *container,
void *buf,
int len
)
{
off_t pos = ftello(container);
uint32_t meta, bc, erflag, length;
if (fread(&meta, sizeof(meta), 1, container) != 1)
return ST_FAIL;
bc = le32toh(meta);
switch (bc) {
case ST_EOM:
case ST_TM:
return bc;
default:
erflag = bc & ST_ERROR;
bc &= ST_LENGTH;
length = (uint32_t)len;
if (bc < length)
length = bc;
if (fread(buf, sizeof(uint8_t), length, container) != length)
return ST_FAIL;
/*
* Now position the file after this record.
*/
pos += RECLEN(bc) + (2 * sizeof(meta));
if (fseeko(container, pos, SEEK_SET) != 0)
return ST_FAIL;
return erflag | length;
}
return ST_FAIL;
}
/*++
* t a p e R e a d R e c o r d L e n g t h
*
* Get the length of the next record on the tape without actually reading
* the data. The tape will be positioned at the start of the next record.
*
* Inputs:
*
* container - pointer open container file
*
* Outputs:
*
* None
*
* Returns:
*
* ST_FAIL - error accessing container file
* ST_EOM - end of media detected
* ST_TM - tape mark detected
* Other - record length (including error flag)
*
--*/
uint32_t tapeReadRecordLength(
FILE *container
)
{
off_t pos = ftello(container);
uint32_t meta, bc, erflag;
if (fread(&meta, sizeof(meta), 1, container) != 1)
return ST_FAIL;
bc = le32toh(meta);
switch (bc) {
case ST_EOM:
case ST_TM:
return bc;
default:
erflag = bc & ST_ERROR;
bc &= ST_LENGTH;
/*
* Now position the file after this record.
*/
pos += RECLEN(bc) + (2 * sizeof(meta));
if (fseeko(container, pos, SEEK_SET) != 0)
return ST_FAIL;
return erflag | bc;
}
return ST_FAIL;
}
/*++
* t a p e R e a d R e c o r d L e n g t h R e v e r s e
*
* Get the length of the previous record on the tape without actually reading
* the data. The tape will be positioned at the start of the previous record.
*
* Inputs:
*
* container - pointer open container file
*
* Outputs:
*
* None
*
* Returns:
*
* ST_FAIL - error accessing container file
* ST_EOM - end of media detected
* ST_TM - tape mark detected
* Other - record length (including error flag)
*
--*/
uint32_t tapeReadRecordLengthReverse(
FILE *container
)
{
uint32_t meta, bc, erflag;
off_t delta;
if ((fseeko(container, -sizeof(meta), SEEK_CUR) != 0) ||
(fread(&meta, sizeof(meta), 1, container) != 1))
return ST_FAIL;
bc = le32toh(meta);
switch (bc) {
case ST_EOM:
case ST_TM:
if (fseeko(container, -sizeof(meta), SEEK_CUR) != 0)
return ST_FAIL;
return bc;
default:
erflag = bc & ST_ERROR;
bc &= ST_LENGTH;
/*
* Now position the file before this record.
*/
delta = RECLEN(bc) + (2 * sizeof(meta));
if (fseeko(container, -delta, SEEK_CUR) != 0)
return ST_FAIL;
return erflag | bc;
}
return ST_FAIL;
}
/*++
* t a p e W r i t e R e c o r d
*
* Write a record to the tape at it's current position leaving the tape
* positioned after the newly written record.
*
* Inputs:
*
* container - pointer open container file
* buf - pointer to the record to be written
* len - length of the record
*
* Outputs:
*
* None
*
* Returns:
*
* 1 if record was successfully written, 0 otherwise
*
--*/
int tapeWriteRecord(
FILE *container,
void *buf,
int len
)
{
uint32_t meta = htole16(len);
int datalen = (len + 1) & ~1;
if ((fwrite(&meta, sizeof(meta), 1, container) != 1) ||
(fwrite(buf, datalen, 1, container) != 1) ||
(fwrite(&meta, sizeof(meta), 1, container) != 1))
return 0;
return 1;
}
/*++
* t a p e W r i t e E O M
*
* Write an end-of-media record to the tape at it's current position and,
* optionally, backup the tape to before the newly written record.
*
* Inputs:
*
* container - pointer open container file
* backup - if 1, position the tape before the new record
*
* Outputs:
*
* None
*
* Returns:
*
* 1 if EOM record successfully written, 0 otherwise
*
--*/
int tapeWriteEOM(
FILE *container,
int backup
)
{
uint32_t eom = htole32(ST_EOM);
if (fwrite(&eom, sizeof(eom), 1, container) != 1)
return 0;
if (backup)
if (fseeko(container, -sizeof(eom), SEEK_CUR) != 0)
return 0;
return 1;
}
/*++
* t a p e W r i t e T M
*
* Write a tape mark record to the tape at it's current position.
*
* Inputs:
*
* container - pointer open container file
*
* Outputs:
*
* None
*
* Returns:
*
* 1 if EOM record successfully written, 0 otherwise
*
--*/
int tapeWriteTM(
FILE *container
)
{
uint32_t tm = htole32(ST_TM);
if (fwrite(&tm, sizeof(tm), 1, container) != 1)
return 0;
return 1;
}
/*++
* t a p e E O M
*
* Position the tape to the end of media so that a subsequent write will
* append a file to the tape.
*
* Inputs:
*
* container - pointer open container file
* eot - pointer to end-of-tape position, NULL if
* not available
*
* Outputs:
*
* None
*
* Returns:
*
* 1 if tape successfully positioned, 0 otherwise
*
--*/
int tapeEOM(
FILE *container,
off_t *eot
)
{
int whence = eot == NULL ? SEEK_END : SEEK_SET;
off_t pos = eot == NULL ? 0 : *eot;
uint32_t bc1, bc2;
/*
* Move to the end of the tape and then look backwards to see how it is
* terminated.
*/
if (fseeko(container, pos, whence) == 0) {
if (ftello(container) == 0) {
/*
* Empty file, we are correctly positioned.
*/
return 1;
}
if ((bc1 = tapeReadRecordLengthReverse(container)) == ST_FAIL)
return 0;
if ((bc1 == ST_EOM) || (bc1 == ST_TM)) {
if (ftello(container) == 0) {
/*
* Only ST_EOM or ST_TM present, we are correctly positioned.
*/
return 1;
}
if ((bc2 = tapeReadRecordLengthReverse(container)) == ST_FAIL)
return 0;
if (bc2 == ST_TM) {
if (ftello(container) == 0) {
/*
* Only ST_TM followed by ST_TM or ST_EOM, we are correctly
* positioned
*/
return 1;
}
/*
* ST_TM followed by ST_TM or ST_EOM with at least one data block
* present, skip over the initial ST_TM.
*/
if (fseeko(container, sizeof(uint32_t), SEEK_CUR) == 0)
return 1;
} else {
/*
* Only a single ST_TM at the end of the container file. This
* indicates that there is a missing ST_TM or ST_EOM. Position
* the tape at the logical end-of-tape so that any subsequent file
* write will fix the problem.
*/
if (fseeko(container, pos, whence) == 0)
return 1;
}
}
}
return 0;
}
/*++
* t a p e R e w i n d
*
* Rewind the tape.
*
* Inputs:
*
* container - pointer open container file
*
* Outputs:
*
* None
*
* Returns:
*
* None
*
--*/
void tapeRewind(
FILE *container
)
{
fseeko(container, 0, SEEK_SET);
}
/*++
* t a p e S k i p F o r w a r d
*
* Skip forward over a number of files. If end-of-media is reached, the skip
* operation will terminate early.
*
* Inputs:
*
* container - pointer open container file
* count - # of files to skip
*
* Outputs:
*
* None
*
* Returns:
*
* 1 if skip was successful, 0 otherwise
*
--*/
int tapeSkipForward(
FILE *container,
unsigned long count
)
{
unsigned long i;
uint32_t bc;
for (i = 0; i < count; i++) {
/*
* Peek at the next record. If it's a tape mark or end-of-media there
* are not more files to skip.
*/
switch (tapePeekRecordLength(container)) {
case ST_FAIL:
return 0;
case ST_TM:
case ST_EOM:
return 1;
}
/*
* Skip forward over 1 file.
*/
do {
switch (bc = tapeReadRecordLength(container)) {
case ST_FAIL:
return 0;
case ST_EOM:
if (fseeko(container, -sizeof(uint32_t), SEEK_CUR) != 0)
return 0;
break;
}
} while ((bc != ST_TM) && (bc != ST_EOM));
}
return 1;
}
/*++
* t a p e S k i p R e v e r s e
*
* Skip backwards over a number of files. If beginning-of-tape is reached,
* the skip operation will terminate early.
*
* Inputs:
*
* container - pointer open container file
* count - # of files to skip
*
* Outputs:
*
* None
*
* Returns:
*
* 1 if skip was successful, 0 otherwise
*
--*/
int tapeSkipReverse(
FILE *container,
unsigned long count
)
{
unsigned long i;
uint32_t bc;
for (i = 0; i < count; i++) {
/*
* If we are at beginning-of-tape, there are no more files to skip.
*/
if (ftello(container) == 0)
return 1;
/*
* If we are not at the beginning of tape, the previous record should
* be a tape mark.
*/
if (tapeReadRecordLengthReverse(container) != ST_TM)
return 0;
/*
* Now skip over the remainder of the file.
*/
do {
if ((bc = tapeReadRecordLengthReverse(container)) == ST_FAIL)
return 0;
} while ((bc != ST_TM) && (ftello(container) != 0));
/*
* Skip over the tape mark since it marks the end of the previous file.
*/
if (bc == ST_TM) {
if (fseeko(container, sizeof(uint32_t), SEEK_CUR) != 0)
return 0;
}
}
return 1;
}

73
converters/fsio/tape.h Normal file
View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2018 John Forecast. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN FORECAST "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 AUTHOR 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.
*/
#ifndef __TAPE_H__
#define __TAPE_H__
/*
* Metadata markers
*/
#define ST_EOM 0xFFFFFFFF /* end of medium */
#define ST_GAP 0xFFFFFFFE /* erase gap */
#define ST_TM 0x00000000 /* tape mark */
/*
* Special code for reporting errors. If actually read from a container
* file, this would be considered an error.
*/
#define ST_FAIL 0xFEFEFEFE
/*
* Record length field layout
*/
#define ST_ERROR 0x80000000 /* record contains an error */
#define ST_MBZ 0x7F000000 /* must be zero */
#define ST_LENGTH 0x00FFFFFF /* record length */
/*
* Data in the .tap container file is rounded up to an even number of bytes
*/
#define RECLEN(c) (((c) + 1) & ~1)
extern int tapeVerify(FILE *, off_t *);
extern off_t tapeGetPosition(FILE *);
extern int tapeSetPosition(FILE *, off_t);
extern uint32_t tapeSkipRecordF(FILE *);
extern uint32_t tapeSkipRecordR(FILE *);
extern uint32_t tapePeekRecordLength(FILE *);
extern uint32_t tapeReadRecord(FILE *, void *, int);
extern uint32_t tapeReadRecordLength(FILE *);
extern uint32_t tapeReadRecordLengthReverse(FILE *);
extern int tapeWriteRecord(FILE *, void *, int);
extern int tapeWriteEOM(FILE *, int);
extern int tapeWriteTM(FILE *);
extern int tapeEOM(FILE *, off_t *);
extern void tapeRewind(FILE *);
extern int tapeSkipForward(FILE *, unsigned long);
extern int tapeSkipReverse(FILE *, unsigned long);
#endif

View File

@@ -0,0 +1,20 @@
# all of these can be over-ridden on the "make" command line if they don't suit your environment.
TOOL=mksimtape
CFLAGS=-O2 -Wall -Wshadow -Wextra -pedantic -Woverflow -Wstrict-overflow
BIN=/usr/local/bin
INSTALL=install
CC=gcc
$(TOOL): $(TOOL).c
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $(TOOL) $(TOOL).c $(LDLIBS)
.PHONY: clean install uninstall
clean:
rm -f $(TOOL)
install: $(TOOL)
$(INSTALL) -p -m u=rx,g=rx,o=rx $(TOOL) $(BIN)
uninstall:
rm -f $(BIN)/$(TOOL)

View File

@@ -0,0 +1,332 @@
/*
* File: mksimtape.c
*
* Make a SIMH tape image
*
* Bob Eager March 2016
*
*/
/*
* History:
*
* 1.0 Initial version.
*
*/
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#define VERSION 1 /* Major version number */
#define EDIT 0 /* Edit number within major version */
#define FALSE 0
#define TRUE 1
#define DEFBLKSIZE 10240
/* General type definitions */
typedef int BOOL,*PBOOL;
typedef char CHAR,*PCHAR;
typedef int INT,*PINT;
typedef unsigned char UCHAR,*PUCHAR;
typedef unsigned int UINT,*PUINT;
typedef void VOID,*PVOID;
#if 0
typedef short SHORT, *PSHORT;
typedef unsigned short USHORT, *PUSHORT;
typedef long LONG,*PLONG;
typedef unsigned long ULONG,*PULONG;
#endif
/* Forward references */
static INT blksize(INT);
static VOID error(PCHAR, ...);
static INT little_endian(VOID);
static VOID putusage(VOID);
static BOOL tape_mark(VOID);
static BOOL write_file(PCHAR, INT);
/* Local storage */
static PCHAR progname; /* Name of program, as a string */
/* Help text */
static const PCHAR helpinfo[] = {
"%s: make SIMH tape image",
"Synopsis: %s file ...",
" ",
"The tape image is written to standard output.",
" ",
"A block size of %2$d is assumed for each file. A different block size",
"may be specified by adding it to the end of the filename, separated by a",
"colon; e.g.:",
" stand:512",
""
};
/*
* Parse arguments and handle options.
*
*/
INT main(INT argc, PCHAR argv[])
{ BOOL rc = TRUE;
INT i, bs;
PCHAR p;
progname = strrchr(argv[0], '/');
if(progname == (PCHAR) NULL) progname = argv[0]; else progname++;
if(argc == 1) {
error("at least one file must be specified", argv[0]);
putusage();
exit(EXIT_FAILURE);
}
for(i = 1; i < argc; i++) {
bs = DEFBLKSIZE;
p = strchr(argv[i], ':');
if(p != (PCHAR) NULL) {
*p = '\0';
bs = strtol(++p, (CHAR **) NULL, 10);
if(bs == 0) {
error("block size for file '%s' is invalid",
argv[i]);
rc = FALSE;
break;
}
}
write_file(argv[i], bs);
tape_mark();
}
tape_mark();
return(rc == TRUE ? EXIT_SUCCESS : EXIT_FAILURE);
}
/*
* Write a file to the 'tape' on stdout.
*
* Inputs:
* file name of file to be written
* bs blocksize to be used
*
* Outputs:
* TRUE written OK
* FALSE write (or other) error
*
* Blocks are rounded up to and even number of bytes, padded with a
* zero byte.
* Each block is preceded and followed by a 4 byte count, the actual
* block data size, in little endian format.
*
*/
static BOOL write_file(PCHAR file, INT bs)
{ BOOL rc = TRUE;
INT n;
INT obs;
INT le_bs;
UCHAR sbuf[4];
FILE *fp;
PCHAR buf;
obs = (bs+1) & ~1;/* Round up output block size to make even */
le_bs = blksize(bs); /* Little endian true block size */
sbuf[0] = (le_bs & 0x000000ff);
sbuf[1] = (le_bs & 0x0000ff00) >> 8;
sbuf[2] = (le_bs & 0x00ff0000) >> 16;
sbuf[3] = (le_bs & 0xff000000) >> 24;
fprintf(stderr, "Writing file %s with block size %d %s\n",
file, obs, bs == obs ? "": "(rounded up)");
fp = fopen(file, "r");
if(fp == (FILE *) NULL) {
error("cannot open file '%s'", file);
return(FALSE);
}
buf = (PCHAR) malloc(obs);
if(buf == (PCHAR) NULL) {
error("cannot allocate memory for buffer");
return(FALSE);
}
for(;;) {
n = fread(buf, 1, bs, fp);
if(n < bs) {
if(!feof(fp)) {
error("error reading file '%s'", file);
rc = FALSE;
break;
}
if(n == 0) break; /* No partial buffer */
memset(&buf[n], '\0', bs-n); /* Zero fill */
}
if(bs != obs) buf[obs-1] = '\0'; /* Pad */
n = fwrite(sbuf, 1, 4, stdout); /* Record header */
if(n != 4) {
error("Error writing to tape image");
rc = FALSE;
break;
}
n = fwrite(buf, 1, obs, stdout);/* Record data */
if(n < obs) {
error("Error writing to tape image");
rc = FALSE;
break;
}
n = fwrite(sbuf, 1, 4, stdout); /* Record trailer */
if(n != 4) {
error("Error writing to tape image");
rc = FALSE;
break;
}
}
free((PCHAR) buf);
fclose(fp);
return(rc);
}
/*
* Write a tape mark to the tape image. This consists of four
* consecutive zero bytes.
*
* Inputs:
* none
*
* Outputs:
* TRUE written OK
* FALSE write (or other) error
*
*/
static BOOL tape_mark(VOID)
{ INT n;
UCHAR sbuf[4] = { 0,0,0,0 };
n = fwrite(sbuf, 1, 4, stdout);
if(n != 4) {
error("Error writing to tape image");
return(FALSE);
}
return(TRUE);
}
/*
* Return a 4 byte block size, in little endian format.
* The input value is never negative.
*
* Inputs:
* mbs block size in machine format
*
* Outputs:
* lbs block size in little endian format
*
*/
static INT blksize(INT mbs)
{ UINT result = 0;
if(little_endian()) return(mbs);
result |= (mbs & 0x000000ff) << 24;
result |= (mbs & 0x0000ff00) << 8;
result |= (mbs & 0x00ff0000) >> 8;
result |= (mbs & 0xff000000) >> 24;
return(result);
}
/*
* Check whether we are on a big endian or little endian machine.
*
* Inputs:
* none
*
* Outputs:
* 0 Big endian
* 1 Little endian
*
*/
static INT little_endian(VOID)
{ UINT i = 1;
PCHAR c = (PCHAR) &i;
return (INT) *c;
}
/*
* Print message on standard error in printf style,
* accompanied by program name.
*
* Inputs:
* mes message to be printed
* ... optional arguments
*
* Outputs:
* none
*
*/
static VOID error(PCHAR mes, ...)
{ va_list ap;
fprintf(stderr, "%s: ", progname);
va_start(ap, mes);
vfprintf(stderr, mes, ap);
va_end(ap);
fputc('\n', stderr);
}
/*
* Output program usage information.
*
* Inputs:
* none
*
* Outputs:
* none
*
*/
static VOID putusage(VOID)
{ PCHAR *p = (PCHAR *) helpinfo;
PCHAR q;
for(;;) {
q = *p++;
if(*q == '\0') break;
fprintf(stderr, q, progname, DEFBLKSIZE);
fputc('\n', stderr);
}
fprintf(stderr, "\nThis is version %d.%d\n", VERSION, EDIT);
}
/*
* End of file: mksimtape.c
*
*/

View File

@@ -0,0 +1,28 @@
mksimtape
---------
This program generates a SIMH-compatible tape image file, from one or
more input files. It should be easily compiled using any reasonable C
compiler, for example:
cc -o mksimtape mksimtape.c
Once compiled, it is run by giving it the names of the files to be
written to the image, in the same order that they should be written. The
tape image is written to standard output, so a typical use might be
this:
mksimtape file1 file2 file3 > tape.out
Each 'file' on the tape is written with a block size of 10240 bytes,
unless otherwise specified. To use a particular block size for a file,
append it to the end of the filename, separated by a colon, viz.:
mksimtape file1:512 file2 file3 > tape.out
This would write 'file1' with a block size of 512 bytes; 'file2' and
'file3' would still be written with a block size of 10240 bytes.
Bob Eager
bob@eager.cx

View File

@@ -44,7 +44,7 @@ if (argc < 2) {
fprintf (stderr, "blocksize defaults to 8192\n");
exit (0);
}
if ((argc >= 3) && ((strcmp("-b", argv[1])) || (strcmp("--blocksize", argv[1])))) {
if ((argc >= 3) && ((strcmp("-b", argv[1]) == 0) || (strcmp("--blocksize", argv[1]) == 0))) {
if (atoi (argv[2]) <= 0) {
fprintf (stderr, "Invalid blocksize: %s\n", argv[2]);
exit (0);

View File

@@ -5,29 +5,17 @@ BIN=/usr/local/bin
INSTALL=install
CC=gcc
SUBDIRS=hpasm macro1 macro11 macro7 macro8x
.PHONY: all clean install uninstall
# Omitted: macro11: needs more complicated Makefiles.
all:
cd hpasm && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd macro1 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd macro7 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
cd macro8x && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"
for subdir in $(SUBDIRS); do \
$(MAKE) -C $$subdir CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)"; \
done
clean:
cd hpasm && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd macro1 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd macro7 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
cd macro8x && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" clean
install:
cd hpasm && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd macro1 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd macro7 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
cd macro8x && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" install
uninstall:
cd hpasm && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd macro1 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd macro7 && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
cd macro8x && $(MAKE) CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" uninstall
clean install uninstall:
for subdir in $(SUBDIRS); do \
$(MAKE) -C $$subdir CFLAGS="$(CFLAGS)" BIN="$(BIN)" INSTALL="$(INSTALL)" CC="$(CC)" $@; \
done

11
crossassemblers/macro11/.gitignore vendored Normal file
View File

@@ -0,0 +1,11 @@
git-info.h
*.d
*.o
dumpobj
macro11
tests/*.lst
tests/*.obj
tests/*.objd
x/*
tests/2.11BSD/l11
tests/2.11BSD-*.mac

View File

@@ -0,0 +1,32 @@
# Minimized from https://about.gitlab.com/2016/10/12/automated-debian-package-build-with-gitlab-ci/
# https://github.com/gitlabhq/gitlabhq/blob/master/vendor/gitlab-ci-yml/C%2B%2B.gitlab-ci.yml
# use the official gcc image, based on debian
# can use verions as well, like gcc:5.2
# see https://hub.docker.com/_/gcc/
#image: gcc
before_script:
- apt-get update
# Defines stages which are to be executed
stages:
- build-gcc
- build-clang
# Stage "build"
run-build-gcc:
stage: build-gcc
script:
- apt-get install -y gcc
- make
- cd tests && ./RunTests
# Stage "build-clang"
run-build-clang:
stage: build-clang
script:
- apt-get install -y clang
- CC=clang make
- cd tests && ./RunTests

45
crossassemblers/macro11/.indent.pro vendored Executable file
View File

@@ -0,0 +1,45 @@
--blank-lines-after-commas
--blank-lines-after-declarations
--blank-lines-after-procedures
--braces-on-if-line
--braces-on-struct-decl-line
--break-before-boolean-operator
--break-function-decl-args
--break-function-decl-args-end
--case-indentation0
--comment-indentation40
--continuation-indentation8
--continue-at-parentheses
--cuddle-do-while
--cuddle-else
--declaration-indentation16
--dont-break-procedure-type
--dont-format-comments
--indent-level4
--honour-newlines
--leave-optional-blank-lines
--line-comments-indentation0
--line-length112
--no-blank-lines-before-block-comments
--no-space-after-function-call-names
--no-tabs
--paren-indentation4
--space-special-semicolon
--tab-size8
-T ADDR_MODE
-T ARG
-T BUFFER
-T EX_TREE
-T FILE
-T MACRO
-T MACRO_STREAM
-T MLB
-T MLBENT
-T STACK
-T STREAM
-T SECTION
-T SYMBOL
-T SYMBOL_ITER
-T SYMBOL_TABLE
-T TEXT_COMPLEX
-T TEXT_RLD

View File

@@ -0,0 +1,12 @@
language: c
dist: bionic
os:
- linux
- osx
compiler:
- gcc
- clang
script:
- make
- cd tests
- ./RunTests

View File

@@ -0,0 +1,137 @@
07.07.2022: Rhialto
version 0.8:
- Improve parsing of symbols, e.g. `4..` is not a symbol.
- More careful file format checking of .MLB files, so that you can
use either RSX or RT format .MLB files, and autodetection works.
- Replace the floating point parser by a version which is based on
integer math only, because the Apple M1 doesn't have the required
long double support in its compiler.
13 changes from Paul Koning that add some features which help to
assemble RSTS/E sources:
- Add default extensions to .include, .library
- Fix .psect without argument, add (ignored) pseudo ops .mdelete,
.cross, .nocross
- Allow TRAP without argument, or with non-literal argument
- Fix .library pseudo
- Always list lines that have an error
- Fix macro calls with omitted argument that has a default value,
followed by additional (not omitted) arguments.
- Implement .ENABLE MCL
- Treat unexpected .IF argument as true, not false. This appears to
be what the reference assembler does, at least it is necessary for
certain RSTS source files to assemble without error.
- Allow formal name of .IRP and .IRPC to be enclosed in < >.
- Just like .RAD50, .IDENT accepts an argument that can contain not
just delimited string characters but also values in < >.
- Allow expression (with constant value) in .RADIX
- Bugfixes in macro expansion, incl duplicate named arguments
- Fix references to blank section: Its name is empty, not ". BLK."
05.01.2022: Rhialto
version 0.7.2:
- Improved error messages for bad addressing modes
(due to gitlab issue #10)
- Undefined symbols are now listed in the symbol table.
- The weird way the unary "operator" % works in expressions is
now implemented.
The docs on page 3-8/9 aren't very precise but testing showed
that any expression with a register in it can be used as a
register, and (if used to define a symbol) is listed in the
symbol table as such. %3+1 is <%3>+1 is R4.
- Fixed registers being used in .word or immediate operands:
no longer generated as being relocatable expressions.
- 'make tests' works more portably.
16.05.2021: Rhialto
version 0.7.1:
- Fixed immediate source operand of LDEXP, LD[IL][FD]
which is an integer, unlike several other FPP instructions.
(gitlab issue #7)
- Start each pass with .DSABL LSB (gitlab issue #8)
19.03.2021: Rhialto
version 0.7:
- Fixed the end-of-line check for MARK, EMT, TRAP.
- Left/right shift operator _; disabled when the -yus option is used.
Contributed by Stephen Casner.
- Added some missing instructions: LDCFD, CSM, TSTSET, WRTLCK.
13.02.2021: Rhialto
version 0.6:
- Fixed rounding issues with floating point literals.
- Fixed FPP instructions which take fp immediate operands.
- Fixed bounds check on FPP AC0-3 operands.
- Fix listing to show a % before values that represent a register
number.
- Added checks for junk text following correct code. This revealed
some small other issues, now fixed.
- Added CIS instructions; as an extension, for the Inline variants
you can specify the descriptor addresses etc as arguments to
the instruction (much like an implied .word).
25.04.2020: Rhialto
version 0.5:
- Fixed bug with checking addressing mode for JSR and bugs
with .REPT 0, unneeded relocation on pc-relative mode.
- Very simple .LIST and .NLIST implementation.
- Add ^pl and ^ph expressions from 2.11BSD's m11.
- Object-ified macro libraries with an eye to support the .sml
files from 2.11BSD's m11. But since the given file does not
just contain .MACROs (it even contains conditionals) I'm not
sure how it is supposed to work.
- Added 2.11BSD/m11 as test files. To make this reasonable, a
few small features they use have been recognized and ignored.
- Add -rsx and -rt11 to switch object file format (from Kevin Handy)
- Add obj2bin from https://github.com/AK6DN/obj2bin.git
09.11.2015: Rhialto
version 0.4:
- Fixed various bugs. The most notable was extensive use-
after-free in the expression tree, which crashed on NetBSD but
apparently not on other systems.
- Lots of changes to make this MACRO11 more like the MACRO11 of
RSX-11M+ 4.6. I used Kermit-11 source files for comparison.
"The Manual" I'm refering to is
AA-KX10A-TC_PDP-11_MACRO-11_Reference_Manual_May88.pdf at
www.bitsavers.org/pdf/dec/pdp11/rsx11/RSX11Mplus_V4.x/4a/ and
I use an installed system to double-check.
----------- Joerg Hoppe's entries ------------------
19.4.2009: JH
version 0.3
- bugfix: Illegal labels and illegal opcodes are processed as
"implied .WORD" directives.
Expression errors in "do_word()" did not process any input character,
so parser did go into an endless loop.
- Switchable syntax extensions with -yxx options:
symbol len can be adjusted with "-ysl" command line option.
"-yus" option allows underscore "_" char in symbols.
This was needed to process code generated by my favorite disassembler.
- command line help added (-h option)
17.4.2009: JH
version 0.3
- ".INCLUDE" re-enabled
- refactoring: big 6000+ lines "macro11.c" split into 10 modules.
15.4.2009: JH
Begin rework by Joerg Hoppe (j_hoppe@t-online.de)
All my changes are marked with "/*JH: .. */" comments
----------- Richard Krebiehls entries ------------------
15-July-2001
version 0.2
removed references to snprintf from dumpobj.c and
mlb.c for portability
fixed a type cast warning in dumpobj.c compare_gsdlines
Removed strcasecmp from macro11.c for portability
Removed references to wnewmem.c from makefile (isn't needed)
makefile more compatible with non-gnu make and compiler
main prints version 0.2
14-July-2001
First release, version 0.1.

View File

@@ -0,0 +1,87 @@
#####
#
# Makefile for macro11 and dumpobj
#
WARNS ?= -Wall -Wshadow -Wextra -pedantic -Woverflow -Wstrict-overflow
OBJFORMAT ?= -DDEFAULT_OBJECTFORMAT_RT11=0
#SANITIZE ?= -fsanitize=address -fsanitize=undefined -fsanitize-recover=all -fno-omit-frame-pointer
DEBUG ?= -ggdb $(SANITIZE)
OPT ?= -O3
CFLAGS ?= -std=gnu99 $(WARNS) $(DEBUG) $(OPT) $(OBJFORMAT)
MACRO11_SRCS = macro11.c \
assemble.c assemble_globals.c assemble_aux.c \
extree.c listing.c macros.c parse.c rept_irpc.c symbols.c \
mlb2.c mlb-rsx.c mlb-rt11.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: git-info.h $(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
git-info.h:
./make-git-info
# Bootstrap dependency on the git header file, which otherwise
# gets generated too late.
macro11.o: git-info.h
macro11.c: git-info.h
clean:
-rm -f $(MACRO11_OBJS) $(DUMPOBJ_OBJS) macro11 dumpobj
-rm -f *.d
-rm -f git-info.h
# Since the only tests we have so far are for crashes,
# just try to assemble. Later, we will need expected/actual tests.
# Test that all options requiring a value bail out if it's not present.
argtests: macro11
@ for OPT in -e -d -m -p -o -l -ysl ; do \
./macro11 foo.mac $$OPT 2> /dev/null; \
if [ $$? = 1 ]; then echo PASS; else echo FAIL; fi; \
echo " $$OPT missing value"; \
./macro11 foo.mac $$OPT -v 2> /dev/null; \
if [ $$? = 1 ]; then echo PASS; else echo FAIL; fi; \
echo " $$OPT fol. by option"; \
done
@ ./macro11 foo.mac $$OPT -x -v 2> /dev/null; \
if [ $$? = 1 ]; then echo PASS; else echo FAIL; fi; \
echo " -x must be the last option"
LSAN_OPTIONS=suppressions=../macro11.supp
tests: macro11 argtests
cd tests && env LSAN_OPTIONS="${LSAN_OPTIONS}" ./RunTests
# Automatic dependency generation
ifneq ($(MAKECMDGOALS),clean)
-include $(ALL_SRCS:.c=.d)
endif
# Make .d files as side effect of compiling .c to .o
%.d %.o: %.c
$(CC) $(CFLAGS) -c -o $*.o $<
@set -e; rm -f $*.d; \
$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o \1.d : ,g' < $@.$$$$ > $*.d; \
rm -f $@.$$$$

View File

@@ -0,0 +1,187 @@
A MACRO-11 assembler for the PDP-11 in portable C source code.
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.
modified 2009 by Joerg Hoppe,
modified 2015-2017,2020,2021 by Olaf 'Rhialto' Seibert.
Files:
macro11.c Command line parsing and driving the passes.
assemble.c Handles all of the opcodes and directives.
assemble_aux.c Helper functions mostly called from assemble().
assemble_globals.c Global variables for assemble().
extree.c Expression tree: memory management and evaluation.
listing.c Listing generation.
macros.c Define macros and make them available as stream2s.
parse.c Basic parsing for numbers, labels, strings, expressions
rept_irpc.c stream2 subclass for processing .REPT and .IREPT.
object.c Functions for writing RSX-11 compatible .OBJ files.
mlb-rsx.c Classes (!) for reading RSX-11 macro libraries.
mlb-rt11.c Classes (!) for reading RT-11 macro libraries.
mlb2.c Glue functions for macro libraries in general.
stream2.c Functions for managing input streams and buffers.
rad50.c Functions for converting text to and from RAD50.
util.c A few general utility fuctions.
macro11.h, object.h, mlb.h, stream2.h, rad50.h, util.h
types and symbols exported from the associated sources.
dumpobj.c A program I wrote to examine the output from
RT-11's MACRO.SAV program and compare it with my
own output.
Makefile A GNU makefile for Linux; simple enough, it
should be convertible to any Unix.
Contains automatic dependency generation.
macro11.dsp, dumpobj.dsp, macro11.dsw
Visual Studio 6 projects. Out of date.
README This file
LICENSE The copyright notice and license
CHANGES A list of changes from previous versions
TODO A list of things that may need fixing
Notes:
Sorry, I am a believer in 4 column hardware tabs, for a number of
reasons, mostly regarding editing convenience. (I did untabify this
README file though.)
The bulk of Richard's development was done in Microsoft Visual Studio 6,
but currently Olaf maintains it using a Unix (NetBSD) system. I build
with gcc and a lot of warning options, and from time to time check with
a Linux system which has a different gcc version, and clang. The Visual
Studio project files are out of date.
Richard used the MACRO11 from RT-11 as reference, but I use the one
from RSX-11M+. It turns out there are some small file format
differences. I used the dumpobj command to compare the output of this
macro11 with the reference version when assembling Kermit-11 source
files, and currently there seem to be no significant differences.
The macro11 command line:
macro11 [options...] files...
Options:
-v Prints program version.
-e opt .ENABL option. Implemented options are AMA, GBL,
and also .LIST options ME, BEX, and
MD, though the status of listing control is
presently very poor.
-d opt .DSABL option; same options as -e.
-m macname Gives a macro library name.
Up to 32 macro libraries may be specified, one per
-m option.
The current object file format (default, or from
-rt11 or -rsx before this option) is used first to
read the file; if this fails, the other format is
tried.
Note: unlike MACRO.SAV, SYSMAC.SML is not
automatically included; you must name it.
-p macpath For any .MCALL <macro> directive, macro11 will
first search -m macro libraries, then it will
search the MCALL path for a file named <macro>.MAC
to locate the body of the macro. The MCALL path
is an environment variable containing directory
names separated by delimiters (":" for Unix-style
targets; ";" for Windows). The -p command line
options appends a directory name to the MCALL
path.
-I incpath For any .INCLUDE <file> directive, macro11 will
search the INCLUDE path for a file named <file>
to include. The INCLUDE path works like the MCALL
path. If not specified at all, the default is the
current directory. If <file> contains a drive
and/or directory in RSX/RT-11 form
(DEV:[DIR]FILE.EXT) then the search is also tried
without DEV: and without DEV:[DIR].
-o objname Gives the name of the object file. No extension
is assumed; if you want .OBJ you have to say it.
With no -o option, no object file is generated.
-l lstname Gives the name of a listing file. The name "-"
may be given to write the listing to stdout. No
extension is assumed; if you want .LST you have to
say it. With no -l option, no listing file is
written.
-x Tells macro11 not to assemble anything, but rather
to simply extract all the macros in all the -m
macro libraries into individual .MAC files in the
current directory. This should be the last option
given, as none following will be processed.
This also works for extracting an object library
(.OLB) file.
-rsx Tells macro11 to generate rsx style object files.
This is the default.
-rt11 Tells macro11 to generate rt11 style object files.
Various options starting with -y enable extensions:
-ysl <num> Allow longer symbols up to the given length.
The maximal allowed value is 64.
-yus Allow underscore in symbol names.
-yl1 Include the processing of the first pass in the
listing file. This may be useful for finding
phase errors.
files... Any number of input files. They will be assembled
as if they were concatenated together.
You may define the MCALL and INCLUDE environment variable prior to
invoking macro11, as a path to directories containing macros or files to
be included, respectively.
=======================================================================
Included in subdirectory obj2bin is a Perl script from Don North,
copied from https://github.com/AK6DN/obj2bin. The copied version may
get out of date; when in doubt check the original.
=======================================================================

View File

@@ -1,3 +1,10 @@
.packed pdf page 80
listing format errors: ignore whitespace of input
documentation: print supported directives
---------------------------------------
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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
#ifndef ASSEMBLE__H
#define ASSEMBLE__H
#include "stream2.h"
#include "object.h"
#define DOT (current_pc->value) /* Handy reference to the current location */
int assemble_stack(
STACK *stack,
TEXT_RLD *tr);
int get_next_lsb(
void);
#endif

View File

@@ -0,0 +1,833 @@
/*
Smaller operators for assemble
*/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "util.h"
#include "assemble_aux.h" /* my own definitions */
#include "assemble_globals.h"
#include "macros.h"
#include "assemble.h"
#include "listing.h"
#include "symbols.h"
#include "parse.h"
/* Allocate a new section */
SECTION *new_section(
void)
{
SECTION *sect = memcheck(malloc(sizeof(SECTION)));
sect->flags = 0;
sect->size = 0;
sect->pc = 0;
sect->type = 0;
sect->sector = 0;
sect->label = NULL;
return sect;
}
/* This is called by places that are about to store some code, or
which want to manually update DOT. */
void change_dot(
TEXT_RLD *tr,
int size)
{
if (size > 0) {
if (last_dot_section != current_pc->section) {
text_define_location(tr, current_pc->section->label, &current_pc->value);
last_dot_section = current_pc->section;
last_dot_addr = current_pc->value;
}
if (last_dot_addr != current_pc->value) {
text_modify_location(tr, &current_pc->value);
last_dot_addr = current_pc->value;
}
/* Update for next time */
last_dot_addr += size;
}
if (DOT + size > current_pc->section->size)
current_pc->section->size = DOT + size;
}
/* store_word stores a word to the object file and lists it to the
listing file */
int store_word(
STREAM *str,
TEXT_RLD *tr,
int size,
unsigned word)
{
change_dot(tr, size);
list_word(str, DOT, word, size, "");
return text_word(tr, &DOT, size, word);
}
/* store_word stores a word to the object file and lists it to the
listing file */
static int store_displaced_word(
STREAM *str,
TEXT_RLD *tr,
int size,
unsigned word)
{
change_dot(tr, size);
list_word(str, DOT, word, size, "'");
return text_displaced_word(tr, &DOT, size, word);
}
static int store_global_displaced_offset_word(
STREAM *str,
TEXT_RLD *tr,
int size,
unsigned word,
char *global)
{
change_dot(tr, size);
list_word(str, DOT, word, size, "G");
return text_global_displaced_offset_word(tr, &DOT, size, word, global);
}
static int store_global_offset_word(
STREAM *str,
TEXT_RLD *tr,
int size,
unsigned word,
char *global)
{
change_dot(tr, size);
list_word(str, DOT, word, size, "G");
return text_global_offset_word(tr, &DOT, size, word, global);
}
static int store_internal_word(
STREAM *str,
TEXT_RLD *tr,
int size,
unsigned word)
{
change_dot(tr, size);
list_word(str, DOT, word, size, "'");
return text_internal_word(tr, &DOT, size, word);
}
static int store_psect_displaced_offset_word(
STREAM *str,
TEXT_RLD *tr,
int size,
unsigned word,
char *name)
{
change_dot(tr, size);
list_word(str, DOT, word, size, "'");
return text_psect_displaced_offset_word(tr, &DOT, size, word, name);
}
static int store_psect_offset_word(
STREAM *str,
TEXT_RLD *tr,
int size,
unsigned word,
char *name)
{
change_dot(tr, size);
list_word(str, DOT, word, size, "'");
return text_psect_offset_word(tr, &DOT, size, word, name);
}
int store_limits(
STREAM *str,
TEXT_RLD *tr)
{
change_dot(tr, 4);
list_word(str, DOT, 0, 2, "");
list_word(str, DOT + 2, 0, 2, "");
return text_limits(tr, &DOT);
}
/* free_addr_mode frees the storage consumed by an addr_mode */
void free_addr_mode(
ADDR_MODE *mode)
{
if (mode->offset)
free_tree(mode->offset);
mode->offset = NULL;
}
/* Get the register indicated by the expression */
unsigned get_register(
EX_TREE *expr)
{
unsigned reg;
if (expr->type == EX_LIT && expr->data.lit <= 7) {
reg = expr->data.lit;
return reg;
}
if (expr->type == EX_SYM && expr->data.symbol->section->type == SECTION_REGISTER) {
reg = expr->data.symbol->value;
return reg;
}
return NO_REG;
}
/*
implicit_gbl is a self-recursive routine that adds undefined symbols
to the "implicit globals" symbol table, or alternatively adds the
symbol as an UNDEFINED symbol.
*/
void implicit_gbl(
EX_TREE *value)
{
if (pass || !value)
return; /* Only do this in first pass */
switch (num_subtrees(value)) {
case 0:
switch (value->type) {
case EX_UNDEFINED_SYM:
{
if (!(value->data.symbol->flags & SYMBOLFLAG_LOCAL)) {
/* Unless it's a local symbol, */
if (enabl_gbl) {
/* either make the undefined symbol into an
implicit global */
add_sym(value->data.symbol->label, 0, SYMBOLFLAG_GLOBAL,
&absolute_section, &implicit_st);
} else {
/* or add it to the undefined symbol table,
purely for listing purposes.
It also works to add it to symbol_st,
all code is carefully made for that. */
#define ADD_UNDEFINED_SYMBOLS_TO_MAIN_SYMBOL_TABLE 0
#if ADD_UNDEFINED_SYMBOLS_TO_MAIN_SYMBOL_TABLE
add_sym(value->data.symbol->label, 0, SYMBOLFLAG_UNDEFINED,
&absolute_section, &symbol_st);
#else
add_sym(value->data.symbol->label, 0, SYMBOLFLAG_UNDEFINED,
&absolute_section, &undefined_st);
#endif
}
}
}
break;
case EX_LIT:
case EX_SYM:
case EX_TEMP_SYM: // Impossible on this pass
return;
default:
break;
}
break;
case 2:
implicit_gbl(value->data.child.right);
/* FALLS THROUGH */
case 1:
implicit_gbl(value->data.child.left);
break;
}
}
/* Done between the first and second passes */
/* Migrates the symbols from the "implicit" table into the main table. */
void migrate_implicit(
void)
{
SYMBOL_ITER iter;
SYMBOL *isym,
*sym;
for (isym = first_sym(&implicit_st, &iter); isym != NULL; isym = next_sym(&implicit_st, &iter)) {
sym = lookup_sym(isym->label, &symbol_st);
if (sym) {
continue; // It's already in there. Great.
}
isym->flags |= SYMBOLFLAG_IMPLICIT_GLOBAL;
sym = add_sym(isym->label, isym->value, isym->flags, isym->section, &symbol_st);
// Just one other thing - migrate the stmtno
sym->stmtno = isym->stmtno;
}
}
/* Done between second pass and listing */
/* Migrates the symbols from the "undefined" table into the main table. */
void migrate_undefined(
void)
{
SYMBOL_ITER iter;
SYMBOL *isym,
*sym;
for (isym = first_sym(&undefined_st, &iter); isym != NULL; isym = next_sym(&undefined_st, &iter)) {
sym = lookup_sym(isym->label, &symbol_st);
if (sym) {
continue; /* It's already in there. Great. */
}
isym->flags |= SYMBOLFLAG_UNDEFINED; /* Just in case */
sym = add_sym(isym->label, isym->value, isym->flags, isym->section, &symbol_st);
/* Just one other thing - migrate the stmtno */
sym->stmtno = isym->stmtno;
}
}
int express_sym_offset(
EX_TREE *value,
SYMBOL **sym,
unsigned *offset)
{
implicit_gbl(value); /* Translate tree's undefined syms
into global syms */
/* Internally relocatable symbols will have been summed down into
EX_TEMP_SYM's. */
if (value->type == EX_SYM || value->type == EX_TEMP_SYM) {
*sym = value->data.symbol;
*offset = 0;
return 1;
}
/* What remains is external symbols. */
if (value->type == EX_ADD) {
EX_TREE *left = value->data.child.left;
EX_TREE *right = value->data.child.right;
if ((left->type != EX_SYM && left->type != EX_UNDEFINED_SYM) || right->type != EX_LIT)
return 0; /* Failed. */
*sym = left->data.symbol;
*offset = right->data.lit;
return 1;
}
if (value->type == EX_SUB) {
EX_TREE *left = value->data.child.left;
EX_TREE *right = value->data.child.right;
if ((left->type != EX_SYM && left->type != EX_UNDEFINED_SYM) || right->type != EX_LIT)
return 0; /* Failed. */
*sym = left->data.symbol;
*offset = (unsigned) -(int) (right->data.lit);
return 1;
}
return 0;
}
/*
Translate an EX_TREE into a TEXT_COMPLEX suitable for encoding
into the object file. */
int complex_tree(
TEXT_COMPLEX *tx,
EX_TREE *tree)
{
switch (tree->type) {
case EX_LIT:
text_complex_lit(tx, tree->data.lit);
return 1;
case EX_TEMP_SYM:
case EX_SYM:
{
SYMBOL *sym = tree->data.symbol;
/* This check may not be needed; so far it made no difference. */
if (sym->flags & SYMBOLFLAG_UNDEFINED) {
return 0;
}
if (SYM_IS_IMPORTED(sym)) {
text_complex_global(tx, sym->label);
} else {
text_complex_psect(tx, sym->section->sector, sym->value);
}
}
return 1;
case EX_COM:
if (!complex_tree(tx, tree->data.child.left))
return 0;
text_complex_com(tx);
return 1;
case EX_NEG:
if (!complex_tree(tx, tree->data.child.left))
return 0;
text_complex_neg(tx);
return 1;
case EX_ADD:
if (!complex_tree(tx, tree->data.child.left))
return 0;
if (!complex_tree(tx, tree->data.child.right))
return 0;
text_complex_add(tx);
return 1;
case EX_SUB:
if (!complex_tree(tx, tree->data.child.left))
return 0;
if (!complex_tree(tx, tree->data.child.right))
return 0;
text_complex_sub(tx);
return 1;
case EX_MUL:
if (!complex_tree(tx, tree->data.child.left))
return 0;
if (!complex_tree(tx, tree->data.child.right))
return 0;
text_complex_mul(tx);
return 1;
case EX_DIV:
if (!complex_tree(tx, tree->data.child.left))
return 0;
if (!complex_tree(tx, tree->data.child.right))
return 0;
text_complex_div(tx);
return 1;
case EX_AND:
if (!complex_tree(tx, tree->data.child.left))
return 0;
if (!complex_tree(tx, tree->data.child.right))
return 0;
text_complex_and(tx);
return 1;
case EX_OR:
if (!complex_tree(tx, tree->data.child.left))
return 0;
if (!complex_tree(tx, tree->data.child.right))
return 0;
text_complex_or(tx);
return 1;
default:
return 0;
}
}
/* store a word which is represented by a complex expression. */
static void store_complex(
STREAM *refstr,
TEXT_RLD *tr,
int size,
EX_TREE *value)
{
TEXT_COMPLEX tx;
change_dot(tr, size); /* About to store - update DOT */
implicit_gbl(value); /* Turn undefined symbols into globals */
text_complex_begin(&tx); /* Open complex expression */
if (!complex_tree(&tx, value)) { /* Translate */
report(refstr, "Invalid expression (complex relocation)\n");
store_word(refstr, tr, size, 0);
} else {
list_word(refstr, DOT, 0, size, "C");
text_complex_commit(tr, &DOT, size, &tx, 0);
}
}
/* store_complex_displaced is the same as store_complex but uses the
"displaced" RLD code */
static void store_complex_displaced(
STREAM *refstr,
TEXT_RLD *tr,
int size,
EX_TREE *value)
{
TEXT_COMPLEX tx;
change_dot(tr, size);
implicit_gbl(value); /* Turn undefined symbols into globals */
text_complex_begin(&tx);
if (!complex_tree(&tx, value)) {
report(refstr, "Invalid expression (complex displaced relocation)\n");
store_word(refstr, tr, size, 0);
} else {
list_word(refstr, DOT, 0, size, "C");
text_complex_commit_displaced(tr, &DOT, size, &tx, 0);
}
}
/*
mode_extension - writes the extension word required by an addressing
mode */
void mode_extension(
TEXT_RLD *tr,
ADDR_MODE *mode,
STREAM *str)
{
EX_TREE *value = mode->offset;
SYMBOL *sym;
unsigned offset;
/* Also frees the mode. */
if (value == NULL) {
free_addr_mode(mode);
return;
}
if (value->type == EX_LIT) {
if (mode->pcrel) { /* PC-relative? */
if (current_pc->section->flags & PSECT_REL) {
store_displaced_word(str, tr, 2, value->data.lit);
} else {
/* I can compute this myself. */
store_word(str, tr, 2, value->data.lit - DOT - 2);
}
} else {
store_word(str, tr, 2, value->data.lit); /* Just a
known
value. */
}
} else if (express_sym_offset(value, &sym, &offset)) {
if (SYM_IS_IMPORTED(sym)) {
/* Reference to a global symbol. */
/* Global symbol plus offset */
if (mode->pcrel)
store_global_displaced_offset_word(str, tr, 2, offset, sym->label);
else
store_global_offset_word(str, tr, 2, offset, sym->label);
} else if (sym->section->type == SECTION_REGISTER) {
/* Delayed action: evaluate() excludes SECTION_REGISTER when
* turning symbols into EX_LIT. Do it here now. */
store_word(str, tr, 2, sym->value + offset);
} else {
/* Relative to non-external symbol. */
if (current_pc->section == sym->section) {
/* In the same section */
if (mode->pcrel) {
/* I can compute this myself. */
store_word(str, tr, 2, sym->value + offset - DOT - 2);
} else
store_internal_word(str, tr, 2, sym->value + offset);
} else {
/* In a different section */
if (mode->pcrel)
store_psect_displaced_offset_word(str, tr, 2, sym->value + offset, sym->section->label);
else
store_psect_offset_word(str, tr, 2, sym->value + offset, sym->section->label);
}
}
} else {
/* Complex relocation */
if (mode->pcrel)
store_complex_displaced(str, tr, 2, mode->offset);
else
store_complex(str, tr, 2, mode->offset);
}
free_addr_mode(mode);
}
/* eval_defined - take an EX_TREE and returns TRUE if the tree
represents "defined" symbols. */
int eval_defined(
EX_TREE *value)
{
switch (value->type) {
case EX_LIT:
return 1;
case EX_SYM:
return 1;
case EX_UNDEFINED_SYM:
return 0;
case EX_AND:
return eval_defined(value->data.child.left) && eval_defined(value->data.child.right);
case EX_OR:
return eval_defined(value->data.child.left) || eval_defined(value->data.child.right);
default:
return 0;
}
}
/* eval_undefined - take an EX_TREE and returns TRUE if it represents
"undefined" symbols. */
int eval_undefined(
EX_TREE *value)
{
switch (value->type) {
case EX_UNDEFINED_SYM:
return 1;
case EX_SYM:
return 0;
case EX_AND:
return eval_undefined(value->data.child.left) && eval_undefined(value->data.child.right);
case EX_OR:
return eval_undefined(value->data.child.left) || eval_undefined(value->data.child.right);
default:
return 0;
}
}
/* push_cond - a new conditional (.IF) block has been activated. Push
its context. */
void push_cond(
int ok,
STREAM *str)
{
last_cond++;
assert(last_cond < MAX_CONDS);
conds[last_cond].ok = ok;
conds[last_cond].file = memcheck(strdup(str->name));
conds[last_cond].line = str->line;
}
/*
pop_cond - pop stacked conditionals. */
void pop_cond(
int to)
{
while (last_cond > to) {
free(conds[last_cond].file);
last_cond--;
}
}
/* go_section - sets current_pc to a new program section */
void go_section(
TEXT_RLD *tr,
SECTION *sect)
{
(void)tr;
if (current_pc->section == sect)
return; /* This is too easy */
/* save current PC value for old section */
current_pc->section->pc = DOT;
/* Set current section and PC value */
current_pc->section = sect;
DOT = sect->pc;
}
/*
store_value - used to store a value represented by an expression
tree into the object file. Used by do_word and .ASCII/.ASCIZ.
*/
void store_value(
STACK *stack,
TEXT_RLD *tr,
int size,
EX_TREE *value)
{
SYMBOL *sym;
unsigned offset;
implicit_gbl(value); /* turn undefined symbols into globals */
if (value->type == EX_LIT) {
store_word(stack->top, tr, size, value->data.lit);
} else if (!express_sym_offset(value, &sym, &offset)) {
store_complex(stack->top, tr, size, value);
} else {
if (SYM_IS_IMPORTED(sym)) {
store_global_offset_word(stack->top, tr, size, sym->value + offset, sym->label);
} else if (sym->section->type == SECTION_REGISTER) {
/* Delayed action: evaluate() excludes SECTION_REGISTER when
* turning symbols into EX_LIT. Do it here now. */
store_word(stack->top, tr, size, sym->value + offset);
} else if (sym->section != current_pc->section) {
store_psect_offset_word(stack->top, tr, size, sym->value + offset, sym->section->label);
} else {
store_internal_word(stack->top, tr, size, sym->value + offset);
}
}
}
/* do_word - used by .WORD, .BYTE, and implied .WORD. */
int do_word(
STACK *stack,
TEXT_RLD *tr,
char *cp,
int size)
{
int comma;
if (size == 2 && (DOT & 1)) {
report(stack->top, ".WORD on odd boundary\n");
store_word(stack->top, tr, 1, 0); /* Align it */
}
cp = skipwhite(cp);
do {
if (cp[0] == ',') {
/* Empty expressions count as 0 */
store_word(stack->top, tr, size, 0);
} else {
EX_TREE *value = parse_expr(cp, 0);
if (value->type != EX_ERR && value->cp > cp) {
store_value(stack, tr, size, value);
cp = value->cp;
} else {
report(stack->top, "Invalid expression in .WORD\n");
cp = ""; /* force loop to end */
}
free_tree(value);
}
} while (cp = skipdelim_comma(cp, &comma), !EOL(*cp));
if (comma) {
/* Trailing empty expressions count as 0 */
store_word(stack->top, tr, size, 0);
}
return 1;
}
/*
check_branch - check branch distance.
*/
int check_branch(
STACK *stack,
unsigned offset,
int min,
int max)
{
int s_offset;
if (offset & 1) {
report(stack->top, "Bad branch target (odd address)\n");
}
/* Sign-extend */
if (offset & 0100000)
s_offset = offset | ~0177777;
else
s_offset = offset & 077777;
if (s_offset > max || s_offset < min) {
char temp[16];
/* printf can't do signed octal. */
my_ltoa(s_offset, temp, 8);
report(stack->top, "Branch target out of range (distance=%s)\n", temp);
return 0;
}
return 1;
}
/* write_globals writes out the GSD prior to the second assembly pass */
void write_globals(
FILE *obj)
{
GSD gsd;
SYMBOL *sym;
SECTION *psect;
SYMBOL_ITER sym_iter;
int isect;
if (obj == NULL) {
for (isect = 0; isect < sector; isect++) {
psect = sections[isect];
psect->sector = isect; /* Assign it a sector */
psect->pc = 0; /* Reset its PC for second pass */
}
return; /* Nothing more to do if no OBJ file. */
}
gsd_init(&gsd, obj);
gsd_mod(&gsd, module_name);
if (ident)
gsd_ident(&gsd, ident);
/* write out each PSECT with its global stuff */
/* Sections must be written out in the order that they
appear in the assembly file. */
for (isect = 0; isect < sector; isect++) {
psect = sections[isect];
gsd_psect(&gsd, psect->label, psect->flags, psect->size);
psect->sector = isect; /* Assign it a sector */
psect->pc = 0; /* Reset its PC for second pass */
sym = first_sym(&symbol_st, &sym_iter);
while (sym) {
if ((sym->flags & SYMBOLFLAG_GLOBAL) && sym->section == psect) {
gsd_global(&gsd, sym->label,
((sym->flags & SYMBOLFLAG_DEFINITION) ? GLOBAL_DEF : 0) |
((sym->flags & SYMBOLFLAG_WEAK) ? GLOBAL_WEAK : 0) |
((sym->section->flags & PSECT_REL) ? GLOBAL_REL : 0) |
0100,
/* Looks undefined, but add it in anyway */
sym->value);
}
sym = next_sym(&symbol_st, &sym_iter);
}
}
/* Now write out the transfer address */
if (xfer_address->type == EX_LIT) {
gsd_xfer(&gsd, ". ABS.", xfer_address->data.lit);
} else {
SYMBOL *lsym;
unsigned offset;
if (!express_sym_offset(xfer_address, &lsym, &offset)) {
report(NULL, "Illegal program transfer address\n");
} else {
gsd_xfer(&gsd, lsym->section->label, lsym->value + offset);
}
}
gsd_flush(&gsd);
gsd_end(&gsd);
}

View File

@@ -0,0 +1,98 @@
#ifndef ASSEMBLE_AUX__H
#define ASSEMBLE_AUX__H
#include "stream2.h"
#include "object.h"
#include "extree.h"
#define NO_REG 0777
typedef struct addr_mode {
unsigned type; /* The bits that represent the addressing mode */
/* bits 0:2 are register number */
/* bit 3 is indirect */
/* bits 4:6 are mode, where 0=Rn, 1=(Rn)+,
2=-(Rn), 3=offset(Rn) */
int pcrel; /* the addressing mode is PC-relative */
EX_TREE *offset; /* Expression giving the offset */
} ADDR_MODE;
#define MODE_INDIRECT 010 /* (R0), @(R0)+, @-(R0), @42(R0) */
#define MODE_REG 000 /* R0 */
#define MODE_AUTO_INCR 020 /* (R0)+ */
#define MODE_AUTO_DECR 040 /* -(R0) */
#define MODE_OFFSET 060 /* 42(R0) */
#define MODE_PC 007
void push_cond(
int ok,
STREAM *str);
void pop_cond(
int to);
int express_sym_offset(
EX_TREE *value,
SYMBOL **sym,
unsigned *offset);
void change_dot(
TEXT_RLD *tr,
int size);
int store_word(
STREAM *str,
TEXT_RLD *tr,
int size,
unsigned word);
int store_limits(
STREAM *str,
TEXT_RLD *tr);
void store_value(
STACK *stack,
TEXT_RLD *tr,
int size,
EX_TREE *value);
int do_word(
STACK *stack,
TEXT_RLD *tr,
char *cp,
int size);
SECTION *new_section(
void);
void go_section(
TEXT_RLD *tr,
SECTION *sect);
void free_addr_mode(
ADDR_MODE *mode);
int eval_defined(
EX_TREE *value);
int eval_undefined(
EX_TREE *value);
void mode_extension(
TEXT_RLD *tr,
ADDR_MODE *mode,
STREAM *str);
int check_branch(
STACK *stack,
unsigned offset,
int min,
int max);
unsigned get_register(
EX_TREE *expr);
void write_globals(
FILE *obj);
void migrate_implicit(
void);
void migrate_undefined(
void);
#endif

View File

@@ -0,0 +1,108 @@
#define ASSEMBLE_GLOBALS__C
#include "assemble_globals.h" /* own definitions */
#include "object.h"
/* GLOBAL VARIABLES */
int pass = 0; /* The current assembly pass. 0 = first pass */
int stmtno = 0; /* The current source line number */
int radix = 8; /* The current input conversion radix */
int lsb = 0; /* The current local symbol section identifier */
int lsb_used = 0; /* Whether there was a local symbol using this lsb */
int next_lsb = 0; /* The number of the next local symbol block */
int last_macro_lsb = 0; /* The last block in which a macro
automatic label was created */
int last_locsym = 32768; /* The last local symbol number generated */
int enabl_debug = 0; /* Whether assembler debugging is enabled */
int opt_enabl_ama = 0; /* May be changed by command line */
int enabl_ama; /* When set, chooses absolute (037) versus
PC-relative */
/* (067) addressing mode */
int enabl_lsb = 0; /* When set, stops non-local symbol
definitions from delimiting local
symbol sections. */
int enabl_gbl = 1; /* Implicit definition of global symbols */
int enabl_lc = 1; /* If lowercase disabled, convert assembler
source to upper case. */
int enabl_lcm = 0; /* If lowercase disabled, .IF IDN/DIF are
case-sensitive. */
int enabl_mcl = 0; /* When set, unknown symbols are looked up
as if .MCALL <sym> had been done. */
int suppressed = 0; /* Assembly suppressed by failed conditional */
MLB *mlbs[MAX_MLBS]; /* macro libraries specified on the
command line */
int nr_mlbs = 0; /* Number of macro libraries */
COND conds[MAX_CONDS]; /* Stack of recent conditions */
int last_cond; /* 0 means no stacked cond. */
SECTION *sect_stack[SECT_STACK_SIZE]; /* 32 saved sections */
int dot_stack[SECT_STACK_SIZE]; /* 32 saved sections */
int sect_sp; /* Stack pointer */
char *module_name = NULL; /* The module name (taken from the 'TITLE'); */
unsigned *ident = NULL; /* Encoded .IDENT name */
EX_TREE *xfer_address = NULL; /* The transfer address */
SYMBOL *current_pc; /* The current program counter */
unsigned last_dot_addr; /* Last coded PC... */
SECTION *last_dot_section; /* ...and its program section */
/* The following are dummy psects for symbols which have meaning to
the assembler: */
SECTION register_section = {
"*REGISTERS*", SECTION_REGISTER, 0, 0, 0, 0
}; /* the section containing the registers */
SECTION pseudo_section = {
"*PSEUDO*", SECTION_PSEUDO, 0, 0, 0, 0
}; /* the section containing the
pseudo-operations */
SECTION instruction_section = {
"*INSTR*", SECTION_INSTRUCTION, 0, 0, 0, 0
}; /* the section containing instructions */
SECTION macro_section = {
"*MACRO*", SECTION_SYSTEM, 0, 0, 0, 0
}; /* Section for macros */
/* These are real psects that get written out to the object file */
SECTION absolute_section = {
". ABS.", SECTION_SYSTEM, PSECT_GBL | PSECT_COM, 0, 0, 0
}; /* The default
absolute section */
SECTION blank_section = {
"", SECTION_SYSTEM, PSECT_REL, 0, 0, 1
}; /* The default relocatable section */
SECTION *sections[256] = {
/* Array of sections in the order they were
defined */
&absolute_section, &blank_section,
};
int sector = 2; /* number of such sections */

View File

@@ -0,0 +1,94 @@
#ifndef ASSEMBLE_GLOBALS__H
#define ASSEMBLE_GLOBALS__H
#include "mlb.h"
#include "symbols.h"
#include "extree.h"
#define MAX_MLBS 32 /* number of macro libraries */
#define MAX_CONDS 256
typedef struct cond {
int ok; /* What the condition evaluated to */
char *file; /* What file and line it occurred */
int line;
} COND;
#define SECT_STACK_SIZE 32
#ifndef ASSEMBLE_GLOBALS__C
/* GLOBAL VARIABLES */
extern int pass; /* The current assembly pass. 0 = first pass */
extern int stmtno; /* The current source line number */
extern int radix; /* The current input conversion radix */
extern int lsb; /* The current local symbol section identifier */
extern int lsb_used; /* Whether there was a local symbol using this lsb */
extern int next_lsb; /* The number of the next local symbol block */
extern int last_macro_lsb; /* The last block in which a macro
automatic label was created */
extern int last_locsym; /* The last local symbol number generated */
extern int enabl_debug; /* Whether assembler debugging is enabled */
extern int opt_enabl_ama; /* May be changed by command line */
extern int enabl_ama; /* When set, chooses absolute (037) versus
PC-relative */
/* (067) addressing mode */
extern int enabl_lsb; /* When set, stops non-local symbol
definitions from delimiting local
symbol sections. */
extern int enabl_gbl; /* Implicit definition of global symbols */
extern int enabl_lc; /* If lowercase disabled, convert assembler
source to upper case. */
extern int enabl_lcm; /* If lowercase disabled, .IF IDN/DIF are
case-sensitive. */
extern int suppressed; /* Assembly suppressed by failed conditional */
extern MLB *mlbs[MAX_MLBS]; /* macro libraries specified on the command line */
extern int nr_mlbs; /* Number of macro libraries */
extern int enabl_mcl; /* If MCALL of unknown symbols is enabled. */
extern COND conds[MAX_CONDS]; /* Stack of recent conditions */
extern int last_cond; /* 0 means no stacked cond. */
extern SECTION *sect_stack[SECT_STACK_SIZE]; /* 32 saved sections */
extern int dot_stack[SECT_STACK_SIZE]; /* 32 saved sections */
extern int sect_sp; /* Stack pointer */
extern char *module_name; /* The module name (taken from the 'TITLE'); */
extern unsigned *ident; /* .IDENT name (encoded RAD50 value) */
extern EX_TREE *xfer_address; /* The transfer address */
extern SYMBOL *current_pc; /* The current program counter */
extern unsigned last_dot_addr; /* Last coded PC... */
extern SECTION *last_dot_section; /* ...and its program section */
/* The following are dummy psects for symbols which have meaning to
the assembler: */
extern SECTION register_section;
extern SECTION pseudo_section; /* the section containing the pseudo-operations */
extern SECTION instruction_section; /* the section containing instructions */
extern SECTION macro_section; /* Section for macros */
/* These are real psects that get written out to the object file */
extern SECTION absolute_section; /* The default absolute section */
extern SECTION blank_section;
extern SECTION *sections[256]; /* Array of sections in the order they were defined */
extern int sector; /* number of such sections */
#endif
#endif

View File

@@ -1,12 +0,0 @@
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.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,957 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "extree.h" /* my own definitions */
#include "util.h"
#include "assemble_globals.h"
#include "assemble_aux.h"
#include "listing.h"
#include "object.h"
#define DEBUG_REGEXPR 0
/* Diagnostic: print an expression tree. I used this in various
places to help me diagnose parse problems, by putting in calls to
print_tree when I didn't understand why something wasn't working.
This is currently dead code, nothing calls it; but I don't want it
to go away. Hopefully the compiler will realize when it's dead, and
eliminate it. */
void print_tree(
FILE *printfile,
EX_TREE *tp,
int depth)
{
SYMBOL *sym;
if (printfile == NULL) {
return;
}
if (tp == NULL) {
fprintf(printfile, "(null)");
return;
}
switch (tp->type) {
case EX_LIT:
fprintf(printfile, "%o", tp->data.lit & 0177777);
break;
case EX_SYM:
case EX_TEMP_SYM:
sym = tp->data.symbol;
fprintf(printfile, "%s{%s%o:%s}", tp->data.symbol->label, symflags(sym), sym->value,
sym->section->label);
break;
case EX_UNDEFINED_SYM:
fprintf(printfile, "%s{%o:undefined}", tp->data.symbol->label, tp->data.symbol->value);
break;
case EX_COM:
fprintf(printfile, "^C<");
print_tree(printfile, tp->data.child.left, depth + 4);
fprintf(printfile, ">");
break;
case EX_NEG:
fprintf(printfile, "-<");
print_tree(printfile, tp->data.child.left, depth + 4);
fputc('>', printfile);
break;
case EX_REG:
fprintf(printfile, "%%<");
print_tree(printfile, tp->data.child.left, depth + 4);
fputc('>', printfile);
break;
case EX_ERR:
fprintf(printfile, "{expression error}");
if (tp->data.child.left) {
fputc('<', printfile);
print_tree(printfile, tp->data.child.left, depth + 4);
fputc('>', printfile);
}
break;
case EX_ADD:
fputc('<', printfile);
print_tree(printfile, tp->data.child.left, depth + 4);
fputc('+', printfile);
print_tree(printfile, tp->data.child.right, depth + 4);
fputc('>', printfile);
break;
case EX_SUB:
fputc('<', printfile);
print_tree(printfile, tp->data.child.left, depth + 4);
fputc('-', printfile);
print_tree(printfile, tp->data.child.right, depth + 4);
fputc('>', printfile);
break;
case EX_MUL:
fputc('<', printfile);
print_tree(printfile, tp->data.child.left, depth + 4);
fputc('*', printfile);
print_tree(printfile, tp->data.child.right, depth + 4);
fputc('>', printfile);
break;
case EX_DIV:
fputc('<', printfile);
print_tree(printfile, tp->data.child.left, depth + 4);
fputc('/', printfile);
print_tree(printfile, tp->data.child.right, depth + 4);
fputc('>', printfile);
break;
case EX_AND:
fputc('<', printfile);
print_tree(printfile, tp->data.child.left, depth + 4);
fputc('&', printfile);
print_tree(printfile, tp->data.child.right, depth + 4);
fputc('>', printfile);
break;
case EX_OR:
fputc('<', printfile);
print_tree(printfile, tp->data.child.left, depth + 4);
fputc('!', printfile);
print_tree(printfile, tp->data.child.right, depth + 4);
fputc('>', printfile);
break;
case EX_LSH:
fputc('<', printfile);
print_tree(printfile, tp->data.child.left, depth + 4);
fputc('_', printfile);
print_tree(printfile, tp->data.child.right, depth + 4);
fputc('>', printfile);
break;
default:
fprintf(printfile, "(node %d)", tp->type);
break;
}
if (depth == 0)
fputc('\n', printfile);
}
/* num_subtrees tells you how many subtrees this EX_TREE has. */
int num_subtrees(
EX_TREE *tp)
{
switch (tp->type) {
case EX_UNDEFINED_SYM:
case EX_TEMP_SYM:
case EX_SYM:
case EX_LIT:
return 0;
break;
case EX_COM:
case EX_NEG:
case EX_REG:
case EX_ERR:
return 1;
case EX_ADD:
case EX_SUB:
case EX_MUL:
case EX_DIV:
case EX_AND:
case EX_OR:
case EX_LSH:
return 2;
}
return 0;
}
/* free_tree frees an expression tree. */
void free_tree(
EX_TREE *tp)
{
if (!tp)
return;
switch (num_subtrees(tp)) {
case 0:
switch (tp->type) {
case EX_UNDEFINED_SYM:
case EX_TEMP_SYM:
free(tp->data.symbol->label);
free(tp->data.symbol);
break;
case EX_SYM:
case EX_LIT:
break;
default:
assert(0);
break;
}
break;
case 2:
free_tree(tp->data.child.right);
/* FALLTHROUGH */
case 1:
free_tree(tp->data.child.left);
break;
}
free(tp);
}
/* new_temp_sym allocates a new EX_TREE entry of type "TEMPORARY
SYMBOL" (slight semantic difference from "UNDEFINED"). */
static EX_TREE *new_temp_sym(
char *label,
SECTION *section,
unsigned value)
{
SYMBOL *sym;
EX_TREE *tp;
sym = memcheck(malloc(sizeof(SYMBOL)));
sym->label = memcheck(strdup(label));
sym->flags = SYMBOLFLAG_DEFINITION;
sym->stmtno = stmtno;
sym->next = NULL;
sym->section = section;
sym->value = value;
tp = new_ex_tree(EX_TEMP_SYM);
tp->data.symbol = sym;
return tp;
}
SYMBOL *dup_symbol(
SYMBOL *sym)
{
SYMBOL *res;
if (sym == NULL) {
return NULL;
}
res = memcheck(malloc(sizeof(SYMBOL)));
res->label = memcheck(strdup(sym->label));
res->flags = sym->flags;
res->stmtno = sym->stmtno;
res->next = NULL;
res->section = sym->section;
res->value = sym->value;
return res;
}
EX_TREE *dup_tree(
EX_TREE *tp)
{
EX_TREE *res = NULL;
if (tp == NULL) {
return NULL;
}
res = new_ex_tree(tp->type);
res->cp = tp->cp;
switch (num_subtrees(tp)) {
case 0:
switch (tp->type) {
case EX_UNDEFINED_SYM:
case EX_TEMP_SYM:
res->data.symbol = dup_symbol(tp->data.symbol);
break;
/* The symbol reference in EX_SYM is not freed in free_tree() */
case EX_SYM:
res->data.symbol = tp->data.symbol;
break;
case EX_LIT:
res->data.lit = tp->data.lit;
break;
default:
assert(0);
break;
}
break;
case 2:
res->data.child.right = dup_tree(tp->data.child.right);
/* FALLTHROUGH */
case 1:
res->data.child.left = dup_tree(tp->data.child.left);
break;
}
return res;
}
#define RELTYPE(tp) (((tp)->type == EX_SYM || (tp)->type == EX_TEMP_SYM) && \
(tp)->data.symbol->section->flags & PSECT_REL)
/* evaluate "evaluates" an EX_TREE, ideally trying to produce a
constant value, else a symbol plus an offset.
Leaves the input tree untouched and creates a new tree as result. */
EX_TREE *evaluate_rec(
EX_TREE *tp,
int flags,
int *outflags)
{
EX_TREE *res;
char *cp = tp->cp;
switch (tp->type) {
case EX_SYM:
{
SYMBOL *sym = tp->data.symbol;
/* Change some symbols to "undefined" */
if (flags & EVALUATE_DEFINEDNESS) {
int is_undefined = 0;
/* I'd prefer this behavior, but MACRO.SAV is a bit too primitive. */
#if 0
/* A temporary symbol defined later is "undefined." */
if (!(sym->flags & PERMANENT) && sym->stmtno > stmtno)
is_undefined = 1;
#endif
/* A global symbol with no assignment is "undefined." */
/* Go figure. */
if (SYM_IS_IMPORTED(sym))
is_undefined = 1;
/* A symbol marked as undefined is undefined */
if (sym->flags & SYMBOLFLAG_UNDEFINED)
is_undefined = 1;
if (is_undefined) {
res = new_temp_sym(tp->data.symbol->label, tp->data.symbol->section,
tp->data.symbol->value);
res->type = EX_UNDEFINED_SYM;
break;
}
}
/* Turn defined absolute symbol to a literal */
if (!(sym->section->flags & PSECT_REL)
&& !SYM_IS_IMPORTED(sym)) {
res = new_ex_lit(sym->value);
if (sym->section->type == SECTION_REGISTER) {
*outflags |= EVALUATE_OUT_IS_REGISTER;
}
break;
}
/* Make a temp copy of any reference to "." since it might
change as complex relocatable expressions are written out
*/
if (strcmp(sym->label, ".") == 0) {
res = new_temp_sym(".", sym->section, sym->value);
break;
}
/* Copy other symbol reference verbatim. */
res = dup_tree(tp);
break;
}
case EX_LIT:
res = dup_tree(tp);
break;
case EX_TEMP_SYM:
case EX_UNDEFINED_SYM:
/* Copy temp and undefined symbols */
res = new_temp_sym(tp->data.symbol->label, tp->data.symbol->section, tp->data.symbol->value);
res->type = tp->type;
break;
case EX_COM:
/* Complement */
tp = evaluate_rec(tp->data.child.left, flags, outflags);
if (tp->type == EX_LIT) {
/* Complement the literal */
res = new_ex_lit(~tp->data.lit);
free_tree(tp);
} else {
/* Copy verbatim. */
res = new_ex_una(EX_COM, tp);
}
break;
case EX_NEG:
tp = evaluate_rec(tp->data.child.left, flags, outflags);
if (tp->type == EX_LIT) {
/* negate literal */
res = new_ex_lit((unsigned) -(int) tp->data.lit);
free_tree(tp);
} else if (tp->type == EX_TEMP_SYM ||
(tp->type == EX_SYM &&
(tp->data.symbol->flags & SYMBOLFLAG_DEFINITION))) {
/* Make a temp sym with the negative value of the given
sym (this works for symbols within relocatable sections
too) */
res = new_temp_sym("*NEG", tp->data.symbol->section, (unsigned) -(int) tp->data.symbol->value);
res->cp = tp->cp;
free_tree(tp);
} else {
/* Copy verbatim. */
res = new_ex_una(EX_NEG, tp);
}
break;
case EX_REG:
res = evaluate_rec(tp->data.child.left, flags, outflags);
*outflags |= EVALUATE_OUT_IS_REGISTER;
break;
case EX_ERR:
/* Copy */
res = dup_tree(tp);
break;
case EX_ADD:
{
EX_TREE *left,
*right;
left = evaluate_rec(tp->data.child.left, flags, outflags);
right = evaluate_rec(tp->data.child.right, flags, outflags);
/* Both literals? Sum them and return result. */
if (left->type == EX_LIT && right->type == EX_LIT) {
res = new_ex_lit(left->data.lit + right->data.lit);
free_tree(left);
free_tree(right);
break;
}
/* Commutative: A+x == x+A.
Simplify by putting the literal on the right */
if (left->type == EX_LIT) {
EX_TREE *temp = left;
left = right;
right = temp;
}
if (right->type == EX_LIT && /* Anything plus 0 == itself */
right->data.lit == 0) {
res = left;
free_tree(right);
break;
}
/* Relative symbol plus lit is replaced with a temp sym
holding the sum */
if (RELTYPE(left) && right->type == EX_LIT) {
SYMBOL *sym = left->data.symbol;
res = new_temp_sym("*ADD", sym->section, sym->value + right->data.lit);
free_tree(left);
free_tree(right);
break;
}
/* Associative: <A+x>+y == A+<x+y> */
/* and if x+y is constant, I can do that math. */
if (left->type == EX_ADD && right->type == EX_LIT) {
EX_TREE *leftright = left->data.child.right;
if (leftright->type == EX_LIT) {
/* Do the shuffle */
res = left;
leftright->data.lit += right->data.lit;
free_tree(right);
break;
}
}
/* Associative: <A-x>+y == A+<y-x> */
/* and if y-x is constant, I can do that math. */
if (left->type == EX_SUB && right->type == EX_LIT) {
EX_TREE *leftright = left->data.child.right;
if (leftright->type == EX_LIT) {
/* Do the shuffle */
res = left;
leftright->data.lit = right->data.lit - leftright->data.lit;
free_tree(right);
break;
}
}
/* Anything else returns verbatim */
res = new_ex_bin(EX_ADD, left, right);
}
break;
case EX_SUB:
{
EX_TREE *left,
*right;
left = evaluate_rec(tp->data.child.left, flags, outflags);
right = evaluate_rec(tp->data.child.right, flags, outflags);
/* Both literals? Subtract them and return a lit. */
if (left->type == EX_LIT && right->type == EX_LIT) {
res = new_ex_lit(left->data.lit - right->data.lit);
free_tree(left);
free_tree(right);
break;
}
if (right->type == EX_LIT && /* Symbol minus 0 == symbol */
right->data.lit == 0) {
res = left;
free_tree(right);
break;
}
/* A relocatable minus an absolute - make a new temp sym
to represent that. */
if (RELTYPE(left) && right->type == EX_LIT) {
SYMBOL *sym = left->data.symbol;
res = new_temp_sym("*SUB", sym->section, sym->value - right->data.lit);
free_tree(left);
free_tree(right);
break;
}
if (RELTYPE(left) && RELTYPE(right) && left->data.symbol->section == right->data.symbol->section) {
/* Two defined symbols in the same psect. Resolve
their difference as a literal. */
res = new_ex_lit(left->data.symbol->value - right->data.symbol->value);
free_tree(left);
free_tree(right);
break;
}
/* Associative: <A+x>-y == A+<x-y> */
/* and if x-y is constant, I can do that math. */
if (left->type == EX_ADD && right->type == EX_LIT) {
EX_TREE *leftright = left->data.child.right;
if (leftright->type == EX_LIT) {
/* Do the shuffle */
res = left;
leftright->data.lit -= right->data.lit;
free_tree(right);
break;
}
}
/* Associative: <A-x>-y == A-<x+y> */
/* and if x+y is constant, I can do that math. */
if (left->type == EX_SUB && right->type == EX_LIT) {
EX_TREE *leftright = left->data.child.right;
if (leftright->type == EX_LIT) {
/* Do the shuffle */
res = left;
leftright->data.lit += right->data.lit;
free_tree(right);
break;
}
}
/* Anything else returns verbatim */
res = new_ex_bin(EX_SUB, left, right);
}
break;
case EX_MUL:
{
EX_TREE *left,
*right;
left = evaluate_rec(tp->data.child.left, flags, outflags);
right = evaluate_rec(tp->data.child.right, flags, outflags);
/* Can only multiply if both are literals */
if (left->type == EX_LIT && right->type == EX_LIT) {
res = new_ex_lit(left->data.lit * right->data.lit);
free_tree(left);
free_tree(right);
break;
}
/* Commutative: A*x == x*A.
Simplify by putting the literal on the right */
if (left->type == EX_LIT) {
EX_TREE *temp = left;
left = right;
right = temp;
}
if (right->type == EX_LIT && /* Symbol times 1 == symbol */
right->data.lit == 1) {
res = left;
free_tree(right);
break;
}
if (right->type == EX_LIT && /* Symbol times 0 == 0 */
right->data.lit == 0) {
res = right;
free_tree(left);
break;
}
/* Associative: <A*x>*y == A*<x*y> */
/* If x*y is constant, I can do this math. */
/* Is this safe? I will potentially be doing it */
/* with greater accuracy than the target platform. */
/* Hmmm. */
if (left->type == EX_MUL && right->type == EX_LIT) {
EX_TREE *leftright = left->data.child.right;
if (leftright->type == EX_LIT) {
/* Do the shuffle */
res = left;
leftright->data.lit *= right->data.lit;
free_tree(right);
break;
}
}
/* Anything else returns verbatim */
res = new_ex_bin(EX_MUL, left, right);
}
break;
case EX_DIV:
{
EX_TREE *left,
*right;
left = evaluate_rec(tp->data.child.left, flags, outflags);
right = evaluate_rec(tp->data.child.right, flags, outflags);
/* Can only divide if both are literals */
if (left->type == EX_LIT && right->type == EX_LIT) {
res = new_ex_lit(left->data.lit / right->data.lit);
free_tree(left);
free_tree(right);
break;
}
if (right->type == EX_LIT && /* Symbol divided by 1 == symbol */
right->data.lit == 1) {
res = left;
free_tree(right);
break;
}
/* Anything else returns verbatim */
res = new_ex_bin(EX_DIV, left, right);
}
break;
case EX_AND:
{
EX_TREE *left,
*right;
left = evaluate_rec(tp->data.child.left, flags, outflags);
right = evaluate_rec(tp->data.child.right, flags, outflags);
/* Operate if both are literals */
if (left->type == EX_LIT && right->type == EX_LIT) {
res = new_ex_lit(left->data.lit & right->data.lit);
free_tree(left);
free_tree(right);
break;
}
/* Commutative: A&x == x&A.
Simplify by putting the literal on the right */
if (left->type == EX_LIT) {
EX_TREE *temp = left;
left = right;
right = temp;
}
if (right->type == EX_LIT && /* Symbol AND 0 == 0 */
right->data.lit == 0) {
res = new_ex_lit(0);
free_tree(left);
free_tree(right);
break;
}
if (right->type == EX_LIT && /* Symbol AND 0177777 == symbol */
right->data.lit == 0177777) {
res = left;
free_tree(right);
break;
}
/* Anything else returns verbatim */
res = new_ex_bin(EX_AND, left, right);
}
break;
case EX_OR:
{
EX_TREE *left,
*right;
left = evaluate_rec(tp->data.child.left, flags, outflags);
right = evaluate_rec(tp->data.child.right, flags, outflags);
/* Operate if both are literals */
if (left->type == EX_LIT && right->type == EX_LIT) {
res = new_ex_lit(left->data.lit | right->data.lit);
free_tree(left);
free_tree(right);
break;
}
/* Commutative: A!x == x!A.
Simplify by putting the literal on the right */
if (left->type == EX_LIT) {
EX_TREE *temp = left;
left = right;
right = temp;
}
if (right->type == EX_LIT && /* Symbol OR 0 == symbol */
right->data.lit == 0) {
res = left;
free_tree(right);
break;
}
if (right->type == EX_LIT && /* Symbol OR 0177777 == 0177777 */
right->data.lit == 0177777) {
res = new_ex_lit(0177777);
free_tree(left);
free_tree(right);
break;
}
/* Anything else returns verbatim */
res = new_ex_bin(EX_OR, left, right);
}
break;
case EX_LSH:
{
EX_TREE *left,
*right;
left = evaluate_rec(tp->data.child.left, flags, outflags);
right = evaluate_rec(tp->data.child.right, flags, outflags);
/* Operate if both are literals */
if (left->type == EX_LIT && right->type == EX_LIT) {
int shift = right->data.lit;
if (shift < 0)
res = new_ex_lit(left->data.lit >> -shift);
else
res = new_ex_lit(left->data.lit << shift);
free_tree(left);
free_tree(right);
break;
}
if (right->type == EX_LIT && /* Symbol shifted 0 == symbol */
right->data.lit == 0) {
res = left;
free_tree(right);
break;
}
if (right->type == EX_LIT && /* Anything shifted 16 == 0 */
((int)right->data.lit > 15 ||
(int)right->data.lit < -15)) {
res = new_ex_lit(0);
free_tree(left);
free_tree(right);
break;
}
if (right->type == EX_LIT) { /* Other shifts become * or / */
int shift = right->data.lit;
if (shift > 0)
res = new_ex_bin(EX_MUL, left, new_ex_lit(1 << shift));
else
res = new_ex_bin(EX_DIV, left, new_ex_lit(1 << -shift));
free_tree(right);
break;
}
/* Anything else returns verbatim */
res = new_ex_bin(EX_LSH, left, right);
}
break;
default:
fprintf(stderr, "evaluate_rec: Invalid tree: ");
print_tree(stderr, tp, 0);
return NULL;
}
res->cp = cp;
return res;
}
EX_TREE *evaluate(
EX_TREE *tp,
int flags)
{
EX_TREE *res;
int outflags = 0;
#if DEBUG_REGEXPR
fprintf(stderr, "evaluate: ");
print_tree(stderr, tp, 0);
#endif /* DEBUG_REGEXPR */
/*
* Check the common simple case for register references: R0...PC.
* Copy those directly, without going into the recursion.
* Therefore, in the recursion it can be assumed that the expression
* is more complex, and it is worth the overhead of converting them
* to an EX_LIT plus the EVALUATE_OUT_IS_REGISTER flag
* (and back again, up here).
*/
if (tp->type == EX_SYM &&
tp->data.symbol->section->type == SECTION_REGISTER &&
!SYM_IS_IMPORTED(tp->data.symbol)) {
res = dup_tree(tp);
} else {
res = evaluate_rec(tp, flags, &outflags);
if (outflags & EVALUATE_OUT_IS_REGISTER) {
int regno = get_register(res);
if (regno == NO_REG) {
report(NULL, "Register expression out of range.\n");
#if DEBUG_REGEXPR
print_tree(stderr, tp, 0);
print_tree(stderr, res, 0);
#endif /* DEBUG_REGEXPR */
/* TODO: maybe make this a EX_TEMP_SYM? */
res = ex_err(res, res->cp);
} else {
EX_TREE *newresult = new_ex_tree(EX_SYM);
newresult->cp = res->cp;
newresult->data.symbol = reg_sym[regno];
free_tree(res);
res = newresult;
}
}
}
return res;
}
/* Allocate an EX_TREE */
EX_TREE *new_ex_tree(
int type)
{
EX_TREE *tr = memcheck(calloc(1, sizeof(EX_TREE)));
tr->type = type;
return tr;
}
/* Create an EX_TREE representing a parse error */
EX_TREE *ex_err(
EX_TREE *tp,
char *cp)
{
EX_TREE *errtp;
errtp = new_ex_tree(EX_ERR);
errtp->cp = cp;
errtp->data.child.left = tp;
return errtp;
}
/* Create an EX_TREE representing a literal value */
EX_TREE *new_ex_lit(
unsigned value)
{
EX_TREE *tp;
tp = new_ex_tree(EX_LIT);
tp->data.lit = value;
return tp;
}
/* Create an EX_TREE representing a binary expression */
EX_TREE *new_ex_bin(
int type,
EX_TREE *left,
EX_TREE *right)
{
EX_TREE *tp;
tp = new_ex_tree(type);
tp->data.child.left = left;
tp->data.child.right = right;
tp->cp = right->cp;
return tp;
}
/* Create an EX_TREE representing a unary expression */
EX_TREE *new_ex_una(
int type,
EX_TREE *left)
{
EX_TREE *tp;
tp = new_ex_tree(type);
tp->data.child.left = left;
tp->data.child.right = NULL;
tp->cp = left->cp;
return tp;
}

View File

@@ -0,0 +1,84 @@
#ifndef EXTREE__H
#define EXTREE__H
#include "symbols.h"
typedef struct ex_tree {
enum ex_type {
EX_LIT = 1,
/* Expression is a literal value */
EX_SYM = 2,
/* Expression has a symbol reference
* (symbol from symbol table, so not freed) */
EX_UNDEFINED_SYM = 3,
/* Expression is undefined sym reference */
EX_TEMP_SYM = 4,
/* Expression is temp sym reference */
EX_COM = 5,
/* One's complement */
EX_NEG = 6,
/* Negate */
EX_REG = 7,
/* register value (%) */
EX_ERR = 8,
/* Expression with an error */
EX_ADD = 9,
/* Add */
EX_SUB = 10,
/* Subtract */
EX_MUL = 11,
/* Multiply */
EX_DIV = 12,
/* Divide */
EX_AND = 13,
/* bitwise and */
EX_OR = 14,
/* bitwise or */
EX_LSH = 15,
/* left shift */
} type;
char *cp; /* points to end of parsed expression */
union {
struct {
struct ex_tree *left,
*right; /* Left, right children */
} child;
unsigned lit; /* Literal value */
SYMBOL *symbol; /* Symbol reference */
} data;
} EX_TREE;
EX_TREE *new_ex_tree(
int type);
void free_tree(
EX_TREE *tp);
EX_TREE *new_ex_lit(
unsigned value);
EX_TREE *ex_err(
EX_TREE *tp,
char *cp);
EX_TREE *new_ex_bin(
int type,
EX_TREE *left,
EX_TREE *right);
EX_TREE *new_ex_una(
int type,
EX_TREE *left);
int num_subtrees(
EX_TREE *tp);
EX_TREE *evaluate(
EX_TREE *tp,
int flags);
#define EVALUATE_DEFINEDNESS 1
#define EVALUATE_OUT_IS_REGISTER 1
#endif

View File

@@ -0,0 +1,198 @@
#define LISTING__C
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdarg.h>
#include "listing.h" /* my own definitions */
#include "util.h"
#include "assemble_globals.h"
/* GLOBAL VARIABLES */
int list_md = 1; /* option to list macro/rept definition = yes */
int list_me = 1; /* option to list macro/rept expansion = yes */
int list_bex = 1; /* option to show binary */
int list_level = 1; /* Listing control level. .LIST
increments; .NLIST decrements */
static char *listline; /* Source lines */
static char *binline; /* for octal expansion */
FILE *lstfile = NULL;
int list_pass_0 = 0;/* Also list what happens during the first pass */
static int errline = 0; /* Set if current line has an error */
/* maybe_list returns TRUE if listing may happen for this line. */
static int can_list(
void)
{
int ok = lstfile != NULL &&
(pass > 0 || list_pass_0);
return ok;
}
/* do_list returns TRUE if listing is enabled. */
static int dolist(
void)
{
int ok = can_list () &&
(list_level > 0 || errline);
return ok;
}
/* list_source saves a text line for later listing by list_flush */
void list_source(
STREAM *str,
char *cp)
{
if (can_list()) {
int len = strcspn(cp, "\n");
/* Not an error yet */
errline = 0;
/* Save the line text away for later... */
if (listline)
free(listline);
listline = memcheck(malloc(len + 1));
memcpy(listline, cp, len);
listline[len] = 0;
if (!binline)
binline = memcheck(malloc(sizeof(LSTFORMAT) + 16));
sprintf(binline, "%*s%*d", (int)SIZEOF_MEMBER(LSTFORMAT, flag), "", (int)SIZEOF_MEMBER(LSTFORMAT, line_number),
str->line);
}
}
/* list_flush produces a buffered list line. */
void list_flush(
void)
{
if (dolist()) {
padto(binline, offsetof(LSTFORMAT, source));
fputs(binline, lstfile);
fputs(listline, lstfile);
fputc('\n', lstfile);
listline[0] = 0;
binline[0] = 0;
}
}
/* list_fit checks to see if a word will fit in the current listing
line. If not, it flushes and prepares another line. */
static void list_fit(
STREAM *str,
unsigned addr)
{
size_t col1 = offsetof(LSTFORMAT, source);
size_t col2 = offsetof(LSTFORMAT, pc);
if (strlen(binline) >= col1) {
list_flush();
listline[0] = 0;
binline[0] = 0;
sprintf(binline, "%*s %6.6o", (int)offsetof(LSTFORMAT, pc), "", addr);
padto(binline, offsetof(LSTFORMAT, words));
} else if (strlen(binline) <= col2) {
sprintf(binline, "%*s%*d %6.6o", (int)SIZEOF_MEMBER(LSTFORMAT, flag), "",
(int)SIZEOF_MEMBER(LSTFORMAT, line_number), str->line, addr);
padto(binline, offsetof(LSTFORMAT, words));
}
}
/* list_value is used to show a computed value */
void list_value(
STREAM *str,
unsigned word)
{
if (dolist()) {
/* Print the value and go */
binline[0] = 0;
sprintf(binline, "%*s%*d %6.6o", (int)SIZEOF_MEMBER(LSTFORMAT, flag), "",
(int)SIZEOF_MEMBER(LSTFORMAT, line_number), str->line, word & 0177777);
}
}
/* Print a word to the listing file */
void list_word(
STREAM *str,
unsigned addr,
unsigned value,
int size,
char *flags)
{
if (dolist()) {
list_fit(str, addr);
if (size == 1)
sprintf(binline + strlen(binline), " %3.3o%1.1s ", value & 0377, flags);
else
sprintf(binline + strlen(binline), "%6.6o%1.1s ", value & 0177777, flags);
}
}
/* Print just a line with the address to the listing file */
void list_location(
STREAM *str,
unsigned addr)
{
if (dolist()) {
list_fit(str, addr);
}
}
/* reports errors */
void report(
STREAM *str,
char *fmt,
...)
{
va_list ap;
char *name = "**";
int line = 0;
if (!pass && list_pass_0 < 2)
return; /* Don't report now. */
errline = 1;
if (str) {
name = str->name;
line = str->line;
}
fprintf(stderr, "%s:%d: ***ERROR ", name, line);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
if (lstfile) {
fprintf(lstfile, "%s:%d: ***ERROR ", name, line);
va_start(ap, fmt);
vfprintf(lstfile, fmt, ap);
va_end(ap);
}
}

View File

@@ -0,0 +1,69 @@
#ifndef LISTING__H
#define LISTING__H
#include "stream2.h"
/*
format of a listing line
Interestingly, no instances of this struct are ever created.
It lives to be a way to layout the format of a list line.
I wonder if I should have bothered.
*/
typedef struct lstformat {
char flag[2]; /* Error flags */
char line_number[6]; /* Line number */
char pc[8]; /* Location */
char words[8][3]; /* three instruction words */
char source[1]; /* source line */
} LSTFORMAT;
/* GLOBAL VARIABLES */
#ifndef LISTING__C
extern int list_md; /* option to list macro/rept definition = yes */
extern int list_me; /* option to list macro/rept expansion = yes */
extern int list_bex; /* option to show binary */
extern int list_level; /* Listing control level. .LIST
increments; .NLIST decrements */
extern FILE *lstfile;
extern int list_pass_0; /* Also list what happens during the first pass */
#endif
void list_word(
STREAM *str,
unsigned addr,
unsigned value,
int size,
char *flags);
void list_value(
STREAM *str,
unsigned word);
void list_location(
STREAM *str,
unsigned word);
void list_source(
STREAM *str,
char *cp);
void list_flush(
void);
void report(
STREAM *str,
char *fmt,
...);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,19 @@
#ifndef MACRO11_H
#define MACRO11_H
#include "git-info.h"
#define BASE_VERSION "0.8"
#if defined(GIT_VERSION)
#define VERSIONSTR BASE_VERSION" ("GIT_VERSION"\n\t"GIT_AUTHOR_DATE")"
#else
#define VERSIONSTR BASE_VERSION" (07 Jul 2022)"
/*#define VERSIONSTR "0.3 (April 21, 2009)" */
/*#define VERSIONSTR "0.2 July 15, 2001" */
#endif
/*
Copyright (c) 2001, Richard Krehbiel
All rights reserved.
@@ -34,6 +47,5 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
extern void *memcheck(void *p);
#endif

View File

@@ -0,0 +1 @@
leak:atexit_handler_alloc

View File

@@ -0,0 +1,701 @@
#define MACROS__C
/*
Dealing with MACROs
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "macros.h" /* my own definitions */
#include "util.h"
#include "assemble_globals.h"
#include "assemble_aux.h"
#include "listing.h"
#include "parse.h"
#include "stream2.h"
#include "symbols.h"
/* Here's where I pretend I'm a C++ compiler. :-/ */
/* *** derive a MACRO_STREAM from a BUFFER_STREAM with a few other args */
/* macro_stream_delete is called when a macro expansion is
exhausted. The unique behavior is to unwind any stacked
conditionals. This allows a nested .MEXIT to work. */
void macro_stream_delete(
STREAM *str)
{
MACRO_STREAM *mstr = (MACRO_STREAM *) str;
pop_cond(mstr->cond);
buffer_stream_delete(str);
}
STREAM_VTBL macro_stream_vtbl = {
macro_stream_delete, buffer_stream_getline, buffer_stream_rewind
};
STREAM *new_macro_stream(
STREAM *refstr,
BUFFER *buf,
MACRO *mac,
int nargs)
{
MACRO_STREAM *mstr = memcheck(malloc(sizeof(MACRO_STREAM))); {
char *name = memcheck(malloc(strlen(refstr->name) + 32));
sprintf(name, "%s:%d->%s", refstr->name, refstr->line, mac->sym.label);
buffer_stream_construct(&mstr->bstr, buf, name);
free(name);
}
mstr->bstr.stream.vtbl = &macro_stream_vtbl;
mstr->nargs = nargs; /* for .NARG directive: nonkeyword arguments in call*/
mstr->cond = last_cond;
return &mstr->bstr.stream;
}
/* read_body fetches the body of .MACRO, .REPT, .IRP, or .IRPC into a
BUFFER. */
void read_body(
STACK *stack,
BUFFER *gb,
char *name,
int called)
{
int nest;
/* Read the stream in until the end marker is hit */
/* Note: "called" says that this body is being pulled from a macro
library, and so under no circumstance should it be listed. */
nest = 1;
for (;;) {
SYMBOL *op;
char *nextline;
char *cp;
nextline = stack_getline(stack); /* Now read the line */
if (nextline == NULL) { /* End of file. */
report(stack->top, "Macro body of '%s' not closed\n", name);
break;
}
if (!(called & CALLED_NOLIST) &&
(list_level - 1 + list_md) > 0) {
list_flush();
list_source(stack->top, nextline);
}
op = get_op(nextline, &cp);
if (op == NULL) { /* Not a pseudo-op */
buffer_append_line(gb, nextline);
continue;
}
if (op->section->type == SECTION_PSEUDO) {
if (op->value == P_MACRO || op->value == P_REPT || op->value == P_IRP || op->value == P_IRPC) {
nest++;
}
if (op->value == P_ENDM || op->value == P_ENDR) {
nest--;
/* If there's a name on the .ENDM, then
* check if the name matches the one on .MACRO.
* See page 7-3.
* Since we don't keep a stack of nested
* .MACRO names, just check for the outer one.
*/
if (nest == 0 && name && op->value == P_ENDM) {
cp = skipwhite(cp);
if (!EOL(*cp)) {
char *label = get_symbol(cp, &cp, NULL);
if (label) {
if (strcmp(label, name) != 0) {
report(stack->top, ".ENDM '%s' does not match .MACRO '%s'\n", label, name);
}
free(label);
}
}
}
}
if (nest == 0)
return; /* All done. */
}
buffer_append_line(gb, nextline);
}
}
/* Diagnostic: dumpmacro dumps a macro definition to stdout.
I used this for debugging; it's not called at all right now, but
I hate to delete good code. */
void dumpmacro(
MACRO *mac,
FILE *fp)
{
ARG *arg;
fprintf(fp, ".MACRO %s ", mac->sym.label);
for (arg = mac->args; arg != NULL; arg = arg->next) {
fputs(arg->label, fp);
if (arg->value) {
fputc('=', fp);
fputs(arg->value, fp);
}
fputc(' ', fp);
}
fputc('\n', fp);
fputs(mac->text->buffer, fp);
fputs(".ENDM\n", fp);
}
/* defmacro - define a macro. */
/* Also used by .MCALL to pull macro definitions from macro libraries */
MACRO *defmacro(
char *cp,
STACK *stack,
int called)
{
MACRO *mac;
ARG *arg,
**argtail;
char *label;
cp = skipwhite(cp);
label = get_symbol(cp, &cp, NULL);
if (label == NULL) {
report(stack->top, "Invalid macro definition\n");
return NULL;
}
if (!(called & CALLED_NODEFINE)) {
/* Allow redefinition of a macro; new definition replaces the old. */
mac = (MACRO *) lookup_sym(label, &macro_st);
if (mac) {
/* Remove from the symbol table... */
remove_sym(&mac->sym, &macro_st);
free_macro(mac);
}
}
mac = new_macro(label);
if (!(called & CALLED_NODEFINE)) {
add_table(&mac->sym, &macro_st);
}
argtail = &mac->args;
cp = skipdelim(cp);
while (!EOL(*cp)) {
arg = new_arg();
arg->locsym = *cp == '?';
if (arg->locsym) /* special argument flag? */
cp++;
arg->label = get_symbol(cp, &cp, NULL);
if (arg->label == NULL) {
/* It turns out that I have code which is badly formatted
but which MACRO.SAV assembles. Sigh. */
/* So, just quit defining arguments. */
break;
#if 0
report(str, "Illegal macro argument\n");
remove_sym(&mac->sym, &macro_st);
free_macro(mac);
return NULL;
#endif
}
cp = skipwhite(cp);
if (*cp == '=') {
/* Default substitution given */
arg->value = getstring(cp + 1, &cp);
if (arg->value == NULL) {
report(stack->top, "Illegal macro argument\n");
remove_sym(&mac->sym, &macro_st);
free_macro(mac);
return NULL;
}
}
/* Append to list of arguments */
arg->next = NULL;
*argtail = arg;
argtail = &arg->next;
cp = skipdelim(cp);
}
/* Read the stream in until the end marker is hit */ {
BUFFER *gb;
int levelmod = 0;
gb = new_buffer();
if ((called & CALLED_NOLIST) && !list_md) {
list_level--;
levelmod = 1;
}
read_body(stack, gb, mac->sym.label, called);
list_level += levelmod;
if (mac->text != NULL) /* Discard old macro body */
buffer_free(mac->text);
mac->text = gb;
}
return mac;
}
/* Allocate a new ARG */
ARG *new_arg(
void)
{
ARG *arg = memcheck(malloc(sizeof(ARG)));
arg->locsym = 0;
arg->value = NULL;
arg->next = NULL;
arg->label = NULL;
return arg;
}
/* Free a list of args (as for a macro, or a macro expansion) */
static void free_args(
ARG *arg)
{
ARG *next;
while (arg) {
next = arg->next;
if (arg->label) {
free(arg->label);
arg->label = NULL;
}
if (arg->value) {
free(arg->value);
arg->value = NULL;
}
free(arg);
arg = next;
}
}
/* find_arg - looks for an arg with the given name in the given
argument list */
static ARG *find_arg(
ARG *arg,
char *name)
{
for (; arg != NULL; arg = arg->next)
if (strcmp(arg->label, name) == 0)
return arg;
return NULL;
}
/* subst_args - given a BUFFER and a list of args, generate a new
BUFFER with argument replacement having taken place. */
BUFFER *subst_args(
BUFFER *text,
ARG *args)
{
char *in;
char *begin;
BUFFER *gb;
char *label;
ARG *arg;
gb = new_buffer();
/* Blindly look for argument symbols in the input. */
/* Don't worry about quotes or comments. */
for (begin = in = text->buffer; in < text->buffer + text->length;) {
char *next;
if (issym((unsigned char)*in)) {
label = get_symbol(in, &next, NULL);
if (label) {
if ((arg = find_arg(args, label))) {
/* An apostrophe may appear before or after the symbol. */
/* In either case, remove it from the expansion. */
if (in > begin && in[-1] == '\'')
in--; /* Don't copy it. */
if (*next == '\'')
next++;
/* Copy prior characters */
buffer_appendn(gb, begin, (int) (in - begin));
/* Copy replacement string */
buffer_append_line(gb, arg->value);
in = begin = next;
--in; /* prepare for subsequent increment */
}
free(label);
in = next;
} else
in++;
} else
in++;
}
/* Append the rest of the text */
buffer_appendn(gb, begin, (int) (in - begin));
return gb; /* Done. */
}
/* eval_str - the language allows an argument expression to be given
as "\expression" which means, evaluate the expression and
substitute the numeric value in the current radix. */
char *eval_str(
STREAM *refstr,
char *arg)
{
EX_TREE *value = parse_expr(arg, 0);
unsigned word = 0;
char temp[10];
if (value->type != EX_LIT) {
report(refstr, "Constant value required\n");
} else
word = value->data.lit;
free_tree(value);
/* printf can't do base 2. */
my_ultoa(word & 0177777, temp, radix);
free(arg);
arg = memcheck(strdup(temp));
return arg;
}
/* getstring_macarg - parse a string that possibly starts with a backslash.
* If so, performs expression evaluation.
*
* The current implementation over-accepts some input.
*
* MACRO V05.05:
.list me
.macro test x
.blkb x
.endm
size = 10
foo = 2
; likes:
test size
test \size
test \<size>
test \<size + foo>
test ^/size + foo/
; dislikes:
test <\size> ; arg is \size which could be ok in other cases
test size + foo ; gets split at the space
test /size + foo/ ; gets split at the space
test \/size + foo/
test \^/size + foo/ ; * accepted by this version
*/
char *getstring_macarg(
STREAM *refstr,
char *cp,
char **endp)
{
if (cp[0] == '\\') {
char *str = getstring(cp + 1, endp);
return eval_str(refstr, str); /* Perform expression evaluation */
} else {
return getstring(cp, endp);
}
}
/* expandmacro - return a STREAM containing the expansion of a macro */
STREAM *expandmacro(
STREAM *refstr,
MACRO *mac,
char *cp)
{
ARG *arg,
*args,
*macarg;
char *label;
STREAM *str;
BUFFER *buf;
int nargs;
int onemore;
args = NULL;
arg = NULL;
nargs = 0; /* for the .NARG directive */
onemore = 0;
/* Parse the arguments */
while (!EOL(*cp) || onemore) {
char *nextcp;
/* Check for named argument */
label = get_symbol(cp, &nextcp, NULL);
if (label && (nextcp = skipwhite(nextcp), *nextcp == '=') && (macarg = find_arg(mac->args, label))) {
/* Check if I've already got a value for it */
if ((arg = find_arg(args, label)) != NULL) {
/* Duplicate is legal; the last one wins. */
if (arg->value) {
free (arg->value);
arg->value = NULL;
}
}
else {
arg = new_arg();
arg->label = label;
arg->next = args;
args = arg;
}
nextcp = skipwhite(nextcp + 1);
arg->value = getstring_macarg(refstr, nextcp, &nextcp);
} else {
if (label)
free(label);
/* Find correct positional argument */
for (macarg = mac->args; macarg != NULL; macarg = macarg->next) {
if (find_arg(args, macarg->label) == NULL)
break; /* This is the next positional arg */
}
if (macarg == NULL)
break; /* Don't pick up any more arguments. */
nextcp = skipwhite (cp);
arg = new_arg();
arg->label = memcheck(strdup(macarg->label)); /* Copy the name */
arg->next = args;
args = arg;
if (*nextcp != ',') {
arg->value = getstring_macarg(refstr, cp, &nextcp);
}
else {
arg->value = NULL;
}
nargs++; /* Count nonkeyword arguments only. */
}
/* If there is a trailing comma, there is an empty last argument */
cp = skipdelim_comma(nextcp, &onemore);
}
/* Now go back and fill in defaults */ {
int locsym;
if (last_macro_lsb != lsb)
locsym = last_locsym = 32768;
else
locsym = last_locsym;
last_macro_lsb = lsb;
for (macarg = mac->args; macarg != NULL; macarg = macarg->next) {
arg = find_arg(args, macarg->label);
if (arg == NULL || arg->value == NULL) {
int wasnull = 0;
if (arg == NULL) {
wasnull = 1;
arg = new_arg();
arg->label = memcheck(strdup(macarg->label));
}
if (macarg->locsym) {
char temp[32];
/* Here's where we generate local labels */
sprintf(temp, "%d$", locsym++);
arg->value = memcheck(strdup(temp));
} else if (macarg->value) {
arg->value = memcheck(strdup(macarg->value));
} else
arg->value = memcheck(strdup(""));
if (wasnull) {
arg->next = args;
args = arg;
}
}
}
last_locsym = locsym;
}
buf = subst_args(mac->text, args);
str = new_macro_stream(refstr, buf, mac, nargs);
free_args(args);
buffer_free(buf);
return str;
}
/* dump_all_macros is a diagnostic function that's currently not
used. I used it while debugging, and I haven't removed it. */
void dump_all_macros(
void)
{
MACRO *mac;
SYMBOL_ITER iter;
for (mac = (MACRO *) first_sym(&macro_st, &iter); mac != NULL; mac = (MACRO *) next_sym(&macro_st, &iter)) {
dumpmacro(mac, lstfile);
fprintf(lstfile, "\n\n");
}
}
/* Allocate a new macro */
MACRO *new_macro(
char *label)
{
MACRO *mac = memcheck(malloc(sizeof(MACRO)));
mac->sym.flags = SYMBOLFLAG_DEFINITION;
mac->sym.label = label;
mac->sym.stmtno = stmtno;
mac->sym.next = NULL;
mac->sym.section = &macro_section;
mac->sym.value = 0;
mac->args = NULL;
mac->text = NULL;
return mac;
}
/* free a macro, its args, its text, etc. */
void free_macro(
MACRO *mac)
{
if (mac->text) {
free(mac->text);
}
free_args(mac->args);
free_sym(&mac->sym);
}
int do_mcall (char *label, STACK *stack)
{
SYMBOL *op; /* The operation SYMBOL */
STREAM *macstr;
BUFFER *macbuf;
char *maccp;
int saveline;
MACRO *mac;
int i;
char macfile[FILENAME_MAX];
char hitfile[FILENAME_MAX];
/* Find the macro in the list of included
macro libraries */
macbuf = NULL;
for (i = 0; i < nr_mlbs; i++)
if ((macbuf = mlb_entry(mlbs[i], label)) != NULL)
break;
if (macbuf != NULL) {
macstr = new_buffer_stream(macbuf, label);
buffer_free(macbuf);
} else {
char *bufend = &macfile[sizeof(macfile)],
*end;
end = stpncpy(macfile, label, sizeof(macfile) - 5);
if (end >= bufend - 5) {
report(stack->top, ".MCALL: name too long: '%s'\n", label);
return 0;
}
stpncpy(end, ".MAC", bufend - end);
my_searchenv(macfile, "MCALL", hitfile, sizeof(hitfile));
if (hitfile[0])
macstr = new_file_stream(hitfile);
else
macstr = NULL;
}
if (macstr != NULL) {
for (;;) {
char *mlabel;
maccp = macstr->vtbl->getline(macstr);
if (maccp == NULL)
break;
mlabel = get_symbol(maccp, &maccp, NULL);
if (mlabel == NULL)
continue;
op = lookup_sym(mlabel, &system_st);
free(mlabel);
if (op == NULL)
continue;
if (op->value == P_MACRO)
break;
}
if (maccp != NULL) {
STACK macstack = {
macstr
};
int savelist = list_level;
saveline = stmtno;
list_level = -1;
mac = defmacro(maccp, &macstack, CALLED_NOLIST);
if (mac == NULL) {
report(stack->top, "Failed to define macro called %s\n", label);
}
stmtno = saveline;
list_level = savelist;
}
macstr->vtbl->delete(macstr);
return 1;
}
return 0;
}

View File

@@ -0,0 +1,79 @@
#ifndef MACROS__H
#define MACROS__H
/* Arguments given to macros or .IRP/.IRPC blocks */
#include "symbols.h"
#include "stream2.h"
typedef struct arg {
struct arg *next; /* Pointer in arg list */
int locsym; /* Whether arg represents an optional
local symbol */
char *label; /* Argument name */
char *value; /* Default or active substitution */
} ARG;
/* A MACRO is a superstructure surrounding a SYMBOL. */
typedef struct macro {
SYMBOL sym; /* Surrounds a symbol, contains the macro
name */
ARG *args; /* The argument list */
BUFFER *text; /* The macro text */
} MACRO;
typedef struct macro_stream {
BUFFER_STREAM bstr; /* Base class: buffer stream */
int nargs; /* Add number-of-macro-arguments */
int cond; /* Add saved conditional stack */
} MACRO_STREAM;
#ifndef MACROS__C
extern STREAM_VTBL macro_stream_vtbl;
#endif
MACRO *new_macro(
char *label);
void free_macro(
MACRO *mac);
MACRO *defmacro(
char *cp,
STACK *stack,
int called);
#define CALLED_NORMAL 0
#define CALLED_NOLIST 1
#define CALLED_NODEFINE 2
STREAM *expandmacro(
STREAM *refstr,
MACRO *mac,
char *cp);
ARG *new_arg(
void);
void read_body(
STACK *stack,
BUFFER *gb,
char *name,
int called);
char *getstring_macarg(
STREAM *refstr,
char *cp,
char **endp);
BUFFER *subst_args(
BUFFER *text,
ARG *args);
int do_mcall (
char *label,
STACK *stack);
#endif

View File

@@ -0,0 +1,21 @@
#!/bin/sh
desc=$(git describe --tags)
if [ "$desc" = "" ]
then
echo "#undef GIT_VERSION" > new-git-info.h
else
auth=$(git log -n 1 "--pretty=format:%an <%ae> %aD")
echo "#define GIT_VERSION "'"'"$desc"'"' >new-git-info.h
echo "#define GIT_AUTHOR_DATE "'"'"$auth"'"' >>new-git-info.h
fi
# move-if-different
if diff new-git-info.h git-info.h >/dev/null 2>&1
then
rm new-git-info.h
else
mv new-git-info.h git-info.h
fi

View File

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

View File

@@ -0,0 +1,582 @@
/*
* Routines for reading from an RSX-11 M+ macro library (like RSXMAC.SML)
*/
/*
Copyright (c) 2001, Richard Krehbiel
Copyright (c) 2015, 2017, Olaf Seibert
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.
*/
/*
* OLB: Object LiBrary
* MLB, SML: MacroLiBrary, System MacroLibrary.
*/
/*
* The MLB file format is (mostly) documented in chapter 10 of
* 3a/AA-JS15A-TC_RSX-11M-PLUS_4.0_Utilities_Manual_Aug87.pdf .
*
* Figure 10-3 (page 10-6):
*
* Library file header
*
* Byte offset (octal!)
* +1 +0
* +------------------------------+------------------------------+
* |Nonzero ID (2) | Library type 0=OLB 1=MLB | 0
* +------------------------------+------------------------------+
* | LBR (Librarian) version | 2
* +------------- -------------+
* | IDENT format | 4
* +------------------------------+------------------------------+
* | Year | 6
* +------------- -------------+
* | Date and Month | 10
* +------------- -------------+
* | Time of Last Day | 12
* +------------- -------------+
* | Insert Hour | 14
* +------------- -------------+
* | Minute | 16
* +------------- -------------+
* | Second | 20
* +------------------------------+------------------------------+
* | Reserved | Size EPT entries | 22
* +------------------------------+------------------------------+
* | EPT starting relative block (Entry Point Table) | 24
* +------------------------------+------------------------------+
* | Nr of EPT entries allocated | 26
* +------------------------------+------------------------------+
* | Nr of EPT entries available | 30
* +------------------------------+------------------------------+
* | Reserved | Size MNT entries | 32
* +------------------------------+------------------------------+
* | MNT starting relative block (Module Name Table) | 34
* +------------------------------+------------------------------+
* | Nr of MNT entries allocated | 36
* +------------------------------+------------------------------+
* | Nr of MNT entries available | 40
* +------------------------------+------------------------------+
* | Logically Deleted | 42
* +------------- -------------+
* | Available (bytes) | 44
* +------------------------------+------------------------------+
* | Contiguous Space | 46
* +------------- -------------+
* | Available (bytes) | 50
* +------------------------------+------------------------------+
* | Next Insert Relative Block | 52
* +------------- -------------+
* | Start Byte Within Block | 54
* +------------------------------+------------------------------+
* | Default Insert Type for Universal Libraries (not for MLB) | 56
* +------------------------------+------------------------------+
*
* Figure 10-5 (page 10-7):
*
* Format of Module Name Table (MNT) element:
* Byte
* +------------------------------+------------------------------+
* | Module Name | 0
* +------------- -------------+
* | RAD50 | 2
* +------------------------------+------------------------------+
* | Address of module Relative Block | 4
* +------------- -------------+
* | header Byte in Block | 6
* +------------------------------+------------------------------+
*
* Figure 10-6 (page 10-8):
*
* Module header format for
* Object And Macro Libraries
* Byte
* 1=deleted module
* +------------------------------+------------------------------+
* | Attributes | Status 0=normal module | 0
* +------------------------------+------------------------------+
* ....
*
* The above layout is from the book but this seems to match my files:
* +------------------------------+------------------------------+
* | Attributes | 0
* +------------------------------+------------------------------+
* | Status 0=normal module 1=deleted module | 2
* +------------------------------+------------------------------+
* | Size Of Module high word | 4
* +------------- -------------+
* | (bytes) low word | 6
* +------------------------------+------------------------------+
* | Date Year | 10
* +------------- -------------+
* | Module Month | 12
* +------------- -------------+
* | Inserted Day | 14
* +------------------------------+------------------------------+
* | Type dependent Information | 16
* +------------- -------------+
* | (undefined for MLB) | 20
* +------------------------------+------------------------------+
*/
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "rad50.h"
#include "stream2.h"
#include "mlb.h"
#include "util.h"
#define MLBDEBUG_OPEN 0
#define MLBDEBUG_ENTRY 0
static MLB *mlb_rsx_open(
char *name,
int allow_object_library);
static BUFFER *mlb_rsx_entry(
MLB *mlb,
char *name);
static void mlb_rsx_close(
MLB *mlb);
static void mlb_rsx_extract(
MLB *mlb);
struct mlb_vtbl mlb_rsx_vtbl = {
.mlb_open = mlb_rsx_open,
.mlb_entry = mlb_rsx_entry,
.mlb_extract = mlb_rsx_extract,
.mlb_close = mlb_rsx_close,
.mlb_is_rt11 = 0,
};
#define BLOCKSIZE 512
#define WORD(cp) ((*(cp) & 0xff) + ((*((cp)+1) & 0xff) << 8))
/* BYTEPOS calculates the byte position within the macro libray file. */
#define BYTEPOS(rec) (((WORD((rec)+4) & 32767) - 1) * BLOCKSIZE + \
(WORD((rec)+6) & 511))
/* 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_rsx_open(
char *name,
int allow_objlib)
{
MLB *mlb = memcheck(malloc(sizeof(MLB)));
char *buff = NULL;
unsigned entsize;
unsigned nr_entries;
unsigned start_block;
int i;
mlb->vtbl = &mlb_rsx_vtbl;
mlb->directory = NULL;
#if MLBDEBUG_OPEN
fprintf(stderr, "mlb_rsx_open('%s', %d)\n", name, allow_objlib);
#endif
mlb->fp = fopen(name, "rb");
if (mlb->fp == NULL) {
mlb_rsx_close(mlb);
return NULL;
}
buff = memcheck(malloc(060)); /* Size of MLB library header */
if (fread(buff, 1, 060, mlb->fp) < 060) {
fprintf(stderr, "mlb_rsx_open error: can't read full header\n");
goto error;
}
mlb->is_objlib = 0;
if (allow_objlib && WORD(buff) == 01000) { /* Is it an object library? */
mlb->is_objlib = 1;
} else if (WORD(buff) != 01001) { /* Is this really a macro library? */
/* fprintf(stderr, "mlb_rsx_open error: first word not correct value\n"); */
goto error;
}
entsize = buff[032]; /* The size of each macro directory
entry */
nr_entries = WORD(buff + 036); /* The number of directory entries */
start_block = WORD(buff + 034) - 1;/* The start RT-11 block of the
directory */
if (entsize < 8) { /* Is this really a macro library? */
fprintf(stderr, "mlb_rsx_open error: entsize too small: %d\n", entsize);
goto error;
}
if (start_block < 1) { /* Is this really a macro library? */
fprintf(stderr, "mlb_rsx_open error: start_block too small: %d\n", start_block);
goto error;
}
#if MLBDEBUG_OPEN
fprintf(stderr, "entsize=%d, nr_entries=%d, start_block=%d\n",
entsize, nr_entries, start_block);
#endif
free(buff); /* Done with that header. */
/* Allocate a buffer for the disk directory */
buff = memcheck(malloc(nr_entries * entsize));
/* Go to the directory */
if (fseek(mlb->fp, start_block * BLOCKSIZE, SEEK_SET) == -1) {
fprintf(stderr, "mlb_rsx_open error: seek error: %d\n", start_block * BLOCKSIZE);
goto error;
}
/* Read the disk directory */
if (fread(buff, entsize, nr_entries, mlb->fp) < nr_entries) {
fprintf(stderr, "mlb_rsx_open error: fread: not enough entries\n");
goto error;
}
/* Shift occupied directory entries to the front of the array */
{
int j;
for (i = 0, j = nr_entries; i < j; i++) {
char *ent1,
*ent2;
int w1, w2;
ent1 = buff + (i * entsize);
/* Unused entries have 0177777 0177777 for the RAD50 name,
which is not legal RAD50. */
w1 = WORD(ent1);
w2 = WORD(ent1 + 2);
if (w1 == 0177777 && w2 == 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 */
} else {
#if MLBDEBUG_OPEN
fprintf(stderr, "entry %d: %02x%02x.%02x%02x\n",
i, ent1[5] & 0xFF, ent1[4] & 0xFF, ent1[7] & 0xFF, ent1[6] & 0xFF);
#endif
/*
* 00 00 rad50-decodes to spaces, which are not a
* valid name for a macro or object file.
*/
if (w1 == 0000000 && w2 == 0000000) {
fprintf(stderr, "mlb_rsx_open error: bad file, null name\n");
goto error;
}
}
}
/* Now i contains the actual number of entries. */
mlb->nentries = i;
#if MLBDEBUG_OPEN
fprintf(stderr, "mlb->nentries=%d\n", mlb->nentries);
#endif
if (mlb->nentries == 0) {
fprintf(stderr, "mlb_rsx_open error: no entries\n");
goto error;
}
/* 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;
#if MLBDEBUG_OPEN
fprintf(stderr, "entry %d: \"%s\" %02x%02x.%02x%02x\n",
j, radname,
ent[5] & 0xFF, ent[4] & 0xFF, ent[7] & 0xFF, ent[6] & 0xFF);
#endif
trim(radname);
if (radname[0] == '\0' || strchr(radname, ' ')) {
fprintf(stderr, "mlb_rsx_open error: entry with space in name\n");
goto error;
}
mlb->directory[j].label = memcheck(strdup(radname));
mlb->directory[j].position = BYTEPOS(ent);
#if MLBDEBUG_OPEN
fprintf(stderr, "entry %d: \"%s\" bytepos=%ld\n", j, mlb->directory[j].label, mlb->directory[j].position);
#endif
mlb->directory[j].length = -1;
if (mlb->directory[j].position < BLOCKSIZE) {
fprintf(stderr, "mlb_rsx_open error: bad entry: position\n");
goto error;
}
}
free(buff);
}
/* Done. Return the struct that represents the opened MLB. */
return mlb;
error:
#if MLBDEBUG_OPEN
fprintf(stderr, "(mlb_rsx_open closing '%s' due to errors)\n", name);
#endif
mlb_rsx_close(mlb); /* Sorry, bad file. */
free(buff);
return NULL;
}
/* mlb_rsx_close discards MLB and closes the file. */
void mlb_rsx_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_rsx_entry returns a BUFFER containing the specified entry from the
macro library, or NULL if not found. */
BUFFER *mlb_rsx_entry(
MLB *mlb,
char *name)
{
int i;
MLBENT *ent = NULL;
BUFFER *buf;
char *bp;
int c;
unsigned char module_header[022];
for (i = 0; i < mlb->nentries; i++) {
ent = &mlb->directory[i];
if (strcmp(mlb->directory[i].label, name) == 0)
break;
}
if (i >= mlb->nentries) {
#if MLBDEBUG_ENTRY
fprintf(stderr, "mlb_rsx_entry: %s not found\n", name);
#endif
return NULL;
}
fseek(mlb->fp, ent->position, SEEK_SET);
#if MLBDEBUG_ENTRY
fprintf(stderr, "mlb_rsx_entry: %s at position %ld\n", name, (long)ent->position);
#endif
#define MODULE_HEADER_SIZE 022
if (fread(module_header, MODULE_HEADER_SIZE, 1, mlb->fp) < 1) {
#if MLBDEBUG_ENTRY
fprintf(stderr, "mlb_rsx_entry: %s at position %lx can't read 022 bytes\n", name, (long)ent->position);
#endif
return NULL;
}
#if MLBDEBUG_ENTRY
for (i = 0; i < MODULE_HEADER_SIZE; i++) {
fprintf(stderr, "%02x ", module_header[i]);
}
fprintf(stderr, "\n");
#endif
ent->length = (WORD(module_header + 04) << 16) +
WORD(module_header + 06);
ent->length -= MODULE_HEADER_SIZE; /* length is including this header */
#if MLBDEBUG_ENTRY
fprintf(stderr, "mlb_rsx_entry: %s at position %lx length = %d\n", name, (long)ent->position, ent->length);
#endif
if (module_header[02] == 1) {
fprintf(stderr, "mlb_rsx_entry: %s at position %lx deleted entry\n", name, (long)ent->position);
/* Deleted Entry */
return NULL;
}
/*
* Allocate a buffer to hold the text.
* The text is always shorter than the on-disk size.
*/
buf = new_buffer();
buffer_resize(buf, ent->length); /* Make it large enough */
bp = buf->buffer;
/*
* Check the file format: variable length records,
* or stream of bytes.
* Not sure if this check is the correct one; I've only
* seen MLB and OLB files with var length records.
*/
if (mlb->is_objlib) {
/* In object libraries, copy the internal structure, since we
* can consider them to be binary.
*/
i = fread(bp, 1, ent->length, mlb->fp);
bp += i;
} else if (module_header[0] & 0x10) {
#if MLBDEBUG_ENTRY
fprintf(stderr, "mlb_rsx_entry: %s at position %lx variable length records\n", name, (long)ent->position);
#endif
/* Variable length records with size before them */
i = ent->length;
while (i > 0) {
int length;
#if MLBDEBUG_ENTRY
fprintf(stderr, "file offset:$%lx\n", (long)ftell(mlb->fp));
#endif
c = fgetc(mlb->fp); /* Get low byte of length */
length = c & 0xFF;
c = fgetc(mlb->fp); /* Get high byte */
length += (c & 0xFF) << 8;
i -= 2;
#if MLBDEBUG_ENTRY
fprintf(stderr, "line length: %d $%x\n", length, length);
#endif
/* Odd lengths are padded with an extra 0 byte */
int padded = length & 1;
if (length > i) {
fprintf(stderr, "line length %d > remaining archive member %d\n", length, i);
length = i;
}
while (length > 0) {
c = fgetc(mlb->fp); /* Get macro byte */
#if MLBDEBUG_ENTRY
fprintf(stderr, "%02x %c length=%d\n", c, c, length);
#endif
i--;
length--;
if (c == '\r' || c == 0) /* If it's a carriage return or 0,
discard it. */
continue;
*bp++ = c;
}
*bp++ = '\n';
if (padded) {
c = fgetc(mlb->fp); /* Get pad byte; need not be 0. */
#if MLBDEBUG_ENTRY
fprintf(stderr, "pad byte %02x %c length=%d\n", c, c, length);
#endif
i--;
}
}
} else {
#if MLBDEBUG_ENTRY
fprintf(stderr, "mlb_rsx_entry: %s at position %lx byte stream records\n", name, (long)ent->position);
#endif
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;
}
}
/* Now resize that buffer to the length actually read. */
buffer_resize(buf, (int) (bp - buf->buffer));
return buf;
}
/* mlb_rsx_extract - walk thru a macro library and store its 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_rsx_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);
if (buf != NULL) {
char *suffix = mlb->is_objlib ? "OBJ" : "MAC";
sprintf(name, "%s.%s", mlb->directory[i].label, suffix);
fp = fopen(name, "w");
int length = buf->length;
fwrite(buf->buffer, 1, length, fp);
fclose(fp);
buffer_free(buf);
}
}
}

View File

@@ -0,0 +1,404 @@
/* Routines for reading from an RT-11 macro library (like SYSMAC.SML) */
/*
Copyright (c) 2001, Richard Krehbiel
Copyright (c) 2017, Olaf Seibert
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 "util.h"
#define MLBDEBUG_OPEN 0
static MLB *mlb_rt11_open(
char *name,
int allow_object_library);
static BUFFER *mlb_rt11_entry(
MLB *mlb,
char *name);
static void mlb_rt11_close(
MLB *mlb);
static void mlb_rt11_extract(
MLB *mlb);
struct mlb_vtbl mlb_rt11_vtbl = {
.mlb_open = mlb_rt11_open,
.mlb_entry = mlb_rt11_entry,
.mlb_extract = mlb_rt11_extract,
.mlb_close = mlb_rt11_close,
.mlb_is_rt11 = 1,
};
/*
* Format description:
* http://www.bitsavers.org/pdf/dec/pdp11/rt11/v5.6_Aug91/AA-PD6PA-TC_RT-11_Volume_and_File_Formats_Manual_Aug91.pdf
* pages 2-27 ff.
*
* A MLB Macro Library Header differs a lot from an Object Library Header.
*/
#define BLOCKSIZE 512
#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) * BLOCKSIZE + \
(WORD((rec)+6) & 511))
/* 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_rt11_open opens a file which is given to be a macro library. */
/* Returns NULL on failure. */
static
MLB *mlb_rt11_open(
char *name,
int allow_object_library)
{
MLB *mlb = memcheck(malloc(sizeof(MLB)));
char *buff;
unsigned entsize;
unsigned nr_entries;
unsigned start_block;
int i;
#if MLBDEBUG_OPEN
fprintf(stderr, "mlb_rt11_open('%s', %d)\n", name, allow_object_library);
#endif
(void)allow_object_library; /* This parameter is not supported */
mlb->vtbl = &mlb_rt11_vtbl;
mlb->directory = NULL;
mlb->fp = fopen(name, "rb");
if (mlb->fp == NULL) {
mlb_rt11_close(mlb);
return NULL;
}
buff = memcheck(malloc(044)); /* Size of MLB library header */
if (fread(buff, 1, 044, mlb->fp) < 044) {
goto error; /* Nope. */
}
if (WORD(buff) != 01001 ||
WORD(buff + 2) != 0500) { /* Is this really a macro library? */
goto error; /* Nope. */
}
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 */
if (entsize < 8) { /* Is this really a macro library? */
fprintf(stderr, "mlb_rt11_open error: entsize too small: %d\n", entsize);
goto error; /* Nope. */
}
if (start_block < 1) { /* Is this really a macro library? */
fprintf(stderr, "mlb_rt11_open error: start_block too small: %d\n", start_block);
goto error; /* Nope. */
}
#if MLBDEBUG_OPEN
fprintf(stderr, "entsize=%d, nr_entries=%d, start_block=%d\n",
entsize, nr_entries, start_block);
#endif
free(buff); /* Done with that header. */
/* Allocate a buffer for the disk directory */
buff = memcheck(malloc(nr_entries * entsize));
/* Go to the directory */
if (fseek(mlb->fp, start_block * BLOCKSIZE, SEEK_SET) == -1) {
fprintf(stderr, "mlb_rt11_open error: seek error: %d\n", start_block * BLOCKSIZE);
goto error;
}
/* Read the disk directory */
if (fread(buff, entsize, nr_entries, mlb->fp) < nr_entries) {
fprintf(stderr, "mlb_rt11_open error: fread: not enough entries\n");
goto error; /* Sorry, read error. */
}
/* 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;
int w1, w2;
ent1 = buff + (i * entsize);
w1 = WORD(ent1);
w2 = WORD(ent1 + 2);
/* Unused entries have 0177777 0177777 for the RAD50 name,
which is not legal RAD50. */
if (w1 == 0177777 && w2 == 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 */
} else {
if (w1 == 0000000 && w2 == 0000000) {
fprintf(stderr, "mlb_rt11_open error: bad file, null name\n");
goto error;
}
}
}
/* Now i contains the actual number of entries. */
mlb->nentries = i;
#if MLBDEBUG_OPEN
fprintf(stderr, "mlb->nentries=%d\n", mlb->nentries);
#endif
if (mlb->nentries == 0) {
fprintf(stderr, "mlb_rt11_open error: no entries\n");
goto error;
}
/* 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);
unsigned long max_filepos;
fseek(mlb->fp, 0, SEEK_END);
max_filepos = ftell(mlb->fp);
/* 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);
if (radname[0] == '\0' || strchr(radname, ' ')) {
fprintf(stderr, "mlb_rt11_open error: entry with space in name\n");
goto error;
}
mlb->directory[j].label = memcheck(strdup(radname));
mlb->directory[j].position = BYTEPOS(ent);
if (mlb->directory[j].position > max_filepos) {
fprintf(stderr, "mlb_rt11_open error: entry past EOF\n");
goto error;
}
if (j < i - 1) {
mlb->directory[j].length = BYTEPOS(ent + entsize) - BYTEPOS(ent);
} else {
unsigned long max = max_filepos;
char c;
/* 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);
}
#if MLBDEBUG_OPEN
fprintf(stderr, "entry #%d '%s' %ld length %d\n",
j,
mlb->directory[j].label,
mlb->directory[j].position,
mlb->directory[j].length);
#endif
}
free(buff);
}
/* Done. Return the struct that represents the opened MLB. */
return mlb;
error:
#if MLBDEBUG_OPEN
fprintf(stderr, "(mlb_rt11_open closing '%s' due to errors)\n", name);
#endif
mlb_rt11_close(mlb); /* Sorry, bad file. */
free(buff);
return NULL;
}
/* mlb_rt11_close discards MLB and closes the file. */
static
void mlb_rt11_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_rt11_entry returns a BUFFER containing the specified entry from the
macro library, or NULL if not found. */
static
BUFFER *mlb_rt11_entry(
MLB *mlb,
char *name)
{
int i;
MLBENT *ent = NULL;
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, (int) (bp - buf->buffer));
return buf;
}
/* mlb_rt11_extract - walk thru a macro library and store its 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.
*/
static
void mlb_rt11_extract(
MLB *mlb)
{
int i;
FILE *fp;
BUFFER *buf;
for (i = 0; i < mlb->nentries; i++) {
char name[32];
buf = mlb_entry(mlb, mlb->directory[i].label);
sprintf(name, "%s.MAC", mlb->directory[i].label);
fp = fopen(name, "w");
fwrite(buf->buffer, 1, buf->length, fp);
fclose(fp);
buffer_free(buf);
}
}

View File

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

View File

@@ -40,23 +40,43 @@ DAMAGE.
/* Routines to open and read entries from a macro library */
typedef struct mlbent
{
char *label;
unsigned long position;
int length;
typedef struct mlbent {
char *label;
unsigned long position;
int length;
} MLBENT;
typedef struct mlb
{
FILE *fp;
MLBENT *directory;
int nentries;
struct mlb_vtbl;
typedef struct mlb {
struct mlb_vtbl *vtbl;
char *name;
FILE *fp;
MLBENT *directory;
int nentries;
int is_objlib; /* is really an object library */
} 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);
typedef struct mlb_vtbl {
MLB *(*mlb_open)(char *name, int allow_object_library);
BUFFER *(*mlb_entry)(MLB *mlb, char *name);
void (*mlb_extract)(MLB *mlb);
void (*mlb_close)(MLB *mlb);
int mlb_is_rt11;
} MLB_VTBL;
extern MLB *mlb_open(
char *name,
int allow_object_library);
extern BUFFER *mlb_entry(
MLB *mlb,
char *name);
extern void mlb_close(
MLB *mlb);
extern void mlb_extract(
MLB *mlb);
extern struct mlb_vtbl mlb_rsx_vtbl;
extern struct mlb_vtbl mlb_rt11_vtbl;
#endif /* MLB_H */

View File

@@ -0,0 +1,106 @@
/*
Copyright (c) 2017, Olaf Seibert
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 <string.h>
#include "util.h"
#include "mlb.h"
#include "object.h"
MLB_VTBL *mlb_vtbls[] = {
&mlb_rsx_vtbl,
&mlb_rt11_vtbl,
NULL
};
static MLB *mlb_open_fmt(
char *name,
int allow_object_library,
int object_format)
{
MLB_VTBL *vtbl;
MLB *mlb = NULL;
int i;
for (i = 0; (vtbl = mlb_vtbls[i]); i++) {
if (vtbl->mlb_is_rt11 == object_format) {
mlb = vtbl->mlb_open(name, allow_object_library);
if (mlb != NULL) {
mlb->name = memcheck(strdup(name));
break;
}
}
}
return mlb;
}
MLB *mlb_open(
char *name,
int allow_object_library)
{
MLB *mlb = NULL;
/*
* First try the open function for the currently set object format.
* If that fails, try the other one.
*/
mlb = mlb_open_fmt(name, allow_object_library, rt11);
if (mlb == NULL) {
mlb = mlb_open_fmt(name, allow_object_library, !rt11);
}
return mlb;
}
BUFFER *mlb_entry(
MLB *mlb,
char *name)
{
return mlb->vtbl->mlb_entry(mlb, name);
}
void mlb_close(
MLB *mlb)
{
free(mlb->name);
mlb->vtbl->mlb_close(mlb);
}
void mlb_extract(
MLB *mlb)
{
mlb->vtbl->mlb_extract(mlb);
}

View File

@@ -0,0 +1,4 @@
# ignore these files:
# ignore these directories:
tests/
# the end

View File

@@ -0,0 +1,162 @@
<B>obj2bin.pl</B> is a PDP-11 object file translator / linker, transforming an .obj file as output from macro11 into an absolute binary load image file (.bin) or other useful formats (.hex).
If run with no options, it prints a usage screen:
```
obj2bin.pl v2.1 by Don North (perl 5.03)
Usage: ./obj2bin.pl [options...] arguments
--help output manpage and exit
--debug enable debug mode
--verbose verbose status reporting
--boot M9312 boot prom .hex
--console M9312 console/diagnostic prom .hex
--binary binary program load image .bin [default]
--ascii ascii m9312 program load image .txt
--rt11 read .obj files in RT11 format
--rsx11 read .obj files in RSX11 format [default]
--bytes=N bytes per block on output hex format
--nocrc inhibit output of CRC-16 in hex format
--logfile=LOGFILE logging message file
--outfile=OUTFILE output .hex/.txt/.bin file
OBJFILE... macro11 object .obj file(s)
Aborted due to command line errors.
```
If run with the --help option it prints a longer manual page:
```
NAME
obj2bin.pl - Convert a Macro-11 program image to PROM/load format
SYNOPSIS
obj2bin.pl [--help] [--debug] [--verbose] [--boot] [--console] [--binary]
[--ascii] [--rt11] [--rsx11] [--bytes=N] [--nocrc] [--logfile=LOGFILE]
--outfile=BINFILE OBJFILE
DESCRIPTION
Converts a Macro-11 object files to various output formats, including
M9312 boot and console PROM, straight binary records, ASCII format for
M9312 console load commands, and loadable absolute binary program images
(.BIN) files.
Multiple .psect/.asect ops are supported, as well as all local
(non-global) relocation directory entries.
Supports either RT-11 or RSX-11 format object files.
OPTIONS
The following options are available:
--help
Output this manpage and exit the program.
--debug
Enable debug mode; print input file records as parsed.
--verbose
Verbose status; output status messages during processing.
--boot
Generate a hex PROM file image suitable for programming into an M9312
boot prom (512x4 geometry, only low half used).
--console
Generate a hex PROM file image suitable for programming into an M9312
console/diagnostic prom (1024x4 geometry).
--ascii
Generate a a sequence of 'L addr' / 'D data' commands for downloading
a program via a terminal emulator thru the M9312 user command
interface. Suitable only for really small test programs.
--binary
Generate binary format load records of the program image (paper tape
format) for loading into SIMH or compatible simulators. These files
can also be copied onto XXDP filesystems to generate runnable program
images (used to write custom diaqnostics).
Binary format is the default if no other option is specified. If more
than one option is specified the last one takes effect.
--rt11
Read input object files in RT-11 format.
--rsx11
Read input object files in RSX-11 format.
RSX-11 object file format is the default if no other option is
specified. If more than one option is specified the last one takes
effect.
--bytes=N
For hex format output files, output N bytes per line (default 16).
--nocrc
For hex format output files, don't automatically stuff the computed
CRC-16 as the last word in the ROM.
--logfile=FILENAME
Generate debug output into this file.
--outfile=FILENAME
Output binary file in format selected by user option.
OBJFILE...
Input object file(s) in .obj format.
ERRORS
The following diagnostic error messages can be produced on STDERR. The
meaning should be fairly self explanatory.
"Aborted due to command line errors" -- bad option or missing file(s)
"Can't open input file '$file'" -- bad filename or unreadable file
"Error: Improper object file format (1)" -- valid RT-11 record must start
with 0x01
"Error: Improper object file format (2)" -- second RT-11 byte must be 0x00
"Error: Improper object file format (3)" -- third byte is low byte of
record length
"Error: Improper object file format (4)" -- fourth byte is high byte of
record length
"Error: Improper object file format (5)" -- bytes five thru end-1 are data
bytes
"Error: Improper object file format (6)" -- last RT-11 byte is checksum
"Error: Bad checksum exp=0x%02X rcv=0x%02X" -- compare rcv'ed checksum vs
exp'ed checksum
EXAMPLES
Some examples of common usage:
obj2bin.pl --help
obj2bin.pl --verbose --boot --out 23-751A9.hex 23-751A9.obj
obj2bin.pl --verbose --binary --rt11 --out memtest.bin memtest.obj
obj2bin.pl --verbose --binary --rsx11 --out prftst.bin prftst.obj mac/printf.obj
AUTHOR
Don North - donorth <ak6dn _at_ mindspring _dot_ com>
HISTORY
Modification history:
2005-05-05 v1.0 donorth - Initial version.
2016-01-15 v1.1 donorth - Added RLD(IR) processing, moved sub's to end.
2016-01-18 v1.2 donorth - Added GSD processing, improved debug output.
2016-01-20 v1.3 donorth - Initial support for linking multiple PSECTs.
2016-01-22 v1.4 donorth - Added objfile/outfile/logfile switches vs stdio.
2016-01-28 v1.5 donorth - Added RLD processing, especially complex.
2017-04-01 v1.9 donorth - Renamed from obj2hex.pl to obj2bin.pl
2017-05-04 v1.95 donorth - Updated capability to read multiple input .obj files.
2020-03-06 v2.0 donorth - Updated help documentation and README.md file.
2020-03-10 v2.1 donorth - Broke down and added RSX-11 input format option.
```

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -38,71 +38,73 @@ 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 */
#include <stdio.h>
#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 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 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 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 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 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 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 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 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 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_BYTE 0200 /* RLD modifies a byte, else a word */
#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. */
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_NOP 00 /* NOP - used for padding */
#define CPLX_ADD 01
#define CPLX_SUB 02
#define CPLX_MUL 03
@@ -112,99 +114,199 @@ DAMAGE.
#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 */
#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 */
extern int rt11; /* Use RT11 object file format */
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);
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,
unsigned *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 */
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);
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;
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);
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);
int write_endmod(
FILE *fp);
#endif /* OBJECT_J */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,74 @@
#ifndef PARSE__H
#define PARSE__H
#include "symbols.h"
#include "assemble_aux.h" /* ADDR_MODE */
// is char 'c' part of a symbol?
#define issym(c) (isalpha(c) || isdigit(c) \
|| (c) == '.' || (c) == '$' \
|| (symbol_allow_underscores && (c) == '_'))
char *skipwhite(
char *cp);
char *skipdelim(
char *cp);
char *skipdelim_comma(
char *cp,
int *comma);
SYMBOL *get_op(
char *cp,
char **endp);
int check_eol(
STACK *stack,
char *cp);
char *getstring(
char *cp,
char **endp);
char *getstring_fn(
char *cp,
char **endp);
char *get_symbol(
char *cp,
char **endp,
int *islocal);
int get_mode(
char *cp,
char **endp,
ADDR_MODE *mode,
char **error);
int get_fp_src_mode(
char *cp,
char **endp,
ADDR_MODE *mode,
char **error);
EX_TREE *parse_expr(
char *cp,
int flags);
EX_TREE *parse_unary_expr(
char *cp,
int flags);
int expr_ok(
EX_TREE *expr);
int parse_float(
char *cp,
char **endp,
int size,
unsigned *flt);
int brackrange(
char *cp,
int *start,
int *length,
char **endp);
#endif

View File

@@ -37,81 +37,124 @@ DAMAGE.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "rad50.h"
static char radtbl[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$. 0123456789";
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 rad50(
char *cp,
char **endp)
{
unsigned long acc = 0;
char *rp;
unsigned long acc = 0;
char *rp;
if(endp)
*endp = cp;
if (endp)
*endp = cp;
if(!*cp) /* Got to check for end-of-string
manually, because strchr will call
it a hit. :-/ */
return acc;
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++;
rp = strchr(radtbl, toupper((unsigned char)*cp));
if (rp == NULL) /* Not a RAD50 character */
return acc;
acc = ((int) (rp - radtbl)) * 03100; /* Convert */
cp++;
/* Now, do the same thing two more times... */
/* 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;
if (endp)
*endp = cp;
if (!*cp)
return acc;
rp = strchr(radtbl, toupper((unsigned char)*cp));
if (rp == NULL)
return acc;
acc += ((int) (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;
if (!*cp)
return acc;
rp = strchr(radtbl, toupper((unsigned char)*cp));
if (rp == NULL)
return acc;
acc += (int) (rp - radtbl);
cp++;
if(endp)
*endp = cp;
cp++;
if (endp)
*endp = cp;
return acc; /* Done. */
return acc; /* Done. */
}
/* rad50x2 - converts from 0 to 6 characters into two words of RAD50. */
void rad50x2(char *cp, unsigned *rp)
void rad50x2(
char *cp,
unsigned *rp)
{
*rp++ = rad50(cp, &cp);
*rp = 0;
if(*cp)
*rp = rad50(cp, &cp);
*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)
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] = ' ';
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] = ' ';
}
/* ascii2rad50 - convert a single character to a RAD50 character */
int ascii2rad50(
char c)
{
char *rp;
if (c == '\0') /* Not a RAD50 character */
return -1;
rp = strchr(radtbl, toupper((unsigned char)c));
if (rp == NULL) /* Not a RAD50 character */
return -1;
return (int) (rp - radtbl); /* Convert */
}
/* packrad50word - packs up to 3 characters into a RAD50 word.
*
* The characters should be in the range [0, 050),
* such as having been converted by ascii2rad50().
*/
unsigned packrad50word(
char *cp,
int len)
{
unsigned long acc = 0;
if (len >= 1) {
acc += (cp[0] % 050) * 050 * 050;
}
if (len >= 2) {
acc += (cp[1] % 050) * 050;
}
if (len >= 3) {
acc += cp[2] % 050;
}
return acc;
}

View File

@@ -34,10 +34,23 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
extern unsigned rad50(char *cp, char **endp);
extern unsigned rad50(
char *cp,
char **endp);
extern void rad50x2(char *cp, unsigned *rp);
extern void rad50x2(
char *cp,
unsigned *rp);
extern void unrad50(unsigned word, char *cp);
extern void unrad50(
unsigned word,
char *cp);
int ascii2rad50(
char c);
unsigned packrad50word(
char *cp,
int len);
#endif /* RAD50_H */

View File

@@ -0,0 +1,406 @@
#define REPT_IRPC__C
/*
.REPT
.IRPC streams
*/
#include <stdlib.h>
#include <string.h>
#include "rept_irpc.h" /* my own definitions */
#include "util.h"
#include "assemble_aux.h"
#include "parse.h"
#include "listing.h"
#include "macros.h"
#include "assemble_globals.h"
/* *** implement REPT_STREAM */
typedef struct rept_stream {
BUFFER_STREAM bstr;
int count; /* The current repeat countdown */
int savecond; /* conditional stack level at time of
expansion */
} REPT_STREAM;
/* rept_stream_getline gets a line from a repeat stream. At the end of
each count, the coutdown is decreated and the stream is reset to
its beginning. */
char *rept_stream_getline(
STREAM *str)
{
REPT_STREAM *rstr = (REPT_STREAM *) str;
char *cp;
for (;;) {
if (rstr->count <= 0)
return NULL;
if ((cp = buffer_stream_getline(str)) != NULL)
return cp;
buffer_stream_rewind(str);
rstr->count--;
}
}
/* rept_stream_delete unwinds nested conditionals like .MEXIT does. */
void rept_stream_delete(
STREAM *str)
{
REPT_STREAM *rstr = (REPT_STREAM *) str;
pop_cond(rstr->savecond); /* complete unterminated
conditionals */
buffer_stream_delete(&rstr->bstr.stream);
}
/* The VTBL */
STREAM_VTBL rept_stream_vtbl = {
rept_stream_delete, rept_stream_getline, buffer_stream_rewind
};
/* expand_rept is called when a .REPT is encountered in the input. */
STREAM *expand_rept(
STACK *stack,
char *cp)
{
EX_TREE *value;
BUFFER *gb;
REPT_STREAM *rstr;
int levelmod;
value = parse_expr(cp, 0);
if (value->type != EX_LIT) {
report(stack->top, ".REPT value must be constant\n");
free_tree(value);
return NULL;
}
/*
* Reading the next lines-to-be-repeated overwrites the line buffer
* that the caller is using. So for junk-at-end-of-line checking we
* need to do it here.
*/
check_eol(stack, value->cp);
list_value(stack->top, value->data.lit);
gb = new_buffer();
levelmod = 0;
if (!list_md) {
list_level--;
levelmod = 1;
}
read_body(stack, gb, NULL, FALSE);
list_level += levelmod;
rstr = memcheck(malloc(sizeof(REPT_STREAM))); {
char *name = memcheck(malloc(strlen(stack->top->name) + 32));
sprintf(name, "%s:%d->.REPT", stack->top->name, stack->top->line);
buffer_stream_construct(&rstr->bstr, gb, name);
free(name);
}
rstr->count = value->data.lit;
rstr->bstr.stream.vtbl = &rept_stream_vtbl;
rstr->savecond = last_cond;
buffer_free(gb);
free_tree(value);
return &rstr->bstr.stream;
}
/* *** implement IRP_STREAM */
typedef struct irp_stream {
BUFFER_STREAM bstr;
char *label; /* The substitution label */
char *items; /* The substitution items (in source code
format) */
int offset; /* Current offset into "items" */
BUFFER *body; /* Original body */
int savecond; /* Saved conditional level */
} IRP_STREAM;
/* irp_stream_getline expands the IRP as the stream is read. */
/* Each time an iteration is exhausted, the next iteration is
generated. */
char *irp_stream_getline(
STREAM *str)
{
IRP_STREAM *istr = (IRP_STREAM *) str;
char *cp;
BUFFER *buf;
ARG *arg;
for (;;) {
if ((cp = buffer_stream_getline(str)) != NULL)
return cp;
cp = istr->items + istr->offset;
if (!*cp)
return NULL; /* No more items. EOF. */
arg = new_arg();
arg->next = NULL;
arg->locsym = 0;
arg->label = istr->label;
arg->value = getstring_macarg(str, cp, &cp);
cp = skipdelim(cp);
istr->offset = (int) (cp - istr->items);
buf = subst_args(istr->body, arg);
free(arg->value);
free(arg);
buffer_stream_set_buffer(&istr->bstr, buf);
buffer_free(buf);
}
}
/* irp_stream_delete - also pops the conditional stack */
void irp_stream_delete(
STREAM *str)
{
IRP_STREAM *istr = (IRP_STREAM *) str;
pop_cond(istr->savecond); /* complete unterminated
conditionals */
buffer_free(istr->body);
free(istr->items);
free(istr->label);
buffer_stream_delete(str);
}
STREAM_VTBL irp_stream_vtbl = {
irp_stream_delete, irp_stream_getline, buffer_stream_rewind
};
/* We occasionally see .IRP with the formal name in angle brackets. I
* have no idea why, but it appears to be legal. So allow that. Not
* sure if it should be allowed elsewhere, e.g., in .MACRO. For now,
* don't. */
static char *get_irp_sym (char *cp, char **endcp, int *islocal)
{
char *ret = NULL;
cp = skipwhite(cp);
if (*cp == '<') {
ret = get_symbol (cp + 1, &cp, islocal);
if (*cp++ != '>') {
*endcp = cp;
return NULL;
}
}
else {
ret = get_symbol (cp, &cp, islocal);
}
*endcp = cp;
return ret;
}
/* expand_irp is called when a .IRP is encountered in the input. */
STREAM *expand_irp(
STACK *stack,
char *cp)
{
char *label,
*items;
BUFFER *gb;
int levelmod = 0;
IRP_STREAM *str;
label = get_irp_sym(cp, &cp, NULL);
if (!label) {
report(stack->top, "Illegal .IRP syntax\n");
return NULL;
}
cp = skipdelim(cp);
items = getstring(cp, &cp);
if (!items) {
report(stack->top, "Illegal .IRP syntax\n");
free(label);
return NULL;
}
check_eol(stack, cp);
gb = new_buffer();
levelmod = 0;
if (!list_md) {
list_level--;
levelmod++;
}
read_body(stack, gb, NULL, FALSE);
list_level += levelmod;
str = memcheck(malloc(sizeof(IRP_STREAM))); {
char *name = memcheck(malloc(strlen(stack->top->name) + 32));
sprintf(name, "%s:%d->.IRP", stack->top->name, stack->top->line);
buffer_stream_construct(&str->bstr, NULL, name);
free(name);
}
str->bstr.stream.vtbl = &irp_stream_vtbl;
str->body = gb;
str->items = items;
str->offset = 0;
str->label = label;
str->savecond = last_cond;
return &str->bstr.stream;
}
/* *** implement IRPC_STREAM */
typedef struct irpc_stream {
BUFFER_STREAM bstr;
char *label; /* The substitution label */
char *items; /* The substitution items (in source code
format) */
int offset; /* Current offset in "items" */
BUFFER *body; /* Original body */
int savecond; /* conditional stack at invocation */
} IRPC_STREAM;
/* irpc_stream_getline - same comments apply as with irp_stream_getline, but
the substitution is character-by-character */
char *irpc_stream_getline(
STREAM *str)
{
IRPC_STREAM *istr = (IRPC_STREAM *) str;
char *cp;
BUFFER *buf;
ARG *arg;
for (;;) {
if ((cp = buffer_stream_getline(str)) != NULL)
return cp;
cp = istr->items + istr->offset;
if (!*cp)
return NULL; /* No more items. EOF. */
arg = new_arg();
arg->next = NULL;
arg->locsym = 0;
arg->label = istr->label;
arg->value = memcheck(malloc(2));
arg->value[0] = *cp++;
arg->value[1] = 0;
istr->offset = (int) (cp - istr->items);
buf = subst_args(istr->body, arg);
free(arg->value);
free(arg);
buffer_stream_set_buffer(&istr->bstr, buf);
buffer_free(buf);
}
}
/* irpc_stream_delete - also pops contidionals */
void irpc_stream_delete(
STREAM *str)
{
IRPC_STREAM *istr = (IRPC_STREAM *) str;
pop_cond(istr->savecond); /* complete unterminated
conditionals */
buffer_free(istr->body);
free(istr->items);
free(istr->label);
buffer_stream_delete(str);
}
STREAM_VTBL irpc_stream_vtbl = {
irpc_stream_delete, irpc_stream_getline, buffer_stream_rewind
};
/* expand_irpc - called when .IRPC is encountered in the input */
STREAM *expand_irpc(
STACK *stack,
char *cp)
{
char *label,
*items;
BUFFER *gb;
int levelmod = 0;
IRPC_STREAM *str;
label = get_irp_sym(cp, &cp, NULL);
if (!label) {
report(stack->top, "Illegal .IRPC syntax\n");
return NULL;
}
cp = skipdelim(cp);
items = getstring(cp, &cp);
if (!items) {
report(stack->top, "Illegal .IRPC syntax\n");
free(label);
return NULL;
}
check_eol(stack, cp);
gb = new_buffer();
levelmod = 0;
if (!list_md) {
list_level--;
levelmod++;
}
read_body(stack, gb, NULL, FALSE);
list_level += levelmod;
str = memcheck(malloc(sizeof(IRPC_STREAM))); {
char *name = memcheck(malloc(strlen(stack->top->name) + 32));
sprintf(name, "%s:%d->.IRPC", stack->top->name, stack->top->line);
buffer_stream_construct(&str->bstr, NULL, name);
free(name);
}
str->bstr.stream.vtbl = &irpc_stream_vtbl;
str->body = gb;
str->items = items;
str->offset = 0;
str->label = label;
str->savecond = last_cond;
return &str->bstr.stream;
}

View File

@@ -0,0 +1,26 @@
#ifndef REPT_IRPC__H
#define REPT_IRPC__H
#include "stream2.h"
#ifndef REPT_IRPC__C
extern STREAM_VTBL rept_stream_vtbl;
extern STREAM_VTBL irp_stream_vtbl;
extern STREAM_VTBL irpc_stream_vtbl;
#endif
STREAM *expand_rept(
STACK *stack,
char *cp);
STREAM *expand_irp(
STACK *stack,
char *cp);
STREAM *expand_irpc(
STACK *stack,
char *cp);
#endif

View File

@@ -42,7 +42,7 @@ DAMAGE.
#include <ctype.h>
#include <stdarg.h>
#include "macro11.h"
#include "util.h"
#include "stream2.h"
@@ -50,331 +50,364 @@ DAMAGE.
/* new_buffer allocates a new buffer */
BUFFER *new_buffer(void)
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 *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)
void buffer_resize(
BUFFER *buff,
int size)
{
buff->size = size;
buff->length = 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));
}
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)
BUFFER *buffer_clone(
BUFFER *from)
{
if(from)
from->use++;
return 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)
void buffer_free(
BUFFER *buf)
{
if(buf)
{
if(--(buf->use) == 0)
{
free(buf->buffer);
free(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)
void buffer_appendn(
BUFFER *buf,
char *str,
int len)
{
int needed = buf->length + len + 1;
int needed = buf->length + len + 1;
if(needed >= buf->size)
{
buf->size = needed + GROWBUF_INCR;
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));
}
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;
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)
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));
char *nl;
if ((nl = strchr(str, '\n')) != NULL)
buffer_appendn(buf, str, (int) (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)
void stream_construct(
STREAM *str,
char *name)
{
str->line = 0;
str->name = memcheck(strdup(name));
str->next = NULL;
str->vtbl = NULL;
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)
void stream_delete(
STREAM *str)
{
free(str->name);
free(str);
free(str->name);
free(str);
}
/* *** class BUFFER_STREAM implementation */
/* STREAM::gets for a buffer stream */
/* STREAM::getline for a buffer stream */
char *buffer_stream_gets(STREAM *str)
char *buffer_stream_getline(
STREAM *str)
{
char *nl;
char *cp;
BUFFER_STREAM *bstr = (BUFFER_STREAM *)str;
BUFFER *buf = bstr->buffer;
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;
if (buf == NULL)
return NULL; /* No buffer */
cp = buf->buffer + bstr->offset;
if (bstr->offset >= buf->length)
return NULL;
/* Find the next line in preparation for the next call */
cp = buf->buffer + bstr->offset;
nl = memchr(cp, '\n', buf->length - bstr->offset);
/* Find the next line in preparation for the next call */
if(nl)
nl++;
nl = memchr(cp, '\n', buf->length - bstr->offset);
bstr->offset = nl - buf->buffer;
str->line++;
if (nl)
nl++;
return cp;
bstr->offset = (int) (nl - buf->buffer);
str->line++;
return cp;
}
/* STREAM::close for a buffer stream */
void buffer_stream_delete(STREAM *str)
void buffer_stream_delete(
STREAM *str)
{
BUFFER_STREAM *bstr = (BUFFER_STREAM *)str;
buffer_free(bstr->buffer);
stream_delete(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)
void buffer_stream_rewind(
STREAM *str)
{
BUFFER_STREAM *bstr = (BUFFER_STREAM *)str;
bstr->offset = 0;
str->line = 0;
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 };
STREAM_VTBL buffer_stream_vtbl = {
buffer_stream_delete, buffer_stream_getline, buffer_stream_rewind
};
void buffer_stream_construct(BUFFER_STREAM *bstr, BUFFER *buf, char *name)
void buffer_stream_construct(
BUFFER_STREAM * bstr,
BUFFER *buf,
char *name)
{
bstr->stream.vtbl = &buffer_stream_vtbl;
bstr->stream.name = memcheck(strdup(name));
bstr->stream.vtbl = &buffer_stream_vtbl;
bstr->buffer = buffer_clone(buf);
bstr->offset = 0;
bstr->stream.line = 0;
bstr->stream.name = memcheck(strdup(name));
bstr->stream.line = 0;
bstr->stream.next = NULL;
bstr->buffer = buffer_clone(buf);
bstr->offset = 0;
}
void buffer_stream_set_buffer(BUFFER_STREAM *bstr, BUFFER *buf)
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;
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)
STREAM *new_buffer_stream(
BUFFER *buf,
char *name)
{
BUFFER_STREAM *bstr = memcheck(malloc(sizeof(BUFFER_STREAM)));
BUFFER_STREAM *bstr = memcheck(malloc(sizeof(BUFFER_STREAM)));
buffer_stream_construct(bstr, buf, name);
return &bstr->stream;
buffer_stream_construct(bstr, buf, name);
return &bstr->stream;
}
/* *** FILE_STREAM implementation */
/* Implement STREAM::gets for a file stream */
/* Implement STREAM::getline for a file stream */
static char *file_gets(STREAM *str)
static char *file_getline(
STREAM *str)
{
int i, c;
FILE_STREAM *fstr = (FILE_STREAM *)str;
int i,
c;
FILE_STREAM *fstr = (FILE_STREAM *) str;
if(fstr->fp == NULL)
return NULL;
if (fstr->fp == NULL)
return NULL;
if(feof(fstr->fp))
return NULL;
if (feof(fstr->fp))
return NULL;
/* Read single characters, end of line when '\n' or '\f' hit */
/* 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;
}
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;
fstr->buffer[i++] = '\n'; /* Silently transform formfeeds
into newlines */
fstr->buffer[i] = 0;
if(c == '\n')
fstr->stream.line++; /* Count a line */
if (c == '\n')
fstr->stream.line++; /* Count a line */
return fstr->buffer;
return fstr->buffer;
}
/* Implement STREAM::destroy for a file stream */
void file_destroy(STREAM *str)
void file_destroy(
STREAM *str)
{
FILE_STREAM *fstr = (FILE_STREAM *)str;
fclose(fstr->fp);
free(fstr->buffer);
stream_delete(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)
void file_rewind(
STREAM *str)
{
FILE_STREAM *fstr = (FILE_STREAM *)str;
rewind(fstr->fp);
str->line = 0;
FILE_STREAM *fstr = (FILE_STREAM *) str;
rewind(fstr->fp);
str->line = 0;
}
static STREAM_VTBL file_stream_vtbl = { file_destroy, file_gets,
file_rewind };
static STREAM_VTBL file_stream_vtbl = {
file_destroy, file_getline, file_rewind
};
/* Prepare and open a stream from a file. */
STREAM *new_file_stream(char *filename)
STREAM *new_file_stream(
char *filename)
{
FILE *fp;
FILE_STREAM *str;
FILE *fp;
FILE_STREAM *str;
fp = fopen(filename, "r");
if(fp == NULL)
return NULL;
fp = fopen(filename, "r");
if (fp == NULL)
return NULL;
str = memcheck(malloc(sizeof(FILE_STREAM)));
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;
str->stream.vtbl = &file_stream_vtbl;
str->stream.name = memcheck(strdup(filename));
str->stream.line = 0;
str->stream.next = NULL;
str->buffer = memcheck(malloc(STREAM_BUFFER_SIZE));
str->fp = fp;
return &str->stream;
return &str->stream;
}
/* STACK functions */
/* stack_init prepares a stack */
void stack_init(STACK *stack)
void stack_init(
STACK *stack)
{
stack->top = NULL; /* Too simple */
stack->top = NULL; /* Too simple */
}
/* stack_pop removes and deletes the topmost STRAM on the stack */
void stack_pop(STACK *stack)
void stack_pop(
STACK *stack)
{
STREAM *top = stack->top;
STREAM *next = top->next;
STREAM *top = stack->top;
STREAM *next = top->next;
top->vtbl->delete(top);
stack->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)
void stack_push(
STACK *stack,
STREAM *str)
{
str->next = stack->top;
stack->top = str;
str->next = stack->top;
stack->top = str;
}
/* stack_gets calls vtbl->gets for the topmost stack entry. When
/* stack_getline calls vtbl->getline 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 *stack_getline(
STACK *stack)
{
char *line;
char *line;
if(stack->top == NULL)
return NULL;
if (stack->top == NULL)
return NULL;
while((line = stack->top->vtbl->gets(stack->top)) == NULL)
{
stack_pop(stack);
if(stack->top == NULL)
return NULL;
}
while ((line = stack->top->vtbl->getline(stack->top)) == NULL) {
stack_pop(stack);
if (stack->top == NULL)
return NULL;
}
return line;
return line;
}

View File

@@ -35,76 +35,100 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
#include <stdio.h>
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
typedef struct stream_vtbl {
void (*delete)(
struct stream *stream); /* Destructor */
char *(*getline)(
struct stream *stream); /* "getline" 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
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
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
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
#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
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
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);
#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);
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);
void buffer_stream_construct(
BUFFER_STREAM * bstr,
BUFFER *buf,
char *name);
char *buffer_stream_getline(
STREAM *str);
void buffer_stream_delete(
STREAM *str);
void buffer_stream_rewind(
STREAM *str);
STREAM *new_file_stream(char *filename);
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);
void stack_init(
STACK *stack);
void stack_push(
STACK *stack,
STREAM *str);
void stack_pop(
STACK *stack);
char *stack_getline(
STACK *stack);
#endif /* STREAM2_H */

View File

@@ -0,0 +1,798 @@
#define SYMBOLS__C
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "symbols.h" /* my own definitions */
#include "util.h"
#include "assemble_globals.h"
#include "listing.h"
#include "object.h"
/* GLOBALS */
int symbol_len = SYMMAX_DEFAULT; /* max. len of symbols. default = 6 */
int symbol_allow_underscores = 0; /* allow "_" in symbol names */
SYMBOL *reg_sym[8]; /* Keep the register symbols in a handy array */
SYMBOL_TABLE system_st; /* System symbols (Instructions,
pseudo-ops, registers) */
SYMBOL_TABLE section_st; /* Program sections */
SYMBOL_TABLE symbol_st; /* User symbols */
SYMBOL_TABLE macro_st; /* Macros */
SYMBOL_TABLE implicit_st; /* The symbols which may be implicit globals */
SYMBOL_TABLE undefined_st; /* The symbols which may be undefined */
void list_section(SECTION *sec);
static void
dump_sym(SYMBOL *sym)
{
report(NULL, "'%s': %06o, stmt %d, flags %o:%s%s%s%s%s%s\n",
sym->label,
sym->value,
sym->stmtno,
sym->flags,
((sym->flags & SYMBOLFLAG_PERMANENT)? " PERMANENT" : ""),
((sym->flags & SYMBOLFLAG_GLOBAL)? " GLOBAL" : ""),
((sym->flags & SYMBOLFLAG_WEAK)? " WEAK" : ""),
((sym->flags & SYMBOLFLAG_DEFINITION)? " DEFINITION" : ""),
((sym->flags & SYMBOLFLAG_UNDEFINED)? " UNDEFINED" : ""),
((sym->flags & SYMBOLFLAG_LOCAL)? " LOCAL" : ""),
((sym->flags & SYMBOLFLAG_IMPLICIT_GLOBAL)? " IMPLICIT_GLOBAL" : ""));
}
void
check_sym_invariants(SYMBOL *sym, char *file, int line)
{
int dump = 0;
if (sym->section == &instruction_section) {
/* The instructions use the flags field differently */
if ((sym->flags & ~OC_MASK) != 0) {
report(NULL, "%s %d: Instruction symbol %s has wrong flags\n", file, line, sym->label);
dump_sym(sym);
}
return;
}
/*
* A symbol is GLOBAL if it appears in the object file's symbol table.
* It can be either exported (if defined) or imported (if not defined).
*
* A common test like this
*
* if ((sym->flags & (SYMBOLFLAG_GLOBAL | SYMBOLFLAG_DEFINITION)) == SYMBOLFLAG_GLOBAL)
*
* tests if a symbol is imported.
*/
switch (sym->flags & (SYMBOLFLAG_PERMANENT|SYMBOLFLAG_GLOBAL|SYMBOLFLAG_DEFINITION|SYMBOLFLAG_UNDEFINED)) {
/* A DEFINITION can independently be PERMANENT and/or GLOBAL */
case SYMBOLFLAG_PERMANENT|SYMBOLFLAG_GLOBAL|SYMBOLFLAG_DEFINITION:
case SYMBOLFLAG_GLOBAL|SYMBOLFLAG_DEFINITION:
case SYMBOLFLAG_PERMANENT| SYMBOLFLAG_DEFINITION:
case SYMBOLFLAG_DEFINITION:
break;
/* A GLOBAL can also be undefined, but then it's still usable */
case SYMBOLFLAG_GLOBAL:
break;
/* A truly UNDEFINED symbol is an error to use */
/* (this seems logically equivalent to all of these flags cleared) */
case SYMBOLFLAG_UNDEFINED:
break;
default:
report(NULL, "%s %d: Symbol %s definedness is inconsistent\n", file, line, sym->label);
dump++;
}
if ( (sym->flags & SYMBOLFLAG_IMPLICIT_GLOBAL) &&
!(sym->flags & SYMBOLFLAG_GLOBAL)) {
report(NULL, "%s %d: Symbol %s globalness is inconsistent\n", file, line, sym->label);
dump++;
}
if ( (sym->flags & SYMBOLFLAG_LOCAL) &&
(sym->flags & SYMBOLFLAG_GLOBAL)) {
report(NULL, "%s %d: Symbol %s is local and global\n", file, line, sym->label);
dump++;
}
if ( (sym->flags & SYMBOLFLAG_PERMANENT) &&
!(sym->flags & SYMBOLFLAG_DEFINITION)) {
report(NULL, "%s %d: Symbol %s is permanent without definition\n", file, line, sym->label);
dump++;
}
if ( (sym->flags & SYMBOLFLAG_WEAK) &&
!(sym->flags & SYMBOLFLAG_GLOBAL)) {
report(NULL, "%s %d: Symbol %s weak/global is inconsistent\n", file, line, sym->label);
dump++;
}
if (dump) {
dump_sym(sym);
}
}
/* hash_name hashes a name into a value from 0-HASH_SIZE */
int hash_name(
char *label)
{
unsigned accum = 0;
while (*label)
accum = (accum << 1) ^ *label++;
accum %= HASH_SIZE;
return accum;
}
/* Diagnostic: symflags returns a char* which gives flags I can use to
show the context of a symbol. */
char *symflags(
SYMBOL *sym)
{
static char temp[8];
char *fp = temp;
if (sym->flags & SYMBOLFLAG_GLOBAL)
*fp++ = 'G';
if (sym->flags & SYMBOLFLAG_PERMANENT)
*fp++ = 'P';
if (sym->flags & SYMBOLFLAG_DEFINITION)
*fp++ = 'D';
*fp = 0;
return fp;
}
/* Allocate a new symbol. Does not add it to any symbol table. */
static SYMBOL *new_sym(
char *label)
{
SYMBOL *sym = memcheck(malloc(sizeof(SYMBOL)));
sym->label = memcheck(strdup(label));
sym->section = NULL;
sym->value = 0;
sym->flags = 0;
return sym;
}
/* Free a symbol. Does not remove it from any symbol table. */
void free_sym(
SYMBOL *sym)
{
if (sym->label) {
check_sym_invariants(sym, __FILE__, __LINE__);
free(sym->label);
sym->label = NULL;
}
free(sym);
}
/* remove_sym removes a symbol from its symbol table. */
void remove_sym(
SYMBOL *sym,
SYMBOL_TABLE *table)
{
SYMBOL **prevp,
*symp;
int hash;
check_sym_invariants(sym, __FILE__, __LINE__);
hash = hash_name(sym->label);
prevp = &table->hash[hash];
while (symp = *prevp, symp != NULL && symp != sym)
prevp = &symp->next;
if (symp)
*prevp = sym->next;
}
/* lookup_sym finds a symbol in a table */
SYMBOL *lookup_sym(
char *label,
SYMBOL_TABLE *table)
{
unsigned hash;
SYMBOL *sym;
hash = hash_name(label);
sym = table->hash[hash];
while (sym && strcmp(sym->label, label) != 0)
sym = sym->next;
if (sym) {
check_sym_invariants(sym, __FILE__, __LINE__);
}
return sym;
}
/* next_sym - returns the next symbol from a symbol table. Must be
preceeded by first_sym. Returns NULL after the last symbol. */
SYMBOL *next_sym(
SYMBOL_TABLE *table,
SYMBOL_ITER *iter)
{
if (iter->current)
iter->current = iter->current->next;
while (iter->current == NULL) {
if (iter->subscript >= HASH_SIZE)
return NULL; /* No more symbols. */
iter->current = table->hash[iter->subscript];
iter->subscript++;
}
return iter->current; /* Got a symbol. */
}
/* first_sym - returns the first symbol from a symbol table. Symbols
are stored in random order. */
SYMBOL *first_sym(
SYMBOL_TABLE *table,
SYMBOL_ITER *iter)
{
iter->subscript = 0;
iter->current = NULL;
return next_sym(table, iter);
}
/* add_table - add a symbol to a symbol table. */
void add_table(
SYMBOL *sym,
SYMBOL_TABLE *table)
{
int hash = hash_name(sym->label);
sym->next = table->hash[hash];
table->hash[hash] = sym;
check_sym_invariants(sym, __FILE__, __LINE__);
}
/* add_sym - used throughout to add or update symbols in a symbol
table. */
SYMBOL *add_sym(
char *labelraw,
unsigned value,
unsigned flags,
SECTION *section,
SYMBOL_TABLE *table)
{
SYMBOL *sym;
char label[SYMMAX_MAX + 1]; // big size
if (isdigit((unsigned char)labelraw[0])) {
// Don't truncate local labels
strncpy(label, labelraw, SYMMAX_MAX);
label[SYMMAX_MAX] = 0;
} else {
//JH: truncate symbol to SYMMAX
strncpy(label, labelraw, symbol_len);
label[symbol_len] = 0;
}
sym = lookup_sym(label, table);
if (sym != NULL) {
// A symbol registered as "undefined" can be changed.
//
check_sym_invariants(sym, __FILE__, __LINE__);
if ((sym->flags & SYMBOLFLAG_UNDEFINED) && !(flags & SYMBOLFLAG_UNDEFINED)) {
sym->flags &= ~(SYMBOLFLAG_PERMANENT | SYMBOLFLAG_UNDEFINED);
}
else if (!(sym->flags & SYMBOLFLAG_UNDEFINED) && (flags & SYMBOLFLAG_UNDEFINED)) {
report(NULL, "INTERNAL ERROR: Turning defined symbol '%s' into undefined\n", label);
return sym;
}
/* Check for compatible definition */
else if (sym->section == section && sym->value == value) {
sym->flags |= flags; /* Merge flags quietly */
check_sym_invariants(sym, __FILE__, __LINE__);
return sym; /* 's okay */
}
if (!(sym->flags & SYMBOLFLAG_PERMANENT)) {
/* permit redefinition */
sym->value = value;
sym->flags |= flags;
sym->section = section;
check_sym_invariants(sym, __FILE__, __LINE__);
return sym;
}
return NULL; /* Bad symbol redefinition */
}
sym = new_sym(label);
sym->flags = flags;
sym->stmtno = stmtno;
sym->section = section;
sym->value = value;
add_table(sym, table);
return sym;
}
/* add_symbols adds all the internal symbols. */
void add_symbols(
SECTION *current_section)
{
current_pc = add_sym(".", 0, SYMBOLFLAG_DEFINITION, current_section, &symbol_st);
#define S (SYMBOLFLAG_PERMANENT | SYMBOLFLAG_DEFINITION)
reg_sym[0] = add_sym("R0", 0, S, &register_section, &system_st);
reg_sym[1] = add_sym("R1", 1, S, &register_section, &system_st);
reg_sym[2] = add_sym("R2", 2, S, &register_section, &system_st);
reg_sym[3] = add_sym("R3", 3, S, &register_section, &system_st);
reg_sym[4] = add_sym("R4", 4, S, &register_section, &system_st);
reg_sym[5] = add_sym("R5", 5, S, &register_section, &system_st);
reg_sym[6] = add_sym("SP", 6, S, &register_section, &system_st);
reg_sym[7] = add_sym("PC", 7, S, &register_section, &system_st);
//JH: symbols longer than current SYMMAX will be truncated. SYMMAX=6 is minimum!
add_sym(".ASCII", P_ASCII, S, &pseudo_section, &system_st);
add_sym(".ASCIZ", P_ASCIZ, S, &pseudo_section, &system_st);
add_sym(".ASECT", P_ASECT, S, &pseudo_section, &system_st);
add_sym(".BLKB", P_BLKB, S, &pseudo_section, &system_st);
add_sym(".BLKW", P_BLKW, S, &pseudo_section, &system_st);
add_sym(".BYTE", P_BYTE, S, &pseudo_section, &system_st);
add_sym(".CSECT", P_CSECT, S, &pseudo_section, &system_st);
add_sym(".CROSS", P_CROSS, S, &pseudo_section, &system_st);
add_sym(".DSABL", P_DSABL, S, &pseudo_section, &system_st);
add_sym(".ENABL", P_ENABL, S, &pseudo_section, &system_st);
add_sym(".END", P_END, S, &pseudo_section, &system_st);
add_sym(".ENDC", P_ENDC, S, &pseudo_section, &system_st);
add_sym(".ENDM", P_ENDM, S, &pseudo_section, &system_st);
add_sym(".ENDR", P_ENDR, S, &pseudo_section, &system_st);
add_sym(".EOT", P_EOT, S, &pseudo_section, &system_st);
add_sym(".ERROR", P_ERROR, S, &pseudo_section, &system_st);
add_sym(".EVEN", P_EVEN, S, &pseudo_section, &system_st);
add_sym(".FLT2", P_FLT2, S, &pseudo_section, &system_st);
add_sym(".FLT4", P_FLT4, S, &pseudo_section, &system_st);
add_sym(".GLOBL", P_GLOBL, S, &pseudo_section, &system_st);
add_sym(".IDENT", P_IDENT, S, &pseudo_section, &system_st);
add_sym(".IF", P_IF, S, &pseudo_section, &system_st);
add_sym(".IFDF", P_IFDF, S, &pseudo_section, &system_st);
add_sym(".IFNDF", P_IFDF, S, &pseudo_section, &system_st);
add_sym(".IFF", P_IFF, S, &pseudo_section, &system_st);
add_sym(".IFT", P_IFT, S, &pseudo_section, &system_st);
add_sym(".IFTF", P_IFTF, S, &pseudo_section, &system_st);
add_sym(".IIF", P_IIF, S, &pseudo_section, &system_st);
add_sym(".INCLUDE", P_INCLUDE, S, &pseudo_section, &system_st);
add_sym(".IRP", P_IRP, S, &pseudo_section, &system_st);
add_sym(".IRPC", P_IRPC, S, &pseudo_section, &system_st);
add_sym(".LIBRARY", P_LIBRARY, S, &pseudo_section, &system_st);
add_sym(".LIMIT", P_LIMIT, S, &pseudo_section, &system_st);
add_sym(".LIST", P_LIST, S, &pseudo_section, &system_st);
add_sym(".MCALL", P_MCALL, S, &pseudo_section, &system_st);
add_sym(".MDELE", P_MDELETE, S, &pseudo_section, &system_st);
add_sym(".MEXIT", P_MEXIT, S, &pseudo_section, &system_st);
add_sym(".NARG", P_NARG, S, &pseudo_section, &system_st);
add_sym(".NCHR", P_NCHR, S, &pseudo_section, &system_st);
add_sym(".NLIST", P_NLIST, S, &pseudo_section, &system_st);
add_sym(".NOCRO", P_NOCROSS, S, &pseudo_section, &system_st);
add_sym(".NTYPE", P_NTYPE, S, &pseudo_section, &system_st);
add_sym(".ODD", P_ODD, S, &pseudo_section, &system_st);
add_sym(".PACKED", P_PACKED, S, &pseudo_section, &system_st);
add_sym(".PAGE", P_PAGE, S, &pseudo_section, &system_st);
add_sym(".PRINT", P_PRINT, S, &pseudo_section, &system_st);
add_sym(".PSECT", P_PSECT, S, &pseudo_section, &system_st);
add_sym(".RADIX", P_RADIX, S, &pseudo_section, &system_st);
add_sym(".RAD50", P_RAD50, S, &pseudo_section, &system_st);
add_sym(".REM", P_REM, S, &pseudo_section, &system_st);
add_sym(".REPT", P_REPT, S, &pseudo_section, &system_st);
add_sym(".RESTORE", P_RESTORE, S, &pseudo_section, &system_st);
add_sym(".SAVE", P_SAVE, S, &pseudo_section, &system_st);
add_sym(".SBTTL", P_SBTTL, S, &pseudo_section, &system_st);
add_sym(".TITLE", P_TITLE, S, &pseudo_section, &system_st);
add_sym(".WORD", P_WORD, S, &pseudo_section, &system_st);
add_sym(".MACRO", P_MACRO, S, &pseudo_section, &system_st);
add_sym(".WEAK", P_WEAK, S, &pseudo_section, &system_st);
#undef S
add_sym("ADC", I_ADC, OC_1GEN, &instruction_section, &system_st);
add_sym("ADCB", I_ADCB, OC_1GEN, &instruction_section, &system_st);
add_sym("ADD", I_ADD, OC_2GEN, &instruction_section, &system_st);
add_sym("ASH", I_ASH, OC_ASH, &instruction_section, &system_st);
add_sym("ASHC", I_ASHC, OC_ASH, &instruction_section, &system_st);
add_sym("ASL", I_ASL, OC_1GEN, &instruction_section, &system_st);
add_sym("ASLB", I_ASLB, OC_1GEN, &instruction_section, &system_st);
add_sym("ASR", I_ASR, OC_1GEN, &instruction_section, &system_st);
add_sym("ASRB", I_ASRB, OC_1GEN, &instruction_section, &system_st);
add_sym("BCC", I_BCC, OC_BR, &instruction_section, &system_st);
add_sym("BCS", I_BCS, OC_BR, &instruction_section, &system_st);
add_sym("BEQ", I_BEQ, OC_BR, &instruction_section, &system_st);
add_sym("BGE", I_BGE, OC_BR, &instruction_section, &system_st);
add_sym("BGT", I_BGT, OC_BR, &instruction_section, &system_st);
add_sym("BHI", I_BHI, OC_BR, &instruction_section, &system_st);
add_sym("BHIS", I_BHIS, OC_BR, &instruction_section, &system_st);
add_sym("BIC", I_BIC, OC_2GEN, &instruction_section, &system_st);
add_sym("BICB", I_BICB, OC_2GEN, &instruction_section, &system_st);
add_sym("BIS", I_BIS, OC_2GEN, &instruction_section, &system_st);
add_sym("BISB", I_BISB, OC_2GEN, &instruction_section, &system_st);
add_sym("BIT", I_BIT, OC_2GEN, &instruction_section, &system_st);
add_sym("BITB", I_BITB, OC_2GEN, &instruction_section, &system_st);
add_sym("BLE", I_BLE, OC_BR, &instruction_section, &system_st);
add_sym("BLO", I_BLO, OC_BR, &instruction_section, &system_st);
add_sym("BLOS", I_BLOS, OC_BR, &instruction_section, &system_st);
add_sym("BLT", I_BLT, OC_BR, &instruction_section, &system_st);
add_sym("BMI", I_BMI, OC_BR, &instruction_section, &system_st);
add_sym("BNE", I_BNE, OC_BR, &instruction_section, &system_st);
add_sym("BPL", I_BPL, OC_BR, &instruction_section, &system_st);
add_sym("BPT", I_BPT, OC_NONE, &instruction_section, &system_st);
add_sym("BR", I_BR, OC_BR, &instruction_section, &system_st);
add_sym("BVC", I_BVC, OC_BR, &instruction_section, &system_st);
add_sym("BVS", I_BVS, OC_BR, &instruction_section, &system_st);
add_sym("CALL", I_CALL, OC_1GEN, &instruction_section, &system_st);
add_sym("CALLR", I_CALLR, OC_1GEN, &instruction_section, &system_st);
add_sym("CCC", I_CCC, OC_NONE, &instruction_section, &system_st);
add_sym("CLC", I_CLC, OC_NONE, &instruction_section, &system_st);
add_sym("CLN", I_CLN, OC_NONE, &instruction_section, &system_st);
add_sym("CLR", I_CLR, OC_1GEN, &instruction_section, &system_st);
add_sym("CLRB", I_CLRB, OC_1GEN, &instruction_section, &system_st);
add_sym("CLV", I_CLV, OC_NONE, &instruction_section, &system_st);
add_sym("CLZ", I_CLZ, OC_NONE, &instruction_section, &system_st);
add_sym("CMP", I_CMP, OC_2GEN, &instruction_section, &system_st);
add_sym("CMPB", I_CMPB, OC_2GEN, &instruction_section, &system_st);
add_sym("COM", I_COM, OC_1GEN, &instruction_section, &system_st);
add_sym("COMB", I_COMB, OC_1GEN, &instruction_section, &system_st);
add_sym("DEC", I_DEC, OC_1GEN, &instruction_section, &system_st);
add_sym("DECB", I_DECB, OC_1GEN, &instruction_section, &system_st);
add_sym("DIV", I_DIV, OC_ASH, &instruction_section, &system_st);
add_sym("EMT", I_EMT, OC_MARK, &instruction_section, &system_st);
add_sym("FADD", I_FADD, OC_1REG, &instruction_section, &system_st);
add_sym("FDIV", I_FDIV, OC_1REG, &instruction_section, &system_st);
add_sym("FMUL", I_FMUL, OC_1REG, &instruction_section, &system_st);
add_sym("FSUB", I_FSUB, OC_1REG, &instruction_section, &system_st);
add_sym("HALT", I_HALT, OC_NONE, &instruction_section, &system_st);
add_sym("INC", I_INC, OC_1GEN, &instruction_section, &system_st);
add_sym("INCB", I_INCB, OC_1GEN, &instruction_section, &system_st);
add_sym("IOT", I_IOT, OC_NONE, &instruction_section, &system_st);
add_sym("JMP", I_JMP, OC_1GEN, &instruction_section, &system_st);
add_sym("JSR", I_JSR, OC_JSR, &instruction_section, &system_st);
add_sym("MARK", I_MARK, OC_MARK, &instruction_section, &system_st);
add_sym("MED6X", I_MED6X, OC_NONE, &instruction_section, &system_st);
add_sym("MED74C", I_MED74C, OC_NONE, &instruction_section, &system_st);
add_sym("MFPD", I_MFPD, OC_1GEN, &instruction_section, &system_st);
add_sym("MFPI", I_MFPI, OC_1GEN, &instruction_section, &system_st);
add_sym("MFPS", I_MFPS, OC_1GEN, &instruction_section, &system_st);
add_sym("MOV", I_MOV, OC_2GEN, &instruction_section, &system_st);
add_sym("MOVB", I_MOVB, OC_2GEN, &instruction_section, &system_st);
add_sym("MTPD", I_MTPD, OC_1GEN, &instruction_section, &system_st);
add_sym("MTPI", I_MTPI, OC_1GEN, &instruction_section, &system_st);
add_sym("MTPS", I_MTPS, OC_1GEN, &instruction_section, &system_st);
add_sym("MUL", I_MUL, OC_ASH, &instruction_section, &system_st);
add_sym("NEG", I_NEG, OC_1GEN, &instruction_section, &system_st);
add_sym("NEGB", I_NEGB, OC_1GEN, &instruction_section, &system_st);
add_sym("NOP", I_NOP, OC_NONE, &instruction_section, &system_st);
add_sym("RESET", I_RESET, OC_NONE, &instruction_section, &system_st);
add_sym("RETURN", I_RETURN, OC_NONE, &instruction_section, &system_st);
add_sym("ROL", I_ROL, OC_1GEN, &instruction_section, &system_st);
add_sym("ROLB", I_ROLB, OC_1GEN, &instruction_section, &system_st);
add_sym("ROR", I_ROR, OC_1GEN, &instruction_section, &system_st);
add_sym("RORB", I_RORB, OC_1GEN, &instruction_section, &system_st);
add_sym("RTI", I_RTI, OC_NONE, &instruction_section, &system_st);
add_sym("RTS", I_RTS, OC_1REG, &instruction_section, &system_st);
add_sym("RTT", I_RTT, OC_NONE, &instruction_section, &system_st);
add_sym("SBC", I_SBC, OC_1GEN, &instruction_section, &system_st);
add_sym("SBCB", I_SBCB, OC_1GEN, &instruction_section, &system_st);
add_sym("SCC", I_SCC, OC_NONE, &instruction_section, &system_st);
add_sym("SEC", I_SEC, OC_NONE, &instruction_section, &system_st);
add_sym("SEN", I_SEN, OC_NONE, &instruction_section, &system_st);
add_sym("SEV", I_SEV, OC_NONE, &instruction_section, &system_st);
add_sym("SEZ", I_SEZ, OC_NONE, &instruction_section, &system_st);
add_sym("SOB", I_SOB, OC_SOB, &instruction_section, &system_st);
add_sym("SPL", I_SPL, OC_1REG, &instruction_section, &system_st);
add_sym("SUB", I_SUB, OC_2GEN, &instruction_section, &system_st);
add_sym("SWAB", I_SWAB, OC_1GEN, &instruction_section, &system_st);
add_sym("SXT", I_SXT, OC_1GEN, &instruction_section, &system_st);
add_sym("TRAP", I_TRAP, OC_MARK, &instruction_section, &system_st);
add_sym("TST", I_TST, OC_1GEN, &instruction_section, &system_st);
add_sym("TSTB", I_TSTB, OC_1GEN, &instruction_section, &system_st);
add_sym("WAIT", I_WAIT, OC_NONE, &instruction_section, &system_st);
add_sym("XFC", I_XFC, OC_NONE, &instruction_section, &system_st);
add_sym("XOR", I_XOR, OC_JSR, &instruction_section, &system_st);
add_sym("MFPT", I_MFPT, OC_NONE, &instruction_section, &system_st);
add_sym("CSM", I_CSM, OC_1GEN, &instruction_section, &system_st);
add_sym("TSTSET", I_TSTSET, OC_1GEN, &instruction_section, &system_st);
add_sym("WRTLCK", I_WRTLCK, OC_1GEN, &instruction_section, &system_st);
/* FPP instructions */
add_sym("ABSD", I_ABSD, OC_FPP_FDST, &instruction_section, &system_st);
add_sym("ABSF", I_ABSF, OC_FPP_FDST, &instruction_section, &system_st);
add_sym("ADDD", I_ADDD, OC_FPP_FSRCAC, &instruction_section, &system_st);
add_sym("ADDF", I_ADDF, OC_FPP_FSRCAC, &instruction_section, &system_st);
add_sym("CFCC", I_CFCC, OC_NONE, &instruction_section, &system_st);
add_sym("CLRD", I_CLRD, OC_FPP_FDST, &instruction_section, &system_st);
add_sym("CLRF", I_CLRF, OC_FPP_FDST, &instruction_section, &system_st);
add_sym("CMPD", I_CMPD, OC_FPP_FSRCAC, &instruction_section, &system_st);
add_sym("CMPF", I_CMPF, OC_FPP_FSRCAC, &instruction_section, &system_st);
add_sym("DIVD", I_DIVD, OC_FPP_FSRCAC, &instruction_section, &system_st);
add_sym("DIVF", I_DIVF, OC_FPP_FSRCAC, &instruction_section, &system_st);
add_sym("LDCDF", I_LDCDF, OC_FPP_FSRCAC, &instruction_section, &system_st);
add_sym("LDCFD", I_LDCFD, OC_FPP_FSRCAC, &instruction_section, &system_st);
add_sym("LDCID", I_LDCID, OC_FPP_SRCAC, &instruction_section, &system_st);
add_sym("LDCIF", I_LDCIF, OC_FPP_SRCAC, &instruction_section, &system_st);
add_sym("LDCLD", I_LDCLD, OC_FPP_SRCAC, &instruction_section, &system_st);
add_sym("LDCLF", I_LDCLF, OC_FPP_SRCAC, &instruction_section, &system_st);
add_sym("LDD", I_LDD, OC_FPP_FSRCAC, &instruction_section, &system_st);
add_sym("LDEXP", I_LDEXP, OC_FPP_SRCAC, &instruction_section, &system_st);
add_sym("LDF", I_LDF, OC_FPP_FSRCAC, &instruction_section, &system_st);
add_sym("LDFPS", I_LDFPS, OC_1GEN, &instruction_section, &system_st);
add_sym("MODD", I_MODD, OC_FPP_FSRCAC, &instruction_section, &system_st);
add_sym("MODF", I_MODF, OC_FPP_FSRCAC, &instruction_section, &system_st);
add_sym("MULD", I_MULD, OC_FPP_FSRCAC, &instruction_section, &system_st);
add_sym("MULF", I_MULF, OC_FPP_FSRCAC, &instruction_section, &system_st);
add_sym("NEGD", I_NEGD, OC_FPP_FDST, &instruction_section, &system_st);
add_sym("NEGF", I_NEGF, OC_FPP_FDST, &instruction_section, &system_st);
add_sym("SETD", I_SETD, OC_NONE, &instruction_section, &system_st);
add_sym("SETF", I_SETF, OC_NONE, &instruction_section, &system_st);
add_sym("SETI", I_SETI, OC_NONE, &instruction_section, &system_st);
add_sym("SETL", I_SETL, OC_NONE, &instruction_section, &system_st);
add_sym("STA0", I_STA0, OC_NONE, &instruction_section, &system_st);
add_sym("STB0", I_STB0, OC_NONE, &instruction_section, &system_st);
add_sym("STCDF", I_STCDF, OC_FPP_ACFDST, &instruction_section, &system_st);
add_sym("STCDI", I_STCDI, OC_FPP_ACFDST, &instruction_section, &system_st);
add_sym("STCDL", I_STCDL, OC_FPP_ACFDST, &instruction_section, &system_st);
add_sym("STCFD", I_STCFD, OC_FPP_ACFDST, &instruction_section, &system_st);
add_sym("STCFI", I_STCFI, OC_FPP_ACFDST, &instruction_section, &system_st);
add_sym("STCFL", I_STCFL, OC_FPP_ACFDST, &instruction_section, &system_st);
add_sym("STD", I_STD, OC_FPP_ACFDST, &instruction_section, &system_st);
add_sym("STEXP", I_STEXP, OC_FPP_ACDST, &instruction_section, &system_st);
add_sym("STF", I_STF, OC_FPP_ACFDST, &instruction_section, &system_st);
add_sym("STFPS", I_STFPS, OC_1GEN, &instruction_section, &system_st);
add_sym("STST", I_STST, OC_1GEN, &instruction_section, &system_st);
add_sym("SUBD", I_SUBD, OC_FPP_FSRCAC, &instruction_section, &system_st);
add_sym("SUBF", I_SUBF, OC_FPP_FSRCAC, &instruction_section, &system_st);
add_sym("TSTD", I_TSTD, OC_FPP_FDST, &instruction_section, &system_st);
add_sym("TSTF", I_TSTF, OC_FPP_FDST, &instruction_section, &system_st);
/* The CIS instructions */
add_sym("ADDNI", I_ADDN|I_CIS_I, OC_CIS3, &instruction_section, &system_st);
add_sym("ADDN", I_ADDN, OC_NONE, &instruction_section, &system_st);
add_sym("ADDPI", I_ADDP|I_CIS_I, OC_CIS3, &instruction_section, &system_st);
add_sym("ADDP", I_ADDP, OC_NONE, &instruction_section, &system_st);
add_sym("ASHNI", I_ASHN|I_CIS_I, OC_CIS3, &instruction_section, &system_st);
add_sym("ASHN", I_ASHN, OC_NONE, &instruction_section, &system_st);
add_sym("ASHPI", I_ASHP|I_CIS_I, OC_CIS3, &instruction_section, &system_st);
add_sym("ASHP", I_ASHP, OC_NONE, &instruction_section, &system_st);
add_sym("CMPCI", I_CMPC|I_CIS_I, OC_CIS3, &instruction_section, &system_st);
add_sym("CMPC", I_CMPC, OC_NONE, &instruction_section, &system_st);
add_sym("CMPNI", I_CMPN|I_CIS_I, OC_CIS2, &instruction_section, &system_st);
add_sym("CMPN", I_CMPN, OC_NONE, &instruction_section, &system_st);
add_sym("CMPPI", I_CMPP|I_CIS_I, OC_CIS2, &instruction_section, &system_st);
add_sym("CMPP", I_CMPP, OC_NONE, &instruction_section, &system_st);
add_sym("CVTLNI",I_CVTLN|I_CIS_I,OC_CIS2, &instruction_section, &system_st);
add_sym("CVTLN", I_CVTLN, OC_NONE, &instruction_section, &system_st);
add_sym("CVTLPI",I_CVTLP|I_CIS_I,OC_CIS2, &instruction_section, &system_st);
add_sym("CVTLP", I_CVTPL, OC_NONE, &instruction_section, &system_st);
add_sym("CVTNLI",I_CVTNL|I_CIS_I,OC_CIS2, &instruction_section, &system_st);
add_sym("CVTNL", I_CVTNL, OC_NONE, &instruction_section, &system_st);
add_sym("CVTPLI",I_CVTPL|I_CIS_I,OC_CIS2, &instruction_section, &system_st);
add_sym("CVTPL", I_CVTPL, OC_NONE, &instruction_section, &system_st);
add_sym("CVTNPI",I_CVTNP|I_CIS_I,OC_CIS2, &instruction_section, &system_st);
add_sym("CVTNP", I_CVTNP, OC_NONE, &instruction_section, &system_st);
add_sym("CVTPNI",I_CVTPN|I_CIS_I,OC_CIS2, &instruction_section, &system_st);
add_sym("CVTPN", I_CVTPN, OC_NONE, &instruction_section, &system_st);
add_sym("DIVPI", I_DIVP|I_CIS_I, OC_CIS3, &instruction_section, &system_st);
add_sym("DIVP", I_DIVP, OC_NONE, &instruction_section, &system_st);
add_sym("LOCCI", I_LOCC|I_CIS_I, OC_CIS2, &instruction_section, &system_st);
add_sym("LOCC", I_LOCC, OC_NONE, &instruction_section, &system_st);
add_sym("L2D0", I_L2Dr+0, OC_NONE, &instruction_section, &system_st);
add_sym("L2D1", I_L2Dr+1, OC_NONE, &instruction_section, &system_st);
add_sym("L2D2", I_L2Dr+2, OC_NONE, &instruction_section, &system_st);
add_sym("L2D3", I_L2Dr+3, OC_NONE, &instruction_section, &system_st);
add_sym("L2D4", I_L2Dr+4, OC_NONE, &instruction_section, &system_st);
add_sym("L2D5", I_L2Dr+5, OC_NONE, &instruction_section, &system_st);
add_sym("L2D6", I_L2Dr+6, OC_NONE, &instruction_section, &system_st);
add_sym("L2D7", I_L2Dr+7, OC_NONE, &instruction_section, &system_st);
add_sym("L3D0", I_L3Dr+0, OC_NONE, &instruction_section, &system_st);
add_sym("L3D1", I_L3Dr+1, OC_NONE, &instruction_section, &system_st);
add_sym("L3D2", I_L3Dr+2, OC_NONE, &instruction_section, &system_st);
add_sym("L3D3", I_L3Dr+3, OC_NONE, &instruction_section, &system_st);
add_sym("L3D4", I_L3Dr+4, OC_NONE, &instruction_section, &system_st);
add_sym("L3D5", I_L3Dr+5, OC_NONE, &instruction_section, &system_st);
add_sym("L3D6", I_L3Dr+6, OC_NONE, &instruction_section, &system_st);
add_sym("L3D7", I_L3Dr+7, OC_NONE, &instruction_section, &system_st);
add_sym("MATCI", I_MATC|I_CIS_I, OC_CIS2, &instruction_section, &system_st);
add_sym("MATC", I_MATC, OC_NONE, &instruction_section, &system_st);
add_sym("MOVCI", I_MOVC|I_CIS_I, OC_CIS3, &instruction_section, &system_st);
add_sym("MOVC", I_MOVC, OC_NONE, &instruction_section, &system_st);
add_sym("MOVRCI",I_MOVRC|I_CIS_I,OC_CIS3, &instruction_section, &system_st);
add_sym("MOVRC", I_MOVRC, OC_NONE, &instruction_section, &system_st);
add_sym("MOVTCI",I_MOVTC|I_CIS_I,OC_CIS4, &instruction_section, &system_st);
add_sym("MOVTC", I_MOVTC, OC_NONE, &instruction_section, &system_st);
add_sym("MULPI", I_MULP|I_CIS_I, OC_CIS3, &instruction_section, &system_st);
add_sym("MULP", I_MULP, OC_NONE, &instruction_section, &system_st);
add_sym("SCANCI",I_SCANC|I_CIS_I,OC_CIS2, &instruction_section, &system_st);
add_sym("SCANC", I_SCANC, OC_NONE, &instruction_section, &system_st);
add_sym("SKPCI", I_SKPC|I_CIS_I, OC_CIS2, &instruction_section, &system_st);
add_sym("SKPC", I_SKPC, OC_NONE, &instruction_section, &system_st);
add_sym("SPANCI",I_SPANC|I_CIS_I,OC_CIS2, &instruction_section, &system_st);
add_sym("SPANC", I_SPANC, OC_NONE, &instruction_section, &system_st);
add_sym("SUBNI", I_SUBN|I_CIS_I, OC_CIS3, &instruction_section, &system_st);
add_sym("SUBN", I_SUBN, OC_NONE, &instruction_section, &system_st);
add_sym("SUBPI", I_SUBP|I_CIS_I, OC_CIS3, &instruction_section, &system_st);
add_sym("SUBP", I_SUBP, OC_NONE, &instruction_section, &system_st);
add_sym(current_section->label, 0, 0, current_section, &section_st);
}
/* sym_hist is a diagnostic function that prints a histogram of the
hash table useage of a symbol table. I used this to try to tune
the hash function for better spread. It's not used now. */
void sym_hist(
SYMBOL_TABLE *st,
char *name)
{
int i;
SYMBOL *sym;
fprintf(lstfile, "Histogram for symbol table %s\n", name);
for (i = 0; i < 1023; i++) {
fprintf(lstfile, "%4d: ", i);
for (sym = st->hash[i]; sym != NULL; sym = sym->next)
fputc('#', lstfile);
fputc('\n', lstfile);
}
}
static int symbol_compar(
const void *a,
const void *b)
{
SYMBOL *sa = *(SYMBOL **)a;
SYMBOL *sb = *(SYMBOL **)b;
return strcmp(sa->label, sb->label);
}
void list_symbol_table(
void)
{
SYMBOL_ITER iter;
SYMBOL *sym;
int skip_locals = 0;
int longest_symbol = symbol_len;
fprintf(lstfile,"\n\nSymbol table\n\n");
/* Count the symbols in the table */
int nsyms = 0;
for (sym = first_sym(&symbol_st, &iter); sym != NULL; sym = next_sym(&symbol_st, &iter)) {
if (skip_locals && sym->flags & SYMBOLFLAG_LOCAL) {
continue;
}
nsyms++;
int len = strlen(sym->label);
if (len > longest_symbol) {
longest_symbol = len;
}
}
/* Sort them by name */
SYMBOL **symbols = malloc(nsyms * sizeof (SYMBOL *));
SYMBOL **symbolp = symbols;
for (sym = first_sym(&symbol_st, &iter); sym != NULL; sym = next_sym(&symbol_st, &iter)) {
if (skip_locals && sym->flags & SYMBOLFLAG_LOCAL) {
continue;
}
*symbolp++ = sym;
}
qsort(symbols, nsyms, sizeof(SYMBOL *), symbol_compar);
symbolp = symbols;
/* Print the listing in NCOLS columns. */
int ncols = (132 / (longest_symbol + 19));
int nlines = (nsyms + ncols - 1) / ncols;
int line;
/*
* DIRER$ =%004562RGX 006
* ^ ^^ ^ ^-- for R symbols: program segment number
* | || +-- Flags: R = relocatable
* | || G = global
* | || X = implicit global
* | || L = local
* | || W = weak
* | |+- value, ****** for if it was not a definition
* | +-- % for a register
* +- label name
*/
for (line = 0; line < nlines; line++) {
int i;
for (i = line; i < nsyms; i += nlines) {
sym = symbols[i];
check_sym_invariants(sym, __FILE__, __LINE__);
fprintf(lstfile,"%-*s", longest_symbol, sym->label);
fprintf(lstfile,"%c", (sym->section->flags & PSECT_REL) ? ' ' : '=');
fprintf(lstfile,"%c", (sym->section->type == SECTION_REGISTER) ? '%' : ' ');
if (!(sym->flags & SYMBOLFLAG_DEFINITION)) {
fprintf(lstfile,"******");
} else {
fprintf(lstfile,"%06o", sym->value & 0177777);
}
fprintf(lstfile,"%c", (sym->section->flags & PSECT_REL) ? 'R' : ' ');
fprintf(lstfile,"%c", (sym->flags & SYMBOLFLAG_GLOBAL) ? 'G' : ' ');
fprintf(lstfile,"%c", (sym->flags & SYMBOLFLAG_IMPLICIT_GLOBAL) ? 'X' : ' ');
fprintf(lstfile,"%c", (sym->flags & SYMBOLFLAG_LOCAL) ? 'L' : ' ');
fprintf(lstfile,"%c", (sym->flags & SYMBOLFLAG_WEAK) ? 'W' : ' ');
if (sym->section->sector != 0) {
fprintf(lstfile," %03d ", sym->section->sector);
} else {
fprintf(lstfile," ");
}
}
fprintf(lstfile,"\n");
}
/* List sections */
fprintf(lstfile,"\n\nProgram sections:\n\n");
int i;
for (i = 0; i < sector; i++) {
list_section(sections[i]);
}
free(symbols);
}
void list_section(
SECTION *sec)
{
if (sec == NULL) {
fprintf(lstfile, "(null)\n");
return;
}
int flags = sec->flags;
fprintf(lstfile, "%-6s %06o %03d ",
sec->label, sec->size & 0177777, sec->sector);
fprintf(lstfile, "(%s,%s,%s,%s,%s,%s)\n",
(flags & PSECT_RO) ? "RO" : "RW",
(flags & PSECT_DATA) ? "D" : "I",
(flags & PSECT_GBL) ? "GBL" : "LCL",
(flags & PSECT_REL) ? "REL" : "ABS",
(flags & PSECT_COM) ? "OVR" : "CON",
(flags & PSECT_SAV) ? "SAV" : "NOSAV");
}

View File

@@ -0,0 +1,419 @@
#ifndef SYMBOLS__H
#define SYMBOLS__H
/* max symbol_len can be adjusted between SYMMAX_DEFAULT and SYMMAX_MAX*/
#define SYMMAX_DEFAULT 6 /* I will honor this many character symbols */
#define SYMMAX_MAX 64
/* Program sections: */
typedef struct section {
char *label; /* Section name */
unsigned type; /* Section type */
#define SECTION_USER 1 /* user-defined */
#define SECTION_SYSTEM 2 /* A system symbol (like "."; value is an enum) */
#define SECTION_INSTRUCTION 3 /* An instruction code (like "MOV"; value is an enum) */
#define SECTION_PSEUDO 4 /* A pseudo-op (.PSECT, .TITLE, .MACRO, .IF; value is an enum) */
#define SECTION_REGISTER 5 /* Symbol is a register (value 0=$0, value 1=$1, ... $7) */
#define SECTION_USERMACRO 6 /* Symbol is a user macro */
unsigned flags; /* Flags, defined in object.h */
unsigned pc; /* Current offset in the section */
unsigned size; /* Current section size */
unsigned sector; /* Used for complex relocation, and naught else */
} SECTION;
#define SYM_IS_IMPORTED(sym) ((sym->flags & (SYMBOLFLAG_GLOBAL | SYMBOLFLAG_DEFINITION)) == SYMBOLFLAG_GLOBAL)
/* Symbol table entries */
typedef struct symbol {
char *label; /* Symbol name */
unsigned value; /* Symbol value */
int stmtno; /* Statement number of symbol's definition */
unsigned flags; /* Symbol flags */
#define SYMBOLFLAG_PERMANENT 1 /* Symbol may not be redefined */
#define SYMBOLFLAG_GLOBAL 2 /* Symbol is global */
#define SYMBOLFLAG_WEAK 4 /* Symbol definition is weak */
#define SYMBOLFLAG_DEFINITION 8 /* Symbol is a global definition, not reference */
#define SYMBOLFLAG_UNDEFINED 16 /* Symbol is a phony, undefined */
#define SYMBOLFLAG_LOCAL 32 /* Set if this is a local label (i.e. 10$) */
#define SYMBOLFLAG_IMPLICIT_GLOBAL 64 /* If migrated from implicit global table to
* normal symbol table */
SECTION *section; /* Section in which this symbol is defined */
struct symbol *next; /* Next symbol with the same hash value */
} SYMBOL;
enum pseudo_ops { P_ASCII,
P_ASCIZ,
P_ASECT,
P_BLKB,
P_BLKW,
P_BYTE,
P_CSECT,
P_CROSS,
P_DSABL,
P_ENABL,
P_END,
P_ENDC,
P_ENDM,
P_ENDR,
P_EOT,
P_ERROR,
P_EVEN,
P_FLT2,
P_FLT4,
P_GLOBL,
P_IDENT,
P_IF,
P_IFF,
P_IFT,
P_IFTF,
P_IIF,
P_IRP,
P_IRPC,
P_LIBRARY,
P_LIMIT,
P_LIST,
P_MCALL,
P_MDELETE,
P_MEXIT,
P_NARG,
P_NCHR,
P_NLIST,
P_NOCROSS,
P_NTYPE,
P_ODD,
P_PACKED,
P_PAGE,
P_PRINT,
P_PSECT,
P_RADIX,
P_RAD50,
P_REM,
P_REPT,
P_RESTORE,
P_SAVE,
P_SBTTL,
P_TITLE,
P_WORD,
P_MACRO,
P_INCLUDE,
P_WEAK,
P_IFDF
};
enum instruction_ops {
I_ADC = 0005500,
I_ADCB = 0105500,
I_ADD = 0060000,
I_ASH = 0072000,
I_ASHC = 0073000,
I_ASL = 0006300,
I_ASLB = 0106300,
I_ASR = 0006200,
I_ASRB = 0106200,
I_BCC = 0103000,
I_BCS = 0103400,
I_BEQ = 0001400,
I_BGE = 0002000,
I_BGT = 0003000,
I_BHI = 0101000,
I_BHIS = 0103000,
I_BIC = 0040000,
I_BICB = 0140000,
I_BIS = 0050000,
I_BISB = 0150000,
I_BIT = 0030000,
I_BITB = 0130000,
I_BLE = 0003400,
I_BLO = 0103400,
I_BLOS = 0101400,
I_BLT = 0002400,
I_BMI = 0100400,
I_BNE = 0001000,
I_BPL = 0100000,
I_BPT = 0000003,
I_BR = 0000400,
I_BVC = 0102000,
I_BVS = 0102400,
I_CALL = 0004700,
I_CALLR = 0000100,
I_CCC = 0000257,
I_CLC = 0000241,
I_CLN = 0000250,
I_CLR = 0005000,
I_CLRB = 0105000,
I_CLV = 0000242,
I_CLZ = 0000244,
I_CMP = 0020000,
I_CMPB = 0120000,
I_COM = 0005100,
I_COMB = 0105100,
I_DEC = 0005300,
I_DECB = 0105300,
I_DIV = 0071000,
I_EMT = 0104000,
I_FADD = 0075000, /* FIS */
I_FDIV = 0075030, /* FIS */
I_FMUL = 0075020, /* FIS */
I_FSUB = 0075010, /* FIS */
I_HALT = 0000000,
I_INC = 0005200,
I_INCB = 0105200,
I_IOT = 0000004,
I_JMP = 0000100,
I_JSR = 0004000,
I_MARK = 0006400,
I_MED6X = 0076600,
I_MED74C = 0076601,
I_MFPD = 0106500,
I_MFPI = 0006500,
I_MFPS = 0106700,
I_MOV = 0010000,
I_MOVB = 0110000,
I_MTPD = 0106600,
I_MTPI = 0006600,
I_MTPS = 0106400,
I_MUL = 0070000,
I_NEG = 0005400,
I_NEGB = 0105400,
I_NOP = 0000240,
I_RESET = 0000005,
I_RETURN = 0000207,
I_ROL = 0006100,
I_ROLB = 0106100,
I_ROR = 0006000,
I_RORB = 0106000,
I_RTI = 0000002,
I_RTS = 0000200,
I_RTT = 0000006,
I_SBC = 0005600,
I_SBCB = 0105600,
I_SCC = 0000277,
I_SEC = 0000261,
I_SEN = 0000270,
I_SEV = 0000262,
I_SEZ = 0000264,
I_SOB = 0077000,
I_SPL = 0000230,
I_SUB = 0160000,
I_SWAB = 0000300,
I_SXT = 0006700,
I_TRAP = 0104400,
I_TST = 0005700,
I_TSTB = 0105700,
I_WAIT = 0000001,
I_XFC = 0076700,
I_XOR = 0074000,
I_MFPT = 0000007,
I_CSM = 0007000,
I_TSTSET = 0007200,
I_WRTLCK = 0007300,
/* CIS - Commercial Instruction Set */
I_CIS_I = 0000100, /* Inline arguments */
I_CIS_P = 0000020, /* Packed instead of Numeric */
I_ADDN = 0076050,
I_ADDP = 0076070,
I_ASHN = 0076056,
I_ASHP = 0076076,
I_CMPC = 0076044,
I_CMPN = 0076052,
I_CMPP = 0076072,
I_CVTLN = 0076057,
I_CVTLP = 0076077,
I_CVTNL = 0076053,
I_CVTPL = 0076073,
I_CVTNP = 0076055,
I_CVTPN = 0076054,
I_DIVP = 0076075,
I_LOCC = 0076040,
I_L2Dr = 0076020,
I_L3Dr = 0076060,
I_MATC = 0076045,
I_MOVC = 0076030,
I_MOVRC= 0076031,
I_MOVTC= 0076032,
I_MULP = 0076074,
I_SCANC= 0076042,
I_SKPC = 0076041,
I_SPANC= 0076043,
I_SUBN = 0076051,
I_SUBP = 0076071,
/* FPU */
I_ABSD = 0170600,
I_ABSF = 0170600,
I_ADDD = 0172000,
I_ADDF = 0172000,
I_CFCC = 0170000,
I_CLRD = 0170400,
I_CLRF = 0170400,
I_CMPD = 0173400,
I_CMPF = 0173400,
I_DIVD = 0174400,
I_DIVF = 0174400,
I_LDCDF = 0177400,
I_LDCFD = 0177400,
I_LDCID = 0177000,
I_LDCIF = 0177000,
I_LDCLD = 0177000,
I_LDCLF = 0177000,
I_LDD = 0172400,
I_LDEXP = 0176400,
I_LDF = 0172400,
I_LDFPS = 0170100,
I_MODD = 0171400,
I_MODF = 0171400,
I_MULD = 0171000,
I_MULF = 0171000,
I_NEGD = 0170700,
I_NEGF = 0170700,
I_SETD = 0170011,
I_SETF = 0170001,
I_SETI = 0170002,
I_SETL = 0170012,
I_STA0 = 0170005,
I_STB0 = 0170006,
I_STCDF = 0176000,
I_STCDI = 0175400,
I_STCDL = 0175400,
I_STCFD = 0176000,
I_STCFI = 0175400,
I_STCFL = 0175400,
I_STD = 0174000,
I_STEXP = 0175000,
I_STF = 0174000,
I_STFPS = 0170200,
I_STST = 0170300,
I_SUBD = 0173000,
I_SUBF = 0173000,
I_TSTD = 0170500,
I_TSTF = 0170500
};
enum operand_codes { OC_MASK = 0xff00,
/* mask over flags for operand types */
OC_NONE = 0x0000,
/* No operands */
OC_1GEN = 0x0100,
/* One general operand (CLR, TST, etc.) */
OC_2GEN = 0x0200,
/* Two general operand (MOV, CMP, etc.) */
OC_BR = 0x0300,
/* Branch */
OC_ASH = 0x0400,
/* ASH and ASHC (one gen, one reg) */
OC_MARK = 0x0500,
/* MARK instruction operand */
OC_JSR = 0x0600,
/* JSR, XOR (one reg, one gen) */
OC_1REG = 0x0700,
/* FADD, FSUB, FMUL, FDIV, RTS */
OC_SOB = 0x0800,
/* SOB */
OC_FPP_FSRCAC = 0x0900,
/* FPP (fsrc gen, floating ac 0-3) */
OC_FPP_SRCAC = 0x0a00,
/* FPP (src gen, floating ac 0-3) */
OC_FPP_ACFDST = 0x0b00,
OC_FPP_ACDST = OC_FPP_ACFDST,
/* FPP (floating ac 0-3, fdst gen) */
/* OC_FPP_FSRC = 0x0c00, */
/* FPP fp source: immediate or fsrc gen */
OC_FPP_FDST = OC_1GEN,
/* FPP fdst general destination */
OC_CIS2 = 0x0d00,
/* CIS with 2 parameter words */
OC_CIS3 = 0x0e00,
/* CIS with 3 parameter words */
OC_CIS4 = 0x0f00,
/* CIS with 4 parameter words */
OC__LAST = 0xff00
};
/* symbol tables */
#define HASH_SIZE 1023
typedef struct symbol_table {
SYMBOL *hash[HASH_SIZE];
} SYMBOL_TABLE;
/* SYMBOL_ITER is used for iterating thru a symbol table. */
typedef struct symbol_iter {
int subscript; /* Current hash subscript */
SYMBOL *current; /* Current symbol */
} SYMBOL_ITER;
#ifndef SYMBOLS__C
extern int symbol_len; /* max. len of symbols. default = 6 */
extern int symbol_allow_underscores; /* allow "_" in symbol names */
extern SYMBOL *reg_sym[8]; /* Keep the register symbols in a handy array */
extern SYMBOL_TABLE system_st; /* System symbols (Instructions,
pseudo-ops, registers) */
extern SYMBOL_TABLE section_st; /* Program sections */
extern SYMBOL_TABLE symbol_st; /* User symbols */
extern SYMBOL_TABLE macro_st; /* Macros */
extern SYMBOL_TABLE implicit_st; /* The symbols which may be implicit globals */
extern SYMBOL_TABLE undefined_st; /* The symbols which may be undefined */
#endif
int hash_name(
char *label);
SYMBOL *add_sym(
char *label,
unsigned value,
unsigned flags,
SECTION *section,
SYMBOL_TABLE *table);
SYMBOL *first_sym(
SYMBOL_TABLE *table,
SYMBOL_ITER *iter);
SYMBOL *lookup_sym(
char *label,
SYMBOL_TABLE *table);
SYMBOL *next_sym(
SYMBOL_TABLE *table,
SYMBOL_ITER *iter);
void free_sym(
SYMBOL *sym);
void remove_sym(
SYMBOL *sym,
SYMBOL_TABLE *table);
char *symflags(
SYMBOL *sym);
void add_table(
SYMBOL *sym,
SYMBOL_TABLE *table);
void add_symbols(
SECTION *current_section);
void list_symbol_table(
void);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,658 @@
1 ;;;; Wrapper for 2.11BSD/m11/debug.m11
2 .list
3 .list
4 .list
5 000001 debug = 1
6 .include "2.11BSD/m11/at.sml"
1 .title at.sml - assembler/translator system macros
2 ; @(#)at.sml 1.3 11/3/82
3
4 .ident /10may4/
5
6 .macro always ;all files of macro
7
8 .macro .data
9 entsec .data
10 .endm .data
11
12 .macro .text
13 entsec .text
14 .endm
15
16 .macro .bss
17 entsec .bss
18 .endm
19
20 mk.symbol=1 ;one to make symbols, 0 otherwise
21 x40= 0
22 pdpv45= 0 ; host machine has 'mul', 'div', sob' instrucs.
23 ; if not you will have to write macros for them
24 $timdf= 7 ; California Time Zone
25 ; should really use ftime(2) for this and for
26 ; DST.
27 ;xfltg= 0 ;define to assmbl out floating hardware
28 rsx11d = 0 ; rsx11d features
29 debug = 0 ; <<< REEDS if non zero includes debug junk
30
31 ft.id= 1 ;have set i & d. set =0 if not
32
33 ft.unx = 1 ; this macro-11 is for UNIX. =0 if not.
34
35 .nlist bex
36
37 tab= 11
38 lf= 12
39 vt= 13
40 ff= 14
41 cr= 15
42 space= 40
43
44 bpmb = 20 ;bytes per macro block
45
46
47
48
49
50 .psect .text con, shr, gbl,ins
51 .psect .data con, dat, prv, gbl
52 .psect .bss con, bss, gbl
53
54 .psect dpure con, dat, prv, gbl
55 .psect mixed con, prv, gbl
56 .psect errmes con, dat, prv, gbl
57 .psect impure con, bss, gbl
58 .psect imppas con, bss, gbl
59 .psect implin con, bss, gbl
60 .psect swtsec con, dat, prv, gbl ; unix command line flags
61 .psect cndsec con, dat, prv, gbl ; gt, le, equ, etc. for '.if'
62 .psect crfsec con, dat, prv, gbl ; args for -cr flag
63 .psect edtsec con, dat, prv, gbl ; args for .enabl
64 .psect lctsec con, dat, prv, gbl ; args for .list
65 .psect psasec con, dat, prv, gbl
66 .psect pstsec con, dat, prv, gbl
67 .psect rolbas con, dat, prv, gbl ; core allocation: starts of tables
68 .psect rolsiz con, dat, prv, gbl ; sizes of table entries
69 .psect roltop con, dat, prv, gbl ; tops of tables
70 .psect xpcor con,bss , gbl ; this one MUST come last in core
71
72
72
73 .macro entsec name ;init a section
74 .psect name con
75 .endm entsec
76
77
78
79 .macro jeq x,?fred
80 bne fred
81 jmp x
82 fred:
83 .endm
84 .macro jne x,?fred
85 beq fred
86 jmp x
87 fred:
88 .endm
89 .macro xitsec
90 entsec .text
91 .endm xitsec
92
93
94 .macro call address
95 jsr pc,address
96 .endm
97
98 .macro return
99 rts pc
100 .endm
101
102
103 .macro always
104 .nlist bex
105 .endm always
106 .endm always
107
108
109 000001 .if ne debug
110
111 .macro ndebug n
112 .globl ndebug,..z
113 mov n,..z
114 call ndebug
115 .endm
116
117 .macro sdebug string
118 .globl sdebug,..z,..zbuf
119 x = 0
120 .irpc t,<string>
121 movb #''t,..zbuf+x
122 x = x+1
123 .endm
124 movb #0,..zbuf+x
125 mov #..zbuf,..z
126 call sdebug
127 .endm
128
129 .iff
130
131 .macro ndebug n
132 .endm
133
134 .macro sdebug string
135 .endm
136
137 .endc
138
139
140 .macro param mne, value ;define default parameters
141 .iif ndf mne, mne= value
142 .list
143 mne= mne
144 .nlist
145 .endm
145
146 .macro putkb addr ;list to kb
147 .globl putkb
148 mov addr,r0
149 call putkb
150 .endm
151
152 .macro putlp addr ;list to lp
153 .globl putlp
154 mov addr,r0
155 call putlp
156 .endm
157
158 .macro putkbl addr ;list to kb and lp
159 .globl putkbl
160 mov addr,r0
161 call putkbl
162 .endm
163
164
165 .macro xmit wrdcnt ;move small # of words
166 .globl xmit0
167 call xmit0-<wrdcnt*2>
168 .endm xmit
169
170
171 ;the macro "genswt" is used to specify a command
172 ;string switch (1st argument) and the address of
173 ;the routine to be called when encountered (2nd arg).
174 ; the switch is made upper-case.
175
176 .macro genswt mne,addr,?label
177 entsec swtsec
178 label: .irpc x,mne
179 .if ge ''x-141
180 .if le ''x-172
181 .byte ''x-40
182 .iff
183 .byte ''x
184 .endc
185 .iff
186 .byte ''x
187 .endc
188 .endm
189 .iif ne <.-label&1>, .byte 0
190 .word addr
191 xitsec
192 .endm
192
193 .macro zread chan
194 .globl zread
195 mov #chan'chn,r0
196 call zread
197 .endm zread
198
199 .macro zwrite chan
200 .globl zwrite
201 mov #chan'chn,r0
202 call zwrite
203 .endm zwrite
203
204 .macro genedt mne,subr ;gen enable/disable table
205 entsec edtsec
206 .rad50 /mne/
207 .if nb subr
208 .word subr
209 .iff
210 .word cpopj
211 .endc
212 .word ed.'mne
213 xitsec
214 .endm genedt
215
216
217 ;the macro "gencnd" is used to specify conditional
218 ;arguments. it takes two or three arguments:
219
220 ; 1- mnemonic
221 ; 2- subroutine to be called
222 ; 3- if non-blank, complement condition
223
224 .macro gencnd mne,subr,toggle ;generate conditional
225 entsec cndsec
226 .rad50 /mne/
227 .if b <toggle>
228 .word subr
229 .iff
230 .word subr+1
231 .endc
232 xitsec
233 .endm
233
234 .macro ch.mne
235
236 ch.ior= '!
237 ch.qtm= '"
238 ch.hsh= '#
239 ch.dol= '$
240 ch.pct= '%
241 ch.and= '&
242 ch.xcl= ''
243
244 ch.lp= '(
245 ch.rp= ')
246 ch.mul= '*
247 ch.add= '+
248 ch.com= ',
249 ch.sub= '-
250 ch.dot= '.
251 ch.div= '/
252
253 ch.col= ':
254 ch.smc= ';
255 ch.lab= '<
256 ch.equ= '=
257 ch.rab= '>
258 ch.qm= '?
259
260 ch.ind= '@
261 ch.bsl= '\
262 ch.uar= '^
263
264 let.a= 'a&^c40
265 let.b= 'b&^c40
266 let.c= 'c&^c40
267 let.d= 'd&^c40
268 let.e= 'e&^c40
269 let.f= 'f&^c40
270 let.g= 'g&^c40
271 let.o= 'o&^c40
272 let.p= 'p&^c40
273 let.r= 'r&^c40
274 let.z= 'z&^c40
275
276 dig.0= '0
277 dig.9= '9
278 .macro ch.mne
279 .endm ch.mne
280 .endm ch.mne
281
282 .macro error num,arg, mess ,?x
283 sdebug <num>
284 .globl err.'arg,ern'num, errbts,errref
285 .if b <mess>
286 deliberate error mistake
287 .endc
288 .if dif 0,num
289 .globl err.xx
290 tst err.xx
291 bne x
292 mov #ern'num,err.xx
293 x:
294 .endc
295 bis #err.'arg,errbts
296 .endm
297
298
299
300 .macro setnz addr ;set addr to non-zero for t/f flags
301 mov sp,addr
302 .endm
303
304
305 .macro bisbic arg ; used by .list/.nlist, .enabl/.dsabl
306 .globl bisbic
307 mov #arg,-(sp)
308 call bisbic
309 tst (sp)+
310 .endm
310
311 ;roll handler calls
312
313 .macro search rolnum ;binary search
314 mov #rolnum,r0
315 .globl search
316 call search
317 .endm
318
319 .macro scan rolnum ;linear scan
320 mov #rolnum,r0
321 .globl scan
322 call scan
323 .endm
324
325 .macro scanw rolnum ;linear scan, one word
326 mov #rolnum,r0
327 .globl scanw
328 call scanw
329 .endm
330
331 .macro next rolnum ;fetch next entry
332 mov #rolnum,r0
333 .globl next
334 call next
335 .endm
336
337 .macro append rolnum ;append to end of roll
338 mov #rolnum,r0
339 .globl append
340 call append
341 .endm
342
343 .macro zap rolnum ;clear roll
344 mov #rolnum,r0
345 .globl zap
346 call zap
347 .endm
348
349 ; call insert ;insert (must be preceded by one
350 ;of the above to set pointers)
351 ; call setrol ;save and set regs for above
351
352 ;flags used in symbol table mode
353
354 .macro st.flg
355
356 .if le ft.unx
357
358 ovrflg= 000004 ;overlay (psect only)
359 defflg= 000010 ;defined
360 relflg= 000040 ;relocatable
361 glbflg= 000100 ;global
362 dfgflg= 000200 ; default global <rsx11d>... reeds's guess
363
364
365 .endc
366
367 .if gt ft.unx
368
369 ; ****** these should not be changed!! ******
370 shrflg= 000001 ;shareable (psect only)
371 .if gt ft.id
372 insflg= shrflg*2 ;instruction space (psect only)
373 bssflg= insflg*2 ;blank section (psect only)
374 m.idf= shrflg!insflg!bssflg ;mask to turn them off
375 .iff
376 bssflg= shrflg*2
377 m.idf= shrflg!bssflg
378 .endc
379 b.idf= 1 ;shift count to make above bits word offset
380 ; ***********************************
381 defflg= 000010 ;defined
382 ovrflg= 000020 ;overlay (psect only)
383 relflg= 000040 ;relocatable
384 glbflg= 000100 ;global
385 dfgflg= 000200 ; default global <rsx11d>... reeds's guess
386
387 .endc
388
389 ;
390 ; default psect attribs.
391 ; can be changed, but make sure all customers know about
392 ; it, including all the linkers.
393 ;
394 pattrs=relflg!defflg ; For .psects and blank .csects
395 aattrs=glbflg!defflg!ovrflg ; For .asect
396 cattrs=glbflg!relflg!defflg!ovrflg ; For named .csects
397
398 regflg= 000001 ;register
399 lblflg= 000002 ;label
400 mdfflg= 000004 ;multilpy defined
401 .macro st.flg
402 .endm
403 .endm st.flg
404
405
406
407 .macro ct.mne
408 .globl cttbl
409 ct.eol = 000 ; eol
410 ct.com = 001 ; comma
411 ct.tab = 002 ; tab
412 ct.sp = 004 ; space
413 ct.pcx = 010 ; printing character
414 ct.num = 020 ; numeric
415 ct.alp = 040 ; alpha, dot, dollar
416 ct.lc = 100 ; lower case alpha
417 ct.smc = 200 ; semi-colon (sign bit)
418
419 ct.pc = ct.com!ct.smc!ct.pcx!ct.num!ct.alp
420 .macro ct.mne
421 .endm ct.mne
422 .endm ct.mne
423
424
425 .end
425
7 .include "2.11BSD/m11/debug.m11"
1 .mcall (at) always
2 .globl $write
3
4 .globl ndebug,sdebug, ..z,..zbuf
5 .globl savreg,dnc
6 .globl xx.flg
7 000000 always
1
2 .macro .data
3 entsec .data
4 .endm .data
5
6 .macro .text
7 entsec .text
8 .endm
9
10 .macro .bss
11 entsec .bss
12 .endm
13
14 000001 mk.symbol=1 ;one to make symbols, 0 otherwise
15 000000 x40= 0
16 000000 pdpv45= 0 ; host machine has 'mul', 'div', sob' instrucs.
17 ; if not you will have to write macros for them
18 000007 $timdf= 7 ; California Time Zone
19 ; should really use ftime(2) for this and for
20 ; DST.
21 ;xfltg= 0 ;define to assmbl out floating hardware
22 000000 rsx11d = 0 ; rsx11d features
23 000000 debug = 0 ; <<< REEDS if non zero includes debug junk
24
25 000001 ft.id= 1 ;have set i & d. set =0 if not
26
27 000001 ft.unx = 1 ; this macro-11 is for UNIX. =0 if not.
28
29 .nlist bex
30
31 000011 tab= 11
32 000012 lf= 12
33 000013 vt= 13
34 000014 ff= 14
35 000015 cr= 15
36 000040 space= 40
37
38 000020 bpmb = 20 ;bytes per macro block
39
40
41
42
43
./2.11BSD/m11/debug.m11:7->ALWAYS:44: ***ERROR Unknown flag SHR given to .PSECT directive
44 .psect .text con, shr, gbl,ins
./2.11BSD/m11/debug.m11:7->ALWAYS:45: ***ERROR Unknown flag DAT given to .PSECT directive
45 .psect .data con, dat, prv, gbl
./2.11BSD/m11/debug.m11:7->ALWAYS:46: ***ERROR Unknown flag BSS given to .PSECT directive
46 .psect .bss con, bss, gbl
47
./2.11BSD/m11/debug.m11:7->ALWAYS:48: ***ERROR Unknown flag DAT given to .PSECT directive
48 .psect dpure con, dat, prv, gbl
./2.11BSD/m11/debug.m11:7->ALWAYS:49: ***ERROR Unknown flag PRV given to .PSECT directive
49 .psect mixed con, prv, gbl
./2.11BSD/m11/debug.m11:7->ALWAYS:50: ***ERROR Unknown flag DAT given to .PSECT directive
50 .psect errmes con, dat, prv, gbl
./2.11BSD/m11/debug.m11:7->ALWAYS:51: ***ERROR Unknown flag BSS given to .PSECT directive
51 .psect impure con, bss, gbl
./2.11BSD/m11/debug.m11:7->ALWAYS:52: ***ERROR Unknown flag BSS given to .PSECT directive
52 .psect imppas con, bss, gbl
./2.11BSD/m11/debug.m11:7->ALWAYS:53: ***ERROR Unknown flag BSS given to .PSECT directive
53 .psect implin con, bss, gbl
./2.11BSD/m11/debug.m11:7->ALWAYS:54: ***ERROR Unknown flag DAT given to .PSECT directive
54 .psect swtsec con, dat, prv, gbl ; unix command line flags
./2.11BSD/m11/debug.m11:7->ALWAYS:55: ***ERROR Unknown flag DAT given to .PSECT directive
55 .psect cndsec con, dat, prv, gbl ; gt, le, equ, etc. for '.if'
./2.11BSD/m11/debug.m11:7->ALWAYS:56: ***ERROR Unknown flag DAT given to .PSECT directive
56 .psect crfsec con, dat, prv, gbl ; args for -cr flag
./2.11BSD/m11/debug.m11:7->ALWAYS:57: ***ERROR Unknown flag DAT given to .PSECT directive
57 .psect edtsec con, dat, prv, gbl ; args for .enabl
./2.11BSD/m11/debug.m11:7->ALWAYS:58: ***ERROR Unknown flag DAT given to .PSECT directive
58 .psect lctsec con, dat, prv, gbl ; args for .list
./2.11BSD/m11/debug.m11:7->ALWAYS:59: ***ERROR Unknown flag DAT given to .PSECT directive
59 .psect psasec con, dat, prv, gbl
./2.11BSD/m11/debug.m11:7->ALWAYS:60: ***ERROR Unknown flag DAT given to .PSECT directive
60 .psect pstsec con, dat, prv, gbl
./2.11BSD/m11/debug.m11:7->ALWAYS:61: ***ERROR Unknown flag DAT given to .PSECT directive
61 .psect rolbas con, dat, prv, gbl ; core allocation: starts of tables
./2.11BSD/m11/debug.m11:7->ALWAYS:62: ***ERROR Unknown flag DAT given to .PSECT directive
62 .psect rolsiz con, dat, prv, gbl ; sizes of table entries
./2.11BSD/m11/debug.m11:7->ALWAYS:63: ***ERROR Unknown flag DAT given to .PSECT directive
63 .psect roltop con, dat, prv, gbl ; tops of tables
./2.11BSD/m11/debug.m11:7->ALWAYS:64: ***ERROR Unknown flag BSS given to .PSECT directive
64 .psect xpcor con,bss , gbl ; this one MUST come last in core
65
66
67
68 .macro entsec name ;init a section
69 .psect name con
70 .endm entsec
71
72
73
74 .macro jeq x,?fred
75 bne fred
76 jmp x
77 fred:
78 .endm
79 .macro jne x,?fred
80 beq fred
81 jmp x
82 fred:
83 .endm
84 .macro xitsec
85 entsec .text
86 .endm xitsec
87
88
89 .macro call address
90 jsr pc,address
91 .endm
92
93 .macro return
94 rts pc
95 .endm
96
97
98 .macro always
99 .nlist bex
100 .endm always
8
9 000000 xitsec
1 000000 entsec .text
1 000000 .psect .text con
10 sdebug:
11 000000 call savreg
1 000000 004767 000000G jsr pc,savreg
12 000004 010046 mov r0,-(sp)
13
14 000006 012702 000004' mov #..s,r2
15 000012 016703 000002' mov ..z,r3
16 000016 012700 000002 mov #2,r0
17 000022 112322 1$: movb (r3)+,(r2)+
18 000024 001402 beq 2$
19 000026 005200 inc r0
20 000030 000774 br 1$
21 2$:
22 000032 112712 000012 movb #12,(r2)
23 000036 010067 000000' mov r0,..n
24 ddd:
25 000042 005767 000000G tst xx.flg
26 000046 001412 beq 100$
27 000050 016746 000000' mov ..n,-(sp) ;write(2, ..s, ..n)
28 000054 012746 000004' mov #..s,-(sp)
29 000060 012746 000002 mov #2,-(sp)
30 000064 005746 tst -(sp) ;simulate return address stack spacing
31 000066 000000G $write
32 000070 062706 000010 add #8.,sp ;toss syscall cruft
33 100$:
34 000074 012600 mov (sp)+,r0
35 000076 return
1 000076 000207 rts pc
36 ndebug:
37 000100 call savreg
1 000100 004767 000000G jsr pc,savreg
38 000104 010046 mov r0,-(sp)
39 000106 012702 000004' mov #..s,r2
40 000112 016701 000002' mov ..z,r1
41 000116 call dnc
1 000116 004767 000000G jsr pc,dnc
42 000122 112722 000012 movb #12,(r2)+
43 000126 010267 000000' mov r2,..n
44 000132 162767 000004' 000000' sub #..s,..n
45 000140 000740 br ddd
46
47 000142 entsec mixed
1 000000 .psect mixed con
48 000000 ..n: .blkw
49 000002 000000 ..z: .word
50 000004 ..s: .blkw 100
51 000204 ..zbuf: .blkw 100
52
53 .end
53
7
Symbol table
$TIMDF= 000007 ..ZBUF 000204RG 006 DDD 000042R 002 LF = 000012 SDEBUG 000000RG 002
$WRITE= ****** G 1$0 000022R L 002 DEBUG = 000000 MK.SYM= 000001 SPACE = 000040
. 000404R 006 100$1 000074R L 002 DNC = ****** G NDEBUG 000100RG 002 TAB = 000011
..N 000000R 006 2$0 000032R L 002 FF = 000014 PDPV45= 000000 VT = 000013
..S 000004R 006 BPMB = 000020 FT.ID = 000001 RSX11D= 000000 X40 = 000000
..Z 000002RG 006 CR = 000015 FT.UNX= 000001 SAVREG= ****** G XX.FLG= ****** G
Program sections:
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
000000 001 (RW,I,LCL,REL,CON,NOSAV)
.TEXT 000142 002 (RW,I,LCL,REL,CON,NOSAV)
.DATA 000000 003 (RW,I,LCL,REL,CON,NOSAV)
.BSS 000000 004 (RW,I,LCL,REL,CON,NOSAV)
DPURE 000000 005 (RW,I,LCL,REL,CON,NOSAV)
MIXED 000404 006 (RW,I,LCL,REL,CON,NOSAV)
ERRMES 000000 007 (RW,I,LCL,REL,CON,NOSAV)
IMPURE 000000 008 (RW,I,LCL,REL,CON,NOSAV)
IMPPAS 000000 009 (RW,I,LCL,REL,CON,NOSAV)
IMPLIN 000000 010 (RW,I,LCL,REL,CON,NOSAV)
SWTSEC 000000 011 (RW,I,LCL,REL,CON,NOSAV)
CNDSEC 000000 012 (RW,I,LCL,REL,CON,NOSAV)
CRFSEC 000000 013 (RW,I,LCL,REL,CON,NOSAV)
EDTSEC 000000 014 (RW,I,LCL,REL,CON,NOSAV)
LCTSEC 000000 015 (RW,I,LCL,REL,CON,NOSAV)
PSASEC 000000 016 (RW,I,LCL,REL,CON,NOSAV)
PSTSEC 000000 017 (RW,I,LCL,REL,CON,NOSAV)
ROLBAS 000000 018 (RW,I,LCL,REL,CON,NOSAV)
ROLSIZ 000000 019 (RW,I,LCL,REL,CON,NOSAV)
ROLTOP 000000 020 (RW,I,LCL,REL,CON,NOSAV)
XPCOR 000000 021 (RW,I,LCL,REL,CON,NOSAV)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,736 @@
1 ;;;; Wrapper for 2.11BSD/m11/often.m11
2 .list
3 .list
4 .list
5 000001 debug = 1
6 .include "2.11BSD/m11/at.sml"
1 .title at.sml - assembler/translator system macros
2 ; @(#)at.sml 1.3 11/3/82
3
4 .ident /10may4/
5
6 .macro always ;all files of macro
7
8 .macro .data
9 entsec .data
10 .endm .data
11
12 .macro .text
13 entsec .text
14 .endm
15
16 .macro .bss
17 entsec .bss
18 .endm
19
20 mk.symbol=1 ;one to make symbols, 0 otherwise
21 x40= 0
22 pdpv45= 0 ; host machine has 'mul', 'div', sob' instrucs.
23 ; if not you will have to write macros for them
24 $timdf= 7 ; California Time Zone
25 ; should really use ftime(2) for this and for
26 ; DST.
27 ;xfltg= 0 ;define to assmbl out floating hardware
28 rsx11d = 0 ; rsx11d features
29 debug = 0 ; <<< REEDS if non zero includes debug junk
30
31 ft.id= 1 ;have set i & d. set =0 if not
32
33 ft.unx = 1 ; this macro-11 is for UNIX. =0 if not.
34
35 .nlist bex
36
37 tab= 11
38 lf= 12
39 vt= 13
40 ff= 14
41 cr= 15
42 space= 40
43
44 bpmb = 20 ;bytes per macro block
45
46
47
48
49
50 .psect .text con, shr, gbl,ins
51 .psect .data con, dat, prv, gbl
52 .psect .bss con, bss, gbl
53
54 .psect dpure con, dat, prv, gbl
55 .psect mixed con, prv, gbl
56 .psect errmes con, dat, prv, gbl
57 .psect impure con, bss, gbl
58 .psect imppas con, bss, gbl
59 .psect implin con, bss, gbl
60 .psect swtsec con, dat, prv, gbl ; unix command line flags
61 .psect cndsec con, dat, prv, gbl ; gt, le, equ, etc. for '.if'
62 .psect crfsec con, dat, prv, gbl ; args for -cr flag
63 .psect edtsec con, dat, prv, gbl ; args for .enabl
64 .psect lctsec con, dat, prv, gbl ; args for .list
65 .psect psasec con, dat, prv, gbl
66 .psect pstsec con, dat, prv, gbl
67 .psect rolbas con, dat, prv, gbl ; core allocation: starts of tables
68 .psect rolsiz con, dat, prv, gbl ; sizes of table entries
69 .psect roltop con, dat, prv, gbl ; tops of tables
70 .psect xpcor con,bss , gbl ; this one MUST come last in core
71
72
72
73 .macro entsec name ;init a section
74 .psect name con
75 .endm entsec
76
77
78
79 .macro jeq x,?fred
80 bne fred
81 jmp x
82 fred:
83 .endm
84 .macro jne x,?fred
85 beq fred
86 jmp x
87 fred:
88 .endm
89 .macro xitsec
90 entsec .text
91 .endm xitsec
92
93
94 .macro call address
95 jsr pc,address
96 .endm
97
98 .macro return
99 rts pc
100 .endm
101
102
103 .macro always
104 .nlist bex
105 .endm always
106 .endm always
107
108
109 000001 .if ne debug
110
111 .macro ndebug n
112 .globl ndebug,..z
113 mov n,..z
114 call ndebug
115 .endm
116
117 .macro sdebug string
118 .globl sdebug,..z,..zbuf
119 x = 0
120 .irpc t,<string>
121 movb #''t,..zbuf+x
122 x = x+1
123 .endm
124 movb #0,..zbuf+x
125 mov #..zbuf,..z
126 call sdebug
127 .endm
128
129 .iff
130
131 .macro ndebug n
132 .endm
133
134 .macro sdebug string
135 .endm
136
137 .endc
138
139
140 .macro param mne, value ;define default parameters
141 .iif ndf mne, mne= value
142 .list
143 mne= mne
144 .nlist
145 .endm
145
146 .macro putkb addr ;list to kb
147 .globl putkb
148 mov addr,r0
149 call putkb
150 .endm
151
152 .macro putlp addr ;list to lp
153 .globl putlp
154 mov addr,r0
155 call putlp
156 .endm
157
158 .macro putkbl addr ;list to kb and lp
159 .globl putkbl
160 mov addr,r0
161 call putkbl
162 .endm
163
164
165 .macro xmit wrdcnt ;move small # of words
166 .globl xmit0
167 call xmit0-<wrdcnt*2>
168 .endm xmit
169
170
171 ;the macro "genswt" is used to specify a command
172 ;string switch (1st argument) and the address of
173 ;the routine to be called when encountered (2nd arg).
174 ; the switch is made upper-case.
175
176 .macro genswt mne,addr,?label
177 entsec swtsec
178 label: .irpc x,mne
179 .if ge ''x-141
180 .if le ''x-172
181 .byte ''x-40
182 .iff
183 .byte ''x
184 .endc
185 .iff
186 .byte ''x
187 .endc
188 .endm
189 .iif ne <.-label&1>, .byte 0
190 .word addr
191 xitsec
192 .endm
192
193 .macro zread chan
194 .globl zread
195 mov #chan'chn,r0
196 call zread
197 .endm zread
198
199 .macro zwrite chan
200 .globl zwrite
201 mov #chan'chn,r0
202 call zwrite
203 .endm zwrite
203
204 .macro genedt mne,subr ;gen enable/disable table
205 entsec edtsec
206 .rad50 /mne/
207 .if nb subr
208 .word subr
209 .iff
210 .word cpopj
211 .endc
212 .word ed.'mne
213 xitsec
214 .endm genedt
215
216
217 ;the macro "gencnd" is used to specify conditional
218 ;arguments. it takes two or three arguments:
219
220 ; 1- mnemonic
221 ; 2- subroutine to be called
222 ; 3- if non-blank, complement condition
223
224 .macro gencnd mne,subr,toggle ;generate conditional
225 entsec cndsec
226 .rad50 /mne/
227 .if b <toggle>
228 .word subr
229 .iff
230 .word subr+1
231 .endc
232 xitsec
233 .endm
233
234 .macro ch.mne
235
236 ch.ior= '!
237 ch.qtm= '"
238 ch.hsh= '#
239 ch.dol= '$
240 ch.pct= '%
241 ch.and= '&
242 ch.xcl= ''
243
244 ch.lp= '(
245 ch.rp= ')
246 ch.mul= '*
247 ch.add= '+
248 ch.com= ',
249 ch.sub= '-
250 ch.dot= '.
251 ch.div= '/
252
253 ch.col= ':
254 ch.smc= ';
255 ch.lab= '<
256 ch.equ= '=
257 ch.rab= '>
258 ch.qm= '?
259
260 ch.ind= '@
261 ch.bsl= '\
262 ch.uar= '^
263
264 let.a= 'a&^c40
265 let.b= 'b&^c40
266 let.c= 'c&^c40
267 let.d= 'd&^c40
268 let.e= 'e&^c40
269 let.f= 'f&^c40
270 let.g= 'g&^c40
271 let.o= 'o&^c40
272 let.p= 'p&^c40
273 let.r= 'r&^c40
274 let.z= 'z&^c40
275
276 dig.0= '0
277 dig.9= '9
278 .macro ch.mne
279 .endm ch.mne
280 .endm ch.mne
281
282 .macro error num,arg, mess ,?x
283 sdebug <num>
284 .globl err.'arg,ern'num, errbts,errref
285 .if b <mess>
286 deliberate error mistake
287 .endc
288 .if dif 0,num
289 .globl err.xx
290 tst err.xx
291 bne x
292 mov #ern'num,err.xx
293 x:
294 .endc
295 bis #err.'arg,errbts
296 .endm
297
298
299
300 .macro setnz addr ;set addr to non-zero for t/f flags
301 mov sp,addr
302 .endm
303
304
305 .macro bisbic arg ; used by .list/.nlist, .enabl/.dsabl
306 .globl bisbic
307 mov #arg,-(sp)
308 call bisbic
309 tst (sp)+
310 .endm
310
311 ;roll handler calls
312
313 .macro search rolnum ;binary search
314 mov #rolnum,r0
315 .globl search
316 call search
317 .endm
318
319 .macro scan rolnum ;linear scan
320 mov #rolnum,r0
321 .globl scan
322 call scan
323 .endm
324
325 .macro scanw rolnum ;linear scan, one word
326 mov #rolnum,r0
327 .globl scanw
328 call scanw
329 .endm
330
331 .macro next rolnum ;fetch next entry
332 mov #rolnum,r0
333 .globl next
334 call next
335 .endm
336
337 .macro append rolnum ;append to end of roll
338 mov #rolnum,r0
339 .globl append
340 call append
341 .endm
342
343 .macro zap rolnum ;clear roll
344 mov #rolnum,r0
345 .globl zap
346 call zap
347 .endm
348
349 ; call insert ;insert (must be preceded by one
350 ;of the above to set pointers)
351 ; call setrol ;save and set regs for above
351
352 ;flags used in symbol table mode
353
354 .macro st.flg
355
356 .if le ft.unx
357
358 ovrflg= 000004 ;overlay (psect only)
359 defflg= 000010 ;defined
360 relflg= 000040 ;relocatable
361 glbflg= 000100 ;global
362 dfgflg= 000200 ; default global <rsx11d>... reeds's guess
363
364
365 .endc
366
367 .if gt ft.unx
368
369 ; ****** these should not be changed!! ******
370 shrflg= 000001 ;shareable (psect only)
371 .if gt ft.id
372 insflg= shrflg*2 ;instruction space (psect only)
373 bssflg= insflg*2 ;blank section (psect only)
374 m.idf= shrflg!insflg!bssflg ;mask to turn them off
375 .iff
376 bssflg= shrflg*2
377 m.idf= shrflg!bssflg
378 .endc
379 b.idf= 1 ;shift count to make above bits word offset
380 ; ***********************************
381 defflg= 000010 ;defined
382 ovrflg= 000020 ;overlay (psect only)
383 relflg= 000040 ;relocatable
384 glbflg= 000100 ;global
385 dfgflg= 000200 ; default global <rsx11d>... reeds's guess
386
387 .endc
388
389 ;
390 ; default psect attribs.
391 ; can be changed, but make sure all customers know about
392 ; it, including all the linkers.
393 ;
394 pattrs=relflg!defflg ; For .psects and blank .csects
395 aattrs=glbflg!defflg!ovrflg ; For .asect
396 cattrs=glbflg!relflg!defflg!ovrflg ; For named .csects
397
398 regflg= 000001 ;register
399 lblflg= 000002 ;label
400 mdfflg= 000004 ;multilpy defined
401 .macro st.flg
402 .endm
403 .endm st.flg
404
405
406
407 .macro ct.mne
408 .globl cttbl
409 ct.eol = 000 ; eol
410 ct.com = 001 ; comma
411 ct.tab = 002 ; tab
412 ct.sp = 004 ; space
413 ct.pcx = 010 ; printing character
414 ct.num = 020 ; numeric
415 ct.alp = 040 ; alpha, dot, dollar
416 ct.lc = 100 ; lower case alpha
417 ct.smc = 200 ; semi-colon (sign bit)
418
419 ct.pc = ct.com!ct.smc!ct.pcx!ct.num!ct.alp
420 .macro ct.mne
421 .endm ct.mne
422 .endm ct.mne
423
424
425 .end
425
7 .include "2.11BSD/m11/often.m11"
1 .title often
2
3 ;
4 ; these are routines which get called periodically:
5 ;
6 ; xctlin once per line
7 ; xctpas once per pass
8 ; xctprg once per program
9 ;
10
11 .ident /sept81/
12
13 .mcall (at)always,st.flg
14 000000 always
1
2 .macro .data
3 entsec .data
4 .endm .data
5
6 .macro .text
7 entsec .text
8 .endm
9
10 .macro .bss
11 entsec .bss
12 .endm
13
14 000001 mk.symbol=1 ;one to make symbols, 0 otherwise
15 000000 x40= 0
16 000000 pdpv45= 0 ; host machine has 'mul', 'div', sob' instrucs.
17 ; if not you will have to write macros for them
18 000007 $timdf= 7 ; California Time Zone
19 ; should really use ftime(2) for this and for
20 ; DST.
21 ;xfltg= 0 ;define to assmbl out floating hardware
22 000000 rsx11d = 0 ; rsx11d features
23 000000 debug = 0 ; <<< REEDS if non zero includes debug junk
24
25 000001 ft.id= 1 ;have set i & d. set =0 if not
26
27 000001 ft.unx = 1 ; this macro-11 is for UNIX. =0 if not.
28
29 .nlist bex
30
31 000011 tab= 11
32 000012 lf= 12
33 000013 vt= 13
34 000014 ff= 14
35 000015 cr= 15
36 000040 space= 40
37
38 000020 bpmb = 20 ;bytes per macro block
39
40
41
42
43
./2.11BSD/m11/often.m11:14->ALWAYS:44: ***ERROR Unknown flag SHR given to .PSECT directive
44 .psect .text con, shr, gbl,ins
./2.11BSD/m11/often.m11:14->ALWAYS:45: ***ERROR Unknown flag DAT given to .PSECT directive
45 .psect .data con, dat, prv, gbl
./2.11BSD/m11/often.m11:14->ALWAYS:46: ***ERROR Unknown flag BSS given to .PSECT directive
46 .psect .bss con, bss, gbl
47
./2.11BSD/m11/often.m11:14->ALWAYS:48: ***ERROR Unknown flag DAT given to .PSECT directive
48 .psect dpure con, dat, prv, gbl
./2.11BSD/m11/often.m11:14->ALWAYS:49: ***ERROR Unknown flag PRV given to .PSECT directive
49 .psect mixed con, prv, gbl
./2.11BSD/m11/often.m11:14->ALWAYS:50: ***ERROR Unknown flag DAT given to .PSECT directive
50 .psect errmes con, dat, prv, gbl
./2.11BSD/m11/often.m11:14->ALWAYS:51: ***ERROR Unknown flag BSS given to .PSECT directive
51 .psect impure con, bss, gbl
./2.11BSD/m11/often.m11:14->ALWAYS:52: ***ERROR Unknown flag BSS given to .PSECT directive
52 .psect imppas con, bss, gbl
./2.11BSD/m11/often.m11:14->ALWAYS:53: ***ERROR Unknown flag BSS given to .PSECT directive
53 .psect implin con, bss, gbl
./2.11BSD/m11/often.m11:14->ALWAYS:54: ***ERROR Unknown flag DAT given to .PSECT directive
54 .psect swtsec con, dat, prv, gbl ; unix command line flags
./2.11BSD/m11/often.m11:14->ALWAYS:55: ***ERROR Unknown flag DAT given to .PSECT directive
55 .psect cndsec con, dat, prv, gbl ; gt, le, equ, etc. for '.if'
./2.11BSD/m11/often.m11:14->ALWAYS:56: ***ERROR Unknown flag DAT given to .PSECT directive
56 .psect crfsec con, dat, prv, gbl ; args for -cr flag
./2.11BSD/m11/often.m11:14->ALWAYS:57: ***ERROR Unknown flag DAT given to .PSECT directive
57 .psect edtsec con, dat, prv, gbl ; args for .enabl
./2.11BSD/m11/often.m11:14->ALWAYS:58: ***ERROR Unknown flag DAT given to .PSECT directive
58 .psect lctsec con, dat, prv, gbl ; args for .list
./2.11BSD/m11/often.m11:14->ALWAYS:59: ***ERROR Unknown flag DAT given to .PSECT directive
59 .psect psasec con, dat, prv, gbl
./2.11BSD/m11/often.m11:14->ALWAYS:60: ***ERROR Unknown flag DAT given to .PSECT directive
60 .psect pstsec con, dat, prv, gbl
./2.11BSD/m11/often.m11:14->ALWAYS:61: ***ERROR Unknown flag DAT given to .PSECT directive
61 .psect rolbas con, dat, prv, gbl ; core allocation: starts of tables
./2.11BSD/m11/often.m11:14->ALWAYS:62: ***ERROR Unknown flag DAT given to .PSECT directive
62 .psect rolsiz con, dat, prv, gbl ; sizes of table entries
./2.11BSD/m11/often.m11:14->ALWAYS:63: ***ERROR Unknown flag DAT given to .PSECT directive
63 .psect roltop con, dat, prv, gbl ; tops of tables
./2.11BSD/m11/often.m11:14->ALWAYS:64: ***ERROR Unknown flag BSS given to .PSECT directive
64 .psect xpcor con,bss , gbl ; this one MUST come last in core
65
66
67
68 .macro entsec name ;init a section
69 .psect name con
70 .endm entsec
71
72
73
74 .macro jeq x,?fred
75 bne fred
76 jmp x
77 fred:
78 .endm
79 .macro jne x,?fred
80 beq fred
81 jmp x
82 fred:
83 .endm
84 .macro xitsec
85 entsec .text
86 .endm xitsec
87
88
89 .macro call address
90 jsr pc,address
91 .endm
92
93 .macro return
94 rts pc
95 .endm
96
97
98 .macro always
99 .nlist bex
100 .endm always
15 000000 st.flg
1
2 000001 .if le ft.unx
3
4 ovrflg= 000004 ;overlay (psect only)
5 defflg= 000010 ;defined
6 relflg= 000040 ;relocatable
7 glbflg= 000100 ;global
8 dfgflg= 000200 ; default global <rsx11d>... reeds's guess
9
10
11 .endc
12
13 000001 .if gt ft.unx
14
15 ; ****** these should not be changed!! ******
16 000001 shrflg= 000001 ;shareable (psect only)
17 000001 .if gt ft.id
18 000002 insflg= shrflg*2 ;instruction space (psect only)
19 000004 bssflg= insflg*2 ;blank section (psect only)
20 000007 m.idf= shrflg!insflg!bssflg ;mask to turn them off
21 .iff
22 bssflg= shrflg*2
23 m.idf= shrflg!bssflg
24 .endc
25 000001 b.idf= 1 ;shift count to make above bits word offset
26 ; ***********************************
27 000010 defflg= 000010 ;defined
28 000020 ovrflg= 000020 ;overlay (psect only)
29 000040 relflg= 000040 ;relocatable
30 000100 glbflg= 000100 ;global
31 000200 dfgflg= 000200 ; default global <rsx11d>... reeds's guess
32
33 .endc
34
35 ;
36 ; default psect attribs.
37 ; can be changed, but make sure all customers know about
38 ; it, including all the linkers.
39 ;
40 000050 pattrs=relflg!defflg ; For .psects and blank .csects
41 000130 aattrs=glbflg!defflg!ovrflg ; For .asect
42 000170 cattrs=glbflg!relflg!defflg!ovrflg ; For named .csects
43
44 000001 regflg= 000001 ;register
45 000002 lblflg= 000002 ;label
46 000004 mdfflg= 000004 ;multilpy defined
47 .macro st.flg
48 .endm
16 .globl xctpas, xctlin, xctprg
17 .globl objsec
18 .globl macdfn
19
20 .globl lst.kb,ioftbl,lstchn, lst.lp
21 .globl lstflg, u.flag
22 .globl io.tty
23 .globl lstdev
24 .globl cradix,pcrcnt
25
26 .globl defttl,chrpnt, setchr,title,endvec
27
28 000000 .text
1 000000 entsec .text
1 000000 .psect .text con
29 xctprg:
30 000000 012700 000000' mov #^pl impure,r0
31 000004 005020 1$: clr (r0)+
32 000006 020027 000000' cmp r0,#^ph implin
33 000012 103774 blo 1$
34 000014 call fixtit
1 000014 004767 000116 jsr pc,fixtit
35 000020 005267 000006G inc endvec+6 ;default to no end vector
36
37 ; fall through to
38
39 xctpas:
40 000024 012700 000000' mov #^pl imppas,r0
41 000030 005020 1$: clr (r0)+
42 000032 020027 000000' cmp r0,#^ph implin
43 000036 103774 blo 1$
44
45 000040 105167 000000G comb objsec ;force sequence break
46
47 000044 012700 000000C mov #lst.kb*400,r0 ;set error slot
48 000050 105767 000000C tstb ioftbl+lstchn ;listing device?
49 000054 001410 beq 2$ ; no
50 000056 052700 000000C bis #lst.kb!100200,r0 ;yes, assume teletype
51 000062 032767 000000G 000000C bit #io.tty,ioftbl+lstchn ;true?
52 000070 001002 bne 2$ ; yes
53 000072 062700 000000C add #<lst.lp-lst.kb>*401,r0 ;no, upgrade to lp
54 000076 010067 000000G 2$: mov r0,lstdev ;set flags
55
56 3$:
57 000102 012767 000010 000000G mov #8.,cradix ;init to octal radix
58
59 000110 005067 000000G clr macdfn
60 ; fall through to
61
62 xctlin:
63 000114 012700 000000' mov #^pl implin,r0
64 000120 005020 1$: clr (r0)+
65 000122 020027 000000' cmp r0,#^ph implin
66 000126 103774 blo 1$
67
68 000130 005367 000000G dec pcrcnt
69 000134 return
1 000134 000207 rts pc
70
71 .globl fixtit
72 fixtit:
73 000136 012767 000000G 000000G mov #defttl,chrpnt
74 000144 call setchr
1 000144 004767 000000G jsr pc,setchr
75 000150 call title
1 000150 004767 000000G jsr pc,title
76 000154 return
1 000154 000207 rts pc
77 .end
77
7
Symbol table
$TIMDF= 000007 CHRPNT= ****** G GLBFLG= 000100 MACDFN= ****** G SHRFLG= 000001
. 000156R 002 CR = 000015 INSFLG= 000002 MDFFLG= 000004 SPACE = 000040
1$0 000004R L 002 CRADIX= ****** G IO.TTY= ****** G MK.SYM= 000001 TAB = 000011
1$1 000030R L 002 DEBUG = 000000 IOFTBL= ****** G OBJSEC= ****** G TITLE = ****** G
1$2 000120R L 002 DEFFLG= 000010 LBLFLG= 000002 OVRFLG= 000020 U.FLAG= ****** G
2$1 000076R L 002 DEFTTL= ****** G LF = 000012 PATTRS= 000050 VT = 000013
3$1 000102R L 002 DFGFLG= 000200 LST.KB= ****** G PCRCNT= ****** G X40 = 000000
AATTRS= 000130 ENDVEC= ****** G LST.LP= ****** G PDPV45= 000000 XCTLIN 000114RG 002
B.IDF = 000001 FF = 000014 LSTCHN= ****** G REGFLG= 000001 XCTPAS 000024RG 002
BPMB = 000020 FIXTIT 000136RG 002 LSTDEV= ****** G RELFLG= 000040 XCTPRG 000000RG 002
BSSFLG= 000004 FT.ID = 000001 LSTFLG= ****** G RSX11D= 000000
CATTRS= 000170 FT.UNX= 000001 M.IDF = 000007 SETCHR= ****** G
Program sections:
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
000000 001 (RW,I,LCL,REL,CON,NOSAV)
.TEXT 000156 002 (RW,I,LCL,REL,CON,NOSAV)
.DATA 000000 003 (RW,I,LCL,REL,CON,NOSAV)
.BSS 000000 004 (RW,I,LCL,REL,CON,NOSAV)
DPURE 000000 005 (RW,I,LCL,REL,CON,NOSAV)
MIXED 000000 006 (RW,I,LCL,REL,CON,NOSAV)
ERRMES 000000 007 (RW,I,LCL,REL,CON,NOSAV)
IMPURE 000000 008 (RW,I,LCL,REL,CON,NOSAV)
IMPPAS 000000 009 (RW,I,LCL,REL,CON,NOSAV)
IMPLIN 000000 010 (RW,I,LCL,REL,CON,NOSAV)
SWTSEC 000000 011 (RW,I,LCL,REL,CON,NOSAV)
CNDSEC 000000 012 (RW,I,LCL,REL,CON,NOSAV)
CRFSEC 000000 013 (RW,I,LCL,REL,CON,NOSAV)
EDTSEC 000000 014 (RW,I,LCL,REL,CON,NOSAV)
LCTSEC 000000 015 (RW,I,LCL,REL,CON,NOSAV)
PSASEC 000000 016 (RW,I,LCL,REL,CON,NOSAV)
PSTSEC 000000 017 (RW,I,LCL,REL,CON,NOSAV)
ROLBAS 000000 018 (RW,I,LCL,REL,CON,NOSAV)
ROLSIZ 000000 019 (RW,I,LCL,REL,CON,NOSAV)
ROLTOP 000000 020 (RW,I,LCL,REL,CON,NOSAV)
XPCOR 000000 021 (RW,I,LCL,REL,CON,NOSAV)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,988 @@
1 ;;;; Wrapper for 2.11BSD/m11/srch.m11
2 .list
3 .list
4 .list
5 000001 debug = 1
6 .include "2.11BSD/m11/at.sml"
1 .title at.sml - assembler/translator system macros
2 ; @(#)at.sml 1.3 11/3/82
3
4 .ident /10may4/
5
6 .macro always ;all files of macro
7
8 .macro .data
9 entsec .data
10 .endm .data
11
12 .macro .text
13 entsec .text
14 .endm
15
16 .macro .bss
17 entsec .bss
18 .endm
19
20 mk.symbol=1 ;one to make symbols, 0 otherwise
21 x40= 0
22 pdpv45= 0 ; host machine has 'mul', 'div', sob' instrucs.
23 ; if not you will have to write macros for them
24 $timdf= 7 ; California Time Zone
25 ; should really use ftime(2) for this and for
26 ; DST.
27 ;xfltg= 0 ;define to assmbl out floating hardware
28 rsx11d = 0 ; rsx11d features
29 debug = 0 ; <<< REEDS if non zero includes debug junk
30
31 ft.id= 1 ;have set i & d. set =0 if not
32
33 ft.unx = 1 ; this macro-11 is for UNIX. =0 if not.
34
35 .nlist bex
36
37 tab= 11
38 lf= 12
39 vt= 13
40 ff= 14
41 cr= 15
42 space= 40
43
44 bpmb = 20 ;bytes per macro block
45
46
47
48
49
50 .psect .text con, shr, gbl,ins
51 .psect .data con, dat, prv, gbl
52 .psect .bss con, bss, gbl
53
54 .psect dpure con, dat, prv, gbl
55 .psect mixed con, prv, gbl
56 .psect errmes con, dat, prv, gbl
57 .psect impure con, bss, gbl
58 .psect imppas con, bss, gbl
59 .psect implin con, bss, gbl
60 .psect swtsec con, dat, prv, gbl ; unix command line flags
61 .psect cndsec con, dat, prv, gbl ; gt, le, equ, etc. for '.if'
62 .psect crfsec con, dat, prv, gbl ; args for -cr flag
63 .psect edtsec con, dat, prv, gbl ; args for .enabl
64 .psect lctsec con, dat, prv, gbl ; args for .list
65 .psect psasec con, dat, prv, gbl
66 .psect pstsec con, dat, prv, gbl
67 .psect rolbas con, dat, prv, gbl ; core allocation: starts of tables
68 .psect rolsiz con, dat, prv, gbl ; sizes of table entries
69 .psect roltop con, dat, prv, gbl ; tops of tables
70 .psect xpcor con,bss , gbl ; this one MUST come last in core
71
72
72
73 .macro entsec name ;init a section
74 .psect name con
75 .endm entsec
76
77
78
79 .macro jeq x,?fred
80 bne fred
81 jmp x
82 fred:
83 .endm
84 .macro jne x,?fred
85 beq fred
86 jmp x
87 fred:
88 .endm
89 .macro xitsec
90 entsec .text
91 .endm xitsec
92
93
94 .macro call address
95 jsr pc,address
96 .endm
97
98 .macro return
99 rts pc
100 .endm
101
102
103 .macro always
104 .nlist bex
105 .endm always
106 .endm always
107
108
109 000001 .if ne debug
110
111 .macro ndebug n
112 .globl ndebug,..z
113 mov n,..z
114 call ndebug
115 .endm
116
117 .macro sdebug string
118 .globl sdebug,..z,..zbuf
119 x = 0
120 .irpc t,<string>
121 movb #''t,..zbuf+x
122 x = x+1
123 .endm
124 movb #0,..zbuf+x
125 mov #..zbuf,..z
126 call sdebug
127 .endm
128
129 .iff
130
131 .macro ndebug n
132 .endm
133
134 .macro sdebug string
135 .endm
136
137 .endc
138
139
140 .macro param mne, value ;define default parameters
141 .iif ndf mne, mne= value
142 .list
143 mne= mne
144 .nlist
145 .endm
145
146 .macro putkb addr ;list to kb
147 .globl putkb
148 mov addr,r0
149 call putkb
150 .endm
151
152 .macro putlp addr ;list to lp
153 .globl putlp
154 mov addr,r0
155 call putlp
156 .endm
157
158 .macro putkbl addr ;list to kb and lp
159 .globl putkbl
160 mov addr,r0
161 call putkbl
162 .endm
163
164
165 .macro xmit wrdcnt ;move small # of words
166 .globl xmit0
167 call xmit0-<wrdcnt*2>
168 .endm xmit
169
170
171 ;the macro "genswt" is used to specify a command
172 ;string switch (1st argument) and the address of
173 ;the routine to be called when encountered (2nd arg).
174 ; the switch is made upper-case.
175
176 .macro genswt mne,addr,?label
177 entsec swtsec
178 label: .irpc x,mne
179 .if ge ''x-141
180 .if le ''x-172
181 .byte ''x-40
182 .iff
183 .byte ''x
184 .endc
185 .iff
186 .byte ''x
187 .endc
188 .endm
189 .iif ne <.-label&1>, .byte 0
190 .word addr
191 xitsec
192 .endm
192
193 .macro zread chan
194 .globl zread
195 mov #chan'chn,r0
196 call zread
197 .endm zread
198
199 .macro zwrite chan
200 .globl zwrite
201 mov #chan'chn,r0
202 call zwrite
203 .endm zwrite
203
204 .macro genedt mne,subr ;gen enable/disable table
205 entsec edtsec
206 .rad50 /mne/
207 .if nb subr
208 .word subr
209 .iff
210 .word cpopj
211 .endc
212 .word ed.'mne
213 xitsec
214 .endm genedt
215
216
217 ;the macro "gencnd" is used to specify conditional
218 ;arguments. it takes two or three arguments:
219
220 ; 1- mnemonic
221 ; 2- subroutine to be called
222 ; 3- if non-blank, complement condition
223
224 .macro gencnd mne,subr,toggle ;generate conditional
225 entsec cndsec
226 .rad50 /mne/
227 .if b <toggle>
228 .word subr
229 .iff
230 .word subr+1
231 .endc
232 xitsec
233 .endm
233
234 .macro ch.mne
235
236 ch.ior= '!
237 ch.qtm= '"
238 ch.hsh= '#
239 ch.dol= '$
240 ch.pct= '%
241 ch.and= '&
242 ch.xcl= ''
243
244 ch.lp= '(
245 ch.rp= ')
246 ch.mul= '*
247 ch.add= '+
248 ch.com= ',
249 ch.sub= '-
250 ch.dot= '.
251 ch.div= '/
252
253 ch.col= ':
254 ch.smc= ';
255 ch.lab= '<
256 ch.equ= '=
257 ch.rab= '>
258 ch.qm= '?
259
260 ch.ind= '@
261 ch.bsl= '\
262 ch.uar= '^
263
264 let.a= 'a&^c40
265 let.b= 'b&^c40
266 let.c= 'c&^c40
267 let.d= 'd&^c40
268 let.e= 'e&^c40
269 let.f= 'f&^c40
270 let.g= 'g&^c40
271 let.o= 'o&^c40
272 let.p= 'p&^c40
273 let.r= 'r&^c40
274 let.z= 'z&^c40
275
276 dig.0= '0
277 dig.9= '9
278 .macro ch.mne
279 .endm ch.mne
280 .endm ch.mne
281
282 .macro error num,arg, mess ,?x
283 sdebug <num>
284 .globl err.'arg,ern'num, errbts,errref
285 .if b <mess>
286 deliberate error mistake
287 .endc
288 .if dif 0,num
289 .globl err.xx
290 tst err.xx
291 bne x
292 mov #ern'num,err.xx
293 x:
294 .endc
295 bis #err.'arg,errbts
296 .endm
297
298
299
300 .macro setnz addr ;set addr to non-zero for t/f flags
301 mov sp,addr
302 .endm
303
304
305 .macro bisbic arg ; used by .list/.nlist, .enabl/.dsabl
306 .globl bisbic
307 mov #arg,-(sp)
308 call bisbic
309 tst (sp)+
310 .endm
310
311 ;roll handler calls
312
313 .macro search rolnum ;binary search
314 mov #rolnum,r0
315 .globl search
316 call search
317 .endm
318
319 .macro scan rolnum ;linear scan
320 mov #rolnum,r0
321 .globl scan
322 call scan
323 .endm
324
325 .macro scanw rolnum ;linear scan, one word
326 mov #rolnum,r0
327 .globl scanw
328 call scanw
329 .endm
330
331 .macro next rolnum ;fetch next entry
332 mov #rolnum,r0
333 .globl next
334 call next
335 .endm
336
337 .macro append rolnum ;append to end of roll
338 mov #rolnum,r0
339 .globl append
340 call append
341 .endm
342
343 .macro zap rolnum ;clear roll
344 mov #rolnum,r0
345 .globl zap
346 call zap
347 .endm
348
349 ; call insert ;insert (must be preceded by one
350 ;of the above to set pointers)
351 ; call setrol ;save and set regs for above
351
352 ;flags used in symbol table mode
353
354 .macro st.flg
355
356 .if le ft.unx
357
358 ovrflg= 000004 ;overlay (psect only)
359 defflg= 000010 ;defined
360 relflg= 000040 ;relocatable
361 glbflg= 000100 ;global
362 dfgflg= 000200 ; default global <rsx11d>... reeds's guess
363
364
365 .endc
366
367 .if gt ft.unx
368
369 ; ****** these should not be changed!! ******
370 shrflg= 000001 ;shareable (psect only)
371 .if gt ft.id
372 insflg= shrflg*2 ;instruction space (psect only)
373 bssflg= insflg*2 ;blank section (psect only)
374 m.idf= shrflg!insflg!bssflg ;mask to turn them off
375 .iff
376 bssflg= shrflg*2
377 m.idf= shrflg!bssflg
378 .endc
379 b.idf= 1 ;shift count to make above bits word offset
380 ; ***********************************
381 defflg= 000010 ;defined
382 ovrflg= 000020 ;overlay (psect only)
383 relflg= 000040 ;relocatable
384 glbflg= 000100 ;global
385 dfgflg= 000200 ; default global <rsx11d>... reeds's guess
386
387 .endc
388
389 ;
390 ; default psect attribs.
391 ; can be changed, but make sure all customers know about
392 ; it, including all the linkers.
393 ;
394 pattrs=relflg!defflg ; For .psects and blank .csects
395 aattrs=glbflg!defflg!ovrflg ; For .asect
396 cattrs=glbflg!relflg!defflg!ovrflg ; For named .csects
397
398 regflg= 000001 ;register
399 lblflg= 000002 ;label
400 mdfflg= 000004 ;multilpy defined
401 .macro st.flg
402 .endm
403 .endm st.flg
404
405
406
407 .macro ct.mne
408 .globl cttbl
409 ct.eol = 000 ; eol
410 ct.com = 001 ; comma
411 ct.tab = 002 ; tab
412 ct.sp = 004 ; space
413 ct.pcx = 010 ; printing character
414 ct.num = 020 ; numeric
415 ct.alp = 040 ; alpha, dot, dollar
416 ct.lc = 100 ; lower case alpha
417 ct.smc = 200 ; semi-colon (sign bit)
418
419 ct.pc = ct.com!ct.smc!ct.pcx!ct.num!ct.alp
420 .macro ct.mne
421 .endm ct.mne
422 .endm ct.mne
423
424
425 .end
425
7 .include "2.11BSD/m11/srch.m11"
1 .title srch
2 .ident /03apr4/
3
4 .mcall (at)always,scan,genedt
5 .mcall (at)sdebug,ndebug
6 000000 always
1
2 .macro .data
3 entsec .data
4 .endm .data
5
6 .macro .text
7 entsec .text
8 .endm
9
10 .macro .bss
11 entsec .bss
12 .endm
13
14 000001 mk.symbol=1 ;one to make symbols, 0 otherwise
15 000000 x40= 0
16 000000 pdpv45= 0 ; host machine has 'mul', 'div', sob' instrucs.
17 ; if not you will have to write macros for them
18 000007 $timdf= 7 ; California Time Zone
19 ; should really use ftime(2) for this and for
20 ; DST.
21 ;xfltg= 0 ;define to assmbl out floating hardware
22 000000 rsx11d = 0 ; rsx11d features
23 000000 debug = 0 ; <<< REEDS if non zero includes debug junk
24
25 000001 ft.id= 1 ;have set i & d. set =0 if not
26
27 000001 ft.unx = 1 ; this macro-11 is for UNIX. =0 if not.
28
29 .nlist bex
30
31 000011 tab= 11
32 000012 lf= 12
33 000013 vt= 13
34 000014 ff= 14
35 000015 cr= 15
36 000040 space= 40
37
38 000020 bpmb = 20 ;bytes per macro block
39
40
41
42
43
./2.11BSD/m11/srch.m11:6->ALWAYS:44: ***ERROR Unknown flag SHR given to .PSECT directive
44 .psect .text con, shr, gbl,ins
./2.11BSD/m11/srch.m11:6->ALWAYS:45: ***ERROR Unknown flag DAT given to .PSECT directive
45 .psect .data con, dat, prv, gbl
./2.11BSD/m11/srch.m11:6->ALWAYS:46: ***ERROR Unknown flag BSS given to .PSECT directive
46 .psect .bss con, bss, gbl
47
./2.11BSD/m11/srch.m11:6->ALWAYS:48: ***ERROR Unknown flag DAT given to .PSECT directive
48 .psect dpure con, dat, prv, gbl
./2.11BSD/m11/srch.m11:6->ALWAYS:49: ***ERROR Unknown flag PRV given to .PSECT directive
49 .psect mixed con, prv, gbl
./2.11BSD/m11/srch.m11:6->ALWAYS:50: ***ERROR Unknown flag DAT given to .PSECT directive
50 .psect errmes con, dat, prv, gbl
./2.11BSD/m11/srch.m11:6->ALWAYS:51: ***ERROR Unknown flag BSS given to .PSECT directive
51 .psect impure con, bss, gbl
./2.11BSD/m11/srch.m11:6->ALWAYS:52: ***ERROR Unknown flag BSS given to .PSECT directive
52 .psect imppas con, bss, gbl
./2.11BSD/m11/srch.m11:6->ALWAYS:53: ***ERROR Unknown flag BSS given to .PSECT directive
53 .psect implin con, bss, gbl
./2.11BSD/m11/srch.m11:6->ALWAYS:54: ***ERROR Unknown flag DAT given to .PSECT directive
54 .psect swtsec con, dat, prv, gbl ; unix command line flags
./2.11BSD/m11/srch.m11:6->ALWAYS:55: ***ERROR Unknown flag DAT given to .PSECT directive
55 .psect cndsec con, dat, prv, gbl ; gt, le, equ, etc. for '.if'
./2.11BSD/m11/srch.m11:6->ALWAYS:56: ***ERROR Unknown flag DAT given to .PSECT directive
56 .psect crfsec con, dat, prv, gbl ; args for -cr flag
./2.11BSD/m11/srch.m11:6->ALWAYS:57: ***ERROR Unknown flag DAT given to .PSECT directive
57 .psect edtsec con, dat, prv, gbl ; args for .enabl
./2.11BSD/m11/srch.m11:6->ALWAYS:58: ***ERROR Unknown flag DAT given to .PSECT directive
58 .psect lctsec con, dat, prv, gbl ; args for .list
./2.11BSD/m11/srch.m11:6->ALWAYS:59: ***ERROR Unknown flag DAT given to .PSECT directive
59 .psect psasec con, dat, prv, gbl
./2.11BSD/m11/srch.m11:6->ALWAYS:60: ***ERROR Unknown flag DAT given to .PSECT directive
60 .psect pstsec con, dat, prv, gbl
./2.11BSD/m11/srch.m11:6->ALWAYS:61: ***ERROR Unknown flag DAT given to .PSECT directive
61 .psect rolbas con, dat, prv, gbl ; core allocation: starts of tables
./2.11BSD/m11/srch.m11:6->ALWAYS:62: ***ERROR Unknown flag DAT given to .PSECT directive
62 .psect rolsiz con, dat, prv, gbl ; sizes of table entries
./2.11BSD/m11/srch.m11:6->ALWAYS:63: ***ERROR Unknown flag DAT given to .PSECT directive
63 .psect roltop con, dat, prv, gbl ; tops of tables
./2.11BSD/m11/srch.m11:6->ALWAYS:64: ***ERROR Unknown flag BSS given to .PSECT directive
64 .psect xpcor con,bss , gbl ; this one MUST come last in core
65
66
67
68 .macro entsec name ;init a section
69 .psect name con
70 .endm entsec
71
72
73
74 .macro jeq x,?fred
75 bne fred
76 jmp x
77 fred:
78 .endm
79 .macro jne x,?fred
80 beq fred
81 jmp x
82 fred:
83 .endm
84 .macro xitsec
85 entsec .text
86 .endm xitsec
87
88
89 .macro call address
90 jsr pc,address
91 .endm
92
93 .macro return
94 rts pc
95 .endm
96
97
98 .macro always
99 .nlist bex
100 .endm always
7
8 .globl srchi
9 .globl search, next, scan, scanc, scanw
10 .globl append, insert, zap
11 .globl rolndx, rolupd, mactop , symbot
12
13 .globl symovf
14
15 .globl xmit0
16 .globl symlp, symhp, dumrol
17 .globl savreg, symbol
18
19 .if df rsx11d
20 .globl ed.reg, edmask, symrol, regrol, cpopj
21 .endc
22
23 000000 xitsec ;start in default sector
1 000000 entsec .text
1 000000 .psect .text con
24
25 srchi: ;search init
26 000000 012700 000000G mov #dumrol,r0 ;end of variable rolls
27 000004 016760 000000G 000000' 1$: mov symhp,<^pl rolbas>(r0) ;point all to top
28 000012 016760 000000G 000000' mov symhp,<^pl roltop>(r0)
29 000020 105060 000001' clrb <^pl rolsiz>+1(r0)
30 000024 162700 000002 sub #2,r0 ;get next lower
31 000030 002365 bge 1$
32 000032 016767 000000G 000012' mov symlp,mactop ;bottom is start of macros
33 000040 062767 000017 000012' add #bpmb-1,mactop ;must be even
34 000046 042767 000017 000012' bic #bpmb-1,mactop
35 000054 016767 000000G 000014' mov symhp,symbot ;for sake of 'uplift' <<< REEDS
36 000062 016767 000000G 000000G mov symhp,symlp ;symlp should always == symbot [debug, REEDS]
37 000070 return
1 000070 000207 rts pc
37
38 .if ndf rsx11d
39
40 search: ;binary roll search
41 call setrol ;set roll registers
42 mov r3,-(sp)
43 sub r3,r1 ;point one slot low
44 mov r2,r3
45 sub r1,r3 ;compute size
46 clr r0 ;get set to compute search offset
47 sec ; (r0 doubles as t/f flag)
48 1$: rol r0 ;shift bit
49 bic r0,r3 ;clear corresponding bit. last one?
50 bne 1$ ; no
51 2$: add r0,r1
52 3$: asr r0 ;end of iteration, halve offset
53 bic #2,r0 ;end?
54 beq 7$ ; yes
55 4$: cmp r2,r1 ;off in no-mans's land?
56 blos 6$ ; yes
57 cmp (r4),(r1) ;no, first words match?
58 bne 5$ ; no
59 cmp 2(r4),2(r1) ;yes, how about second?
60 beq 8$ ; yes, found
61 5$: bhi 2$ ;no, branch if too high
62 6$: sub r0,r1 ;lower index
63 br 3$
64
65 7$: cmp (r1)+,(r1)+ ;point to insertion slot
66 8$: mov (sp)+,r3
67 br scanx ;exit through scan
67
68 .iff
69
70 search:
71 000072 call setrol
1 000072 004767 001004 jsr pc,setrol
72 000076 032767 000000G 000000G bit #ed.reg,edmask ;register definition enabled?
73 000104 001017 bne 10$ ;if ne no
74 000106 020527 000000G cmp r5,#symrol ;symbol roll?
75 000112 001014 bne 10$ ;if ne no
76 000114 032714 000007 bit #7,(r4) ;make ruff ruff test bypass 90%
77 000120 001011 bne 10$ ;if ne don't check for register
78 000122 scan regrol ;scan register roll
1 000122 012700 000000G mov #regrol,r0
2 .globl scan
3 000126 call scan
1 000126 004767 000202 jsr pc,scan
79 000132 010567 000004' mov r5,rolndx ;restore roll index
80 000136 005700 tst r0 ;find symbol?
81 000140 001401 beq 10$ ;if eq no find em
82 000142 return ;
1 000142 000207 rts pc
83 000144 010146 10$: mov r1,-(sp) ;save roll base
84 000146 020102 cmp r1,r2 ;any in roll?
85 000150 001434 beq 5$ ;if eq no
86 000152 160302 sub r3,r2 ;calculate high and low bounds
87 000154 010100 mov r1,r0 ;
88 000156 042716 177770 bic #177770,(sp) ;
89 000162 010001 1$: mov r0,r1 ;calculate trial index
90 000164 060201 add r2,r1 ;
91 000166 006001 ror r1 ;halve result
92 000170 042701 000007 bic #7,r1 ;clear garbage bits
93 000174 051601 bis (sp),r1 ;
94 000176 021114 cmp (r1),(r4) ;compare high parts
95 000200 101014 bhi 3$ ;if hi set new high limit
96 000202 103405 blo 2$ ;if lo set new low limit
97 000204 026164 000002 000002 cmp 2(r1),2(r4) ;compare low parts
98 000212 001414 beq 6$ ;if eq hit
99 000214 101006 bhi 3$ ;if hi set new high limit
100 000216 010100 2$: mov r1,r0 ;set new low limit
101 000220 060300 add r3,r0 ;reduce by one more
102 000222 020002 cmp r0,r2 ;any more to search?
103 000224 101756 blos 1$ ;if los yes
104 000226 060301 add r3,r1 ;point to proper entry
105 000230 000404 br 5$ ;exit
106 000232 010102 3$: mov r1,r2 ;se new high limit
107 000234 160302 sub r3,r2 ;reduce by one more
108 000236 020002 cmp r0,r2 ;any more to search?
109 000240 101750 blos 1$ ;if los yes
110 000242 005000 5$: clr r0 ;set false flag
111 000244 005726 6$: tst (sp)+ ;clean stack
112 000246 000451 br scanx ;vammoosa
113
114 000250 genedt reg
1 000250 entsec edtsec
1 000000 .psect edtsec con
2 000000 070517 .rad50 /reg/
3 .if nb
4 .word
5 .iff
6 000002 000000G .word cpopj
7 .endc
8 000004 000000G .word ed.reg
9 000006 xitsec
1 000006 entsec .text
1 000250 .psect .text con
115
116 .endc
116
117 next: ;get the next entry
118 000250 call setrol
1 000250 004767 000626 jsr pc,setrol
119 000254 016700 000010' mov rolupd,r0
120 000260 060001 add r0,r1
121 000262 060300 add r3,r0
122 000264 020102 cmp r1,r2
123 000266 103441 blo scanx
124 000270 000437 br scanxf
125
126 scanw: ;scan one word
127 000272 call setrol ;set registers
1 000272 004767 000604 jsr pc,setrol
128 000276 005000 clr r0 ;assume false
129 000300 005200 1$: inc r0 ;tally entry count
130 000302 021411 cmp (r4),(r1) ;match?
131 000304 001437 beq scany ; yes
132 000306 060301 add r3,r1 ;no, increment pointer
133 000310 020102 cmp r1,r2 ;finished?
134 000312 103772 blo 1$ ; no
135 000314 005000 clr r0
136 000316 return ;yes, exit false
1 000316 000207 rts pc
137
138 scanc: ;scan continuation
139 000320 call setrof ;set regs
1 000320 004767 000562 jsr pc,setrof
140 000324 016701 000006' mov rolpnt,r1 ;get current pointer
141 000330 060301 add r3,r1 ;update
142 000332 000402 br scanf ;jump into middle
143
144 scan: ;linear roll scan
145 000334 call setrol ;set roll registers
1 000334 004767 000542 jsr pc,setrol
146 000340 005000 scanf: clr r0 ;assume false
147 000342 020102 1$: cmp r1,r2 ;end?
148 000344 103011 bhis scanxf ; yes, exit false
149 000346 005200 inc r0
150 000350 021411 cmp (r4),(r1) ;no, match on first words?
151 000352 001004 bne 2$ ; yes
152 000354 026461 000002 000002 cmp 2(r4),2(r1) ;no, how about second?
153 000362 001403 beq scanx ; yes
154 000364 060301 2$: add r3,r1 ;increment by size
155 000366 000765 br 1$
156
157 .enabl lsb
158 000370 005000 scanxf: clr r0 ;false exit
159 000372 010167 000006' scanx: mov r1,rolpnt ;set entry pointer
160 000376 010067 000010' mov r0,rolupd ;save flag
161 000402 001404 beq 1$ ;branch if not found
162 000404 010402 scany: mov r4,r2 ;pointer to "symbol"
163 000406 005403 neg r3 ;negate entry size
164 000410 000163 000000G jmp xmit0(r3) ;found, xfer arguments
165
166 000414 022424 1$: cmp (r4)+,(r4)+ ;bypass symbol itself
167 000416 006203 asr r3 ;get word count
168 000420 162703 000002 sub #2,r3 ;compensate for above cmp
169 000424 003402 ble 3$ ;branch if end
170 000426 005024 2$: clr (r4)+ ;clear word
171 000430 077302 sob r3,2$
172 000432 3$: return
1 000432 000207 rts pc
173 .dsabl lsb
173
174 append: ;append to end of roll
175 000434 call setrol
1 000434 004767 000442 jsr pc,setrol
176 000440 010267 000006' mov r2,rolpnt ;set pointer
177 000444 005067 000010' clr rolupd
178 000450 000402 br inserf
179
180 insert: ;insert in roll
181 000452 call setrof ;set roll registers (but no arg)
1 000452 004767 000430 jsr pc,setrof
182 000456 016700 000006' inserf: mov rolpnt,r0 ;points to proper slot
183 000462 005767 000010' tst rolupd ;was search true?
184 000466 001045 bne 5$ ; yes
185 000470 105265 000001' incb <^pl rolsiz>+1(r5) ;update entry count
186 000474 060365 000000' add r3,<^pl roltop>(r5) ;update top pointer
187 000500 020265 000002' cmp r2,<^pl rolbas>+2(r5) ;gap between rolls?
188 000504 001036 bne 5$ ; yes, just stuff it
189 000506 016701 000000' mov <^pl rolbas>,r1 ;ditto for separate stack
190 000512 010102 mov r1,r2
191 000514 160302 sub r3,r2
192 000516 010267 000014' mov r2,symbot
193 ;cmp r2,mactop ;room?
194 ;bhi 1$ ; yes
195 ;jmp symovf ;no, error
196 000522 012767 000000G 000002' mov #symovf,upbomb ; where to go on error
197 000530 call uplift
1 000530 004767 000072 jsr pc,uplift
198 000534 066700 000000' add upgap,r0
199 000540 066701 000000' add upgap,r1
200 000544 066702 000000' add upgap,r2
201
202 ; fall through...
203 000550 160100 1$: sub r1,r0 ;compute byte count
204 000552 006200 asr r0 ; now word count
205 000554 001402 beq 4$ ;branch if first time
206
207 000556 012122 2$: mov (r1)+,(r2)+ ;move an entry down
208 000560 077002 sob r0,2$
209 000562 160365 000000' 4$: sub r3,<^pl rolbas>(r5) ;decrement pointers
210 000566 160365 000000' sub r3,<^pl roltop>(r5)
211 000572 162705 000002 sub #2,r5 ;more rolls?
212 000576 002371 bge 4$ ; yes
213 000600 010200 mov r2,r0 ;point to insertion slot
214 000602 006203 5$: asr r3 ;halve size count
215 000604 012420 6$: mov (r4)+,(r0)+ ;move an entry into place
216 000606 077302 sob r3,6$ ;loop if not end
217 000610 016767 000000' 000014' mov <^pl rolbas>,symbot
218 000616 016767 000000' 000000G mov <^pl rolbas>,symlp
219 000624 return
1 000624 000207 rts pc
220
221
222 .globl $brkad, $brksy ; defined in exec.m11
223
224 .globl putn
225 uplift:: ;<<< REEDS. move all the rolls up in core
226 ; can be called from 'insert' above and also
227 ; from 'getblk' in mac.m11. Thanks to Steve
228 ; Ragle for showing the need for a call from
229 ; otherwise growing macros can scribble.
230 ; And to Joel Rubin for debugging help.
231 .irpc xx,<0123>
232 mov r'xx,-(sp)
233 .endm
1 000626 010046 mov r0,-(sp)
2 000630 010146 mov r1,-(sp)
3 000632 010246 mov r2,-(sp)
4 000634 010346 mov r3,-(sp)
234 000636 026767 000014' 000012' cmp symbot,mactop
235 000644 101404 blos 10$
236 000646 005067 000000' clr upgap
237 000652 000167 000174 jmp 99$
238 10$: ; go here if symbot <= mactop
239
240 000656 016767 000000G 000000' mov symhp,upgap ; stash old highest in-space address
241 000664 062767 010102 000000G add #10102,symhp
242 000672 042767 000077 000000G bic #77,symhp ; click bic rounds to next highest mult of 64
243
244 000700 016767 000000G 000000G mov symhp,$brkad
245 000706 016746 000000G mov $brkad,-(sp)
246 000712 005746 tst -(sp)
247 000714 000000G $sbrk
248 000716 103402 bcs 98$
249 000720 022626 cmp (sp)+,(sp)+
250 000722 000403 br 1$
251 98$:
252 000724 022626 cmp (sp)+,(sp)+
253 000726 000177 000002' jmp @upbomb ; error bail-out: symovf or macovf
254 1$:
255 000732 162767 000002 000000G sub #2,symhp ; new highest in-space address
256 000740 016700 000000G mov symhp,r0
257 000744 016701 000000' mov upgap,r1 ; recall old highest address
258 000750 010003 mov r0,r3
259 000752 160103 sub r1,r3 ; r3 has the distance syms were shifted
260 000754 016702 000000G mov symlp,r2 ; symlp is OLD bottom of symbols.
261 000760 005742 tst -(r2) ; r2 ==> word before old bottom
262 2$:
263 000762 011110 mov (r1),(r0)
264 000764 005741 tst -(r1)
265 000766 005740 tst -(r0)
266 000770 020102 cmp r1,r2
267 000772 001373 bne 2$
268
269 000774 010367 000000' 9$: mov r3,upgap ; how much the syms were lifted
270 001000 012700 000000G mov #dumrol,r0 ; swiped from srchi
271 001004 060360 000000' 3$: add r3,<^pl rolbas>(r0)
272 001010 060360 000000' add r3,<^pl roltop>(r0)
273 001014 162700 000002 sub #2,r0
274 001020 002371 bge 3$
275
276 001022 060367 000006' add r3,rolpnt
277 001026 060367 000000G add r3,symlp
278 001032 016767 000000G 000014' mov symlp,symbot
279 001040 005767 000010' tst rolupd
280 001044 001402 beq 30$
281 001046 060367 000010' add r3,rolupd
282 30$:
283 99$:
284 .irpc xx,<3210>
285 mov (sp)+,r'xx
286 .endm
1 001052 012603 mov (sp)+,r3
2 001054 012602 mov (sp)+,r2
3 001056 012601 mov (sp)+,r1
4 001060 012600 mov (sp)+,r0
287 001062 return
1 001062 000207 rts pc
288
289 001064 entsect mixed
1 000000 .psect mixed con
290 000000 upgap: .blkw
291 000002 upbomb:: .blkw ; contains address of error handler
292 000004 xitsec
1 000004 entsec .text
1 001064 .psect .text con
292
293 zap: ;empty a roll
294 001064 call setrol
1 001064 004767 000012 jsr pc,setrol
295 001070 010165 000000' mov r1,<^pl roltop>(r5) ;make top = bottom
296 001074 105065 000001' clrb <^pl rolsiz>+1(r5) ;clear entry count
297 001100 return
1 001100 000207 rts pc
298
299
300 setrol: ;set roll registers
301 001102 010067 000004' mov r0,rolndx ;set argument
302 001106 012600 setrof: mov (sp)+,r0 ;save return address
303 001110 call savreg ;save registers
1 001110 004767 000000G jsr pc,savreg
304 001114 010546 mov r5,-(sp) ; and current character
305 001116 016705 000004' mov rolndx,r5 ;set index
306 001122 016501 000000' mov <^pl rolbas>(r5),r1 ;current base
307 001126 016502 000000' mov <^pl roltop>(r5),r2 ;current top
308 001132 116503 000000' movb <^pl rolsiz>(r5),r3 ;entry size
309 001136 012704 000000G mov #symbol,r4 ;pointer to symbol
310 001142 call (r0) ;call proper routine
1 001142 004710 jsr pc,(r0)
311 001144 012605 mov (sp)+,r5 ;restore current character
312 001146 return ; and rest of regs
1 001146 000207 rts pc
313
314 001150 entsec mixed
1 000004 .psect mixed con
315 000004 rolndx: .blkw ;roll index
316 000006 rolpnt: .blkw ;roll pointer
317 000010 rolupd: .blkw ;roll update
318 000012 mactop: .blkw ;current top of macro storage
319 000014 symbot: .blkw ;current bottom of dynamic rolls.
320 ; @mactop<=@symbot or uplift will fix it
321 000016 xitsec
1 000016 entsec .text
1 001150 .psect .text con
322
323 .end
323
7
Symbol table
$BRKAD= ****** G 2$5 000556R L 002 CR = 000015 ROLNDX 000004RG 006 SYMBOL= ****** G
$BRKSY= ****** G 2$6 000762R L 002 DEBUG = 000000 ROLPNT 000006R 006 SYMBOT 000014RG 006
$SBRK = ****** GX 3$1 000232R L 002 DUMROL= ****** G ROLUPD 000010RG 006 SYMHP = ****** G
$TIMDF= 000007 3$4 000432R L 002 ED.REG= ****** G RSX11D= 000000 SYMLP = ****** G
. 001150R 002 3$6 001004R L 002 EDMASK= ****** G SAVREG= ****** G SYMOVF= ****** G
1$0 000004R L 002 30$6 001052R L 002 FF = 000014 SCAN 000334RG 002 SYMROL= ****** G
1$1 000162R L 002 4$5 000562R L 002 FT.ID = 000001 SCANC 000320RG 002 TAB = 000011
1$2 000300R L 002 5$1 000242R L 002 FT.UNX= 000001 SCANF 000340R 002 UPBOMB 000002RG 006
1$3 000342R L 002 5$5 000602R L 002 INSERF 000456R 002 SCANW 000272RG 002 UPGAP 000000R 006
1$4 000414R L 002 6$1 000244R L 002 INSERT 000452RG 002 SCANX 000372R 002 UPLIFT 000626RG 002
1$5 000550R L 002 6$5 000604R L 002 LF = 000012 SCANXF 000370R 002 VT = 000013
1$6 000732R L 002 9$6 000774R L 002 MACTOP 000012RG 006 SCANY 000404R 002 X40 = 000000
10$1 000144R L 002 98$6 000724R L 002 MK.SYM= 000001 SEARCH 000072RG 002 XMIT0 = ****** G
10$6 000656R L 002 99$6 001052R L 002 NEXT 000250RG 002 SETROF 001106R 002 ZAP 001064RG 002
2$1 000216R L 002 APPEND 000434RG 002 PDPV45= 000000 SETROL 001102R 002
2$3 000364R L 002 BPMB = 000020 PUTN = ****** G SPACE = 000040
2$4 000426R L 002 CPOPJ = ****** G REGROL= ****** G SRCHI 000000RG 002
Program sections:
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
000000 001 (RW,I,LCL,REL,CON,NOSAV)
.TEXT 001150 002 (RW,I,LCL,REL,CON,NOSAV)
.DATA 000000 003 (RW,I,LCL,REL,CON,NOSAV)
.BSS 000000 004 (RW,I,LCL,REL,CON,NOSAV)
DPURE 000000 005 (RW,I,LCL,REL,CON,NOSAV)
MIXED 000016 006 (RW,I,LCL,REL,CON,NOSAV)
ERRMES 000000 007 (RW,I,LCL,REL,CON,NOSAV)
IMPURE 000000 008 (RW,I,LCL,REL,CON,NOSAV)
IMPPAS 000000 009 (RW,I,LCL,REL,CON,NOSAV)
IMPLIN 000000 010 (RW,I,LCL,REL,CON,NOSAV)
SWTSEC 000000 011 (RW,I,LCL,REL,CON,NOSAV)
CNDSEC 000000 012 (RW,I,LCL,REL,CON,NOSAV)
CRFSEC 000000 013 (RW,I,LCL,REL,CON,NOSAV)
EDTSEC 000006 014 (RW,I,LCL,REL,CON,NOSAV)
LCTSEC 000000 015 (RW,I,LCL,REL,CON,NOSAV)
PSASEC 000000 016 (RW,I,LCL,REL,CON,NOSAV)
PSTSEC 000000 017 (RW,I,LCL,REL,CON,NOSAV)
ROLBAS 000000 018 (RW,I,LCL,REL,CON,NOSAV)
ROLSIZ 000000 019 (RW,I,LCL,REL,CON,NOSAV)
ROLTOP 000000 020 (RW,I,LCL,REL,CON,NOSAV)
XPCOR 000000 021 (RW,I,LCL,REL,CON,NOSAV)

View File

@@ -0,0 +1,472 @@
1 ;;;; Wrapper for 2.11BSD/m11/syscalls.m11
2 .list
3 .list
4 .list
5 000001 debug = 1
6 .include "2.11BSD/m11/at.sml"
1 .title at.sml - assembler/translator system macros
2 ; @(#)at.sml 1.3 11/3/82
3
4 .ident /10may4/
5
6 .macro always ;all files of macro
7
8 .macro .data
9 entsec .data
10 .endm .data
11
12 .macro .text
13 entsec .text
14 .endm
15
16 .macro .bss
17 entsec .bss
18 .endm
19
20 mk.symbol=1 ;one to make symbols, 0 otherwise
21 x40= 0
22 pdpv45= 0 ; host machine has 'mul', 'div', sob' instrucs.
23 ; if not you will have to write macros for them
24 $timdf= 7 ; California Time Zone
25 ; should really use ftime(2) for this and for
26 ; DST.
27 ;xfltg= 0 ;define to assmbl out floating hardware
28 rsx11d = 0 ; rsx11d features
29 debug = 0 ; <<< REEDS if non zero includes debug junk
30
31 ft.id= 1 ;have set i & d. set =0 if not
32
33 ft.unx = 1 ; this macro-11 is for UNIX. =0 if not.
34
35 .nlist bex
36
37 tab= 11
38 lf= 12
39 vt= 13
40 ff= 14
41 cr= 15
42 space= 40
43
44 bpmb = 20 ;bytes per macro block
45
46
47
48
49
50 .psect .text con, shr, gbl,ins
51 .psect .data con, dat, prv, gbl
52 .psect .bss con, bss, gbl
53
54 .psect dpure con, dat, prv, gbl
55 .psect mixed con, prv, gbl
56 .psect errmes con, dat, prv, gbl
57 .psect impure con, bss, gbl
58 .psect imppas con, bss, gbl
59 .psect implin con, bss, gbl
60 .psect swtsec con, dat, prv, gbl ; unix command line flags
61 .psect cndsec con, dat, prv, gbl ; gt, le, equ, etc. for '.if'
62 .psect crfsec con, dat, prv, gbl ; args for -cr flag
63 .psect edtsec con, dat, prv, gbl ; args for .enabl
64 .psect lctsec con, dat, prv, gbl ; args for .list
65 .psect psasec con, dat, prv, gbl
66 .psect pstsec con, dat, prv, gbl
67 .psect rolbas con, dat, prv, gbl ; core allocation: starts of tables
68 .psect rolsiz con, dat, prv, gbl ; sizes of table entries
69 .psect roltop con, dat, prv, gbl ; tops of tables
70 .psect xpcor con,bss , gbl ; this one MUST come last in core
71
72
72
73 .macro entsec name ;init a section
74 .psect name con
75 .endm entsec
76
77
78
79 .macro jeq x,?fred
80 bne fred
81 jmp x
82 fred:
83 .endm
84 .macro jne x,?fred
85 beq fred
86 jmp x
87 fred:
88 .endm
89 .macro xitsec
90 entsec .text
91 .endm xitsec
92
93
94 .macro call address
95 jsr pc,address
96 .endm
97
98 .macro return
99 rts pc
100 .endm
101
102
103 .macro always
104 .nlist bex
105 .endm always
106 .endm always
107
108
109 000001 .if ne debug
110
111 .macro ndebug n
112 .globl ndebug,..z
113 mov n,..z
114 call ndebug
115 .endm
116
117 .macro sdebug string
118 .globl sdebug,..z,..zbuf
119 x = 0
120 .irpc t,<string>
121 movb #''t,..zbuf+x
122 x = x+1
123 .endm
124 movb #0,..zbuf+x
125 mov #..zbuf,..z
126 call sdebug
127 .endm
128
129 .iff
130
131 .macro ndebug n
132 .endm
133
134 .macro sdebug string
135 .endm
136
137 .endc
138
139
140 .macro param mne, value ;define default parameters
141 .iif ndf mne, mne= value
142 .list
143 mne= mne
144 .nlist
145 .endm
145
146 .macro putkb addr ;list to kb
147 .globl putkb
148 mov addr,r0
149 call putkb
150 .endm
151
152 .macro putlp addr ;list to lp
153 .globl putlp
154 mov addr,r0
155 call putlp
156 .endm
157
158 .macro putkbl addr ;list to kb and lp
159 .globl putkbl
160 mov addr,r0
161 call putkbl
162 .endm
163
164
165 .macro xmit wrdcnt ;move small # of words
166 .globl xmit0
167 call xmit0-<wrdcnt*2>
168 .endm xmit
169
170
171 ;the macro "genswt" is used to specify a command
172 ;string switch (1st argument) and the address of
173 ;the routine to be called when encountered (2nd arg).
174 ; the switch is made upper-case.
175
176 .macro genswt mne,addr,?label
177 entsec swtsec
178 label: .irpc x,mne
179 .if ge ''x-141
180 .if le ''x-172
181 .byte ''x-40
182 .iff
183 .byte ''x
184 .endc
185 .iff
186 .byte ''x
187 .endc
188 .endm
189 .iif ne <.-label&1>, .byte 0
190 .word addr
191 xitsec
192 .endm
192
193 .macro zread chan
194 .globl zread
195 mov #chan'chn,r0
196 call zread
197 .endm zread
198
199 .macro zwrite chan
200 .globl zwrite
201 mov #chan'chn,r0
202 call zwrite
203 .endm zwrite
203
204 .macro genedt mne,subr ;gen enable/disable table
205 entsec edtsec
206 .rad50 /mne/
207 .if nb subr
208 .word subr
209 .iff
210 .word cpopj
211 .endc
212 .word ed.'mne
213 xitsec
214 .endm genedt
215
216
217 ;the macro "gencnd" is used to specify conditional
218 ;arguments. it takes two or three arguments:
219
220 ; 1- mnemonic
221 ; 2- subroutine to be called
222 ; 3- if non-blank, complement condition
223
224 .macro gencnd mne,subr,toggle ;generate conditional
225 entsec cndsec
226 .rad50 /mne/
227 .if b <toggle>
228 .word subr
229 .iff
230 .word subr+1
231 .endc
232 xitsec
233 .endm
233
234 .macro ch.mne
235
236 ch.ior= '!
237 ch.qtm= '"
238 ch.hsh= '#
239 ch.dol= '$
240 ch.pct= '%
241 ch.and= '&
242 ch.xcl= ''
243
244 ch.lp= '(
245 ch.rp= ')
246 ch.mul= '*
247 ch.add= '+
248 ch.com= ',
249 ch.sub= '-
250 ch.dot= '.
251 ch.div= '/
252
253 ch.col= ':
254 ch.smc= ';
255 ch.lab= '<
256 ch.equ= '=
257 ch.rab= '>
258 ch.qm= '?
259
260 ch.ind= '@
261 ch.bsl= '\
262 ch.uar= '^
263
264 let.a= 'a&^c40
265 let.b= 'b&^c40
266 let.c= 'c&^c40
267 let.d= 'd&^c40
268 let.e= 'e&^c40
269 let.f= 'f&^c40
270 let.g= 'g&^c40
271 let.o= 'o&^c40
272 let.p= 'p&^c40
273 let.r= 'r&^c40
274 let.z= 'z&^c40
275
276 dig.0= '0
277 dig.9= '9
278 .macro ch.mne
279 .endm ch.mne
280 .endm ch.mne
281
282 .macro error num,arg, mess ,?x
283 sdebug <num>
284 .globl err.'arg,ern'num, errbts,errref
285 .if b <mess>
286 deliberate error mistake
287 .endc
288 .if dif 0,num
289 .globl err.xx
290 tst err.xx
291 bne x
292 mov #ern'num,err.xx
293 x:
294 .endc
295 bis #err.'arg,errbts
296 .endm
297
298
299
300 .macro setnz addr ;set addr to non-zero for t/f flags
301 mov sp,addr
302 .endm
303
304
305 .macro bisbic arg ; used by .list/.nlist, .enabl/.dsabl
306 .globl bisbic
307 mov #arg,-(sp)
308 call bisbic
309 tst (sp)+
310 .endm
310
311 ;roll handler calls
312
313 .macro search rolnum ;binary search
314 mov #rolnum,r0
315 .globl search
316 call search
317 .endm
318
319 .macro scan rolnum ;linear scan
320 mov #rolnum,r0
321 .globl scan
322 call scan
323 .endm
324
325 .macro scanw rolnum ;linear scan, one word
326 mov #rolnum,r0
327 .globl scanw
328 call scanw
329 .endm
330
331 .macro next rolnum ;fetch next entry
332 mov #rolnum,r0
333 .globl next
334 call next
335 .endm
336
337 .macro append rolnum ;append to end of roll
338 mov #rolnum,r0
339 .globl append
340 call append
341 .endm
342
343 .macro zap rolnum ;clear roll
344 mov #rolnum,r0
345 .globl zap
346 call zap
347 .endm
348
349 ; call insert ;insert (must be preceded by one
350 ;of the above to set pointers)
351 ; call setrol ;save and set regs for above
351
352 ;flags used in symbol table mode
353
354 .macro st.flg
355
356 .if le ft.unx
357
358 ovrflg= 000004 ;overlay (psect only)
359 defflg= 000010 ;defined
360 relflg= 000040 ;relocatable
361 glbflg= 000100 ;global
362 dfgflg= 000200 ; default global <rsx11d>... reeds's guess
363
364
365 .endc
366
367 .if gt ft.unx
368
369 ; ****** these should not be changed!! ******
370 shrflg= 000001 ;shareable (psect only)
371 .if gt ft.id
372 insflg= shrflg*2 ;instruction space (psect only)
373 bssflg= insflg*2 ;blank section (psect only)
374 m.idf= shrflg!insflg!bssflg ;mask to turn them off
375 .iff
376 bssflg= shrflg*2
377 m.idf= shrflg!bssflg
378 .endc
379 b.idf= 1 ;shift count to make above bits word offset
380 ; ***********************************
381 defflg= 000010 ;defined
382 ovrflg= 000020 ;overlay (psect only)
383 relflg= 000040 ;relocatable
384 glbflg= 000100 ;global
385 dfgflg= 000200 ; default global <rsx11d>... reeds's guess
386
387 .endc
388
389 ;
390 ; default psect attribs.
391 ; can be changed, but make sure all customers know about
392 ; it, including all the linkers.
393 ;
394 pattrs=relflg!defflg ; For .psects and blank .csects
395 aattrs=glbflg!defflg!ovrflg ; For .asect
396 cattrs=glbflg!relflg!defflg!ovrflg ; For named .csects
397
398 regflg= 000001 ;register
399 lblflg= 000002 ;label
400 mdfflg= 000004 ;multilpy defined
401 .macro st.flg
402 .endm
403 .endm st.flg
404
405
406
407 .macro ct.mne
408 .globl cttbl
409 ct.eol = 000 ; eol
410 ct.com = 001 ; comma
411 ct.tab = 002 ; tab
412 ct.sp = 004 ; space
413 ct.pcx = 010 ; printing character
414 ct.num = 020 ; numeric
415 ct.alp = 040 ; alpha, dot, dollar
416 ct.lc = 100 ; lower case alpha
417 ct.smc = 200 ; semi-colon (sign bit)
418
419 ct.pc = ct.com!ct.smc!ct.pcx!ct.num!ct.alp
420 .macro ct.mne
421 .endm ct.mne
422 .endm ct.mne
423
424
425 .end
425
7 .include "2.11BSD/m11/syscalls.m11"
1 .globl $creat, $open, $close, $exit, $read, $write, $sbrk
2 .globl $seek, $gettod, $fork, $wait, $execv
3
4 104401 $exit = ^O104401
5 104402 $fork = ^O104402
6 104403 $read = ^O104403
7 104404 $write = ^O104404
8 104405 $open = ^O104405
9 104406 $close = ^O104406
10 104524 $wait = ^O104524
11 104410 $creat = ^O104410
12 104413 $execv = ^O104413
13 104564 $gettod = ^O104564
14 104505 $sbrk = ^O104505
15 104423 $seek = ^O104423
16
17 .end
17
7
Symbol table
$CLOSE= 104406 G $EXIT = 104401 G $OPEN = 104405 G $SEEK = 104423 G . 000000R 001
$CREAT= 104410 G $FORK = 104402 G $READ = 104403 G $WAIT = 104524 G DEBUG = 000001
$EXECV= 104413 G $GETTO= 104564 G $SBRK = 104505 G $WRITE= 104404 G
Program sections:
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
000000 001 (RW,I,LCL,REL,CON,NOSAV)

Some files were not shown because too many files have changed in this diff Show More