mirror of
https://github.com/open-simh/simtools.git
synced 2026-03-01 09:31:19 +00:00
Merge branch 'master' of https://github.com/tlhackque/open-simtools
# Conflicts: # .gitignore # extracters/ods2/Makefile
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,6 +1,8 @@
|
||||
\#*
|
||||
*~
|
||||
*.bak
|
||||
*.d
|
||||
*.dep
|
||||
*.o
|
||||
*.orig
|
||||
*.vhd
|
||||
|
||||
30
Makefile
30
Makefile
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
21
converters/cosy/Makefile
Normal 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
590
converters/cosy/cosy.c
Normal 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
24
converters/cosy/cosy.txt
Normal 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
35
converters/fsio/Changes
Normal 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
55
converters/fsio/Makefile
Normal 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
242
converters/fsio/declib.c
Normal 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
40
converters/fsio/declib.h
Normal 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
2490
converters/fsio/dos11.c
Normal file
File diff suppressed because it is too large
Load Diff
292
converters/fsio/dos11.h
Normal file
292
converters/fsio/dos11.h
Normal 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
1321
converters/fsio/dosmt.c
Normal file
File diff suppressed because it is too large
Load Diff
101
converters/fsio/dosmt.h
Normal file
101
converters/fsio/dosmt.h
Normal 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
|
||||
51
converters/fsio/fsio-dos11.1
Normal file
51
converters/fsio/fsio-dos11.1
Normal 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
|
||||
111
converters/fsio/fsio-dosmt.1
Normal file
111
converters/fsio/fsio-dosmt.1
Normal 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
|
||||
80
converters/fsio/fsio-os8.1
Normal file
80
converters/fsio/fsio-os8.1
Normal 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
|
||||
89
converters/fsio/fsio-rt11.1
Normal file
89
converters/fsio/fsio-rt11.1
Normal 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
343
converters/fsio/fsio.1
Normal 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
2187
converters/fsio/fsio.c
Normal file
File diff suppressed because it is too large
Load Diff
174
converters/fsio/fsio.h
Normal file
174
converters/fsio/fsio.h
Normal 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
332
converters/fsio/fsio.txt
Normal 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)
|
||||
317
converters/fsio/fsioSimh.txt
Normal file
317
converters/fsio/fsioSimh.txt
Normal 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
377
converters/fsio/local.c
Normal 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
3014
converters/fsio/os8.c
Normal file
File diff suppressed because it is too large
Load Diff
248
converters/fsio/os8.h
Normal file
248
converters/fsio/os8.h
Normal 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
2586
converters/fsio/rt11.c
Normal file
File diff suppressed because it is too large
Load Diff
306
converters/fsio/rt11.h
Normal file
306
converters/fsio/rt11.h
Normal 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
816
converters/fsio/tape.c
Normal 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
73
converters/fsio/tape.h
Normal 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
|
||||
20
converters/mksimtape/Makefile
Normal file
20
converters/mksimtape/Makefile
Normal 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)
|
||||
332
converters/mksimtape/mksimtape.c
Normal file
332
converters/mksimtape/mksimtape.c
Normal 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
|
||||
*
|
||||
*/
|
||||
|
||||
28
converters/mksimtape/mksimtape.txt
Normal file
28
converters/mksimtape/mksimtape.txt
Normal 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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
11
crossassemblers/macro11/.gitignore
vendored
Normal 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
|
||||
32
crossassemblers/macro11/.gitlab-ci.yml
Normal file
32
crossassemblers/macro11/.gitlab-ci.yml
Normal 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
45
crossassemblers/macro11/.indent.pro
vendored
Executable 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
|
||||
12
crossassemblers/macro11/.travis.yml
Normal file
12
crossassemblers/macro11/.travis.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
language: c
|
||||
dist: bionic
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
script:
|
||||
- make
|
||||
- cd tests
|
||||
- ./RunTests
|
||||
137
crossassemblers/macro11/CHANGES
Normal file
137
crossassemblers/macro11/CHANGES
Normal 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.
|
||||
87
crossassemblers/macro11/Makefile
Normal file
87
crossassemblers/macro11/Makefile
Normal 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 $@.$$$$
|
||||
187
crossassemblers/macro11/README
Normal file
187
crossassemblers/macro11/README
Normal 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.
|
||||
|
||||
=======================================================================
|
||||
@@ -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
|
||||
1878
crossassemblers/macro11/assemble.c
Normal file
1878
crossassemblers/macro11/assemble.c
Normal file
File diff suppressed because it is too large
Load Diff
19
crossassemblers/macro11/assemble.h
Normal file
19
crossassemblers/macro11/assemble.h
Normal 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
|
||||
833
crossassemblers/macro11/assemble_aux.c
Normal file
833
crossassemblers/macro11/assemble_aux.c
Normal 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, ¤t_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, ¤t_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);
|
||||
}
|
||||
98
crossassemblers/macro11/assemble_aux.h
Normal file
98
crossassemblers/macro11/assemble_aux.h
Normal 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
|
||||
108
crossassemblers/macro11/assemble_globals.c
Normal file
108
crossassemblers/macro11/assemble_globals.c
Normal 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 */
|
||||
94
crossassemblers/macro11/assemble_globals.h
Normal file
94
crossassemblers/macro11/assemble_globals.h
Normal 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
|
||||
@@ -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
957
crossassemblers/macro11/extree.c
Normal file
957
crossassemblers/macro11/extree.c
Normal 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;
|
||||
}
|
||||
|
||||
84
crossassemblers/macro11/extree.h
Normal file
84
crossassemblers/macro11/extree.h
Normal 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
|
||||
198
crossassemblers/macro11/listing.c
Normal file
198
crossassemblers/macro11/listing.c
Normal 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);
|
||||
}
|
||||
}
|
||||
69
crossassemblers/macro11/listing.h
Normal file
69
crossassemblers/macro11/listing.h
Normal 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
@@ -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
|
||||
|
||||
1
crossassemblers/macro11/macro11.supp
Normal file
1
crossassemblers/macro11/macro11.supp
Normal file
@@ -0,0 +1 @@
|
||||
leak:atexit_handler_alloc
|
||||
701
crossassemblers/macro11/macros.c
Normal file
701
crossassemblers/macro11/macros.c
Normal 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 = ¯o_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, ¯o_st);
|
||||
if (mac) {
|
||||
/* Remove from the symbol table... */
|
||||
remove_sym(&mac->sym, ¯o_st);
|
||||
free_macro(mac);
|
||||
}
|
||||
}
|
||||
|
||||
mac = new_macro(label);
|
||||
|
||||
if (!(called & CALLED_NODEFINE)) {
|
||||
add_table(&mac->sym, ¯o_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, ¯o_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, ¯o_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(¯o_st, &iter); mac != NULL; mac = (MACRO *) next_sym(¯o_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 = ¯o_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;
|
||||
}
|
||||
79
crossassemblers/macro11/macros.h
Normal file
79
crossassemblers/macro11/macros.h
Normal 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
|
||||
21
crossassemblers/macro11/make-git-info
Executable file
21
crossassemblers/macro11/make-git-info
Executable 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
|
||||
@@ -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
|
||||
582
crossassemblers/macro11/mlb-rsx.c
Normal file
582
crossassemblers/macro11/mlb-rsx.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
404
crossassemblers/macro11/mlb-rt11.c
Normal file
404
crossassemblers/macro11/mlb-rt11.c
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
|
||||
106
crossassemblers/macro11/mlb2.c
Normal file
106
crossassemblers/macro11/mlb2.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
4
crossassemblers/macro11/obj2bin/.gitignore
vendored
Normal file
4
crossassemblers/macro11/obj2bin/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# ignore these files:
|
||||
# ignore these directories:
|
||||
tests/
|
||||
# the end
|
||||
162
crossassemblers/macro11/obj2bin/README.md
Normal file
162
crossassemblers/macro11/obj2bin/README.md
Normal 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.
|
||||
|
||||
```
|
||||
1271
crossassemblers/macro11/obj2bin/obj2bin.pl
Normal file
1271
crossassemblers/macro11/obj2bin/obj2bin.pl
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
|
||||
1503
crossassemblers/macro11/parse.c
Normal file
1503
crossassemblers/macro11/parse.c
Normal file
File diff suppressed because it is too large
Load Diff
74
crossassemblers/macro11/parse.h
Normal file
74
crossassemblers/macro11/parse.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
406
crossassemblers/macro11/rept_irpc.c
Normal file
406
crossassemblers/macro11/rept_irpc.c
Normal 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;
|
||||
}
|
||||
26
crossassemblers/macro11/rept_irpc.h
Normal file
26
crossassemblers/macro11/rept_irpc.h
Normal 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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
798
crossassemblers/macro11/symbols.c
Normal file
798
crossassemblers/macro11/symbols.c
Normal 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, ®ister_section, &system_st);
|
||||
reg_sym[1] = add_sym("R1", 1, S, ®ister_section, &system_st);
|
||||
reg_sym[2] = add_sym("R2", 2, S, ®ister_section, &system_st);
|
||||
reg_sym[3] = add_sym("R3", 3, S, ®ister_section, &system_st);
|
||||
reg_sym[4] = add_sym("R4", 4, S, ®ister_section, &system_st);
|
||||
reg_sym[5] = add_sym("R5", 5, S, ®ister_section, &system_st);
|
||||
reg_sym[6] = add_sym("SP", 6, S, ®ister_section, &system_st);
|
||||
reg_sym[7] = add_sym("PC", 7, S, ®ister_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, §ion_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");
|
||||
}
|
||||
419
crossassemblers/macro11/symbols.h
Normal file
419
crossassemblers/macro11/symbols.h
Normal 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
|
||||
1293
crossassemblers/macro11/tests/2.11BSD-m11-code.lst.ok
Normal file
1293
crossassemblers/macro11/tests/2.11BSD-m11-code.lst.ok
Normal file
File diff suppressed because it is too large
Load Diff
658
crossassemblers/macro11/tests/2.11BSD-m11-debug.lst.ok
Normal file
658
crossassemblers/macro11/tests/2.11BSD-m11-debug.lst.ok
Normal 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)
|
||||
1246
crossassemblers/macro11/tests/2.11BSD-m11-errs.lst.ok
Normal file
1246
crossassemblers/macro11/tests/2.11BSD-m11-errs.lst.ok
Normal file
File diff suppressed because it is too large
Load Diff
4714
crossassemblers/macro11/tests/2.11BSD-m11-exec.lst.ok
Normal file
4714
crossassemblers/macro11/tests/2.11BSD-m11-exec.lst.ok
Normal file
File diff suppressed because it is too large
Load Diff
1791
crossassemblers/macro11/tests/2.11BSD-m11-expr.lst.ok
Normal file
1791
crossassemblers/macro11/tests/2.11BSD-m11-expr.lst.ok
Normal file
File diff suppressed because it is too large
Load Diff
1006
crossassemblers/macro11/tests/2.11BSD-m11-fltg.lst.ok
Normal file
1006
crossassemblers/macro11/tests/2.11BSD-m11-fltg.lst.ok
Normal file
File diff suppressed because it is too large
Load Diff
1619
crossassemblers/macro11/tests/2.11BSD-m11-getl.lst.ok
Normal file
1619
crossassemblers/macro11/tests/2.11BSD-m11-getl.lst.ok
Normal file
File diff suppressed because it is too large
Load Diff
2674
crossassemblers/macro11/tests/2.11BSD-m11-lout.lst.ok
Normal file
2674
crossassemblers/macro11/tests/2.11BSD-m11-lout.lst.ok
Normal file
File diff suppressed because it is too large
Load Diff
2330
crossassemblers/macro11/tests/2.11BSD-m11-mac.lst.ok
Normal file
2330
crossassemblers/macro11/tests/2.11BSD-m11-mac.lst.ok
Normal file
File diff suppressed because it is too large
Load Diff
1333
crossassemblers/macro11/tests/2.11BSD-m11-macro.lst.ok
Normal file
1333
crossassemblers/macro11/tests/2.11BSD-m11-macro.lst.ok
Normal file
File diff suppressed because it is too large
Load Diff
1243
crossassemblers/macro11/tests/2.11BSD-m11-misc.lst.ok
Normal file
1243
crossassemblers/macro11/tests/2.11BSD-m11-misc.lst.ok
Normal file
File diff suppressed because it is too large
Load Diff
736
crossassemblers/macro11/tests/2.11BSD-m11-often.lst.ok
Normal file
736
crossassemblers/macro11/tests/2.11BSD-m11-often.lst.ok
Normal 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)
|
||||
3070
crossassemblers/macro11/tests/2.11BSD-m11-pst.lst.ok
Normal file
3070
crossassemblers/macro11/tests/2.11BSD-m11-pst.lst.ok
Normal file
File diff suppressed because it is too large
Load Diff
988
crossassemblers/macro11/tests/2.11BSD-m11-srch.lst.ok
Normal file
988
crossassemblers/macro11/tests/2.11BSD-m11-srch.lst.ok
Normal 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)
|
||||
472
crossassemblers/macro11/tests/2.11BSD-m11-syscalls.lst.ok
Normal file
472
crossassemblers/macro11/tests/2.11BSD-m11-syscalls.lst.ok
Normal 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
Reference in New Issue
Block a user