remove obsolete C code

This commit is contained in:
Mikael Pettersson
2023-08-19 19:18:51 +02:00
parent dfd5ef162e
commit 632c3aafe5
55 changed files with 7 additions and 11250 deletions

View File

@@ -1,94 +0,0 @@
/*
* 8to9.c -- convert octet files to nonet files
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "pdp10-stdio.h"
#define VERSION "pdp10-tools 8to9 version 0.0, built " __DATE__ " " __TIME__ "\n"
int main(int argc, char **argv)
{
const char *infile, *outfile;
FILE *infp;
PDP10_FILE *outfp;
int ch;
infile = NULL;
outfile = NULL;
for (;;) {
ch = getopt(argc, argv, "Vi:o:");
switch (ch) {
case 'V':
printf(VERSION);
return 0;
case 'i':
infile = optarg;
continue;
case 'o':
outfile = optarg;
continue;
case -1:
break;
default:
fprintf(stderr, "%s -o OUTFILE [-i INFILE] [-V]\n", argv[0]);
return 1;
}
break;
}
/* XXX: We currently require a named output file because pdp10-stdio.c doesn't
support fdopen:ing non-seekable files. That should be fixed at some point. */
if (!outfile) {
fprintf(stderr, "%s: no OUTFILE specified\n", argv[0]);
return 1;
} else {
outfp = pdp10_fopen(outfile, "wb");
if (!outfp) {
fprintf(stderr, "%s: %s: failed to open for writing: %s\n", argv[0], outfile, strerror(errno));
return 1;
}
}
if (!infile) {
infp = stdin;
} else {
infp = fopen(infile, "rb");
if (!infp) {
fprintf(stderr, "%s: %s: failed to open for reading: %s\n", argv[0], infile, strerror(errno));
return 1;
}
}
while ((ch = fgetc(infp)) != EOF)
if (pdp10_fputc(ch, outfp) == EOF) {
fprintf(stderr, "%s: %s: failed to write: %s\n", argv[0], outfile, strerror(errno));
return 1;
}
if (pdp10_fclose(outfp) == EOF) {
fprintf(stderr, "%s: %s: failed to close: %s\n", argv[0], outfile, strerror(errno));
return 1;
}
return 0;
}

View File

@@ -1,32 +0,0 @@
# 8to9/Makefile
# Copyright (C) 2013-2015 Mikael Pettersson
#
# This file is part of pdp10-tools.
#
# pdp10-tools is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pdp10-tools is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
CC=gcc
CFLAGS=-O2 -g -Wall
CPPFLAGS=-I../include
8TO9OBJS=8to9.o
LIBOBJS=../lib/pdp10-stdio.o
8to9: $(8TO9OBJS) $(LIBOBJS)
$(LINK.c) -o $@ $^
8to9.o: 8to9.c ../include/pdp10-stdint.h ../include/pdp10-stdio.h
clean:
rm -f $(8TO9OBJS) 8to9 a.out core.*

View File

@@ -1,5 +1,5 @@
# Makefile for pdp10-tools
# Copyright (C) 2013-2018 Mikael Pettersson
# Copyright (C) 2013-2023 Mikael Pettersson
#
# This file is part of pdp10-tools.
#
@@ -16,7 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
SUBDIRS= lib 8to9 ar as nm od readelf sim
SUBDIRS= erlang
all:
make TARGET= subdirs

12
TODO
View File

@@ -1,5 +1,5 @@
# TODO notes for pdp10-tools
# Copyright (C) 2013-2020 Mikael Pettersson <mikpelinux@gmail.com>
# Copyright (C) 2013-2023 Mikael Pettersson <mikpelinux@gmail.com>
#
# This file is part of pdp10-tools.
#
@@ -33,9 +33,7 @@ Tools:
- top-level Makefile: subdirs should error out on error in subdir
- size: implement it
- strip: implement it
- as:
* tunit_{strtab_,}section_enter() should be generalized and merged
* what happens if user defines .comment as say text, and later enters .ident?
* output: move section_symtab into the context
* tunit: add symtab sections analagous to strtab sections?
* add support for extended opcodes (emit second opcode after current .text section)
- ranlib: add wrapper script doing 'ar s'
- sim: improve it so it can run simple applications
- as/ld: add support for PIC
- as/ld: add support for shared objects

View File

@@ -1,32 +0,0 @@
# ar/Makefile
# Copyright (C) 2013-2015 Mikael Pettersson
#
# This file is part of pdp10-tools.
#
# pdp10-tools is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pdp10-tools is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
CC=gcc
CFLAGS=-O2 -g -Wall
CPPFLAGS=-I../include
AROBJS= ar.o
LIBOBJS=../lib/pdp10-stdio.o
ar: $(AROBJS) $(LIBOBJS)
$(LINK.c) -o $@ $^
ar.o: ar.c ../include/pdp10-ar.h ../include/pdp10-inttypes.h ../include/pdp10-stdint.h ../include/pdp10-stdio.h
clean:
rm -f $(AROBJS) ar a.out core.*

1020
ar/ar.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,40 +0,0 @@
# as/Makefile
# Copyright (C) 2013-2015 Mikael Pettersson
#
# This file is part of pdp10-tools.
#
# pdp10-tools is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pdp10-tools is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
CC=gcc
CFLAGS=-O2 -g -Wall
CPPFLAGS=-I../include
ASOBJS=assemble.o hashtab.o input.o main.o output.o parse.o scan.o token.o tunit.o
LIBOBJS=../lib/pdp10-elf36.o ../lib/pdp10-extint.o ../lib/pdp10-opcodes.o ../lib/pdp10-stdio.o
as: $(ASOBJS) $(LIBOBJS)
$(LINK.c) -o $@ $^
assemble.o: assemble.h tunit.h hashtab.h
hashtab.o: hashtab.h
input.o: hashtab.h input.h parse.h scan.h tunit.h token.h token.def
main.o: assemble.h input.h output.h tunit.h hashtab.h
output.o: output.h tunit.h hashtab.h
parse.o: input.h scan.h token.h tunit.h token.def hashtab.h
scan.o: scan.h token.h token.def
token.o: token.h token.def
tunit.o: hashtab.h tunit.h
clean:
rm -f $(ASOBJS) as a.out core.*

View File

@@ -1,106 +0,0 @@
/*
* assemble.c
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "assemble.h"
#include "hashtab.h"
#include "tunit.h"
#include "pdp10-extint.h"
static int assemble_section(struct hashnode *hashnode, void *data)
{
struct section *section = container_of(hashnode, struct section, hashnode);
struct tunit *tunit = data;
unsigned long dot;
struct stmt *stmt;
/* if it's not .text-like then we have nothing to do (for now) */
if (section->sh_type != SHT_PROGBITS
|| section->sh_flags != (SHF_ALLOC | SHF_EXECINSTR))
return 0;
section->dot = (section->dot + 3) & ~(unsigned long)3;
section->image = malloc(section->dot * sizeof(pdp10_uint9_t));
if (!section->image) {
fprintf(stderr, "%s: %s: failed to allocate %zu bytes for text image: %s\n",
tunit->progname, __FUNCTION__, section->dot * sizeof(pdp10_uint9_t), strerror(errno));
return -1;
}
dot = 0;
for (stmt = section->head; stmt; stmt = stmt->next) {
switch (stmt->tag) {
case S_LABEL:
{
struct symbol *symbol;
symbol = tunit_symbol_lookup(tunit, stmt->u.symbol.name);
if (!symbol)
return -1;
if (symbol->section != section
|| !symbol->defined
|| symbol->st_value != dot)
return -1;
break;
}
case S_INSN:
{
pdp10_uint36_t word;
struct pdp10_ext_uint36 ext36;
unsigned int i;
if (dot >= section->dot) {
fprintf(stderr, "%s: %s: internal error: text image overflow\n", tunit->progname, __FUNCTION__);
return -1;
}
word =
((pdp10_uint36_t)(stmt->u.insn.opcode & 0x1FF) << (36 - 9)
| ((stmt->u.insn.accumulator & 0xF) << (36 - 13))
| ((stmt->u.insn.at & 1) << (36 - 14))
| ((stmt->u.insn.indexreg & 0xF) << (36 - 18))
| (stmt->u.insn.address & PDP10_UINT18_MAX));
pdp10_uint36_to_ext(word, &ext36);
for (i = 0; i < 4; ++i)
section->image[dot + i] = ext36.nonet[i];
dot += 4;
break;
}
default:
break;
}
}
if (dot != section->dot) {
fprintf(stderr, "%s: %s: internal error: text image size mismatch\n", tunit->progname, __FUNCTION__);
return -1;
}
return 0;
}
int assemble(struct tunit *tunit)
{
return hashtab_enumerate(&tunit->sections, assemble_section, tunit);
}

View File

@@ -1,27 +0,0 @@
/*
* assemble.h
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ASSEMBLE_H
#define ASSEMBLE_H
#include "tunit.h"
int assemble(struct tunit *tunit);
#endif /* ASSEMBLE_H */

View File

@@ -1,167 +0,0 @@
/*
* hashtab.c
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "hashtab.h"
static struct hashnode **hashtab_alloc_bucket(unsigned int nrelem)
{
size_t nrbytes;
struct hashnode **bucket;
unsigned int i;
nrbytes = nrelem * sizeof(struct hashnode*);
bucket = malloc(nrbytes);
if (!bucket) {
fprintf(stderr, "%s: malloc(%zu) failed: %s\n", __FUNCTION__, nrbytes, strerror(errno));
return NULL;
}
for (i = 0; i < nrelem; ++i)
bucket[i] = NULL;
return bucket;
}
int hashtab_init(struct hashtab *hashtab, unsigned int log2size, hashtab_eq_func_t eq_func)
{
unsigned int size;
size = 1 << log2size;
hashtab->log2size = log2size;
hashtab->mask = size - 1;
hashtab->used = 0;
hashtab->eq_func = eq_func;
hashtab->bucket = hashtab_alloc_bucket(size);
return hashtab->bucket ? 0 : -1;
}
struct hashnode *hashtab_lookup(const struct hashtab *hashtab, uintptr_t hashval, const void *data)
{
unsigned int i;
struct hashnode *hashnode;
i = hashval & hashtab->mask;
hashnode = hashtab->bucket[i];
while (hashnode != NULL) {
if (hashnode->hashval == hashval
&& (hashtab->eq_func == NULL || (*hashtab->eq_func)(hashnode, data) != 0))
break;
hashnode = hashnode->next;
}
return hashnode;
}
static int hashtab_grow(struct hashtab *hashtab)
{
unsigned int old_size, new_size, new_mask, i;
struct hashnode **old_bucket, **new_bucket;
old_size = 1 << hashtab->log2size;
new_size = old_size << 1;
new_bucket = hashtab_alloc_bucket(new_size);
if (!new_bucket)
return -1;
old_bucket = hashtab->bucket;
hashtab->log2size += 1;
new_mask = new_size - 1;
hashtab->mask = new_mask;
hashtab->bucket = new_bucket;
for (i = 0; i < old_size; ++i) {
struct hashnode *hashnode = old_bucket[i];
while (hashnode != NULL) {
struct hashnode *next = hashnode->next;
unsigned int j = hashnode->hashval & new_mask;
hashnode->next = new_bucket[j];
new_bucket[j] = hashnode;
hashnode = next;
}
}
free(old_bucket);
return 0;
}
int hashtab_insert(struct hashtab *hashtab, struct hashnode *hashnode)
{
unsigned int i, size;
i = hashnode->hashval & hashtab->mask;
hashnode->next = hashtab->bucket[i];
hashtab->bucket[i] = hashnode;
hashtab->used += 1;
size = 1 << hashtab->log2size;
if (hashtab->used > (4 * size) / 5) /* rehash at 80% */
return hashtab_grow(hashtab);
return 0;
}
struct hashnode *hashtab_reset(struct hashtab *hashtab)
{
unsigned int i, size;
struct hashnode **bucket, *all_nodes, *head, *tail;
all_nodes = NULL;
bucket = hashtab->bucket;
size = 1 << hashtab->log2size;
for (i = 0; i < size; ++i) {
head = bucket[i];
if (head) {
bucket[i] = NULL;
tail = head;
while (tail->next)
tail = tail->next;
tail->next = all_nodes;
all_nodes = head;
}
}
hashtab->used = 0;
return all_nodes;
}
int hashtab_enumerate(const struct hashtab *hashtab,
int (*func)(struct hashnode *hashnode, void *data),
void *data)
{
unsigned int i, size;
struct hashnode **bucket, *head;
int status;
bucket = hashtab->bucket;
size = 1 << hashtab->log2size;
for (i = 0; i < size; ++i) {
head = bucket[i];
while (head != NULL) {
status = (*func)(head, data);
if (status != 0)
return status;
head = head->next;
}
}
return 0;
}

View File

@@ -1,52 +0,0 @@
/*
* hashtab.h
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HASHTAB_H
#define HASHTAB_H
#include <stdint.h> /* uintptr_t */
struct hashnode {
uintptr_t hashval;
struct hashnode *next;
};
typedef int (*hashtab_eq_func_t)(const struct hashnode *hashnode, const void *data);
struct hashtab {
unsigned int log2size;
unsigned int mask; /* INV: mask == (1 << log2size) - 1 */
unsigned int used;
hashtab_eq_func_t eq_func;
struct hashnode **bucket;
};
int hashtab_init(struct hashtab *hashtab, unsigned int log2size, hashtab_eq_func_t eq_func);
struct hashnode *hashtab_lookup(const struct hashtab *hashtab, uintptr_t hashval, const void *data);
int hashtab_insert(struct hashtab *hashtab, struct hashnode *hashnode);
struct hashnode *hashtab_reset(struct hashtab *hashtab);
int hashtab_enumerate(const struct hashtab *hashtab,
int (*func)(struct hashnode *hashnode, void *data),
void *data);
#endif /* HASHTAB_H */

View File

@@ -1,279 +0,0 @@
/*
* input.c
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hashtab.h"
#include "input.h"
#include "parse.h"
#include "scan.h"
#include "tunit.h"
static int do_append(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt, unsigned long dot_incr)
{
struct stmt *stmt2;
struct section *section;
stmt2 = malloc(sizeof *stmt2);
if (!stmt2) {
fprintf(stderr, "%s: %s line %u: malloc(%zu) failed: %s\n",
scan_state->progname, scan_state->filename, scan_state->linenr, sizeof *stmt2, strerror(errno));
return -1;
}
*stmt2 = *stmt;
stmt2->next = NULL;
section = tunit->cursect;
*section->tailptr = stmt2;
section->tailptr = &stmt2->next;
section->dot += dot_incr;
return 0;
}
static int do_dot_file(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt)
{
struct symbol *symbol;
symbol = tunit_symbol_enter(tunit, stmt->u.string.text);
if (!symbol)
return -1;
symbol->section = NULL;
symbol->defined = 1;
symbol->st_value = 0;
symbol->st_size = 0;
symbol->st_info = ELF_ST_INFO(STB_LOCAL, STT_FILE);
return 0;
}
static int do_dot_globl(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt)
{
struct symbol *symbol;
symbol = tunit_symbol_enter(tunit, stmt->u.symbol.name);
if (!symbol)
return -1;
if (ELF_ST_BIND(symbol->st_info) != STB_LOCAL) {
fprintf(stderr, "%s: %s line %u: symbol %s already has non-zero binding type %u\n",
scan_state->progname, scan_state->filename, scan_state->linenr, stmt->u.symbol.name, ELF_ST_BIND(symbol->st_info));
return -1;
}
symbol->st_info = ELF_ST_INFO(STB_GLOBAL, ELF_ST_TYPE(symbol->st_info));
return 0;
}
static int do_dot_ident(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt)
{
struct strtab *strtab;
strtab = tunit_strtab_section_enter(tunit, ".comment");
if (!strtab)
return -1;
if (strtab->section.sh_type == SHT_NULL) {
/* The ELF specification doesn't specify attribute values for .comment
* sections, apart from sh_type, but GNU binutils formats them as string
* tables with the following attribute values.
*/
strtab->section.sh_type = SHT_PROGBITS;
strtab->section.sh_flags = SHF_MERGE | SHF_STRINGS;
strtab->section.sh_entsize = 1;
strtab->section.sh_addralign = 1;
}
(void)strtab_enter(tunit, strtab, stmt->u.string.text);
return 0;
}
static int do_dot_size(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt)
{
struct symbol *symbol;
symbol = tunit_symbol_enter(tunit, stmt->u.symbol.name);
if (!symbol)
return -1;
if (!symbol->section
|| !symbol->defined) {
fprintf(stderr, "%s: %s line %u: symbol %s undefined\n",
scan_state->progname, scan_state->filename, scan_state->linenr, stmt->u.symbol.name);
return -1;
}
if (symbol->st_size) {
fprintf(stderr, "%s: %s line %u: size of symbol %s already defined\n",
scan_state->progname, scan_state->filename, scan_state->linenr, stmt->u.symbol.name);
return -1;
}
if (symbol->section != tunit->cursect) {
fprintf(stderr, "%s: %s line %u: symbol %s is not defined in current section\n",
scan_state->progname, scan_state->filename, scan_state->linenr, stmt->u.symbol.name);
return -1;
}
symbol->st_size = tunit->cursect->dot - symbol->st_value;
return 0;
}
static int do_dot_text(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt)
{
struct section *section;
section = tunit_section_enter(tunit, ".text");
if (!section)
return -1;
if (section->sh_type == SHT_NULL) {
section->sh_type = SHT_PROGBITS;
section->sh_flags = SHF_ALLOC | SHF_EXECINSTR;
section->sh_addralign = 4; /* XXX: PDP10-specific */
}
tunit->cursect = section;
return 0;
}
static int do_dot_type_function(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt)
{
struct symbol *symbol;
symbol = tunit_symbol_enter(tunit, stmt->u.symbol.name);
if (!symbol)
return -1;
if (ELF_ST_TYPE(symbol->st_info) != STT_NOTYPE) {
fprintf(stderr, "%s: %s line %u: symbol %s already has non-zero type %u\n",
scan_state->progname, scan_state->filename, scan_state->linenr, stmt->u.symbol.name, ELF_ST_TYPE(symbol->st_info));
return -1;
}
symbol->st_info = ELF_ST_INFO(ELF_ST_BIND(symbol->st_info), STT_FUNC);
return 0;
}
static int do_label(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt)
{
struct symbol *symbol;
struct section *section;
symbol = tunit_symbol_enter(tunit, stmt->u.symbol.name);
if (!symbol)
return -1;
if (symbol->section
|| symbol->defined
|| symbol->st_value) {
fprintf(stderr, "%s: %s line %u: symbol %s already defined\n",
scan_state->progname, scan_state->filename, scan_state->linenr, stmt->u.symbol.name);
return -1;
}
section = tunit->cursect;
symbol->section = section;
symbol->defined = 1;
symbol->st_value = section->dot;
return do_append(scan_state, tunit, stmt, 0);
}
static int do_insn(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt)
{
if (tunit->cursect->dot & 3) { /* XXX: PDP10-specific */
fprintf(stderr, "%s: %s line %u: misaligned instruction\n",
scan_state->progname, scan_state->filename, scan_state->linenr);
return -1;
}
return do_append(scan_state, tunit, stmt, 4); /* XXX: PDP10-specific sizeof */
}
static int interpret(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt)
{
switch (stmt->tag) {
case S_DOT_FILE:
return do_dot_file(scan_state, tunit, stmt);
case S_DOT_GLOBL:
return do_dot_globl(scan_state, tunit, stmt);
case S_DOT_IDENT:
return do_dot_ident(scan_state, tunit, stmt);
case S_DOT_SIZE:
return do_dot_size(scan_state, tunit, stmt);
case S_DOT_TEXT:
return do_dot_text(scan_state, tunit, stmt);
case S_DOT_TYPE_FUNCTION:
return do_dot_type_function(scan_state, tunit, stmt);
case S_LABEL:
return do_label(scan_state, tunit, stmt);
case S_INSN:
return do_insn(scan_state, tunit, stmt);
default:
fprintf(stderr, "%s: %s line %u: parser returned unexpected stmt->tag %u\n",
scan_state->progname, scan_state->filename, scan_state->linenr, stmt->tag);
return -1;
}
}
int input(char **files, int nrfiles, struct tunit *tunit)
{
char fake_file[3];
char *fake_files[1];
struct scan_state scan_state;
int i;
struct stmt stmt;
int status;
if (nrfiles <= 0) {
fake_file[0] = '-';
fake_file[1] = '-';
fake_file[2] = '\0';
fake_files[0] = fake_file;
files = fake_files;
nrfiles = 1;
}
scan_init(&scan_state, tunit->progname);
for (i = 0; i < nrfiles; ++i) {
if (scan_open(&scan_state, files[i]) < 0)
return -1;
for (;;) {
status = parse_stmt(&scan_state, &stmt);
if (status < 0)
return -1;
if (status == 0)
break;
if (interpret(&scan_state, tunit, &stmt) < 0)
return -1;
}
}
return 0;
}

View File

@@ -1,27 +0,0 @@
/*
* input.h
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INPUT_H
#define INPUT_H
#include "tunit.h"
int input(char **files, int nrfiles, struct tunit *tunit);
#endif /* INPUT_H */

View File

@@ -1,72 +0,0 @@
/*
* main.c -- as clone for pdp10-elf
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <unistd.h>
#include "assemble.h"
#include "input.h"
#include "output.h"
#include "tunit.h"
#define VERSION "pdp10-tools as version 0.2, built " __DATE__ " " __TIME__ "\n"
int main(int argc, char **argv)
{
const char *outfile = "a.out";
struct tunit tunit;
for (;;) {
int ch;
ch = getopt(argc, argv, "vo:VQ:");
switch (ch) {
case 'Q': /* SVR4 compat, ignored */
continue;
case 'V': /* SVR4 compat, alias for -v */
case 'v':
printf(VERSION);
continue;
case 'o':
outfile = optarg;
continue;
case -1:
break;
default:
fprintf(stderr, "Usage: %s [-v] [-o outfile] [files..]\n", argv[0]);
return 1;
}
break;
}
if (tunit_init(&tunit, argv[0]) < 0)
return 1;
if (input(&argv[optind], argc - optind, &tunit) < 0)
return 1;
if (assemble(&tunit) < 0)
return 1;
if (output(&tunit, outfile) < 0)
return 1;
tunit_fini(&tunit);
return 0;
}

View File

@@ -1,363 +0,0 @@
/*
* output.c
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pdp10-elf36.h"
#include "pdp10-stdint.h"
#include "pdp10-stdio.h"
#include "hashtab.h"
#include "output.h"
#include "tunit.h"
static int output_padding(PDP10_FILE *pdp10fp, unsigned int nrbytes)
{
for (; nrbytes; --nrbytes)
if (pdp10_elf36_write_uint9(pdp10fp, '\0') < 0)
return -1;
return 0;
}
struct context {
struct tunit *tunit;
Elf36_Word shnum;
Elf36_Word offset;
struct strtab shstrtab;
Elf36_Word symnum;
struct strtab symstrtab;
PDP10_FILE *pdp10fp;
};
static int append_section(struct context *context, struct section *section)
{
if (section->dot == 0)
return 0;
/* enter name before reading ->dot to allow this to work for .shstrtab too */
section->sh_name = strtab_enter(context->tunit, &context->shstrtab, section->name);
if (section->sh_name == 0)
return -1;
section->st_shndx = context->shnum;
++context->shnum;
section->sh_offset = (context->offset + (section->sh_addralign - 1)) & ~(section->sh_addralign - 1);
context->offset = section->sh_offset + section->dot;
return 0;
}
static int process_section(struct hashnode *hashnode, void *data)
{
struct section *section = container_of(hashnode, struct section, hashnode);
struct context *context = data;
return append_section(context, section);
}
static int output_section_prologue(struct context *context, struct section *section)
{
if (section->st_shndx != context->shnum)
abort();
++context->shnum;
if (section->sh_offset < context->offset)
abort();
if (output_padding(context->pdp10fp, section->sh_offset - context->offset) < 0)
return -1;
return 0;
}
static void output_section_epilogue(struct context *context, struct section *section)
{
context->offset = section->sh_offset + section->dot;
}
static int output_section(struct hashnode *hashnode, void *data)
{
struct section *section = container_of(hashnode, struct section, hashnode);
struct context *context = data;
if (section->dot == 0 || (section->image == NULL && section->output == NULL))
return 0;
if (output_section_prologue(context, section) < 0)
return -1;
if (section->output) {
if (section->output(context->pdp10fp, section) < 0)
return -1;
} else {
unsigned int i;
for (i = 0; i < section->dot; ++i)
if (pdp10_elf36_write_uint9(context->pdp10fp, section->image[i]) < 0)
return -1;
}
output_section_epilogue(context, section);
return 0;
}
static int output_section_header(struct context *context, const struct section *section)
{
Elf36_Shdr shdr;
shdr.sh_name = section->sh_name;
shdr.sh_type = section->sh_type;
shdr.sh_flags = section->sh_flags;
shdr.sh_addr = 0;
shdr.sh_offset = section->sh_offset;
shdr.sh_size = section->dot;
shdr.sh_link = section->sh_link;
shdr.sh_info = 0; /* XXX: for symtab, LAST_LOCAL + 1 */
shdr.sh_addralign = section->sh_addralign;
shdr.sh_entsize = section->sh_entsize;
return pdp10_elf36_write_shdr(context->pdp10fp, &shdr);
}
static int output_shdr(struct hashnode *hashnode, void *data)
{
struct section *section = container_of(hashnode, struct section, hashnode);
struct context *context = data;
if (section->dot == 0)
return 0;
return output_section_header(context, section);
}
static int output_strtab(struct context *context, struct strtab *strtab)
{
return output_section(&strtab->section.hashnode, context);
}
static int process_symbol(struct hashnode *hashnode, void *data)
{
struct symbol *symbol = container_of(hashnode, struct symbol, hashnode);
struct context *context = data;
++context->symnum;
symbol->st_name = strtab_enter(context->tunit, &context->symstrtab, symbol->name);
if (symbol->st_name == 0)
return -1;
return 0;
}
struct finalize_symbol_context {
Elf36_Sym *symtab;
unsigned int i;
};
static int finalize_symbol(struct hashnode *hashnode, void *data)
{
struct symbol *symbol = container_of(hashnode, struct symbol, hashnode);
struct finalize_symbol_context *fsctx = data;
Elf36_Word st_shndx;
fsctx->symtab[fsctx->i].st_name = symbol->st_name;
fsctx->symtab[fsctx->i].st_value = symbol->st_value;
fsctx->symtab[fsctx->i].st_size = symbol->st_size;
fsctx->symtab[fsctx->i].st_info = symbol->st_info;
fsctx->symtab[fsctx->i].st_other = STV_DEFAULT;
if (symbol->section)
st_shndx = symbol->section->st_shndx;
else
st_shndx = SHN_ABS;
fsctx->symtab[fsctx->i].st_shndx = st_shndx;
++fsctx->i;
return 0;
}
int output(struct tunit *tunit, const char *outfile)
{
struct context context;
Elf36_Sym *symtab;
struct section section_symtab;
Elf36_Ehdr ehdr;
context.tunit = tunit;
context.shnum = 1;
context.offset = ELF36_EHDR_SIZEOF;
strtab_init(&context.shstrtab, ".shstrtab");
context.symnum = 0;
strtab_init(&context.symstrtab, ".strtab");
context.pdp10fp = NULL;
if (hashtab_enumerate(&tunit->sections, process_section, &context) < 0)
return -1;
if (hashtab_enumerate(&tunit->symbols, process_symbol, &context) < 0)
return -1;
symtab = NULL;
section_init(&section_symtab, ".symtab");
/* if we have symbols, synthesize .strtab and .symtab */
if (context.symnum) {
struct finalize_symbol_context fsctx;
if (append_section(&context, &context.symstrtab.section) < 0)
return -1;
++context.symnum; /* for initial stub entry */
symtab = malloc(context.symnum * sizeof(Elf36_Sym));
if (!symtab) {
fprintf(stderr, "%s: failed to allocate %zu bytes for Elf36 symbol table: %s\n",
tunit->progname, context.symnum * sizeof(Elf36_Sym), strerror(errno));
return -1;
}
symtab[0].st_name = 0;
symtab[0].st_value = 0;
symtab[0].st_size = 0;
symtab[0].st_info = ELF36_ST_INFO(STB_LOCAL, STT_NOTYPE);
symtab[0].st_other = 0;
symtab[0].st_shndx = SHN_UNDEF;
fsctx.symtab = symtab;
fsctx.i = 1;
if (hashtab_enumerate(&tunit->symbols, finalize_symbol, &fsctx) < 0)
return -1;
section_symtab.sh_type = SHT_SYMTAB;
section_symtab.sh_entsize = ELF36_SYM_SIZEOF;
section_symtab.sh_link = context.symstrtab.section.st_shndx;
section_symtab.sh_addralign = 4; /* XXX: PDP10-specific */
section_symtab.dot = context.symnum * ELF36_SYM_SIZEOF;
if (append_section(&context, &section_symtab) < 0)
return -1;
}
/* if we have sections, synthesize .shstrtab */
if (context.shnum > 1) {
if (append_section(&context, &context.shstrtab.section) < 0)
return -1;
/* align context.offset for the section header table, which is last in the file */
context.offset = (context.offset + (4 - 1)) & ~(Elf36_Word)(4 - 1);
} else {
context.shnum = 0;
context.offset = 0;
}
ehdr.e_ident[EI_MAG0] = ELFMAG0;
ehdr.e_ident[EI_MAG1] = ELFMAG1;
ehdr.e_ident[EI_MAG2] = ELFMAG2;
ehdr.e_ident[EI_MAG3] = ELFMAG3;
ehdr.e_ident[EI_CLASS] = ELFCLASS36;
ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
ehdr.e_ident[EI_VERSION] = EV_CURRENT;
ehdr.e_ident[EI_OSABI] = ELFOSABI_NONE;
ehdr.e_ident[EI_ABIVERSION] = 0;
{
int i;
for (i = EI_PAD; i < EI_NIDENT; ++i)
ehdr.e_ident[i] = 0;
}
ehdr.e_type = ET_REL;
ehdr.e_machine = EM_PDP10;
ehdr.e_version = EV_CURRENT;
ehdr.e_entry = 0;
ehdr.e_phoff = 0;
ehdr.e_shoff = context.offset;
ehdr.e_flags = 0;
ehdr.e_ehsize = ELF36_EHDR_SIZEOF;
ehdr.e_phentsize = 0;
ehdr.e_phnum = 0;
ehdr.e_shentsize = ELF36_SHDR_SIZEOF;
ehdr.e_shnum = context.shnum;
ehdr.e_shstrndx = context.shstrtab.section.st_shndx;
context.pdp10fp = pdp10_fopen(outfile, "wb");
if (!context.pdp10fp) {
fprintf(stderr, "%s: failed to open %s: %s\n", tunit->progname, outfile, strerror(errno));
return -1;
}
if (pdp10_elf36_write_ehdr(context.pdp10fp, &ehdr) < 0)
return -1;
context.shnum = 1;
context.offset = ELF36_EHDR_SIZEOF;
if (hashtab_enumerate(&tunit->sections, output_section, &context) < 0)
return -1;
if (context.symnum) {
unsigned int i;
if (output_strtab(&context, &context.symstrtab) < 0)
return -1;
if (output_section_prologue(&context, &section_symtab) < 0)
return -1;
for (i = 0; i < context.symnum; ++i)
if (pdp10_elf36_write_sym(context.pdp10fp, &symtab[i]) < 0)
return -1;
output_section_epilogue(&context, &section_symtab);
}
if (context.shnum > 1) {
struct section section0;
if (output_strtab(&context, &context.shstrtab) < 0)
return -1;
if (ehdr.e_shoff < context.offset)
abort();
if (output_padding(context.pdp10fp, ehdr.e_shoff - context.offset) < 0)
return -1;
section_init(&section0, "<fake section 0>");
section0.sh_addralign = 0;
if (output_section_header(&context, &section0) < 0)
return -1;
if (hashtab_enumerate(&tunit->sections, output_shdr, &context) < 0)
return -1;
if (context.symnum) {
if (output_section_header(&context, &context.symstrtab.section) < 0)
return -1;
if (output_section_header(&context, &section_symtab) < 0)
return -1;
}
if (output_section_header(&context, &context.shstrtab.section) < 0)
return -1;
}
pdp10_fclose(context.pdp10fp);
return 0;
}

View File

@@ -1,27 +0,0 @@
/*
* output.h
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OUTPUT_H
#define OUTPUT_H
#include "tunit.h"
int output(struct tunit *tunit, const char *outfile);
#endif /* OUTPUT_H */

View File

@@ -1,467 +0,0 @@
/*
* parse.c
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pdp10-opcodes.h"
#include "input.h" /* for struct stmt */
#include "parse.h"
#include "scan.h"
#include "token.h"
static int error(struct scan_state *scan_state, const char *msg, enum token token, const union token_attribute *token_attr)
{
fprintf(stderr, "%s: %s line %u: syntax error: %s; current token is ",
scan_state->progname, scan_state->filename, scan_state->linenr, msg);
token_print(stderr, token, token_attr);
fprintf(stderr, "\n");
return -1;
}
static int parse_dot_file_or_ident(struct scan_state *scan_state, struct stmt *stmt, enum stmt_tag tag, const char *errmsg)
{
enum token token;
union token_attribute token_attr;
token = scan_token(scan_state, &token_attr);
if (token == T_STRING) {
stmt->u.string.text = token_attr.text;
token = scan_token(scan_state, &token_attr);
if (token == T_NEWLINE) {
stmt->tag = tag;
return 1;
}
}
return error(scan_state, errmsg, token, &token_attr);
}
static int parse_dot_file(struct scan_state *scan_state, struct stmt *stmt)
{
return parse_dot_file_or_ident(scan_state, stmt, S_DOT_FILE, "junk after .file directive");
}
static int parse_dot_ident(struct scan_state *scan_state, struct stmt *stmt)
{
return parse_dot_file_or_ident(scan_state, stmt, S_DOT_IDENT, "junk after .ident directive");
}
static int parse_dot_globl(struct scan_state *scan_state, struct stmt *stmt)
{
enum token token;
union token_attribute token_attr;
token = scan_token(scan_state, &token_attr);
if (token == T_SYMBOL) {
stmt->u.symbol.name = token_attr.text;
token = scan_token(scan_state, &token_attr);
if (token == T_NEWLINE) {
stmt->tag = S_DOT_GLOBL;
return 1;
}
}
return error(scan_state, "junk after .globl directive", token, &token_attr);
}
/* for now, accepts: .size <sym>,.-<sym> */
static int parse_dot_size(struct scan_state *scan_state, struct stmt *stmt)
{
enum token token;
union token_attribute token_attr;
token = scan_token(scan_state, &token_attr);
if (token == T_SYMBOL) {
stmt->u.symbol.name = token_attr.text;
token = scan_token(scan_state, &token_attr);
if (token == T_COMMA) {
token = scan_token(scan_state, &token_attr);
if (token == T_DOT) {
token = scan_token(scan_state, &token_attr);
if (token == T_MINUS) {
token = scan_token(scan_state, &token_attr);
if (token == T_SYMBOL
&& strcmp(token_attr.text, stmt->u.symbol.name) == 0) {
token = scan_token(scan_state, &token_attr);
if (token == T_NEWLINE) {
stmt->tag = S_DOT_SIZE;
return 1;
}
}
}
}
}
}
return error(scan_state, "junk after .size directive", token, &token_attr);
}
static int parse_dot_text(struct scan_state *scan_state, struct stmt *stmt)
{
enum token token;
union token_attribute token_attr;
token = scan_token(scan_state, &token_attr);
if (token == T_NEWLINE) {
stmt->tag = S_DOT_TEXT;
return 1;
}
return error(scan_state, "junk after .text directive", token, &token_attr);
}
static int parse_dot_type(struct scan_state *scan_state, struct stmt *stmt)
{
enum token token;
union token_attribute token_attr;
token = scan_token(scan_state, &token_attr);
if (token == T_SYMBOL) {
stmt->u.symbol.name = token_attr.text;
token = scan_token(scan_state, &token_attr);
if (token == T_COMMA) {
token = scan_token(scan_state, &token_attr);
if (token == T_AT) {
token = scan_token(scan_state, &token_attr);
if (token == T_SYMBOL
&& strcmp(token_attr.text, "function") == 0) {
token = scan_token(scan_state, &token_attr);
if (token == T_NEWLINE) {
stmt->tag = S_DOT_TYPE_FUNCTION;
return 1;
}
}
}
}
}
return error(scan_state, "junk after .type directive", token, &token_attr);
}
/*
* Recognize:
*
* <label> ::= <symbol> ":"
*
* <insn> ::= <symbol> (<accumulator> ",")? <address> <newline>
*
* <accumulator> ::= <uinteger> [uint <= 0xF]
*
* <address> ::= "@"? <displacement>? <index>?
*
* <displacement> ::= <uinteger> [uint <= 1^18 - 1]
* <displacement> ::= "(" <uinteger> ")" [uint <= 1^18 - 1]
*
* <index> ::= "(" <indexreg> ")"
* <indexreg> ::= <uinteger> [uint <= 0xF]
*
* Examples:
* foo:
* popj 17,
* pushj 17,bar
* movei 1,@fum(2)
*
* Ambiguous examples:
*
* <symbol> (<uinteger>) <newline>
*
* This is ambigouous since we have no special notation for <register>, and the same kind of
* parentheses are used for expression grouping in the displacement as for the index register.
*
* This might denote an insn with a parenthesized displacement and no index,
* or it might denote an insn with an index but no displacement.
*
* However, the uinteger in an indexreg cannot be > 0xF, and it rarely makes sense to form
* an effective address with a displacement <= 0xF and no index.
*
* Therefore, if the uinteger is <= 0xF this is an index with no displacement,
* otherwise it is a displacement without an index.
*/
static int parse_insn_index_after_lparen(struct scan_state *scan_state, struct stmt *stmt)
{
enum token token;
union token_attribute token_attr;
token = scan_token(scan_state, &token_attr);
if (token != T_UINTEGER
|| token_attr.uint > 0xF)
return error(scan_state, "invalid <indexreg>", token, &token_attr);
stmt->u.insn.indexreg = token_attr.uint;
token = scan_token(scan_state, &token_attr);
if (token != T_RPAREN)
return error(scan_state, "junk after '(' <indexreg>", token, &token_attr);
token = scan_token(scan_state, &token_attr);
if (token != T_NEWLINE)
return error(scan_state, "junk after '(' <indexreg> ')'", token, &token_attr);
return 1;
}
static int parse_insn_address_after_lparen_uinteger_rparen(struct scan_state *scan_state, struct stmt *stmt, union token_attribute *uinteger_attr)
{
enum token token;
union token_attribute token_attr;
token = scan_token(scan_state, &token_attr);
switch (token) {
case T_NEWLINE: /* might be <displacement> or <index>, inspect the <uinteger>'s value to disambiguate */
if (uinteger_attr->uint > PDP10_UINT18_MAX)
return error(scan_state, "invalid <displacement>", T_UINTEGER, uinteger_attr);
if (uinteger_attr->uint <= 0xF) /* it's the <index> */
stmt->u.insn.indexreg = uinteger_attr->uint;
else /* it's the <displacement> */
stmt->u.insn.address = uinteger_attr->uint;
return 1;
case T_LPAREN: /* the <uinteger> is the <displacement>, followed by <index> */
if (uinteger_attr->uint > PDP10_UINT18_MAX)
return error(scan_state, "invalid <displacement>", T_UINTEGER, uinteger_attr);
stmt->u.insn.address = uinteger_attr->uint;
return parse_insn_index_after_lparen(scan_state, stmt);
default:
return error(scan_state, "junk in <address> after '(' <uinteger> ')'", token, &token_attr);
}
}
static int parse_insn_address_after_lparen_uinteger(struct scan_state *scan_state, struct stmt *stmt, union token_attribute *uinteger_attr)
{
enum token token;
union token_attribute token_attr;
token = scan_token(scan_state, &token_attr);
switch (token) {
case T_RPAREN: /* might be <displacement> or <index> */
return parse_insn_address_after_lparen_uinteger_rparen(scan_state, stmt, uinteger_attr);
default:
return error(scan_state, "junk in <address> after '(' <uinteger>", token, &token_attr);
}
}
static int parse_insn_address_after_lparen(struct scan_state *scan_state, struct stmt *stmt)
{
enum token token;
union token_attribute token_attr;
token = scan_token(scan_state, &token_attr);
switch (token) {
case T_UINTEGER: /* might be <displacement> or <index> */
return parse_insn_address_after_lparen_uinteger(scan_state, stmt, &token_attr);
default:
return error(scan_state, "junk in <address> after '('", token, &token_attr);
}
}
static int parse_insn_after_displacement(struct scan_state *scan_state, struct stmt *stmt)
{
enum token token;
union token_attribute token_attr;
token = scan_token(scan_state, &token_attr);
switch (token) {
case T_NEWLINE: /* no <index> */
return 1;
case T_LPAREN: /* need <index> */
return parse_insn_index_after_lparen(scan_state, stmt);
default:
return error(scan_state, "junk in <address> after <displacement>", token, &token_attr);
}
}
static int parse_insn_address_after_at(struct scan_state *scan_state, struct stmt *stmt)
{
enum token token;
union token_attribute token_attr;
token = scan_token(scan_state, &token_attr);
switch (token) {
case T_NEWLINE:
return 1;
case T_LPAREN: /* might be <displacement> or <index> */
return parse_insn_address_after_lparen(scan_state, stmt);
case T_UINTEGER:
if (token_attr.uint > PDP10_UINT18_MAX)
return error(scan_state, "invalid <displacement>", token, &token_attr);
stmt->u.insn.address = token_attr.uint;
return parse_insn_after_displacement(scan_state, stmt);
default:
return error(scan_state, "invalid <address>", token, &token_attr);
}
}
static int parse_insn_address(struct scan_state *scan_state, struct stmt *stmt, const struct pdp10_insn *insndesc)
{
enum token token;
union token_attribute token_attr;
token = scan_token(scan_state, &token_attr);
if (token == T_NEWLINE)
return 1;
if (insndesc->fmt & PDP10_INSN_E_UNUSED)
return error(scan_state, "<address> not allowed in this instruction", token, &token_attr);
switch (token) {
case T_LPAREN: /* might be <displacement> or <index> */
return parse_insn_address_after_lparen(scan_state, stmt);
case T_UINTEGER:
if (token_attr.uint > PDP10_UINT18_MAX)
return error(scan_state, "invalid <displacement>", token, &token_attr);
stmt->u.insn.address = token_attr.uint;
return parse_insn_after_displacement(scan_state, stmt);
case T_AT:
stmt->u.insn.at = 1;
return parse_insn_address_after_at(scan_state, stmt);
default:
return error(scan_state, "invalid <address>", token, &token_attr);
}
}
static int parse_insn_after_symbol_uinteger(
struct scan_state *scan_state, struct stmt *stmt, const struct pdp10_insn *insndesc, union token_attribute *uinteger_attr)
{
enum token token;
union token_attribute token_attr;
token = scan_token(scan_state, &token_attr);
if (token == T_COMMA) { /* the <uinteger> is the <accumulator> */
if (uinteger_attr->uint > 0xF)
return error(scan_state, "invalid <accumulator>", T_UINTEGER, uinteger_attr);
if ((insndesc->fmt & 3) == PDP10_INSN_A_OPCODE
|| (insndesc->fmt & 3) == PDP10_INSN_A_UNUSED)
return error(scan_state, "<accumulator> not allowed in this instruction", T_UINTEGER, uinteger_attr);
stmt->u.insn.accumulator = uinteger_attr->uint;
return parse_insn_address(scan_state, stmt, insndesc);
}
if (insndesc->fmt & PDP10_INSN_E_UNUSED)
return error(scan_state, "<address> not allowed in this instruction", token, &token_attr);
switch (token) {
case T_LPAREN: /* the <uinteger> is the <displacement>, followed by <index> */
if (uinteger_attr->uint > PDP10_UINT18_MAX)
return error(scan_state, "invalid <displacement>", T_UINTEGER, uinteger_attr);
stmt->u.insn.address = uinteger_attr->uint;
return parse_insn_index_after_lparen(scan_state, stmt);
case T_NEWLINE: /* the <uinteger> is the <displacement>, there is no <accumulator> or <index> */
if (uinteger_attr->uint > PDP10_UINT18_MAX)
return error(scan_state, "invalid <displacement>", T_UINTEGER, uinteger_attr);
stmt->u.insn.address = uinteger_attr->uint;
return 1;
default:
return error(scan_state, "junk after <symbol> <uinteger>", token, &token_attr);
}
}
static int parse_after_symbol(struct scan_state *scan_state, struct stmt *stmt, union token_attribute *symbol_attr)
{
enum token token;
union token_attribute token_attr;
const struct pdp10_insn *insndesc;
const pdp10_cpu_models_t models = PDP10_KL10_271up; /* XXX: make it user-selectable */
token = scan_token(scan_state, &token_attr);
if (token == T_COLON) {
stmt->u.symbol.name = symbol_attr->text;
stmt->tag = S_LABEL;
return 1;
}
insndesc = pdp10_insn_from_name(models, symbol_attr->text);
if (!insndesc)
return error(scan_state, "invalid instruction name", T_SYMBOL, symbol_attr);
stmt->tag = S_INSN;
stmt->u.insn.at = 0;
stmt->u.insn.address = 0;
stmt->u.insn.indexreg = 0;
/* XXX: this is too intimate with quirky ->high13 representation */
/* XXX: what about IO insns? should we just store high13 as-is? */
if ((insndesc->fmt & 3) == PDP10_INSN_A_OPCODE) {
stmt->u.insn.opcode = (insndesc->high13 >> 4) & 0x1FF;
stmt->u.insn.accumulator = insndesc->high13 & 0xF;
} else {
stmt->u.insn.opcode = (insndesc->high13 >> 4) & 0x1FF;
stmt->u.insn.accumulator = 0;
}
switch (token) {
case T_NEWLINE:
return 1;
case T_UINTEGER: /* might be <accumulator> or <displacement> */
return parse_insn_after_symbol_uinteger(scan_state, stmt, insndesc, &token_attr);
default:
break;
}
if (insndesc->fmt & PDP10_INSN_E_UNUSED)
return error(scan_state, "<address> not allowed in this instruction", token, &token_attr);
switch (token) {
case T_AT:
stmt->u.insn.at = 1;
return parse_insn_address_after_at(scan_state, stmt);
case T_LPAREN: /* might be <displacement> or <index> */
return parse_insn_address_after_lparen(scan_state, stmt);
default:
return error(scan_state, "junk after instruction name", token, &token_attr);
}
}
int parse_stmt(struct scan_state *scan_state, struct stmt *stmt)
{
enum token token;
union token_attribute token_attr;
for (;;) {
token = scan_token(scan_state, &token_attr);
switch (token) {
/*
* directives
*/
case T_DOT_FILE:
return parse_dot_file(scan_state, stmt);
case T_DOT_GLOBL:
return parse_dot_globl(scan_state, stmt);
case T_DOT_IDENT:
return parse_dot_ident(scan_state, stmt);
case T_DOT_SIZE:
return parse_dot_size(scan_state, stmt);
case T_DOT_TEXT:
return parse_dot_text(scan_state, stmt);
case T_DOT_TYPE:
return parse_dot_type(scan_state, stmt);
/*
* other symbols
*/
case T_SYMBOL: /* start of label, insn, or symbol assignment */
return parse_after_symbol(scan_state, stmt, &token_attr);
/*
* synthetic symbols
*/
case T_ERROR:
return -1; /* diagnostics already emitted by scan.c */
case T_EOF:
return 0;
case T_NEWLINE:
continue;
default:
return error(scan_state, "expected directive, label, or instruction", token, &token_attr);
}
}
}

View File

@@ -1,28 +0,0 @@
/*
* parse.h
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PARSE_H
#define PARSE_H
#include "input.h" /* for struct stmt */
#include "scan.h"
int parse_stmt(struct scan_state *scan_state, struct stmt *stmt);
#endif /* PARSE_H */

435
as/scan.c
View File

@@ -1,435 +0,0 @@
/*
* scan.c
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <limits.h> /* XXX: for UCHAR_MAX, deleteme */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "scan.h"
#include "token.h"
void scan_init(struct scan_state *scan_state, const char *progname)
{
scan_state->progname = progname;
scan_state->filename = "<stdin>";
scan_state->linenr = 1;
}
int scan_open(struct scan_state *scan_state, const char *filename)
{
if (filename[0] == '-' && filename[1] == '-' && filename[2] == '\0') {
scan_state->filename = "<stdin>";
filename = "/dev/stdin";
} else
scan_state->filename = filename;
if (freopen(filename, "r", stdin) == NULL) {
fprintf(stderr, "%s: Error opening %s: %s\n", scan_state->progname, filename, strerror(errno));
return -1;
}
return 0;
}
static void scan_ungetc(struct scan_state *scan_state, int ch)
{
if (ch != EOF && ungetc(ch, stdin) == EOF)
fprintf(stderr, "%s: %s line %u: ungetc %d failed: %s\n",
scan_state->progname, scan_state->filename, scan_state->linenr, ch, strerror(errno));
}
static int scan_getchar(void)
{
return fgetc(stdin);
}
static void badchar(struct scan_state *scan_state, int ch, const char *context)
{
char buf[7];
if (ch == EOF) {
buf[0] = '<';
buf[1] = 'E';
buf[2] = 'O';
buf[3] = 'F';
buf[4] = '>';
buf[5] = '\0';
} else if (' ' <= ch && ch <= '~') {
buf[0] = '\'';
buf[1] = ch;
buf[2] = '\'';
buf[3] = '\0';
} else {
buf[0] = '\'';
buf[1] = '\\';
buf[2] = '0' + ((ch >> 6) & 3);
buf[3] = '0' + ((ch >> 3) & 7);
buf[4] = '0' + (ch & 7);
buf[5] = '\'';
buf[6] = '\0';
}
fprintf(stderr, "%s: %s line %u: invalid character %s%s\n",
scan_state->progname, scan_state->filename, scan_state->linenr, buf, context);
}
static unsigned int get_chval(int ch)
{
if ('0' <= ch && ch <= '9')
return ch - '0';
if ('A' <= ch && ch <= 'F')
return ch - ('A' - 10);
if ('a' <= ch && ch <= 'f')
return ch - ('a' - 10);
return -1U;
}
static int is_octal_digit(int ch)
{
return ch >= '0' && ch <= '7';
}
static int do_escape(struct scan_state *scan_state)
{
int ch;
ch = scan_getchar();
switch (ch) {
case 'n':
return '\n';
case 't':
return '\t';
case 'f':
return '\f';
case 'r':
return '\r';
case 'b':
return '\b';
case '\\':
case '\'':
case '"':
return ch;
default:
if (is_octal_digit(ch)) {
unsigned int val = ch - '0';
ch = scan_getchar();
if (is_octal_digit(ch)) {
val = val * 8 + (ch - '0');
ch = scan_getchar();
if (is_octal_digit(ch))
val = val * 8 + (ch - '0');
else
scan_ungetc(scan_state, ch);
} else
scan_ungetc(scan_state, ch);
/* XXX: this should be PDP10_UINT9_MAX, but our string elements are still char not pdp10_uint9_t for now */
if (val > UCHAR_MAX) {
fprintf(stderr, "%s: %s line %u: out of range character escape value %#x\n",
scan_state->progname, scan_state->filename, scan_state->linenr, val);
return EOF;
}
return val & UCHAR_MAX;
}
break;
}
badchar(scan_state, ch, "in \\ character escape");
if (ch == '\n')
++scan_state->linenr;
return EOF;
}
/* XXX: string literals should be sequences of pdp10_uint9_t, not sequences of char */
static enum token do_string(struct scan_state *scan_state, union token_attribute *token_attr)
{
char charbuf[4096]; /* 4095 char + NUL, XXX: make it dynamic */
unsigned int len;
char *text;
int ch;
len = 0;
for (;;) {
ch = scan_getchar();
switch (ch) {
case '"':
text = malloc(len + 1);
if (!text) {
fprintf(stderr, "%s: %s line %u: malloc(%u) failed: %s\n",
scan_state->progname, scan_state->filename, scan_state->linenr, len + 1, strerror(errno));
return T_ERROR;
}
strcpy(text, charbuf);
token_attr->text = text;
return T_STRING;
case '\\':
ch = do_escape(scan_state);
if (ch == EOF)
return T_ERROR;
break;
case EOF:
case '\n':
badchar(scan_state, ch, "in string literal");
if (ch == '\n')
++scan_state->linenr;
return T_ERROR;
default:
break;
}
if (len >= sizeof charbuf - 1) {
fprintf(stderr, "%s: %s line %u: too long string literal\n",
scan_state->progname, scan_state->filename, scan_state->linenr);
return T_ERROR;
}
charbuf[len] = ch;
++len;
}
}
static int is_symbol_internal_char(int ch)
{
return
('A' <= ch && ch <= 'Z')
|| ('a' <= ch && ch <= 'z')
|| ('0' <= ch && ch <= '9')
|| ch == '_'
|| ch == '$'
|| ch == '.';
}
static enum token do_symbol(struct scan_state *scan_state, union token_attribute *token_attr, int ch)
{
char charbuf[128]; /* 127 chars + NUL, XXX: make it dynamic */
unsigned int len;
char *text;
len = 0;
do {
if (len >= sizeof charbuf - 1) {
fprintf(stderr, "%s: %s line %u: too long symbol\n",
scan_state->progname, scan_state->filename, scan_state->linenr);
return T_ERROR;
}
charbuf[len] = ch;
++len;
ch = scan_getchar();
} while (is_symbol_internal_char(ch));
charbuf[len] = '\0';
scan_ungetc(scan_state, ch);
if (charbuf[0] == '.') {
enum token low, high;
if (charbuf[1] == '\0')
return T_DOT;
/* see token.def, reserved symbols occupy tokens [0,T_SYMBOL[ */
low = 0;
high = T_SYMBOL;
while (low < high) {
enum token middle;
int cmp;
middle = (low + high) / 2;
cmp = strcmp(charbuf, token_info[middle].print_name);
if (cmp < 0)
high = middle;
else if (cmp > 0)
low = middle + 1;
else
return middle;
}
}
text = malloc(len + 1);
if (!text) {
fprintf(stderr, "%s: %s line %u: malloc(%u) failed: %s\n",
scan_state->progname, scan_state->filename, scan_state->linenr, len + 1, strerror(errno));
return T_ERROR;
}
strcpy(text, charbuf);
token_attr->text = text;
return T_SYMBOL;
}
static enum token do_number(struct scan_state *scan_state, union token_attribute *token_attr, int ch)
{
unsigned int base, chval;
pdp10_uint36_t numval;
base = (ch == '0') ? 8 : 10;
numval = ch - '0';
/* handle 0x<first hexdig> */
ch = scan_getchar();
if (base == 8 && (ch == 'x' || ch == 'X')) {
base = 16;
/* must have at least one hex digit after 0x */
ch = scan_getchar();
chval = get_chval(ch);
if (chval >= 16) {
badchar(scan_state, ch, " after 0x in hexadecimal literal");
return T_ERROR;
}
numval = chval;
ch = scan_getchar();
}
/* the number is non-empty, consume and accumulate trailing
characters as long as they are valid in the base */
for (;;) {
chval = get_chval(ch);
if (chval >= base)
break;
numval = numval * base + chval; /* XXX: check for overflow */
ch = scan_getchar();
}
/* XXX: check for <decimal>{b,f} which is a local label reference */
/* plain integer literal */
scan_ungetc(scan_state, ch);
token_attr->uint = numval;
return T_UINTEGER;
}
static int do_line_comment(struct scan_state *scan_state)
{
for (;;) {
int ch = scan_getchar();
switch (ch) {
case '\n':
++scan_state->linenr;
return T_NEWLINE;
case EOF:
badchar(scan_state, ch, "in line comment");
return T_ERROR;
default:
continue;
}
}
}
static enum token do_slash(struct scan_state *scan_state)
{
int ch;
ch = scan_getchar();
if (ch != '*') {
scan_ungetc(scan_state, ch);
return T_ERROR; /* XXX: NYI: T_DIV */
}
for (;;) { /* INV: seen comment start but not comment end */
ch = scan_getchar();
switch (ch) {
case EOF:
badchar(scan_state, ch, "in /*...*/-style comment");
return T_ERROR;
case '*':
for (;;) { /* INV: previous character was a '*' */
ch = scan_getchar();
switch (ch) {
case '*':
continue;
case '/':
return T_EOF; /* indicate a C comment */
case EOF:
badchar(scan_state, ch, "in /*...*/-style comment");
return T_ERROR;
case '\n':
++scan_state->linenr;
/*FALLTHROUGH*/
default:
break;
}
break;
}
continue;
case '\n':
++scan_state->linenr;
/*FALLTHROUGH*/
default:
continue;
}
}
}
enum token scan_token(struct scan_state *scan_state, union token_attribute *token_attr)
{
int ch;
ch = scan_getchar();
for (;; ch = scan_getchar()) {
switch (ch) {
case ' ':
case '\t':
case '\r':
case '\f':
continue;
case '\n':
++scan_state->linenr;
return T_NEWLINE;
case '#':
return do_line_comment(scan_state);
case EOF:
return T_EOF;
case '@':
return T_AT;
case ':':
return T_COLON;
case ',':
return T_COMMA;
case '(':
return T_LPAREN;
case ')':
return T_RPAREN;
case '/':
{
enum token token = do_slash(scan_state);
if (token == T_EOF) /* special case to indicate a C comment */
continue;
return token;
}
case '"':
return do_string(scan_state, token_attr);
case '-':
return T_MINUS;
case '.':
/* Dot may start a floating point literal, but tests show that
gcc always outputs floating point values as integer literals,
so we shouldn't have to support floating point literals at all. */
case '$':
case '_':
return do_symbol(scan_state, token_attr, ch);
default:
if ('0' <= ch && ch <= '9') /* number or <decimal>{b,f} */
return do_number(scan_state, token_attr, ch);
if (('A' <= ch && ch <= 'Z') ||
('a' <= ch && ch <= 'z'))
return do_symbol(scan_state, token_attr, ch);
break;
}
badchar(scan_state, ch, "");
return T_ERROR;
}
}

View File

@@ -1,35 +0,0 @@
/*
* scan.h
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SCAN_H
#define SCAN_H
#include "token.h"
struct scan_state {
const char *progname; /* for diagnostics, does not change after scan_init() */
const char *filename; /* for diagnostics, set by scan_open() */
unsigned int linenr;
};
void scan_init(struct scan_state *scan_state, const char *progname);
int scan_open(struct scan_state *scan_state, const char *filename);
enum token scan_token(struct scan_state *scan_state, union token_attribute *token_attr);
#endif /* SCAN_H */

View File

@@ -1,25 +0,0 @@
/*
* test1.s
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
.text
.globl start
start:
movei 1,0
jsys 94
halt

View File

@@ -1,21 +0,0 @@
/*
* test2.c
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
int foo(void) { return 27; }

View File

@@ -1,30 +0,0 @@
/*
* test2.s
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
.file "z.c"
.text
.globl foo
.type foo, @function
foo:
movei 1,33
popj 017,
.size foo, .-foo
.ident "GCC: (GNU) 4.3.0.- for XKL-2 (XKL LLC, Kirkland, WA, USA) Built 2013-08-15 23:03 +0200 on porter by mikpe"
.section .note.GNU-stack,"",@progbits

View File

@@ -1,58 +0,0 @@
/*
* token.c
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "pdp10-inttypes.h"
#include "token.h"
const struct token_info token_info[] = {
#define TOKEN(T,P,F) { P, F },
#include "token.def"
#undef TOKEN
};
void token_print(FILE *fp, enum token token, const union token_attribute *token_attr)
{
const struct token_info *ti;
if (token >= sizeof token_info / sizeof token_info[0]) {
fprintf(fp, "<invalid token %u>", token);
return;
}
ti = &token_info[token];
fprintf(fp, "%.*s", (int) sizeof ti->print_name, ti->print_name);
if (!token_attr)
return;
switch (ti->attribute_fmt) {
case TAFMT_UINT:
fprintf(fp, " [%" PDP10_PRIu36 "]", token_attr->uint);
break;
case TAFMT_SYMBOL:
fprintf(fp, " [%s]", token_attr->text);
break;
case TAFMT_STRING:
fprintf(fp, " [\"%s\"]", token_attr->text);
break;
default:
break;
}
}

View File

@@ -1,103 +0,0 @@
/*
* token.def -- token definitions for PDP10 assembler
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* TOKEN(T_<name>, <print name>, <attribute fmt>)
*/
/* reserved symbols including directives; MUST come first and MUST be listed in increasing alphanumeric order */
TOKEN(T_DOT_FILE, ".file", TAFMT_NONE)
TOKEN(T_DOT_GLOBL, ".globl", TAFMT_NONE)
TOKEN(T_DOT_IDENT, ".ident", TAFMT_NONE)
TOKEN(T_DOT_SIZE, ".size", TAFMT_NONE)
TOKEN(T_DOT_TEXT, ".text", TAFMT_NONE)
TOKEN(T_DOT_TYPE, ".type", TAFMT_NONE)
/* non-reserved symbols; T_SYMBOL MUST be the first token after the list of reserved symbols */
TOKEN(T_SYMBOL, "<symbol>", TAFMT_SYMBOL)
/* literals */
TOKEN(T_UINTEGER, "<integer>", TAFMT_UINT)
TOKEN(T_STRING, "<string>", TAFMT_STRING)
/* special symbols including operators and separators */
TOKEN(T_AT, "@", TAFMT_NONE)
TOKEN(T_COLON, ":", TAFMT_NONE)
TOKEN(T_COMMA, ",", TAFMT_NONE)
TOKEN(T_DOT, ".", TAFMT_NONE)
TOKEN(T_LPAREN, "(", TAFMT_NONE)
TOKEN(T_MINUS, "-", TAFMT_NONE)
TOKEN(T_RPAREN, ")", TAFMT_NONE)
/* synthetic symbols */
TOKEN(T_NEWLINE, "<newline>", TAFMT_NONE)
TOKEN(T_EOF, "<eof>", TAFMT_NONE)
TOKEN(T_ERROR, "<error>", TAFMT_NONE)
/* XXX: old tokens not yet resurrected */
#if 0
TOKEN(T_DOT_ALIGN, ".align", TAFMT_NONE)
TOKEN(T_DOT_ASCII, ".ascii", TAFMT_NONE)
TOKEN(T_DOT_ASCIZ, ".asciz", TAFMT_NONE)
TOKEN(T_DOT_BALIGN, ".balign", TAFMT_NONE)
TOKEN(T_DOT_BSS, ".bss", TAFMT_NONE)
TOKEN(T_DOT_BYTE, ".byte", TAFMT_NONE)
TOKEN(T_DOT_COMM, ".comm", TAFMT_NONE)
TOKEN(T_DOT_DATA, ".data", TAFMT_NONE)
TOKEN(T_DOT_HIDDEN, ".hidden", TAFMT_NONE)
TOKEN(T_DOT_INTERNAL, ".internal", TAFMT_NONE)
TOKEN(T_DOT_LOCAL, ".local", TAFMT_NONE)
TOKEN(T_DOT_LONG, ".long", TAFMT_NONE)
TOKEN(T_DOT_ORG, ".org", TAFMT_NONE)
TOKEN(T_DOT_P2ALIGN, ".p2align", TAFMT_NONE)
TOKEN(T_DOT_POPSECTION, ".popsection", TAFMT_NONE)
TOKEN(T_DOT_PREVIOUS, ".previous", TAFMT_NONE)
TOKEN(T_DOT_PROTECTED, ".protected", TAFMT_NONE)
TOKEN(T_DOT_PUSHSECTION, ".pushsection", TAFMT_NONE)
TOKEN(T_DOT_RODATA, ".rodata", TAFMT_NONE)
TOKEN(T_DOT_SECTION, ".section", TAFMT_NONE)
TOKEN(T_DOT_SET, ".set", TAFMT_NONE)
TOKEN(T_DOT_SHORT, ".short", TAFMT_NONE)
TOKEN(T_DOT_SUBSECTION, ".subsection", TAFMT_NONE)
TOKEN(T_DOT_SYMVER, ".symver", TAFMT_NONE)
TOKEN(T_DOT_WEAK, ".weak", TAFMT_NONE)
TOKEN(T_DOT_WEAKREF, ".weakref", TAFMT_NONE)
/* other symbols */
TOKEN(T_REGISTER, "<register>", TAFMT_UINT)
TOKEN(T_LOCAL_LABEL, "<local label>", TAFMT_UINT) /* 1f, 2b */
/* literals */
/* operators, separators */
TOKEN(T_TILDE, "~", TAFMT_NONE)
TOKEN(T_MUL, "*", TAFMT_NONE)
TOKEN(T_DIV, "/", TAFMT_NONE)
TOKEN(T_REM, "%", TAFMT_NONE)
TOKEN(T_LSHIFT, "<<", TAFMT_NONE)
TOKEN(T_RSHIFT, ">>", TAFMT_NONE)
TOKEN(T_OR, "|", TAFMT_NONE)
TOKEN(T_AND, "&", TAFMT_NONE)
TOKEN(T_CARET, "^", TAFMT_NONE)
TOKEN(T_BANG, "!", TAFMT_NONE)
TOKEN(T_PLUS, "+", TAFMT_NONE)
TOKEN(T_EQ, "=", TAFMT_NONE)
TOKEN(T_EQEQ, "==", TAFMT_NONE)
TOKEN(T_NEQ, "!=", TAFMT_NONE)
TOKEN(T_LT, "<", TAFMT_NONE)
TOKEN(T_GT, ">", TAFMT_NONE)
TOKEN(T_GE, ">=", TAFMT_NONE)
TOKEN(T_LE, "<=", TAFMT_NONE)
TOKEN(T_ANDAND, "&&", TAFMT_NONE)
TOKEN(T_OROR, "||", TAFMT_NONE)
#endif

View File

@@ -1,56 +0,0 @@
/*
* token.h
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TOKEN_H
#define TOKEN_H
#include <stdio.h>
#include "pdp10-stdint.h"
enum token {
#define TOKEN(T,P,F) T,
#include "token.def"
#undef TOKEN
};
enum {
TAFMT_NONE = 0,
TAFMT_UINT = 1,
TAFMT_SYMBOL = 2,
TAFMT_STRING = 3,
};
struct token_info {
char print_name[15];
unsigned char attribute_fmt;
};
/* token_info[] is indexed by token and is used by token_print() to print tokens;
it is also public so the scanner can map directive names to tokens without
duplicating the names or the name-to-token mapping */
extern const struct token_info token_info[];
union token_attribute {
const char *text; /* symbol, string */
pdp10_uint36_t uint; /* uinteger */
};
void token_print(FILE *fp, enum token token, const union token_attribute *token_attr);
#endif /* TOKEN_H */

View File

@@ -1,302 +0,0 @@
/*
* tunit.c
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pdp10-elf36.h"
#include "hashtab.h"
#include "tunit.h"
/*
* String hash function, used for both section names and symbol names.
*/
static uintptr_t string_hash(const char *string)
{
const unsigned char *s;
uintptr_t h;
unsigned char c;
s = (const unsigned char*)string;
h = 0;
while ((c = *s++) != '\0')
h = (h << 5) + h + c;
return h;
}
/*
* Sections hash table.
*/
static struct section *section_from_hashnode(const struct hashnode *hashnode)
{
return hashnode ? container_of(hashnode, struct section, hashnode) : NULL;
}
static int section_eq(const struct hashnode *hashnode, const void *data)
{
return strcmp(section_from_hashnode(hashnode)->name, (const char*)data) == 0;
}
void section_init(struct section *section, const char *name)
{
section->hashnode.hashval = 0;
section->hashnode.next = NULL;
section->name = name;
section->head = NULL;
section->tailptr = &section->head;
section->dot = 0;
section->output = NULL;
section->image = NULL;
section->st_shndx = 0;
section->sh_name = 0;
section->sh_type = SHT_NULL;
section->sh_flags = 0;
section->sh_offset = 0;
section->sh_link = 0;
section->sh_addralign = 1;
section->sh_entsize = 0;
}
struct section *tunit_section_enter(struct tunit *tunit, const char *name)
{
struct section *section;
uintptr_t hashval;
hashval = string_hash(name);
section = section_from_hashnode(hashtab_lookup(&tunit->sections, hashval, name));
if (section)
return section;
section = malloc(sizeof *section);
if (!section) {
fprintf(stderr, "%s: %s: malloc(%zu) failed: %s\n", tunit->progname, __FUNCTION__, sizeof *section, strerror(errno));
return NULL;
}
section_init(section, name);
section->hashnode.hashval = hashval;
if (hashtab_insert(&tunit->sections, &section->hashnode) < 0)
return NULL;
return section;
}
static int sections_init(struct tunit *tunit)
{
struct section *section;
if (hashtab_init(&tunit->sections, 2, section_eq) < 0)
return -1;
section = tunit_section_enter(tunit, ".text");
if (!section)
return -1;
section->sh_type = SHT_PROGBITS;
section->sh_flags = SHF_ALLOC | SHF_EXECINSTR;
section->sh_addralign = 4; /* XXX: PDP10-specific */
tunit->cursect = section;
return 0;
}
/*
* String tables.
*/
pdp10_uint36_t strtab_enter(struct tunit *tunit, struct strtab *strtab, const char *name)
{
struct strtab_entry *prev, *here;
pdp10_uint36_t index;
index = 1;
prev = NULL;
here = strtab->head;
while (here != NULL) {
if (strcmp(name, here->string) == 0)
return index;
index += here->nrbytes;
prev = here;
here = here->next;
}
here = malloc(sizeof *here);
if (!here) {
fprintf(stderr, "%s: failed to allocate %zu bytes for a strtab_entry: %s\n",
tunit->progname, sizeof *here, strerror(errno));
return 0;
}
here->next = NULL;
here->string = name;
here->nrbytes = strlen(name) + 1;
if (prev) {
prev->next = here;
} else {
strtab->head = here;
index = 1;
strtab->section.dot = 1;
}
strtab->section.dot += here->nrbytes;
return index;
}
static int strtab_section_output(PDP10_FILE *pdp10fp, const struct section *section)
{
const struct strtab *strtab = container_of(section, const struct strtab, section);
struct strtab_entry *here;
unsigned int i;
if (pdp10_elf36_write_uint9(pdp10fp, '\0') < 0)
return -1;
for (here = strtab->head; here; here = here->next)
for (i = 0; i < here->nrbytes; ++i)
if (pdp10_elf36_write_uint9(pdp10fp, here->string[i]) < 0)
return -1;
return 0;
}
void strtab_init(struct strtab *strtab, const char *name)
{
section_init(&strtab->section, name);
strtab->section.sh_type = SHT_STRTAB;
strtab->section.sh_addralign = 1;
strtab->section.output = strtab_section_output;
strtab->head = NULL;
}
static struct strtab *strtab_from_hashnode(const struct hashnode *hashnode)
{
return hashnode ? container_of(hashnode, struct strtab, section.hashnode) : NULL;
}
/* XXX: generalize and merge with tunit_section_enter() */
struct strtab *tunit_strtab_section_enter(struct tunit *tunit, const char *name)
{
uintptr_t hashval;
struct strtab *strtab;
hashval = string_hash(name);
strtab = strtab_from_hashnode(hashtab_lookup(&tunit->sections, hashval, name));
if (strtab)
return strtab;
strtab = malloc(sizeof *strtab);
if (!strtab) {
fprintf(stderr, "%s: %s: malloc(%zu) failed: %s\n", tunit->progname, __FUNCTION__, sizeof *strtab, strerror(errno));
return NULL;
}
strtab_init(strtab, name);
/* XXX: undo stuff strtab_init() did which breaks .ident */
strtab->section.sh_type = SHT_NULL;
strtab->section.hashnode.hashval = hashval;
if (hashtab_insert(&tunit->sections, &strtab->section.hashnode) < 0)
return NULL;
return strtab;
}
/*
* Symbols hash table.
*/
static struct symbol *symbol_from_hashnode(const struct hashnode *hashnode)
{
return hashnode ? container_of(hashnode, struct symbol, hashnode) : NULL;
}
static int symbol_eq(const struct hashnode *hashnode, const void *data)
{
return strcmp(symbol_from_hashnode(hashnode)->name, (const char*)data) == 0;
}
struct symbol *tunit_symbol_lookup(struct tunit *tunit, const char *name)
{
uintptr_t hashval;
struct symbol *symbol;
hashval = string_hash(name);
symbol = symbol_from_hashnode(hashtab_lookup(&tunit->symbols, hashval, name));
if (!symbol)
fprintf(stderr, "%s: %s: symbol %s not found\n", tunit->progname, __FUNCTION__, name);
return symbol;
}
struct symbol *tunit_symbol_enter(struct tunit *tunit, const char *name)
{
uintptr_t hashval;
struct symbol *symbol;
hashval = string_hash(name);
symbol = symbol_from_hashnode(hashtab_lookup(&tunit->symbols, hashval, name));
if (symbol)
return symbol;
symbol = malloc(sizeof *symbol);
if (!symbol) {
fprintf(stderr, "%s: %s: malloc(%zu) failed: %s\n", tunit->progname, __FUNCTION__, sizeof *symbol, strerror(errno));
return NULL;
}
symbol->hashnode.hashval = hashval;
symbol->name = name;
symbol->section = NULL;
symbol->defined = 0;
symbol->st_value = 0;
symbol->st_size = 0;
symbol->st_info = 0;
symbol->st_name = 0;
if (hashtab_insert(&tunit->symbols, &symbol->hashnode) < 0)
return NULL;
return symbol;
}
static int symbols_init(struct tunit *tunit)
{
return hashtab_init(&tunit->symbols, 8, symbol_eq);
}
/*
* Translation unit init and fini ops.
*/
int tunit_init(struct tunit *tunit, const char *progname)
{
tunit->progname = progname;
if (sections_init(tunit) < 0)
return -1;
if (symbols_init(tunit) < 0)
return -1;
return 0;
}
void tunit_fini(struct tunit *tunit)
{
}

View File

@@ -1,152 +0,0 @@
/*
* tunit.h
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TUNIT_H
#define TUNIT_H
#include <stddef.h>
#include "pdp10-elf36.h"
#include "pdp10-stdio.h"
#include "hashtab.h"
/*
* A directive, label, or instruction is parsed to a statement, which is
* either interpreted immediately or appended to the representation of the
* current section.
*/
enum stmt_tag {
/* directives */
S_DOT_FILE,
S_DOT_GLOBL,
S_DOT_IDENT,
S_DOT_SIZE,
S_DOT_TEXT,
S_DOT_TYPE_FUNCTION,
/* non-directives */
S_LABEL,
S_INSN,
};
struct stmt {
struct stmt *next;
enum stmt_tag tag;
union {
struct { /* S_DOT_FILE, S_DOT_IDENT */
const char *text; /* XXX: should be pdp10_uint9_t* */
} string;
struct { /* S_DOT_GLOBL, S_LABEL, S_DOT_SIZE, S_DOT_TYPE_FUNCTION */
const char *name;
} symbol;
struct { /* S_INSN */
unsigned int opcode;
unsigned int accumulator;
int at;
unsigned int address; /* XXX: relocatable expr */
unsigned int indexreg;
} insn;
} u;
};
/*
* Sections.
*
* There are several kinds of sections:
* - generic sections with an image array
* these contain instructions or initialized data
* - strtab sections
* these contain a strtab and a specialised ->output() method
*/
struct section {
struct hashnode hashnode;
const char *name;
struct stmt *head, **tailptr;
unsigned long dot;
int (*output)(PDP10_FILE*, const struct section*); /* must be present if ->image is NULL */
pdp10_uint9_t *image; /* assigned during assembly, must be present if ->output is NULL */
Elf36_Word st_shndx; /* assigned during output */
Elf36_Word sh_name; /* assigned during output */
Elf36_Word sh_type;
Elf36_Word sh_flags;
Elf36_Word sh_offset; /* assigned during output */
Elf36_Word sh_link; /* assigned during output */
Elf36_Word sh_addralign;
Elf36_Word sh_entsize; /* assigned during output */
};
struct strtab_entry {
struct strtab_entry *next;
const char *string;
unsigned int nrbytes; /* strlen(string) + 1 */
};
struct strtab {
struct section section;
struct strtab_entry *head;
};
struct symbol {
struct hashnode hashnode;
const char *name;
struct section *section; /* NULL if UNDEF or ABS, otherwise non-NULL */
unsigned char defined;
Elf36_Addr st_value;
Elf36_Word st_size;
Elf36_Uchar st_info;
Elf36_Word st_name; /* assigned during output */
};
/*
* The translation unit object is the top-level container for the
* representation of the sections, other information collected from
* the input, and information synthesized during assembly.
*/
struct tunit {
const char *progname;
struct hashtab sections;
struct section *cursect;
struct hashtab symbols;
};
int tunit_init(struct tunit *tunit, const char *progname);
void tunit_fini(struct tunit *tunit);
void section_init(struct section *section, const char *name);
struct section *tunit_section_enter(struct tunit *tunit, const char *name);
struct strtab *tunit_strtab_section_enter(struct tunit *tunit, const char *name);
void strtab_init(struct strtab *strtab, const char *name);
pdp10_uint36_t strtab_enter(struct tunit *tunit, struct strtab *strtab, const char *name);
struct symbol *tunit_symbol_lookup(struct tunit *tunit, const char *name);
struct symbol *tunit_symbol_enter(struct tunit *tunit, const char *name);
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#endif /* TUNIT_H */

View File

@@ -1,126 +0,0 @@
/*
* pdp10-ar.h
* Copyright (C) 2013-2019 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This is essentially the standard SVR4/GNU AR format, with 'char'
* replaced by 'pdp10_uint9_t' throughout.
* Groups of 4 bytes in the symbol table denote pdp10_uint36_t
* values rather than plain int or uint32_t values.
*/
#ifndef PDP10_AR_H
#define PDP10_AR_H
#include "pdp10-stdint.h" /* pdp10_{u,}int{9,18,36}_t */
#define PDP10_ARMAG { '!', '<', 'a', 'r', 'c', 'h', '>', '\n' } /* String that begins an archive file. */
#define PDP10_SARMAG 8 /* Size of that string. */
#define PDP10_ARFMAG { '`', '\n' } /* String in ar_fmag at end of each header. */
struct pdp10_ar_hdr {
pdp10_uint9_t ar_name[16]; /* Member file name, sometimes / terminated. */
pdp10_uint9_t ar_date[12]; /* File modification time, decimal seconds since Epoch. */
pdp10_uint9_t ar_uid[6]; /* File user id, in decimal. */
pdp10_uint9_t ar_gid[6]; /* File group id, in decimal. */
pdp10_uint9_t ar_mode[8]; /* File mode, in octal. */
pdp10_uint9_t ar_size[10]; /* File size, in decimal. */
pdp10_uint9_t ar_fmag[2]; /* Always contains ARFMAG. */
};
#define PDP10_ARHDR_SIZEOF 60
/*
* Additional information summarized from the FreeBSD ar(5) manual page
* <https://www.freebsd.org/cgi/man.cgi?query=ar&sektion=5>.
*
* DESCRIPTION
*
* The archive file starts with an identifying byte sequence of the seven ASCII characters
* '!<arch>' followed by an ASCII linefeed character (see the constant "ARMAG" in the header
* file <ar.h>).
* Archive members follow the initial identifying byte sequence. Each archive member is
* prefixed by a fixed size header describing the file attributes associated with the member.
*
* Archive Headers
*
* Archive headers are placed at an even offset in the archive file. If the data for an
* archive member ends at an odd byte offset, then a padding byte with value 0x0A is used
* to position the next archive header on an even byte offset.
*
* Unused bytes in the fields of an archive header are set to the value 0x20.
*
* Representing File Names
*
* SVR4/GNU
* File names that are up to 15 characters long are stored directly in the ar_name
* field of the header, terminated by a "/" character.
* If the file name is larger than would fit in the space for the ar_name field,
* then the actual file name is kept in the archive string table, and the decimal
* offset of the file name in the string table is stored in the ar_name field,
* prefixed by a "/" character.
*
* Special Archive Members
*
* The following archive members are special.
*
* "/"
* In the SVR4/GNU variant of the archive format, the archive member with name "/"
* denotes an archive symbol table. If present, this member will be the very first
* member of the archive.
*
* "//"
* In the SVR4/GNU variant of the archive format, the archive member with name "//"
* denotes the archive string table. This special member is used to hold filenames
* that do not fit in the file name field of the header. If present, this member
* immediately follows the archive symbol table if an archive symbol table is present,
* or is the first member otherwise.
*
* Archive String Tables
*
* An archive string table is used in the SVR4/GNU archive format to hold file names that
* are too large to fit into the constraints of the ar_name field of the archive header.
* An archive string table contains a sequence of file names. Each file name in the archive
* string table is terminated by the sequence 0x2F, 0x0A (the ASCII string "/\n"). No
* padding is used to separate adjacent file names.
*
* Archive Symbol Tables
*
* Archive symbol tables are used to speed up link editing by providing a mapping between
* the program symbols defined in the archive and the corresponding archive members.
* Archive symbol tables are managed by the ranlib utility. The format of archive symbol
* tables is as follows:
*
* SVR4/GNU
* In the SVR4/GNU archive format, the archive symbol table starts with a 4-byte binary
* value consisting of the number of entries contained in the archive symbol table.
* This count of entries is stored most significant byte first. Next, there are 'count'
* 4-byte numbers, each stored most significant byte first. Each number is a binary
* offset to the archive header for the member in the archive file for the corresponding
* symbol table entry. After the binary offset values, there are 'count' NUL-terminated
* strings in sequence, holding the symbol names for the corresponding symbol table entries.
*/
/*
* Further references:
* <http://www.linker-aliens.org/blogs/ali/entry/64_bit_archives_needed/>
* <http://linux.die.net/man/1/llvm-ar>
* "man -s 3HEAD ar.h" on Solaris 10
*/
#endif /* PDP10_AR_H */

View File

@@ -1,155 +0,0 @@
/*
* pdp10-arith.h -- arithmetic on PDP10 integer types
* Copyright (C) 2013-2018 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PDP10_ARITH_H
#define PDP10_ARITH_H
#include "pdp10-stdint.h"
/* Zero-extend a pdp10_{u,}int36_t to the full width of its representation type.
* Use this to prepare operands before unsigned operations, or to correct results
* after signed operations.
*/
static inline pdp10_uint36_t pdp10_zext_uint36(pdp10_uint36_t x)
{
return x & PDP10_UINT36_MAX;
}
/* Sign-extend a pdp10_int36_t to the full width of its representation type.
* Use this to prepare operands before signed operations.
*
* Based on the following trick for sign-extending an octet x: ((x & 0xff) ^ 0x80) - 0x80,
* c.f. <http://sourceware.org/ml/binutils/2001-05/msg00093.html>.
*/
static inline pdp10_int36_t pdp10_sext_int36(pdp10_uint36_t x)
{
const pdp10_uint36_t PDP10_UINT36_SBIT = ~(PDP10_UINT36_MAX >> 1) & PDP10_UINT36_MAX;
return ((x & PDP10_UINT36_MAX) ^ PDP10_UINT36_SBIT) - PDP10_UINT36_SBIT;
}
/* Sign-extend a pdp10_uint18_t to the full width of its representation type. */
static inline pdp10_uint18_t pdp10_sext_uint18(pdp10_uint18_t x)
{
const pdp10_uint18_t PDP10_UINT18_SBIT = ~(PDP10_UINT18_MAX >> 1) & PDP10_UINT18_MAX;
return ((x & PDP10_UINT18_MAX) ^ PDP10_UINT18_SBIT) - PDP10_UINT18_SBIT;
}
static inline pdp10_uint36_t pdp10_neg_int36(pdp10_uint36_t x)
{
return pdp10_zext_uint36(-pdp10_sext_int36(x));
}
static inline pdp10_uint36_t pdp10_not_int36(pdp10_uint36_t x)
{
return pdp10_zext_uint36(~pdp10_sext_int36(x));
}
static inline pdp10_uint36_t pdp10_add_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return pdp10_zext_uint36(pdp10_sext_int36(x) + pdp10_sext_int36(y));
}
static inline pdp10_uint36_t pdp10_sub_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return pdp10_zext_uint36(pdp10_sext_int36(x) - pdp10_sext_int36(y));
}
static inline pdp10_uint36_t pdp10_mul_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return pdp10_zext_uint36(pdp10_sext_int36(x) * pdp10_sext_int36(y));
}
static inline pdp10_uint36_t pdp10_div_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return pdp10_zext_uint36(pdp10_sext_int36(x) / pdp10_sext_int36(y));
}
static inline pdp10_uint36_t pdp10_rem_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return pdp10_zext_uint36(pdp10_sext_int36(x) % pdp10_sext_int36(y));
}
static inline pdp10_uint36_t pdp10_lsl_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return pdp10_zext_uint36(pdp10_zext_uint36(x) << pdp10_zext_uint36(y));
}
static inline pdp10_uint36_t pdp10_lsr_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return pdp10_zext_uint36(pdp10_zext_uint36(x) >> pdp10_zext_uint36(y));
}
static inline pdp10_uint36_t pdp10_asr_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return pdp10_zext_uint36(pdp10_sext_int36(x) >> pdp10_zext_uint36(y));
}
static inline pdp10_uint36_t pdp10_or_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return (pdp10_zext_uint36(x) | pdp10_zext_uint36(y));
}
static inline pdp10_uint36_t pdp10_and_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return (pdp10_zext_uint36(x) & pdp10_zext_uint36(y));
}
static inline pdp10_uint36_t pdp10_xor_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return (pdp10_zext_uint36(x) ^ pdp10_zext_uint36(y));
}
static inline int pdp10_eq_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return pdp10_zext_uint36(x) == pdp10_zext_uint36(y);
}
static inline int pdp10_ne_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return pdp10_zext_uint36(x) != pdp10_zext_uint36(y);
}
static inline int pdp10_lt_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return pdp10_sext_int36(x) < pdp10_sext_int36(y);
}
static inline int pdp10_gt_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return pdp10_sext_int36(x) > pdp10_sext_int36(y);
}
static inline int pdp10_ge_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return pdp10_sext_int36(x) >= pdp10_sext_int36(y);
}
static inline int pdp10_le_int36(pdp10_uint36_t x, pdp10_uint36_t y)
{
return pdp10_sext_int36(x) <= pdp10_sext_int36(y);
}
static inline int pdp10_nonzero_int36(pdp10_uint36_t x)
{
return pdp10_zext_uint36(x) != 0;
}
#endif /* PDP10_ARITH_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,45 +0,0 @@
/*
* pdp10-extint.h
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Provide types and procedures for converting 18 and 36-bit integers
* to and from arrays of 9-bit bytes (nonets). Use these together with
* pdp10_fread() and pdp10_fwrite() to convert 18 and 36-bit integers
* between host-level and file-level binary representations.
*/
#ifndef PDP10_EXTINT_H
#define PDP10_EXTINT_H
#include "pdp10-stdint.h"
struct pdp10_ext_uint18 {
pdp10_uint9_t nonet[2];
};
void pdp10_uint18_to_ext(pdp10_uint18_t val, struct pdp10_ext_uint18 *ext);
pdp10_uint18_t pdp10_uint18_from_ext(const struct pdp10_ext_uint18 *ext);
struct pdp10_ext_uint36 {
pdp10_uint9_t nonet[4];
};
void pdp10_uint36_to_ext(pdp10_uint36_t val, struct pdp10_ext_uint36 *ext);
pdp10_uint36_t pdp10_uint36_from_ext(const struct pdp10_ext_uint36 *ext);
#endif /* PDP10_EXTINT_H */

View File

@@ -1,55 +0,0 @@
/*
* pdp10-inttypes.h -- inttypes.h clone for PDP10
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Provide format conversions for 18 and 36-bit integers.
* For 9-bit integers, pdp_uint9_t, just use the regular
* int-sized d/o/u/x formats.
*/
#ifndef PDP10_INTTYPES_H
#define PDP10_INTTYPES_H
#include <inttypes.h>
#include "pdp10-stdint.h"
#if defined(UINT18_MAX)
#define PDP10_PRId18 PRId18
#define PDP10_PRIo18 PRIo18
#define PDP10_PRIu18 PRIu18
#define PDP10_PRIx18 PRIx18
#else
#define PDP10_PRId18 PRId32
#define PDP10_PRIo18 PRIo32
#define PDP10_PRIu18 PRIu32
#define PDP10_PRIx18 PRIx32
#endif
#if defined(UINT36_MAX)
#define PDP10_PRId36 PRId36
#define PDP10_PRIo36 PRIo36
#define PDP10_PRIu36 PRIu36
#define PDP10_PRIx36 PRIx36
#else
#define PDP10_PRId36 PRId64
#define PDP10_PRIo36 PRIo64
#define PDP10_PRIu36 PRIu64
#define PDP10_PRIx36 PRIx64
#endif
#endif /* PDP10_INTTYPES_H */

View File

@@ -1,241 +0,0 @@
/*
* pdp10-opcodes.h
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Word Representation
* ===================
*
*
* 11111111112222222222333333
* 012345678901234567890123456789012345
* +------------------------------------+
* | |
* +------------------------------------+
*
* The basic storage unit is a 36-bit wide word. Its bits are numbered 0
* to 35, in left-to-right order, with bit 0 being the most significant
* and bit 35 the least significant. (Similar to IBM's bit numbering but
* opposite to most modern processors.)
*
* The architecture supports sub-word storage units via special instructions
* and specially formatted "byte" pointers, where a byte may be from 0 to 36
* bits wide. Incrementing a byte pointer moves it right over a word towards
* its less significant bits, implying a big-endian storage model.
*
* A 72-bit long integer is composed of two adjacent words. It stores the most
* significant bits in first word (lower address) and the least significant bits
* in the second word (higher address), again implying a big-endian storage model.
*
*
* Instruction Representation
* ==========================
*
* Basic instructions are stored in 36-bit words with the following format:
*
* 111 1 1111 112222222222333333
* 012345678 9012 3 4567 890123456789012345
* +---------+----+-+----+------------------+
* | opcode | A |I| X | Y |
* +---------+----+-+----+------------------+
* 9 bits 4 1 4 18 bits
*
* A 9-bit opcode is stored in the high 9 bits.
* A is a 4-bit field specifying the accumulator (a register).
* I is a 1-bit field specifying indirect addressing.
* X is a 4-bit field specifying the index register.
* Y is an 18-bit field specifying an address or offset.
*
* E, the effective addreess, is computed from I, X, and Y.
*
* In some instructions A contains further opcode bits.
*
* In some instructions A is unused and should be zero.
*
* Instructions that not compute an effective address E
* should have I, X, and Y set to zero.
*
* IO instructions have a slightly different format:
*
* 111 1 1111 112222222222333333
* 012 3456789 012 3 4567 890123456789012345
* +---+-------+---+-+----+------------------+
* |op1| device|op2|I| X | Y |
* +---+-------+---+-+----+------------------+
* 3 7 bits 3 1 4 18 bits
*
* The op1 field is all-bits-one (7), the device field addresses the selected device,
* and the op2 field specifies the operation. Both devices internal to the processor
* and devices attached via external buses can be accessed.
*
* Some non-IO instructions also have a 7 in their high three bits.
*
* Extended instructions consist of two separate instruction words:
*
* A:
* 111 1 1111 112222222222333333
* 012345678 9012 3 4567 890123456789012345
* +---------+----+-+----+------------------+
* | 0123 | A |I| X | Y |
* +---------+----+-+----+------------------+
* 9 bits 4 1 4 18 bits
*
* E0:
* 111 1 1111 112222222222333333
* 012345678 9012 3 4567 890123456789012345
* +---------+----+-+----+------------------+
* | xopcode |0000|I| X | Y |
* +---------+----+-+----+------------------+
* 9 bits 4 1 4 18 bits
*
* The first word is stored at address A in the instruction stream in the basic
* format with opcode 0123. The second word is stored at the effective address
* E0 specified by the the first word. Its accumulator field is unused and must
* be zero for compatibility with future extensions.
*/
/*
* Known PDP10 CPU models, each represented by a distinct bit value.
*
* These are combined with bit-wise 'and', 'or', and 'not' operations
* to form sets of CPU models, used to check if a given mnemonic or
* opcode is available for a selected set of CPUs.
*/
enum {
/*
* DEC processors.
*/
PDP10_NONE = 0,
PDP6_166 = 1 << 0, /* DEC PDP-6 Type 166 Arithmetic Processor */
PDP10_KA10 = 1 << 1, /* DEC PDP-10 KA10 */
PDP10_KA10_ITS = 1 << 2, /* DEC PDP-10 KA10, ITS microcode */
PDP10_KI10 = 1 << 3, /* DEC PDP-10 KI10 */
PDP10_KL10 = 1 << 4, /* DEC PDP-10 KL10 */
PDP10_KL10_ITS = 1 << 5, /* DEC PDP-10 KL10, ITS microcode */
PDP10_KL10_271 = 1 << 6, /* DEC PDP-10 KL10, microcode version >= 271 (many extensions) */
PDP10_KS10 = 1 << 7, /* DEC PDP-10 KS10 */
PDP10_KS10_ITS = 1 << 8, /* DEC PDP-10 KS10, ITS microcode */
PDP10_KC10 = 1 << 9, /* DEC PDP-10 KC10 (Jupiter, full extended addressing) */
PDP10_KD10 = 1 << 10, /* DEC PDP-10 KD10 (Minnow, KS10 extended to match KC10 specs) */
/*
* XKL Processors.
*
* The XKL-2 is believed to have been built, and to contain some instruction set
* extensions, but no details are known about it at this time.
*/
PDP10_XKL1 = 1 << 11, /* XKL TOAD-1 XKL-1, KL10 clone with KC10-like full extended addressing */
/*
* Other clones, not yet supported.
*
* System Concepts SC-20, SC-25, SC-30M, SC-40 (KC10-like)
*
* Foonly F-1, F-2, F-3, F-4 (KI10/KL10-hybrid)
*
* Xerox PARC MAXC (KI10-like?)
*/
/*
* Convenience constants for combinations of CPU models.
*/
PDP10_ALL = PDP10_XKL1 | (PDP10_XKL1 - 1), /* XXX: depends on XKL1 being last above */
PDP10_KL10_271up = PDP10_KL10_271 | PDP10_XKL1,
PDP10_KL10any = PDP10_KL10 | PDP10_KL10_ITS | PDP10_KL10_271up,
PDP10_KL10up = PDP10_KL10any | PDP10_KS10,
PDP10_KI10_to_KL10 = PDP10_KI10 | PDP10_KL10any,
PDP10_KI10up = PDP10_KI10 | PDP10_KL10up,
PDP10_KA10any = PDP10_KA10 | PDP10_KA10_ITS,
PDP10_KA10up = PDP10_KA10any | PDP10_KI10up,
PDP10_KA10_to_KI10 = PDP10_KA10 | PDP10_KI10, /* XXX: should that be KA10_any? */
PDP10_KA10_to_KL10 = PDP10_KA10_to_KI10 | PDP10_KL10any,
PDP10_not_KS10_or_XKL1 = PDP10_ALL & ~(PDP10_KS10 | PDP10_XKL1), /* XXX: should that be KS10_any? */
PDP10_ITS = PDP10_KA10_ITS | PDP10_KL10_ITS | PDP10_KS10_ITS,
PDP6_166_to_PDP10_KI10 = PDP6_166 | PDP10_KA10_to_KI10,
};
typedef unsigned short pdp10_cpu_models_t;
/*
* Device names for IO instructions.
*/
struct pdp10_cpu_device {
const char *name;
unsigned char device; /* device field in bits 3-9 of IO instructions */
pdp10_cpu_models_t models;
};
const struct pdp10_cpu_device *
pdp10_cpu_device_from_name(pdp10_cpu_models_t models, const char *name);
/*
* Instructions.
*/
enum {
/* Each instruction belongs to exactly one of these primary categories,
which determine how the high 13 bits are to be interpreted: */
/* XXX: change this to separate mutually exclusive bits to simplify usage */
PDP10_INSN_BASIC = 0,
PDP10_INSN_A_OPCODE = 1,
PDP10_INSN_A_UNUSED = 2,
PDP10_INSN_IO = 3,
/* Flag set to indicate that E is unused. */
PDP10_INSN_E_UNUSED = 4,
/* Flag set to indicate that this is the second word of an extended instruction. */
PDP10_INSN_EXTENDED = 8,
};
typedef unsigned char pdp10_insn_fmt_t;
struct pdp10_insn {
const char *name;
/*
* The high13 field is 13 bits, formatted as:
* <9 bit opcode><0000> BASIC, A_UNUSED
* <9 + 4 bit opcode> A_OPCODE
* <111><0000000><3 bit op> IO
*
* An extended instruction uses the BASIC format with opcode 0123 for
* the first word, and the A_UNUSED | EXTENDED format for the second word.
*/
unsigned short high13;
pdp10_insn_fmt_t fmt;
pdp10_cpu_models_t models;
};
/* for assembly */
const struct pdp10_insn *
pdp10_insn_from_name(pdp10_cpu_models_t models, const char *name);
/* for disassembly */
const struct pdp10_insn *
pdp10_insn_from_high13(pdp10_cpu_models_t models, unsigned int high13, int extended);

View File

@@ -1,88 +0,0 @@
/*
* pdp10-stdint.h -- stdint.h clone for PDP10
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Provide stdint.h-like type names and macros for 9, 18, and 36-bit unsigned
* integer types.
*
* Standard uint<N>_t types must not contain any any extraneous bits, but that
* cannot be guaranteed for these 9, 18, and 36-bit types when they are embedded
* in larger 16, 32, and 64-bit host types. For arithmetic on these types, use
* the operations provided by pdp10-arith.h.
*
* Do not use these 18 or 36-bit types for file-level binary data structures,
* instead use the pdp10-extint.h and pdp10-stdio.h facilities to explicitly
* convert between file-level and host-level binary data structures.
*/
#ifndef PDP10_STDINT_H
#define PDP10_STDINT_H
#include <stdint.h>
#if defined(UINT9_MAX)
typedef uint9_t pdp10_uint9_t;
#define PDP10_UINT9_MAX UINT9_MAX
#define PDP10_UINT9_C(c) UINT9_C(c)
#else /* !UINT9_MAX */
typedef uint16_t pdp10_uint9_t;
#define PDP10_UINT9_MAX ((1U << 9) - 1)
#define PDP10_UINT9_C(c) c
#endif /* !UINT9_MAX */
#if defined(UINT18_MAX)
typedef uint18_t pdp10_uint18_t;
#define PDP10_UINT18_MAX UINT18_MAX
#define PDP10_UINT18_C(c) UINT18_C(c)
#else /* !UINT18_MAX */
typedef uint32_t pdp10_uint18_t;
#define PDP10_UINT18_MAX ((1UL << 18) - 1)
#define PDP10_UINT18_C(c) c ## U
#endif /* !UINT18_MAX */
#if defined(UINT36_MAX)
typedef uint36_t pdp10_uint36_t;
#define PDP10_UINT36_MAX UINT36_MAX
#define PDP10_UINT36_C(c) UINT36_C(c)
typedef int36_t pdp10_int36_t;
#define PDP10_INT36_MAX INT36_MAX
#define PDP10_INT36_C(c) INT36_C(c)
#else /* !UINT36_MAX */
typedef uint64_t pdp10_uint36_t;
#define PDP10_UINT36_MAX ((1ULL << 36) - 1)
#define PDP10_UINT36_C(c) c ## ULL
typedef int64_t pdp10_int36_t;
#define PDP10_INT36_MAX ((1LL << (36 - 1)) - 1)
#define PDP10_INT36_C(c) c ## LL
#endif /* !UINT36_MAX */
#endif /* PDP10_STDINT_H */

View File

@@ -1,58 +0,0 @@
/*
* pdp10-stdio.h -- I/O of nonet-based files on octet-based hosts
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Provide stdio.h-like interface for I/O to and from files with 9-bit logical bytes (nonets),
* represented by native files with 8-bit physical bytes (octets).
*/
#ifndef PDP10_STDIO_H
#define PDP10_STDIO_H
#include <sys/types.h> /* off_t */
#include <stdint.h>
struct pdp10_file;
typedef struct pdp10_file PDP10_FILE;
/* append modes are not permitted */
PDP10_FILE *pdp10_fdopen(int fd, const char *mode);
PDP10_FILE *pdp10_fopen(const char *path, const char *mode);
int pdp10_fflush(PDP10_FILE *pdp10fp);
int pdp10_fclose(PDP10_FILE *pdp10fp);
int pdp10_fgetc(PDP10_FILE *pdp10fp); /* returns a nonet, [0-511], or EOF */
int pdp10_fputc(uint16_t nonet_ch, PDP10_FILE *pdp10fp);
enum {
PDP10_SEEK_SET = 0,
PDP10_SEEK_CUR = 1,
PDP10_SEEK_END = 2,
};
int pdp10_fseeko(PDP10_FILE *pdp10fp, off_t offset, int whence);
off_t pdp10_ftello(PDP10_FILE *pdp10fp);
/* pdp10_fread() and pdp10_fwrite() deliberately only permit transfers of strings
* (size == 1), marshalled 9/18/36-bit primitives (nmemb == 1, size == 1, 2, or 4),
* or empty objects (size == 0 || nmemb == 0). To transfer structures, transfer
* their primitive fields individually.
*/
size_t pdp10_fread(uint16_t *ptr, size_t size, size_t nmemb, PDP10_FILE *pdp10fp);
size_t pdp10_fwrite(const uint16_t *ptr, size_t size, size_t nmemb, PDP10_FILE *pdp10fp);
#endif /* PDP10_STDIO_H */

View File

@@ -1,33 +0,0 @@
# lib/Makefile
# Copyright (C) 2013-2015 Mikael Pettersson
#
# This file is part of pdp10-tools.
#
# pdp10-tools is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pdp10-tools is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
CC=gcc
CFLAGS=-O2 -g -Wall
CPPFLAGS=-I../include
LIBOBJS=pdp10-elf36.o pdp10-extint.o pdp10-opcodes.o pdp10-stdio.o
all: $(LIBOBJS)
pdp10-elf36.o: pdp10-elf36.c ../include/pdp10-elf36.h ../include/pdp10-extint.h ../include/pdp10-stdint.h ../include/pdp10-stdio.h
pdp10-extint.o: pdp10-extint.c ../include/pdp10-extint.h ../include/pdp10-stdint.h
pdp10-opcode.o: pdp10-opcode.c ../include/pdp10-opcodes.h
pdp10-stdio.o: pdp10-stdio.c ../include/pdp10-stdio.h
clean:
rm -f $(LIBOBJS) a.out core.*

View File

@@ -1,294 +0,0 @@
/*
* pdp10-elf36.c -- I/O of Elf36 files
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pdp10-elf36.h"
#include "pdp10-extint.h"
#include "pdp10-stdio.h"
int pdp10_elf36_write_uint9(PDP10_FILE *pdp10fp, pdp10_uint9_t val)
{
return pdp10_fputc(val, pdp10fp);
}
int pdp10_elf36_read_uint9(PDP10_FILE *pdp10fp, pdp10_uint9_t *dst)
{
int val;
val = pdp10_fgetc(pdp10fp);
if (val < 0)
return -1;
*dst = val;
return 0;
}
int pdp10_elf36_write_uint18(PDP10_FILE *pdp10fp, pdp10_uint18_t val)
{
struct pdp10_ext_uint18 ext18;
unsigned int i;
pdp10_uint18_to_ext(val, &ext18);
for (i = 0; i < 2; ++i)
if (pdp10_elf36_write_uint9(pdp10fp, ext18.nonet[i]) < 0)
return -1;
return 0;
}
int pdp10_elf36_read_uint18(PDP10_FILE *pdp10fp, pdp10_uint18_t *dst)
{
unsigned int i;
struct pdp10_ext_uint18 ext18;
for (i = 0; i < 2; ++i)
if (pdp10_elf36_read_uint9(pdp10fp, &ext18.nonet[i]) < 0)
return -1;
*dst = pdp10_uint18_from_ext(&ext18);
return 0;
}
int pdp10_elf36_write_uint36(PDP10_FILE *pdp10fp, pdp10_uint36_t val)
{
struct pdp10_ext_uint36 ext36;
unsigned int i;
pdp10_uint36_to_ext(val, &ext36);
for (i = 0; i < 4; ++i)
if (pdp10_elf36_write_uint9(pdp10fp, ext36.nonet[i]) < 0)
return -1;
return 0;
}
int pdp10_elf36_read_uint36(PDP10_FILE *pdp10fp, pdp10_uint36_t *dst)
{
unsigned int i;
struct pdp10_ext_uint36 ext36;
for (i = 0; i < 4; ++i)
if (pdp10_elf36_read_uint9(pdp10fp, &ext36.nonet[i]) < 0)
return -1;
*dst = pdp10_uint36_from_ext(&ext36);
return 0;
}
int pdp10_elf36_write_sint36(PDP10_FILE *pdp10fp, pdp10_int36_t val)
{
return pdp10_elf36_write_uint36(pdp10fp, val);
}
int pdp10_elf36_read_sint36(PDP10_FILE *pdp10fp, pdp10_int36_t *dst)
{
pdp10_uint36_t tmp;
if (pdp10_elf36_read_uint36(pdp10fp, &tmp) < 0)
return -1;
*dst = tmp;
return 0;
}
int pdp10_elf36_write_ehdr(PDP10_FILE *pdp10fp, const Elf36_Ehdr *ehdr)
{
int i;
for (i = 0; i < EI_NIDENT; ++i)
if (pdp10_elf36_write_uint9(pdp10fp, ehdr->e_ident[i]) < 0)
return -1;
if (pdp10_elf36_write_uint18(pdp10fp, ehdr->e_type) < 0
|| pdp10_elf36_write_uint18(pdp10fp, ehdr->e_machine) < 0
|| pdp10_elf36_write_uint36(pdp10fp, ehdr->e_version) < 0
|| pdp10_elf36_write_uint36(pdp10fp, ehdr->e_entry) < 0
|| pdp10_elf36_write_uint36(pdp10fp, ehdr->e_phoff) < 0
|| pdp10_elf36_write_uint36(pdp10fp, ehdr->e_shoff) < 0
|| pdp10_elf36_write_uint36(pdp10fp, ehdr->e_flags) < 0
|| pdp10_elf36_write_uint18(pdp10fp, ehdr->e_ehsize) < 0
|| pdp10_elf36_write_uint18(pdp10fp, ehdr->e_phentsize) < 0
|| pdp10_elf36_write_uint18(pdp10fp, ehdr->e_phnum) < 0
|| pdp10_elf36_write_uint18(pdp10fp, ehdr->e_shentsize) < 0
|| pdp10_elf36_write_uint18(pdp10fp, ehdr->e_shnum) < 0
|| pdp10_elf36_write_uint18(pdp10fp, ehdr->e_shstrndx) < 0)
return -1;
return 0;
}
int pdp10_elf36_read_ehdr(PDP10_FILE *pdp10fp, Elf36_Ehdr *ehdr)
{
int i;
for (i = 0; i < EI_NIDENT; ++i)
if (pdp10_elf36_read_uint9(pdp10fp, &ehdr->e_ident[i]) < 0)
return -1;
if (pdp10_elf36_read_uint18(pdp10fp, &ehdr->e_type) < 0
|| pdp10_elf36_read_uint18(pdp10fp, &ehdr->e_machine) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &ehdr->e_version) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &ehdr->e_entry) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &ehdr->e_phoff) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &ehdr->e_shoff) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &ehdr->e_flags) < 0
|| pdp10_elf36_read_uint18(pdp10fp, &ehdr->e_ehsize) < 0
|| pdp10_elf36_read_uint18(pdp10fp, &ehdr->e_phentsize) < 0
|| pdp10_elf36_read_uint18(pdp10fp, &ehdr->e_phnum) < 0
|| pdp10_elf36_read_uint18(pdp10fp, &ehdr->e_shentsize) < 0
|| pdp10_elf36_read_uint18(pdp10fp, &ehdr->e_shnum) < 0
|| pdp10_elf36_read_uint18(pdp10fp, &ehdr->e_shstrndx) < 0)
return -1;
return 0;
}
int pdp10_elf36_write_shdr(PDP10_FILE *pdp10fp, const Elf36_Shdr *shdr)
{
if (pdp10_elf36_write_uint36(pdp10fp, shdr->sh_name) < 0
|| pdp10_elf36_write_uint36(pdp10fp, shdr->sh_type) < 0
|| pdp10_elf36_write_uint36(pdp10fp, shdr->sh_flags) < 0
|| pdp10_elf36_write_uint36(pdp10fp, shdr->sh_addr) < 0
|| pdp10_elf36_write_uint36(pdp10fp, shdr->sh_offset) < 0
|| pdp10_elf36_write_uint36(pdp10fp, shdr->sh_size) < 0
|| pdp10_elf36_write_uint36(pdp10fp, shdr->sh_link) < 0
|| pdp10_elf36_write_uint36(pdp10fp, shdr->sh_info) < 0
|| pdp10_elf36_write_uint36(pdp10fp, shdr->sh_addralign) < 0
|| pdp10_elf36_write_uint36(pdp10fp, shdr->sh_entsize) < 0)
return -1;
return 0;
}
int pdp10_elf36_read_shdr(PDP10_FILE *pdp10fp, Elf36_Shdr *shdr)
{
if (pdp10_elf36_read_uint36(pdp10fp, &shdr->sh_name) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &shdr->sh_type) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &shdr->sh_flags) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &shdr->sh_addr) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &shdr->sh_offset) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &shdr->sh_size) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &shdr->sh_link) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &shdr->sh_info) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &shdr->sh_addralign) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &shdr->sh_entsize) < 0)
return -1;
return 0;
}
int pdp10_elf36_write_sym(PDP10_FILE *pdp10fp, const Elf36_Sym *sym)
{
if (pdp10_elf36_write_uint36(pdp10fp, sym->st_name) < 0
|| pdp10_elf36_write_uint36(pdp10fp, sym->st_value) < 0
|| pdp10_elf36_write_uint36(pdp10fp, sym->st_size) < 0
|| pdp10_elf36_write_uint9(pdp10fp, sym->st_info) < 0
|| pdp10_elf36_write_uint9(pdp10fp, sym->st_other) < 0
|| pdp10_elf36_write_uint18(pdp10fp, sym->st_shndx) < 0)
return -1;
return 0;
}
int pdp10_elf36_read_sym(PDP10_FILE *pdp10fp, Elf36_Sym *sym)
{
if (pdp10_elf36_read_uint36(pdp10fp, &sym->st_name) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &sym->st_value) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &sym->st_size) < 0
|| pdp10_elf36_read_uint9(pdp10fp, &sym->st_info) < 0
|| pdp10_elf36_read_uint9(pdp10fp, &sym->st_other) < 0
|| pdp10_elf36_read_uint18(pdp10fp, &sym->st_shndx) < 0)
return -1;
return 0;
}
int pdp10_elf36_write_rel(PDP10_FILE *pdp10fp, const Elf36_Rel *rel)
{
if (pdp10_elf36_write_uint36(pdp10fp, rel->r_offset) < 0
|| pdp10_elf36_write_uint36(pdp10fp, rel->r_info) < 0)
return -1;
return 0;
}
int pdp10_elf36_read_rel(PDP10_FILE *pdp10fp, Elf36_Rel *rel)
{
if (pdp10_elf36_read_uint36(pdp10fp, &rel->r_offset) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &rel->r_info) < 0)
return -1;
return 0;
}
int pdp10_elf36_write_rela(PDP10_FILE *pdp10fp, const Elf36_Rela *rela)
{
if (pdp10_elf36_write_uint36(pdp10fp, rela->r_offset) < 0
|| pdp10_elf36_write_uint36(pdp10fp, rela->r_info) < 0
|| pdp10_elf36_write_sint36(pdp10fp, rela->r_addend) < 0)
return -1;
return 0;
}
int pdp10_elf36_read_rela(PDP10_FILE *pdp10fp, Elf36_Rela *rela)
{
if (pdp10_elf36_read_uint36(pdp10fp, &rela->r_offset) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &rela->r_info) < 0
|| pdp10_elf36_read_sint36(pdp10fp, &rela->r_addend) < 0)
return -1;
return 0;
}
/* XXX: I/O of Elf36_Note: NYI */
int pdp10_elf36_write_phdr(PDP10_FILE *pdp10fp, const Elf36_Phdr *phdr)
{
if (pdp10_elf36_write_uint36(pdp10fp, phdr->p_type) < 0
|| pdp10_elf36_write_uint36(pdp10fp, phdr->p_offset) < 0
|| pdp10_elf36_write_uint36(pdp10fp, phdr->p_vaddr) < 0
|| pdp10_elf36_write_uint36(pdp10fp, phdr->p_paddr) < 0
|| pdp10_elf36_write_uint36(pdp10fp, phdr->p_filesz) < 0
|| pdp10_elf36_write_uint36(pdp10fp, phdr->p_memsz) < 0
|| pdp10_elf36_write_uint36(pdp10fp, phdr->p_flags) < 0
|| pdp10_elf36_write_uint36(pdp10fp, phdr->p_align) < 0)
return -1;
return 0;
}
int pdp10_elf36_read_phdr(PDP10_FILE *pdp10fp, Elf36_Phdr *phdr)
{
if (pdp10_elf36_read_uint36(pdp10fp, &phdr->p_type) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &phdr->p_offset) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &phdr->p_vaddr) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &phdr->p_paddr) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &phdr->p_filesz) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &phdr->p_memsz) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &phdr->p_flags) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &phdr->p_align) < 0)
return -1;
return 0;
}
int pdp10_elf36_write_dyn(PDP10_FILE *pdp10fp, const Elf36_Dyn *dyn)
{
if (pdp10_elf36_write_sint36(pdp10fp, dyn->d_tag) < 0
|| pdp10_elf36_write_uint36(pdp10fp, dyn->d_un.d_val) < 0)
return -1;
return 0;
}
int pdp10_elf36_read_dyn(PDP10_FILE *pdp10fp, Elf36_Dyn *dyn)
{
if (pdp10_elf36_read_sint36(pdp10fp, &dyn->d_tag) < 0
|| pdp10_elf36_read_uint36(pdp10fp, &dyn->d_un.d_val) < 0)
return -1;
return 0;
}

View File

@@ -1,61 +0,0 @@
/*
* pdp10-extint.c
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Provide types and procedures for converting 18 and 36-bit integers
* to and from arrays of 9-bit bytes (nonets). Use these together with
* pdp10_fread() and pdp10_fwrite() to convert 18 and 36-bit integers
* between host-level and file-level binary representations.
*/
#include "pdp10-extint.h"
/*
* The behaviour of the PDP10's byte pointers implies a big-endian storage model,
* as does the layout of its 72-bit long integers.
*/
void pdp10_uint18_to_ext(pdp10_uint18_t val, struct pdp10_ext_uint18 *ext)
{
ext->nonet[0] = (val >> 9) & 0x1FF;
ext->nonet[1] = val & 0x1FF;
}
pdp10_uint18_t pdp10_uint18_from_ext(const struct pdp10_ext_uint18 *ext)
{
return
((pdp10_uint18_t)(ext->nonet[0] & 0x1FF) << 9)
| (ext->nonet[1] & 0x1FF);
}
void pdp10_uint36_to_ext(pdp10_uint36_t val, struct pdp10_ext_uint36 *ext)
{
ext->nonet[0] = (val >> 27) & 0x1FF;
ext->nonet[1] = (val >> 18) & 0x1FF;
ext->nonet[2] = (val >> 9) & 0x1FF;
ext->nonet[3] = val & 0x1FF;
}
pdp10_uint36_t pdp10_uint36_from_ext(const struct pdp10_ext_uint36 *ext)
{
return
((pdp10_uint36_t)(ext->nonet[0] & 0x1FF) << 27)
| ((pdp10_uint36_t)(ext->nonet[1] & 0x1FF) << 18)
| ((pdp10_uint36_t)(ext->nonet[2] & 0x1FF) << 9)
| (ext->nonet[3] & 0x1FF);
}

View File

@@ -1,863 +0,0 @@
/*
* pdp10-opcodes.c
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "pdp10-opcodes.h"
/*
* Macros to initialize both high13 and fmt in instruction entries.
* May be followed by | PDP10_INSN_E_UNUSED and/or | PDP10_INSN_EXTENDED.
*
* The convention in documentation is to list opcodes as three or five-digit
* octal numbers, with zeros in IO device subfields. Five-digit numbers have
* two excess bits, which are removed by the macros to produce 13 bits.
*/
#define BASIC(OPCODE9) ((OPCODE9) << 4), PDP10_INSN_BASIC
#define A_OPCODE(OPCODE15) ((OPCODE15) >> 2), PDP10_INSN_A_OPCODE
#define A_UNUSED(OPCODE9) ((OPCODE9) << 4), PDP10_INSN_A_UNUSED
#define IO(OPCODE15) ((OPCODE15) >> 2), PDP10_INSN_IO
/* Much of the contents of these tables is based on code in
Lars Brinkhoff's pdp10-its-disassembler, but the code has
since been completely rewritten and extended. */
static const struct pdp10_insn pdp10_insn[] = {
/* name, high13, fmt, models */
/* 000: ILLEGAL */
/* 001-037: LUUOs */
/* ITS MUUOs */
{ ".iot", BASIC(0040), PDP10_ITS },
{ ".open", BASIC(0041), PDP10_ITS },
{ ".oper", BASIC(0042), PDP10_ITS },
{ ".call", A_OPCODE(004300), PDP10_ITS },
{ ".dismis", A_OPCODE(004304), PDP10_ITS },
{ ".lose", A_OPCODE(004310), PDP10_ITS }, /* XXX: .trans? */
{ ".tranad", A_OPCODE(004314), PDP10_ITS },
{ ".value", A_OPCODE(004320), PDP10_ITS },
{ ".utran", A_OPCODE(004324), PDP10_ITS },
{ ".core", A_OPCODE(004330), PDP10_ITS },
{ ".trand", A_OPCODE(004334), PDP10_ITS },
{ ".dstart", A_OPCODE(004340), PDP10_ITS },
{ ".fdele", A_OPCODE(004344), PDP10_ITS },
{ ".dstrtl", A_OPCODE(004350), PDP10_ITS },
{ ".suset", A_OPCODE(004354), PDP10_ITS },
{ ".ltpen", A_OPCODE(004360), PDP10_ITS },
{ ".vscan", A_OPCODE(004364), PDP10_ITS },
{ ".potset", A_OPCODE(004370), PDP10_ITS },
{ ".uset", BASIC(0044), PDP10_ITS },
{ ".break", BASIC(0045), PDP10_ITS },
{ ".status", BASIC(0046), PDP10_ITS },
{ ".access", BASIC(0047), PDP10_ITS },
/* TOPS-10 MUUOs (formats and models guesstimates) [XXX: all should be & ~PDP10_ITS] */
{ ".call", BASIC(0040), PDP10_KA10up },
{ ".init", BASIC(0041), PDP10_KA10up },
/* 042-046: reserved MUUOs */
{ ".calli", BASIC(0047), PDP10_KA10up },
{ ".open", BASIC(0050), PDP10_KA10up },
{ ".ttcall", BASIC(0051), PDP10_KA10up },
{ ".rename", BASIC(0055), PDP10_KA10up },
{ ".in", BASIC(0056), PDP10_KA10up },
{ ".out", BASIC(0057), PDP10_KA10up },
{ ".setsts", BASIC(0060), PDP10_KA10up },
{ ".stato", BASIC(0061), PDP10_KA10up },
{ ".status", BASIC(0062), PDP10_KA10up },
{ ".getsts", BASIC(0062), PDP10_KA10up }, /* XXX: alias for .status? */
{ ".statz", BASIC(0063), PDP10_KA10up },
{ ".inbuf", BASIC(0064), PDP10_KA10up },
{ ".outbuf", BASIC(0065), PDP10_KA10up },
{ ".input", BASIC(0066), PDP10_KA10up },
{ ".output", BASIC(0067), PDP10_KA10up },
{ ".close", BASIC(0070), PDP10_KA10up },
{ ".releas", BASIC(0071), PDP10_KA10up },
{ ".mtape", BASIC(0072), PDP10_KA10up },
{ ".ugetf", BASIC(0073), PDP10_KA10up },
{ ".useti", BASIC(0074), PDP10_KA10up },
{ ".useto", BASIC(0075), PDP10_KA10up },
{ ".lookup", BASIC(0076), PDP10_KA10up },
{ ".enter", BASIC(0077), PDP10_KA10up },
{ ".ujen", BASIC(0100), PDP10_KA10 }, /* XXX: or KI10up??? */
/* 101: unassigned */
{ "gfad", BASIC(0102), PDP10_KL10_271 }, /* XXX: or 271up??? */
{ "gfsb", BASIC(0103), PDP10_KL10_271 }, /* XXX: or 271up??? */
/* TOPS-20 MUUO */
{ "jsys", BASIC(0104), PDP10_KI10up }, /* XXX: & ~PDP10_ITS */
{ "adjsp", BASIC(0105), PDP10_KL10up },
{ "gfmp", BASIC(0106), PDP10_KL10_271 }, /* XXX: or 271up??? */
{ "gfdv", BASIC(0107), PDP10_KL10_271 }, /* XXX: or 271up??? */
{ "dfad", BASIC(0110), PDP10_KI10up },
{ "dfsb", BASIC(0111), PDP10_KI10up },
{ "dfmp", BASIC(0112), PDP10_KI10up },
{ "dfdv", BASIC(0113), PDP10_KI10up },
{ "dadd", BASIC(0114), PDP10_KL10up },
{ "dsub", BASIC(0115), PDP10_KL10up },
{ "dmul", BASIC(0116), PDP10_KL10up },
{ "ddiv", BASIC(0117), PDP10_KL10up },
{ "dmove", BASIC(0120), PDP10_KI10up },
{ "dmovn", BASIC(0121), PDP10_KI10up },
{ "fix", BASIC(0122), PDP10_KI10up },
{ "extend", BASIC(0123), PDP10_KL10up },
{ "dmovem", BASIC(0124), PDP10_KI10up },
{ "dmovnm", BASIC(0125), PDP10_KI10up },
{ "fixr", BASIC(0126), PDP10_KI10up },
{ "fltr", BASIC(0127), PDP10_KI10up },
{ "ufa", BASIC(0130), PDP10_KA10_to_KI10 }, /* XXX: and TOPS-10 KL10 */
{ "dfn", BASIC(0131), PDP10_KA10_to_KI10 }, /* XXX: and TOPS-10 KL10 */
{ "fsc", BASIC(0132), PDP10_ALL },
{ "ibp", A_OPCODE(013300), PDP10_ALL },
{ "adjbp", BASIC(0133), PDP10_KL10up }, /* A != 0 */
{ "ildb", BASIC(0134), PDP10_ALL },
{ "ldb", BASIC(0135), PDP10_ALL },
{ "idpb", BASIC(0136), PDP10_ALL },
{ "dpb", BASIC(0137), PDP10_ALL },
{ "fad", BASIC(0140), PDP10_ALL },
{ "fadl", BASIC(0141), PDP6_166_to_PDP10_KI10 }, /* XXX: and TOPS-10 KL10, not the PDP6? */
{ "fadm", BASIC(0142), PDP10_ALL },
{ "fadb", BASIC(0143), PDP10_ALL },
{ "fadr", BASIC(0144), PDP10_ALL },
{ "fadri", BASIC(0145), PDP10_KA10up },
{ "fadrl", BASIC(0145), PDP6_166 }, /* XXX: conflicts with fadri? */
{ "fadrm", BASIC(0146), PDP10_ALL },
{ "fadrb", BASIC(0147), PDP10_ALL },
{ "fsb", BASIC(0150), PDP10_ALL },
{ "fsbl", BASIC(0151), PDP6_166_to_PDP10_KI10 }, /* XXX: and TOPS-10 KL10 */
{ "fsbm", BASIC(0152), PDP10_ALL },
{ "fsbb", BASIC(0153), PDP10_ALL },
{ "fsbr", BASIC(0154), PDP10_ALL },
{ "fsbri", BASIC(0155), PDP10_KA10up },
{ "fsbrl", BASIC(0155), PDP6_166 }, /* XXX: conflicts with fsbri? */
{ "fsbrm", BASIC(0156), PDP10_ALL },
{ "fsbrb", BASIC(0157), PDP10_ALL },
{ "fmp", BASIC(0160), PDP10_ALL },
{ "fmpl", BASIC(0161), PDP6_166_to_PDP10_KI10 }, /* XXX: and TOPS-10 KL10 */
{ "fmpm", BASIC(0162), PDP10_ALL },
{ "fmpb", BASIC(0163), PDP10_ALL },
{ "fmpr", BASIC(0164), PDP10_ALL },
{ "fmpri", BASIC(0165), PDP10_KA10up },
{ "fmprl", BASIC(0165), PDP6_166 }, /* XXX: conflicts with fmpri? */
{ "fmprm", BASIC(0166), PDP10_ALL },
{ "fmprb", BASIC(0167), PDP10_ALL },
{ "fdv", BASIC(0170), PDP10_ALL },
{ "fdvl", BASIC(0171), PDP6_166_to_PDP10_KI10 }, /* XXX: and TOPS-10 KL10 */
{ "fdvm", BASIC(0172), PDP10_ALL },
{ "fdvb", BASIC(0173), PDP10_ALL },
{ "fdvr", BASIC(0174), PDP10_ALL },
{ "fdvri", BASIC(0175), PDP10_KA10up },
{ "fdvrl", BASIC(0175), PDP6_166 }, /* XXX: conflicts with fdvri? */
{ "fdvrm", BASIC(0176), PDP10_ALL },
{ "fdvrb", BASIC(0177), PDP10_ALL },
{ "move", BASIC(0200), PDP10_ALL },
{ "movei", BASIC(0201), PDP10_ALL },
{ "movem", BASIC(0202), PDP10_ALL },
{ "moves", BASIC(0203), PDP10_ALL },
{ "movs", BASIC(0204), PDP10_ALL },
{ "movsi", BASIC(0205), PDP10_ALL },
{ "movsm", BASIC(0206), PDP10_ALL },
{ "movss", BASIC(0207), PDP10_ALL },
{ "movn", BASIC(0210), PDP10_ALL },
{ "movni", BASIC(0211), PDP10_ALL },
{ "movnm", BASIC(0212), PDP10_ALL },
{ "movns", BASIC(0213), PDP10_ALL },
{ "movm", BASIC(0214), PDP10_ALL },
{ "movmi", BASIC(0215), PDP10_ALL },
{ "movmm", BASIC(0216), PDP10_ALL },
{ "movms", BASIC(0217), PDP10_ALL },
{ "imul", BASIC(0220), PDP10_ALL },
{ "imuli", BASIC(0221), PDP10_ALL },
{ "imulm", BASIC(0222), PDP10_ALL },
{ "imulb", BASIC(0223), PDP10_ALL },
{ "mul", BASIC(0224), PDP10_ALL },
{ "muli", BASIC(0225), PDP10_ALL },
{ "mulm", BASIC(0226), PDP10_ALL },
{ "mulb", BASIC(0227), PDP10_ALL },
{ "idiv", BASIC(0230), PDP10_ALL },
{ "idivi", BASIC(0231), PDP10_ALL },
{ "idivm", BASIC(0232), PDP10_ALL },
{ "idivb", BASIC(0233), PDP10_ALL },
{ "div", BASIC(0234), PDP10_ALL },
{ "divi", BASIC(0235), PDP10_ALL },
{ "divm", BASIC(0236), PDP10_ALL },
{ "divb", BASIC(0237), PDP10_ALL },
{ "ash", BASIC(0240), PDP10_ALL },
{ "rot", BASIC(0241), PDP10_ALL },
{ "lsh", BASIC(0242), PDP10_ALL },
{ "jffo", BASIC(0243), PDP10_KA10up },
{ "ashc", BASIC(0244), PDP10_ALL },
{ "rotc", BASIC(0245), PDP10_ALL },
{ "lshc", BASIC(0246), PDP10_ALL },
/* 247: MUUO (XKL-1, KD10, KC10), unassigned/trapping (KI10, KL10, KS10?), unassigned/nop (KA10, PDP-6?) */
{ "exch", BASIC(0250), PDP10_ALL },
{ "blt", BASIC(0251), PDP10_ALL },
{ "aobjp", BASIC(0252), PDP10_ALL },
{ "aobjn", BASIC(0253), PDP10_ALL },
/*
* 254: JRST instruction family.
* Special cases first, followed by the generic entry.
* 25414, 25440 (jrstil?), 25444, 25454, 25464, 25470, 25470: unassigned
*/
{ "portal", A_OPCODE(025404), PDP10_ALL },
{ "jrstf", A_OPCODE(025410), PDP10_ALL },
{ "halt", A_OPCODE(025420), PDP10_ALL },
{ "xjrstf", A_OPCODE(025424), PDP10_KL10up },
{ "xjen", A_OPCODE(025430), PDP10_KL10up },
{ "xpcw", A_OPCODE(025434), PDP10_KL10up },
{ "jen", A_OPCODE(025450), PDP10_ALL },
{ "sfm", A_OPCODE(025460), PDP10_KL10up },
{ "jrst", A_UNUSED(0254), PDP10_ALL },
/*
* 255: JFCL instruction family.
* Special cases first, followed by the generic entry.
* 25514, 25524, 25534, 25544, 25550, 25554, 25560, 25564, 25570, 25574: unassigned
*/
{ "nop", A_OPCODE(025500) | PDP10_INSN_E_UNUSED, PDP10_ALL },
{ "jfov", A_OPCODE(025504), PDP10_KA10up },
{ "jpcch", A_OPCODE(025504), PDP6_166 }, /* XXX: CHECKME, conflicts with jfov? */
{ "jcry1", A_OPCODE(025510), PDP10_ALL },
{ "jcry0", A_OPCODE(025520), PDP10_ALL },
{ "jcry", A_OPCODE(025530), PDP10_ALL },
{ "jov", A_OPCODE(025540), PDP10_ALL },
{ "jfcl", BASIC(0255), PDP10_ALL },
{ "xct", A_UNUSED(0256), PDP10_ALL }, /* A zero, or in user mode, or is a KA10 */
{ "pxct", BASIC(0256), PDP10_ALL }, /* A non-zero and in executive mode */
{ "map", BASIC(0257), PDP10_KA10_to_KI10 }, /* XXX: and TOPS-10 KL10, nop on KA10 */
{ "pushj", BASIC(0260), PDP10_ALL },
{ "push", BASIC(0261), PDP10_ALL },
{ "pop", BASIC(0262), PDP10_ALL },
{ "popj", BASIC(0263) | PDP10_INSN_E_UNUSED, PDP10_ALL },
{ "jsr", A_UNUSED(0264), PDP10_ALL },
{ "jsp", BASIC(0265), PDP10_ALL },
{ "jsa", BASIC(0266), PDP10_ALL },
{ "jra", BASIC(0267), PDP10_ALL },
{ "add", BASIC(0270), PDP10_ALL },
{ "addi", BASIC(0271), PDP10_ALL },
{ "addm", BASIC(0272), PDP10_ALL },
{ "addb", BASIC(0273), PDP10_ALL },
{ "sub", BASIC(0274), PDP10_ALL },
{ "subi", BASIC(0275), PDP10_ALL },
{ "subm", BASIC(0276), PDP10_ALL },
{ "subb", BASIC(0277), PDP10_ALL },
{ "cai", BASIC(0300), PDP10_ALL },
{ "cail", BASIC(0301), PDP10_ALL },
{ "caie", BASIC(0302), PDP10_ALL },
{ "caile", BASIC(0303), PDP10_ALL },
{ "caia", BASIC(0304), PDP10_ALL },
{ "caige", BASIC(0305), PDP10_ALL },
{ "cain", BASIC(0306), PDP10_ALL },
{ "caig", BASIC(0307), PDP10_ALL },
{ "cam", BASIC(0310), PDP10_ALL },
{ "caml", BASIC(0311), PDP10_ALL },
{ "came", BASIC(0312), PDP10_ALL },
{ "camle", BASIC(0313), PDP10_ALL },
{ "cama", BASIC(0314), PDP10_ALL },
{ "camge", BASIC(0315), PDP10_ALL },
{ "camn", BASIC(0316), PDP10_ALL },
{ "camg", BASIC(0317), PDP10_ALL },
{ "jump", BASIC(0320), PDP10_ALL },
{ "jumpl", BASIC(0321), PDP10_ALL },
{ "jumpe", BASIC(0322), PDP10_ALL },
{ "jumple", BASIC(0323), PDP10_ALL },
{ "jumpa", BASIC(0324), PDP10_ALL },
{ "jumpge", BASIC(0325), PDP10_ALL },
{ "jumpn", BASIC(0326), PDP10_ALL },
{ "jumpg", BASIC(0327), PDP10_ALL },
{ "skip", BASIC(0330), PDP10_ALL },
{ "skipl", BASIC(0331), PDP10_ALL },
{ "skipe", BASIC(0332), PDP10_ALL },
{ "skiple", BASIC(0333), PDP10_ALL },
{ "skipa", BASIC(0334), PDP10_ALL },
{ "skipge", BASIC(0335), PDP10_ALL },
{ "skipn", BASIC(0336), PDP10_ALL },
{ "skipg", BASIC(0337), PDP10_ALL },
{ "aoj", BASIC(0340), PDP10_ALL },
{ "aojl", BASIC(0341), PDP10_ALL },
{ "aoje", BASIC(0342), PDP10_ALL },
{ "aojle", BASIC(0343), PDP10_ALL },
{ "aoja", BASIC(0344), PDP10_ALL },
{ "aojge", BASIC(0345), PDP10_ALL },
{ "aojn", BASIC(0346), PDP10_ALL },
{ "aojg", BASIC(0347), PDP10_ALL },
{ "aos", BASIC(0350), PDP10_ALL },
{ "aosl", BASIC(0351), PDP10_ALL },
{ "aose", BASIC(0352), PDP10_ALL },
{ "aosle", BASIC(0353), PDP10_ALL },
{ "aosa", BASIC(0354), PDP10_ALL },
{ "aosge", BASIC(0355), PDP10_ALL },
{ "aosn", BASIC(0356), PDP10_ALL },
{ "aosg", BASIC(0357), PDP10_ALL },
{ "soj", BASIC(0360), PDP10_ALL },
{ "sojl", BASIC(0361), PDP10_ALL },
{ "soje", BASIC(0362), PDP10_ALL },
{ "sojle", BASIC(0363), PDP10_ALL },
{ "soja", BASIC(0364), PDP10_ALL },
{ "sojge", BASIC(0365), PDP10_ALL },
{ "sojn", BASIC(0366), PDP10_ALL },
{ "sojg", BASIC(0367), PDP10_ALL },
{ "sos", BASIC(0370), PDP10_ALL },
{ "sosl", BASIC(0371), PDP10_ALL },
{ "sose", BASIC(0372), PDP10_ALL },
{ "sosle", BASIC(0373), PDP10_ALL },
{ "sosa", BASIC(0374), PDP10_ALL },
{ "sosge", BASIC(0375), PDP10_ALL },
{ "sosn", BASIC(0376), PDP10_ALL },
{ "sosg", BASIC(0377), PDP10_ALL },
{ "setz", BASIC(0400) | PDP10_INSN_E_UNUSED, PDP10_ALL },
{ "setzi", BASIC(0401) | PDP10_INSN_E_UNUSED, PDP10_ALL },
{ "setzm", A_UNUSED(0402), PDP10_ALL },
{ "setzb", BASIC(0403), PDP10_ALL },
{ "and", BASIC(0404), PDP10_ALL },
{ "andi", BASIC(0405), PDP10_ALL },
{ "andm", BASIC(0406), PDP10_ALL },
{ "andb", BASIC(0407), PDP10_ALL },
{ "andca", BASIC(0410), PDP10_ALL },
{ "andcai", BASIC(0411), PDP10_ALL },
{ "andcam", BASIC(0412), PDP10_ALL },
{ "andcab", BASIC(0413), PDP10_ALL },
{ "setm", BASIC(0414), PDP10_ALL },
{ "xmovei", BASIC(0415), PDP10_KL10up }, /* in non-zero section, setmi in zero section */
{ "setmi", BASIC(0415), PDP10_ALL }, /* on KL10up, depends on current section */
{ "setmm", A_UNUSED(0416), PDP10_ALL },
{ "setmb", BASIC(0417), PDP10_ALL },
{ "andcm", BASIC(0420), PDP10_ALL },
{ "andcmi", BASIC(0421), PDP10_ALL },
{ "andcmm", BASIC(0422), PDP10_ALL },
{ "andcmb", BASIC(0423), PDP10_ALL },
{ "seta", BASIC(0424) | PDP10_INSN_E_UNUSED, PDP10_ALL },
{ "setai", BASIC(0425) | PDP10_INSN_E_UNUSED, PDP10_ALL },
{ "setam", BASIC(0426), PDP10_ALL },
{ "setab", BASIC(0427), PDP10_ALL },
{ "xor", BASIC(0430), PDP10_ALL },
{ "xori", BASIC(0431), PDP10_ALL },
{ "xorm", BASIC(0432), PDP10_ALL },
{ "xorb", BASIC(0433), PDP10_ALL },
{ "ior", BASIC(0434), PDP10_ALL },
{ "or", BASIC(0434), PDP10_ALL }, /* alias for ior */
{ "iori", BASIC(0435), PDP10_ALL },
{ "ori", BASIC(0435), PDP10_ALL }, /* alias for iori */
{ "iorm", BASIC(0436), PDP10_ALL },
{ "orm", BASIC(0436), PDP10_ALL }, /* alias for iorm */
{ "iorb", BASIC(0437), PDP10_ALL },
{ "orb", BASIC(0437), PDP10_ALL }, /* alias for iorb */
{ "andcb", BASIC(0440), PDP10_ALL },
{ "andcbi", BASIC(0441), PDP10_ALL },
{ "andcbm", BASIC(0442), PDP10_ALL },
{ "andcbb", BASIC(0443), PDP10_ALL },
{ "eqv", BASIC(0444), PDP10_ALL },
{ "eqvi", BASIC(0445), PDP10_ALL },
{ "eqvm", BASIC(0446), PDP10_ALL },
{ "eqvb", BASIC(0447), PDP10_ALL },
{ "setca", BASIC(0450) | PDP10_INSN_E_UNUSED, PDP10_ALL },
{ "setcai", BASIC(0451) | PDP10_INSN_E_UNUSED, PDP10_ALL },
{ "setcam", BASIC(0452), PDP10_ALL },
{ "setcab", BASIC(0453), PDP10_ALL },
{ "orca", BASIC(0454), PDP10_ALL },
{ "orcai", BASIC(0455), PDP10_ALL },
{ "orcam", BASIC(0456), PDP10_ALL },
{ "orcab", BASIC(0457), PDP10_ALL },
{ "setcm", BASIC(0460), PDP10_ALL },
{ "setcmi", BASIC(0461), PDP10_ALL },
{ "setcmm", A_UNUSED(0462), PDP10_ALL },
{ "setcmb", BASIC(0463), PDP10_ALL },
{ "orcm", BASIC(0464), PDP10_ALL },
{ "orcmi", BASIC(0465), PDP10_ALL },
{ "orcmm", BASIC(0466), PDP10_ALL },
{ "orcmb", BASIC(0467), PDP10_ALL },
{ "orcb", BASIC(0470), PDP10_ALL },
{ "orcbi", BASIC(0471), PDP10_ALL },
{ "orcbm", BASIC(0472), PDP10_ALL },
{ "orcbb", BASIC(0473), PDP10_ALL },
{ "seto", BASIC(0474) | PDP10_INSN_E_UNUSED, PDP10_ALL },
{ "setoi", BASIC(0475) | PDP10_INSN_E_UNUSED, PDP10_ALL },
{ "setom", A_UNUSED(0476), PDP10_ALL },
{ "setob", BASIC(0477), PDP10_ALL },
{ "hll", BASIC(0500), PDP10_ALL },
{ "xhlli", BASIC(0501), PDP10_KL10up }, /* in non-zero section, hlli in zero section */
{ "hlli", BASIC(0501), PDP10_ALL }, /* on KL10up, depends on current section */
{ "hllm", BASIC(0502), PDP10_ALL },
{ "hlls", BASIC(0503), PDP10_ALL },
{ "hrl", BASIC(0504), PDP10_ALL },
{ "hrli", BASIC(0505), PDP10_ALL },
{ "hrlm", BASIC(0506), PDP10_ALL },
{ "hrls", BASIC(0507), PDP10_ALL },
{ "hllz", BASIC(0510), PDP10_ALL },
{ "hllzi", BASIC(0511), PDP10_ALL },
{ "hllzm", BASIC(0512), PDP10_ALL },
{ "hllzs", BASIC(0513), PDP10_ALL },
{ "hrlz", BASIC(0514), PDP10_ALL },
{ "hrlzi", BASIC(0515), PDP10_ALL },
{ "hrlzm", BASIC(0516), PDP10_ALL },
{ "hrlzs", BASIC(0517), PDP10_ALL },
{ "hllo", BASIC(0520), PDP10_ALL },
{ "hlloi", BASIC(0521), PDP10_ALL },
{ "hllom", BASIC(0522), PDP10_ALL },
{ "hllos", BASIC(0523), PDP10_ALL },
{ "hrlo", BASIC(0524), PDP10_ALL },
{ "hrloi", BASIC(0525), PDP10_ALL },
{ "hrlom", BASIC(0526), PDP10_ALL },
{ "hrlos", BASIC(0527), PDP10_ALL },
{ "hlle", BASIC(0530), PDP10_ALL },
{ "hllei", BASIC(0531), PDP10_ALL },
{ "hllem", BASIC(0532), PDP10_ALL },
{ "hlles", BASIC(0533), PDP10_ALL },
{ "hrle", BASIC(0534), PDP10_ALL },
{ "hrlei", BASIC(0535), PDP10_ALL },
{ "hrlem", BASIC(0536), PDP10_ALL },
{ "hrles", BASIC(0537), PDP10_ALL },
{ "hrr", BASIC(0540), PDP10_ALL },
{ "hrri", BASIC(0541), PDP10_ALL },
{ "hrrm", BASIC(0542), PDP10_ALL },
{ "hrrs", BASIC(0543), PDP10_ALL },
{ "hlr", BASIC(0544), PDP10_ALL },
{ "hlri", BASIC(0545), PDP10_ALL },
{ "hlrm", BASIC(0546), PDP10_ALL },
{ "hlrs", BASIC(0547), PDP10_ALL },
{ "hrrz", BASIC(0550), PDP10_ALL },
{ "hrrzi", BASIC(0551), PDP10_ALL },
{ "hrrzm", BASIC(0552), PDP10_ALL },
{ "hrrzs", BASIC(0553), PDP10_ALL },
{ "hlrz", BASIC(0554), PDP10_ALL },
{ "hlrzi", BASIC(0555), PDP10_ALL },
{ "hlrzm", BASIC(0556), PDP10_ALL },
{ "hlrzs", BASIC(0557), PDP10_ALL },
{ "hrro", BASIC(0560), PDP10_ALL },
{ "hrroi", BASIC(0561), PDP10_ALL },
{ "hrrom", BASIC(0562), PDP10_ALL },
{ "hrros", BASIC(0563), PDP10_ALL },
{ "hlro", BASIC(0564), PDP10_ALL },
{ "hlroi", BASIC(0565), PDP10_ALL },
{ "hlrom", BASIC(0566), PDP10_ALL },
{ "hlros", BASIC(0567), PDP10_ALL },
{ "hrre", BASIC(0570), PDP10_ALL },
{ "hrrei", BASIC(0571), PDP10_ALL },
{ "hrrem", BASIC(0572), PDP10_ALL },
{ "hrres", BASIC(0573), PDP10_ALL },
{ "hlre", BASIC(0574), PDP10_ALL },
{ "hlrei", BASIC(0575), PDP10_ALL },
{ "hlrem", BASIC(0576), PDP10_ALL },
{ "hlres", BASIC(0577), PDP10_ALL },
{ "trn", BASIC(0600), PDP10_ALL },
{ "tln", BASIC(0601), PDP10_ALL },
{ "trne", BASIC(0602), PDP10_ALL },
{ "tlne", BASIC(0603), PDP10_ALL },
{ "trna", BASIC(0604), PDP10_ALL },
{ "tlna", BASIC(0605), PDP10_ALL },
{ "trnn", BASIC(0606), PDP10_ALL },
{ "tlnn", BASIC(0607), PDP10_ALL },
{ "tdn", BASIC(0610), PDP10_ALL },
{ "tsn", BASIC(0611), PDP10_ALL },
{ "tdne", BASIC(0612), PDP10_ALL },
{ "tsne", BASIC(0613), PDP10_ALL },
{ "tdna", BASIC(0614), PDP10_ALL },
{ "tsna", BASIC(0615), PDP10_ALL },
{ "tdnn", BASIC(0616), PDP10_ALL },
{ "tsnn", BASIC(0617), PDP10_ALL },
{ "trz", BASIC(0620), PDP10_ALL },
{ "tlz", BASIC(0621), PDP10_ALL },
{ "trze", BASIC(0622), PDP10_ALL },
{ "tlze", BASIC(0623), PDP10_ALL },
{ "trza", BASIC(0624), PDP10_ALL },
{ "tlza", BASIC(0625), PDP10_ALL },
{ "trzn", BASIC(0626), PDP10_ALL },
{ "tlzn", BASIC(0627), PDP10_ALL },
{ "tdz", BASIC(0630), PDP10_ALL },
{ "tsz", BASIC(0631), PDP10_ALL },
{ "tdze", BASIC(0632), PDP10_ALL },
{ "tsze", BASIC(0633), PDP10_ALL },
{ "tdza", BASIC(0634), PDP10_ALL },
{ "tsza", BASIC(0635), PDP10_ALL },
{ "tdzn", BASIC(0636), PDP10_ALL },
{ "tszn", BASIC(0637), PDP10_ALL },
{ "trc", BASIC(0640), PDP10_ALL },
{ "tlc", BASIC(0641), PDP10_ALL },
{ "trce", BASIC(0642), PDP10_ALL },
{ "tlce", BASIC(0643), PDP10_ALL },
{ "trca", BASIC(0644), PDP10_ALL },
{ "tlca", BASIC(0645), PDP10_ALL },
{ "trcn", BASIC(0646), PDP10_ALL },
{ "tlcn", BASIC(0647), PDP10_ALL },
{ "tdc", BASIC(0650), PDP10_ALL },
{ "tsc", BASIC(0651), PDP10_ALL },
{ "tdce", BASIC(0652), PDP10_ALL },
{ "tsce", BASIC(0653), PDP10_ALL },
{ "tdca", BASIC(0654), PDP10_ALL },
{ "tsca", BASIC(0655), PDP10_ALL },
{ "tdcn", BASIC(0656), PDP10_ALL },
{ "tscn", BASIC(0657), PDP10_ALL },
{ "tro", BASIC(0660), PDP10_ALL },
{ "tlo", BASIC(0661), PDP10_ALL },
{ "troe", BASIC(0662), PDP10_ALL },
{ "tloe", BASIC(0663), PDP10_ALL },
{ "troa", BASIC(0664), PDP10_ALL },
{ "tloa", BASIC(0665), PDP10_ALL },
{ "tron", BASIC(0666), PDP10_ALL },
{ "tlon", BASIC(0667), PDP10_ALL },
{ "tdo", BASIC(0670), PDP10_ALL },
{ "tso", BASIC(0671), PDP10_ALL },
{ "tdoe", BASIC(0672), PDP10_ALL },
{ "tsoe", BASIC(0673), PDP10_ALL },
{ "tdoa", BASIC(0674), PDP10_ALL },
{ "tsoa", BASIC(0675), PDP10_ALL },
{ "tdon", BASIC(0676), PDP10_ALL },
{ "tson", BASIC(0677), PDP10_ALL },
/*
* I/O and system instructions. Lots of model-specifics here.
* XXX: these are all & ~PDP10_ITS
*/
{ "aprid", A_OPCODE(070000), PDP10_KL10any | PDP10_KS10 | PDP10_XKL1 }, /* alias for BLKI APR, */
{ "rsw", A_OPCODE(070004), PDP10_KA10_to_KI10 }, /* alias for DATAI APR, */
{ "wrfil", A_OPCODE(070010), PDP10_KL10any }, /* alias for BLKO APR, */
{ "wrapr", A_OPCODE(070020), PDP10_KS10 | PDP10_XKL1 }, /* alias for CONO APR, */
{ "rdapr", A_OPCODE(070024), PDP10_KS10 | PDP10_XKL1 }, /* alias for CONI APR, */
{ "rdera", A_OPCODE(070040), PDP10_KL10any }, /* alias for BLKI PI, */
{ "sbdiag", A_OPCODE(070050), PDP10_KL10any }, /* alias for BLKO PI, */
{ "wrpi", A_OPCODE(070060), PDP10_KS10 | PDP10_XKL1 }, /* alias for CONO PI, */
{ "rdpi", A_OPCODE(070064), PDP10_KS10 | PDP10_XKL1 }, /* alias for CONI PI, */
{ "rdubr", A_OPCODE(070104), PDP10_KS10 | PDP10_XKL1 }, /* alias for DATAI PAG, */
{ "clrpt", A_OPCODE(070110), PDP10_KL10any | PDP10_KS10 | PDP10_XKL1 }, /* alias for BLKO PAG, */
{ "wrubr", A_OPCODE(070114), PDP10_KS10 | PDP10_XKL1 }, /* alias for DATAO PAG, */
{ "wrebr", A_OPCODE(070120), PDP10_KS10 }, /* alias for CONO PAG, */
{ "rdebr", A_OPCODE(070124), PDP10_KS10 }, /* alias for CONI PAG, */
{ "swpia", A_OPCODE(070144) | PDP10_INSN_E_UNUSED, PDP10_KL10any | PDP10_XKL1 }, /* alias for DATAI CCA, */
{ "swpva", A_OPCODE(070150) | PDP10_INSN_E_UNUSED, PDP10_KL10any | PDP10_XKL1 }, /* alias for BLKO CCA, */
{ "swpua", A_OPCODE(070154) | PDP10_INSN_E_UNUSED, PDP10_KL10any | PDP10_XKL1 }, /* alias for DATAO CCA, */
{ "swpio", A_OPCODE(070164), PDP10_KL10any | PDP10_XKL1 }, /* alias for CONI CCA, */
{ "swpvo", A_OPCODE(070170), PDP10_KL10any | PDP10_XKL1 }, /* alias for CONSZ CCA, */
{ "swpuo", A_OPCODE(070174), PDP10_KL10any | PDP10_XKL1 }, /* alias for CONSO CCA, */
{ "rdperf", A_OPCODE(070200), PDP10_KL10any }, /* alias for BLKI TIM, */
{ "rdspb", A_OPCODE(070200), PDP10_KS10 | PDP10_XKL1 },
{ "rdtime", A_OPCODE(070204), PDP10_KL10any }, /* alias for DATAI TIM, */
{ "rdcsb", A_OPCODE(070204), PDP10_KS10 | PDP10_XKL1 },
{ "wrpae", A_OPCODE(070210), PDP10_KL10any }, /* alias for BLKO TIM, */
{ "rdpur", A_OPCODE(070210), PDP10_KS10 | PDP10_XKL1 },
{ "rdcstm", A_OPCODE(070214), PDP10_KS10 | PDP10_XKL1 },
{ "rdtim", A_OPCODE(070220), PDP10_KS10 }, /* alias for CONO TIM, */
{ "rdint", A_OPCODE(070224), PDP10_KS10 }, /* alias for CONI TIM, */
{ "rdhsb", A_OPCODE(070230), PDP10_KS10 },
{ "rdmact", A_OPCODE(070240), PDP10_KL10any }, /* alias for BLKI MTR, */
{ "wrspb", A_OPCODE(070240), PDP10_KS10 | PDP10_XKL1 },
{ "rdeact", A_OPCODE(070244), PDP10_KL10any }, /* alias for DATAI MTR, */
{ "wrcsb", A_OPCODE(070244), PDP10_KS10 | PDP10_XKL1 },
{ "wrpur", A_OPCODE(070250), PDP10_KS10 | PDP10_XKL1 },
{ "wrcstm", A_OPCODE(070254), PDP10_KS10 | PDP10_XKL1 },
{ "wrtime", A_OPCODE(070260), PDP10_KL10any }, /* alias for CONO MTR, */
{ "wrtim", A_OPCODE(070260), PDP10_KS10 },
{ "wrint", A_OPCODE(070264), PDP10_KS10 },
{ "wrhsb", A_OPCODE(070270), PDP10_KS10 },
{ "umove", BASIC(0704), PDP10_KS10 },
{ "umovem", BASIC(0705), PDP10_KS10 },
{ "tioe", BASIC(0710), PDP10_KS10 },
{ "tion", BASIC(0711), PDP10_KS10 },
{ "rdio", BASIC(0712), PDP10_KS10 },
{ "wrio", BASIC(0713), PDP10_KS10 },
{ "bsio", BASIC(0714), PDP10_KS10 },
{ "bcio", BASIC(0715), PDP10_KS10 },
{ "tioeb", BASIC(0720), PDP10_KS10 },
{ "tionb", BASIC(0721), PDP10_KS10 },
{ "rdiob", BASIC(0722), PDP10_KS10 },
{ "wriob", BASIC(0723), PDP10_KS10 },
{ "bsiob", BASIC(0724), PDP10_KS10 },
{ "bciob", BASIC(0725), PDP10_KS10 },
/*
* KA10/KL10 ITS system instructions.
*/
{ "lpm", A_OPCODE(010200), PDP10_KA10_ITS | PDP10_KL10_ITS },
{ "spm", A_OPCODE(010204), PDP10_KA10_ITS | PDP10_KL10_ITS },
{ "lpmr", A_OPCODE(010210), PDP10_KA10_ITS | PDP10_KL10_ITS },
{ "lpmri", A_OPCODE(010230), PDP10_KA10_ITS | PDP10_KL10_ITS },
/*
* KA10 ITS system instructions.
*/
{ "xctr", A_OPCODE(010300), PDP10_KA10_ITS },
{ "xctri", A_OPCODE(010320), PDP10_KA10_ITS },
/*
* KL10 ITS system instructions.
*/
{ "xctr", BASIC(0074), PDP10_KL10_ITS },
{ "xctri", BASIC(0075), PDP10_KL10_ITS },
{ "lpmr", BASIC(0076), PDP10_KL10_ITS },
{ "spm", BASIC(0077), PDP10_KL10_ITS },
/*
* KS10 ITS system instructions.
*/
{ "xctr", BASIC(0102), PDP10_KS10_ITS },
{ "xctri", BASIC(0103), PDP10_KS10_ITS },
{ "aprid", A_OPCODE(070000), PDP10_KS10_ITS },
#if 0
/* ITS appears to prefer CONO and CONI over these mnemonics */
{ "wrapr", A_OPCODE(070020), PDP10_KS10_ITS },
{ "rdapr", A_OPCODE(070024), PDP10_KS10_ITS },
{ "wrpi", A_OPCODE(070060), PDP10_KS10_ITS },
{ "rdpi", A_OPCODE(070064), PDP10_KS10_ITS },
#endif
{ "clrcsh", A_OPCODE(070100), PDP10_KS10_ITS },
{ "rdubr", A_OPCODE(070104), PDP10_KS10_ITS },
{ "clrpt", A_OPCODE(070110), PDP10_KS10_ITS },
{ "wrubr", A_OPCODE(070114), PDP10_KS10_ITS },
{ "wrebr", A_OPCODE(070120), PDP10_KS10_ITS },
{ "rdebr", A_OPCODE(070124), PDP10_KS10_ITS },
{ "sdbr1", A_OPCODE(070200), PDP10_KS10_ITS },
{ "sdbr2", A_OPCODE(070204), PDP10_KS10_ITS },
{ "sdbr3", A_OPCODE(070210), PDP10_KS10_ITS },
{ "sdbr4", A_OPCODE(070214), PDP10_KS10_ITS },
{ "rdtim", A_OPCODE(070220), PDP10_KS10_ITS },
{ "rdint", A_OPCODE(070224), PDP10_KS10_ITS },
{ "rdhsb", A_OPCODE(070230), PDP10_KS10_ITS },
{ "spm", A_OPCODE(070234), PDP10_KS10_ITS },
{ "ldbr1", A_OPCODE(070240), PDP10_KS10_ITS },
{ "ldbr2", A_OPCODE(070244), PDP10_KS10_ITS },
{ "ldbr3", A_OPCODE(070250), PDP10_KS10_ITS },
{ "ldbr4", A_OPCODE(070254), PDP10_KS10_ITS },
{ "wrtim", A_OPCODE(070260), PDP10_KS10_ITS },
{ "wrint", A_OPCODE(070264), PDP10_KS10_ITS },
{ "wrhsb", A_OPCODE(070270), PDP10_KS10_ITS },
{ "lpmr", A_OPCODE(070274), PDP10_KS10_ITS },
{ "umove", BASIC(0704), PDP10_KS10_ITS },
{ "umovem", BASIC(0705), PDP10_KS10_ITS },
{ "iordi", BASIC(0710), PDP10_KS10_ITS },
{ "iordq", BASIC(0711), PDP10_KS10_ITS },
{ "iord", BASIC(0712), PDP10_KS10_ITS },
{ "iowr", BASIC(0713), PDP10_KS10_ITS },
{ "iowri", BASIC(0714), PDP10_KS10_ITS },
{ "iowrq", BASIC(0715), PDP10_KS10_ITS },
{ "bltbu", BASIC(0716), PDP10_KS10_ITS },
{ "bltub", BASIC(0717), PDP10_KS10_ITS },
{ "iordbi", BASIC(0720), PDP10_KS10_ITS },
{ "iordbq", BASIC(0721), PDP10_KS10_ITS },
{ "iordb", BASIC(0722), PDP10_KS10_ITS },
{ "iowrb", BASIC(0723), PDP10_KS10_ITS },
{ "iowrbi", BASIC(0724), PDP10_KS10_ITS },
{ "iowrbq", BASIC(0725), PDP10_KS10_ITS },
/*
* XKL-1 system instructions.
*/
{ "rdadb", A_OPCODE(070004), PDP10_XKL1 },
{ "sysid", A_OPCODE(070010), PDP10_XKL1 },
{ "wradb", A_OPCODE(070014), PDP10_XKL1 },
{ "szapr", A_OPCODE(070030), PDP10_XKL1 },
{ "snapr", A_OPCODE(070034), PDP10_XKL1 },
{ "wctrlf", A_OPCODE(070040), PDP10_XKL1 },
{ "rctrlf", A_OPCODE(070044), PDP10_XKL1 },
{ "simird", A_OPCODE(070050), PDP10_XKL1 },
{ "wrkpa", A_OPCODE(070054), PDP10_XKL1 },
{ "szpi", A_OPCODE(070070), PDP10_XKL1 },
{ "snpi", A_OPCODE(070074), PDP10_XKL1 },
{ "apr0", BASIC(0700), PDP10_XKL1 },
{ "clrpt", A_OPCODE(070110), PDP10_XKL1 },
{ "wrerr", A_OPCODE(070120), PDP10_XKL1 },
{ "rderr", A_OPCODE(070124), PDP10_XKL1 },
{ "wrctx", A_OPCODE(070130), PDP10_XKL1 },
{ "rdctx", A_OPCODE(070134), PDP10_XKL1 },
{ "rddcsh", A_OPCODE(070140), PDP10_XKL1 },
{ "dwrcsh", A_OPCODE(070160), PDP10_XKL1 },
{ "swpio", A_OPCODE(070164), PDP10_XKL1 },
{ "swpvo", A_OPCODE(070170), PDP10_XKL1 },
{ "swpuo", A_OPCODE(070174), PDP10_XKL1 },
{ "apr1", BASIC(0701), PDP10_XKL1 },
{ "rditm", A_OPCODE(070220), PDP10_XKL1 },
{ "rdtime", A_OPCODE(070224), PDP10_XKL1 },
{ "drdptb", A_OPCODE(070230), PDP10_XKL1 },
{ "wrtime", A_OPCODE(070234), PDP10_XKL1 },
{ "writm", A_OPCODE(070260), PDP10_XKL1 },
{ "dwrptb", A_OPCODE(070270), PDP10_XKL1 },
{ "apr2", BASIC(0702), PDP10_XKL1 },
{ "rdcty", A_OPCODE(070304), PDP10_XKL1 },
{ "wrcty", A_OPCODE(070314), PDP10_XKL1 },
{ "wrctys", A_OPCODE(070320), PDP10_XKL1 },
{ "rdctys", A_OPCODE(070324), PDP10_XKL1 },
{ "szcty", A_OPCODE(070330), PDP10_XKL1 },
{ "sncty", A_OPCODE(070334), PDP10_XKL1 },
{ "apr3", BASIC(0703), PDP10_XKL1 },
{ "pmove", BASIC(0704), PDP10_XKL1 },
{ "pmovem", BASIC(0705), PDP10_XKL1 },
{ "nmove", BASIC(0706), PDP10_XKL1 },
{ "nmovem", BASIC(0707), PDP10_XKL1 },
{ "ldlpn", BASIC(0710), PDP10_XKL1 },
{ "rdcfg", BASIC(0711), PDP10_XKL1 },
{ "amove", BASIC(0714), PDP10_XKL1 },
{ "amovem", BASIC(0715), PDP10_XKL1 },
{ "umove", BASIC(0716), PDP10_XKL1 },
{ "umovem", BASIC(0717), PDP10_XKL1 },
/*
* 166 / KA10 / KI10 / KL10 I/O instructions.
*
* These take an operand which determines which device to access.
* Most of the system instructions above are instances of these with
* pre-determined values for the device operands.
*/
{ "blki", IO(070000), PDP10_not_KS10_or_XKL1 },
{ "datai", IO(070004), PDP10_not_KS10_or_XKL1 },
{ "blko", IO(070010), PDP10_not_KS10_or_XKL1 },
{ "datao", IO(070014), PDP10_not_KS10_or_XKL1 },
{ "cono", IO(070020), PDP10_not_KS10_or_XKL1 },
{ "coni", IO(070024), PDP10_not_KS10_or_XKL1 },
{ "consz", IO(070030), PDP10_not_KS10_or_XKL1 },
{ "conso", IO(070034), PDP10_not_KS10_or_XKL1 },
};
/*
* Internal device names for IO instructions.
*
* The convention in documentation is to list 7-bit device codes as three-digit
* octal numbers. Three-digit numbers have two excess bits, which are removed
* the the DEVICE() macro to produce 7 bits.
*/
#define DEVICE(DEVICE9) ((DEVICE9) >> 2)
static const struct pdp10_cpu_device pdp10_cpu_device[] = {
/* name, device, models */
{ "apr", DEVICE(0000), PDP10_KA10_to_KL10 }, /* Arithmetic processor */
{ "pi", DEVICE(0004), PDP10_KA10_to_KL10 }, /* Priority interrupt */
{ "pag", DEVICE(0010), PDP10_KI10_to_KL10 }, /* Pager */
{ "cca", DEVICE(0014), PDP10_KL10any }, /* Cache */
{ "tim", DEVICE(0020), PDP10_KL10any }, /* Timer */
{ "mtr", DEVICE(0024), PDP10_KL10any }, /* Meters */
};
/*
* Extended instructions, second word.
*/
#define EXTENDED(OPCODE9) A_UNUSED(OPCODE9) | PDP10_INSN_EXTENDED
static const struct pdp10_insn pdp10_extended_insn[] = {
/* name, high13, fmt, models */
{ "cmpsl", EXTENDED(0001) | PDP10_INSN_E_UNUSED, PDP10_KL10up },
{ "cmpse", EXTENDED(0002) | PDP10_INSN_E_UNUSED, PDP10_KL10up },
{ "cmpsle", EXTENDED(0003) | PDP10_INSN_E_UNUSED, PDP10_KL10up },
{ "edit", EXTENDED(0004) | PDP10_INSN_E_UNUSED, PDP10_KL10up },
{ "cmpsge", EXTENDED(0005) | PDP10_INSN_E_UNUSED, PDP10_KL10up },
{ "cmpsn", EXTENDED(0006) | PDP10_INSN_E_UNUSED, PDP10_KL10up },
{ "cmpsg", EXTENDED(0007) | PDP10_INSN_E_UNUSED, PDP10_KL10up },
{ "cvtdbo", EXTENDED(0010), PDP10_KL10up },
{ "cvtdbt", EXTENDED(0011), PDP10_KL10up },
{ "cvtbdo", EXTENDED(0012), PDP10_KL10up },
{ "cvtbdt", EXTENDED(0013), PDP10_KL10up },
{ "movso", EXTENDED(0014), PDP10_KL10up },
{ "movst", EXTENDED(0015), PDP10_KL10up },
{ "movslj", EXTENDED(0016) | PDP10_INSN_E_UNUSED, PDP10_KL10up },
{ "movsrj", EXTENDED(0017) | PDP10_INSN_E_UNUSED, PDP10_KL10up },
{ "xblt", EXTENDED(0020) | PDP10_INSN_E_UNUSED, PDP10_KL10up },
{ "gsngl", EXTENDED(0021), PDP10_KL10_271 },
{ "gdble", EXTENDED(0022), PDP10_KL10_271 },
{ "gdfix", EXTENDED(0023), PDP10_KL10_271 },
{ "gdfixr", EXTENDED(0025), PDP10_KL10_271 },
{ "gfix", EXTENDED(0024), PDP10_KL10_271 },
{ "gfixr", EXTENDED(0026), PDP10_KL10_271 },
{ "dgfltr", EXTENDED(0027), PDP10_KL10_271 },
{ "gfltr", EXTENDED(0030), PDP10_KL10_271 },
{ "gfsc", EXTENDED(0031), PDP10_KL10_271 },
};
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
static const struct pdp10_insn *
insn_from_name(const struct pdp10_insn *insn, unsigned int nr_insn, pdp10_cpu_models_t models, const char *name)
{
unsigned int i;
for (i = 0; i < nr_insn; ++i)
if (strcmp(name, insn[i].name) == 0
&& (insn[i].models & models) == models)
return &insn[i];
return (const struct pdp10_insn *)0;
}
const struct pdp10_insn *
pdp10_insn_from_name(pdp10_cpu_models_t models, const char *name)
{
const struct pdp10_insn *insn;
insn = insn_from_name(pdp10_insn, ARRAY_SIZE(pdp10_insn), models, name);
if (!insn)
insn = insn_from_name(pdp10_extended_insn, ARRAY_SIZE(pdp10_extended_insn), models, name);
return insn;
}
const struct pdp10_cpu_device *
pdp10_cpu_device_from_name(pdp10_cpu_models_t models, const char *name)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(pdp10_cpu_device); ++i)
if (strcmp(name, pdp10_cpu_device[i].name) == 0
&& (pdp10_cpu_device[i].models & models) == models)
return &pdp10_cpu_device[i];
return (const struct pdp10_cpu_device *)0;
}
static int high13_matches(unsigned int high13, const struct pdp10_insn *insn)
{
switch (insn->fmt & 3) {
case PDP10_INSN_BASIC:
/* ignore A field (low 4 bits) */
high13 &= ~017;
break;
case PDP10_INSN_A_OPCODE:
/* all bits significant, nothing to ignore */
break;
case PDP10_INSN_A_UNUSED:
/* A should be zero, don't ignore it */
break;
case PDP10_INSN_IO:
/* ignore device field (middle 7 bits) */
high13 &= ~01770;
break;
}
return high13 == insn->high13;
}
const struct pdp10_insn *
pdp10_insn_from_high13(pdp10_cpu_models_t models, unsigned int high13, int extended)
{
unsigned int i, nr_insn;
const struct pdp10_insn *insn;
if (extended) {
insn = pdp10_extended_insn;
nr_insn = ARRAY_SIZE(pdp10_extended_insn);
} else {
insn = pdp10_insn;
nr_insn = ARRAY_SIZE(pdp10_insn);
}
for (i = 0; i < nr_insn; ++i)
if (high13_matches(high13, &insn[i])
&& (insn[i].models & models) == models)
return &insn[i];
return (const struct pdp10_insn *)0;
}

View File

@@ -1,439 +0,0 @@
/*
* pdp10-stdio.c
* Copyright (C) 2013-2019 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Provide stdio.h-like interface for I/O to and from files with 9-bit logical bytes (nonets),
* represented by native files with 8-bit physical bytes (octets).
*
* Theory of operation:
*
* - The state of a pdp10 file is composed of: a FILE* for an underlying octet file,
* the current read/write position in the nonet file, a 16-bit shift register buffering
* partial octets (writes) or partial nonets (reads), a counter indicating the number
* of bits in the shift register (which may be negative after a call to pdp10_fseek),
* and a boolean flag indicating if there may be unwritten buffered output.
*
* - Write streams: pdp10_fputc adds 9 bits to shiftreg and 9 to shiftreg_nr_bits, then each
* complete group of 8 bits in shiftreg is shifted out and written to the octet file.
* Between pdp10_fputc calls shiftreg contains between 0 and 7 bits, inclusive, during a
* pdp10_fputc it may temporarily contain up to 7+9 == 16 bits.
*
* - Read streams: pdp10_fgetc reads an octet from the octet file and adds 8 bits to shiftreg
* and 8 to shiftreg_nr_bits; this is repeated once more if needed to make shiftreg
* contain at least 9 bits. Then 9 bits are shifted out of shiftreg and returned.
* Between pdp10_fgetc calls shiftreg contains between 0 and 7 bits, inclusive, during an
* fgetc it may contain up to 8+8 == 16 bits.
*
* - An output operation (pdp10_fputc or pdp10_fwrite) may not be directly followed by an
* input operation (pdp10_fgetc or pdp10_fread) without an intervening call to pdp10_fflush
* or pdp10_fseeko, and an input operation may not be directly followed by an output
* operation without an intervening call to pdp10_fseeko, unless the input operation
* encountered end-of-file. (Same restriction as ANSI/ISO C.)
*
* - A pdp10_fseeko repositions the octet file to the closest octet boundary at or before the
* requested nonet boundary, and sets shiftreg_nr_bits to the bit difference, as a number
* between 0 and -7, inclusive. A subsequent pdp10_fgetc or pdp10_fputc detects this
* special state and reinitializes shiftreg as appropriate for that I/O direction.
*/
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "pdp10-stdio.h"
struct pdp10_file {
FILE *octet_fp;
off_t nonet_pos; /* current read or write nonet offset */
unsigned int shiftreg; /* contains 0 to 16 buffered bits */
int shiftreg_nr_bits;
int writing; /* non-zero if shiftreg may contain pending output data */
};
static PDP10_FILE *pdp10_fpopen(FILE *octet_fp, const char *mode)
{
PDP10_FILE *pdp10fp;
int oerrno;
if (!octet_fp) {
return NULL;
} else if (mode[0] == 'a') { /* "a+" won't work, and "a" is not yet implemented */
errno = EINVAL;
} else {
pdp10fp = malloc(sizeof *pdp10fp);
if (pdp10fp) {
pdp10fp->octet_fp = octet_fp;
pdp10fp->nonet_pos = 0;
pdp10fp->shiftreg = 0;
pdp10fp->shiftreg_nr_bits = 0;
pdp10fp->writing = 0;
return pdp10fp;
}
}
oerrno = errno;
fclose(octet_fp);
errno = oerrno;
return NULL;
}
PDP10_FILE *pdp10_fdopen(int fd, const char *mode)
{
off_t octet_pos;
octet_pos = lseek(fd, 0, SEEK_CUR);
if (octet_pos == -1)
return NULL;
/* XXX: for simplicity we require that octet_pos is zero,
otherwise we could follow up with a pdp10_fseeko() call */
if (octet_pos != 0) {
errno = EINVAL;
return NULL;
}
return pdp10_fpopen(fdopen(fd, mode), mode);
}
PDP10_FILE *pdp10_fopen(const char *path, const char *mode)
{
return pdp10_fpopen(fopen(path, mode), mode);
}
static int pdp10_flush_buffered_write(PDP10_FILE *pdp10fp)
{
int octet_ch;
if (!pdp10fp->writing)
return 0;
if (pdp10fp->shiftreg_nr_bits <= 0)
return 0;
/* read the next octet which we will partially overwrite */
if (fseeko(pdp10fp->octet_fp, 0, SEEK_CUR) == -1)
return EOF;
octet_ch = fgetc(pdp10fp->octet_fp);
/* rewind by one octet, or by zero octets if we read EOF above */
if (fseeko(pdp10fp->octet_fp, octet_ch == EOF ? 0 : -1, SEEK_CUR) == -1)
return EOF;
if (octet_ch == EOF)
octet_ch = 0;
octet_ch &= (1 << (8 - pdp10fp->shiftreg_nr_bits)) - 1;
octet_ch |= (pdp10fp->shiftreg << (8 - pdp10fp->shiftreg_nr_bits)) & 0xFF;
if (fputc(octet_ch, pdp10fp->octet_fp) == EOF)
return EOF;
/* rewind by one octet to permit further writes; XXX: this is unnecessary
when the flush is called from fclose() or fseeko() */
if (fseeko(pdp10fp->octet_fp, -1, SEEK_CUR) == -1)
return EOF;
return 0;
}
int pdp10_fflush(PDP10_FILE *pdp10fp)
{
if (pdp10_flush_buffered_write(pdp10fp) == EOF)
return EOF;
return fflush(pdp10fp->octet_fp);
}
int pdp10_fclose(PDP10_FILE *pdp10fp)
{
int status;
FILE *octet_fp;
status = pdp10_flush_buffered_write(pdp10fp);
octet_fp = pdp10fp->octet_fp;
free(pdp10fp);
if (fclose(octet_fp) == EOF)
status = EOF;
return status;
}
static int pdp10_fgetc_one_octet(PDP10_FILE *pdp10fp)
{
int octet_ch;
octet_ch = fgetc(pdp10fp->octet_fp);
if (octet_ch == EOF)
return -1; /* incomplete nonets are discarded */
/* XXX: big-endian conversion */
pdp10fp->shiftreg = (pdp10fp->shiftreg << 8) | (octet_ch & 0xFF);
pdp10fp->shiftreg_nr_bits += 8;
return 0;
}
int pdp10_fgetc(PDP10_FILE *pdp10fp)
{
uint16_t nonet_ch;
pdp10fp->writing = 0;
if (pdp10fp->shiftreg_nr_bits < 9) {
/*
* There are three cases to consider here:
*
* 1. 1 <= shiftreg_nr_bits <= 8.
* We have a partially filled nonet in the buffer.
* We'll read one octet.
*
* 2. shiftreg_nr_bits == 0.
* The last read took us to a 72-bit boundary, emptying the buffer.
* We'll read two octets.
*
* 3. -7 <= shiftreg_nr_bits <= -1.
* An fseek placed octet_pos 1 to 7 bits before nonet_pos.
* We'll read two octets, but the first -shiftreg_nr_bits
* bits will be discarded.
*
* Either way we read one or two octets, append them to the buffer,
* and increment shiftreg_nr_bits by the number of bits read.
*
* An EOF during read permits the next operation to be a write, without
* an intervening fflush() or fseeko(). Therefore we must reposition
* octet_pos before nonet_pos if an EOF occurs here.
*/
if (pdp10_fgetc_one_octet(pdp10fp) < 0
|| (pdp10fp->shiftreg_nr_bits < 9
&& pdp10_fgetc_one_octet(pdp10fp) < 0)) {
if (pdp10fp->shiftreg_nr_bits > 0) {
/* if this fseeko() fails then presumably subsequent fseeko()s
will also fail; if not, then data may not be read or written
where we expect it to be XXX */
(void)fseeko(pdp10fp->octet_fp, -1, SEEK_CUR);
pdp10fp->shiftreg_nr_bits -= 8;
}
return EOF;
}
}
/* XXX: big-endian conversion */
nonet_ch = (pdp10fp->shiftreg >> (pdp10fp->shiftreg_nr_bits - 9)) & 0x1FF;
pdp10fp->shiftreg_nr_bits -= 9;
pdp10fp->nonet_pos += 1;
return nonet_ch;
}
static int pdp10_fputc_one_octet(PDP10_FILE *pdp10fp)
{
unsigned char rest_bits;
unsigned char octet_ch;
rest_bits = pdp10fp->shiftreg_nr_bits - 8;
octet_ch = (pdp10fp->shiftreg >> rest_bits) & 0xFF;
if (fputc((char)octet_ch, pdp10fp->octet_fp) == EOF)
return -1;
pdp10fp->shiftreg_nr_bits = rest_bits;
return 0;
}
int pdp10_fputc(uint16_t nonet_ch, PDP10_FILE *pdp10fp)
{
if (pdp10fp->shiftreg_nr_bits < 0) {
int octet_ch;
/*
* -7 <= shiftreg_nr_bits <= -1.
* An fseek placed octet_pos 1 to 7 bits before nonet_pos.
* We will peek at the octet at octet_pos, and preload shiftreg with the
* -shiftreg_nr_bits high bits from the octet.
*/
/* read the next octet, which we will partially overwrite */
#if 0 /* XXX: the pdp10_fseek did that already */
if (fseeko(pdp10fp->octet_fp, 0, SEEK_CUR) == -1)
return EOF;
#endif
octet_ch = fgetc(pdp10fp->octet_fp);
/* rewind by one octet, or by zero octets if we read EOF above */
if (fseeko(pdp10fp->octet_fp, octet_ch == EOF ? 0 : -1, SEEK_CUR) == -1)
return EOF;
if (octet_ch == EOF)
octet_ch = 0;
pdp10fp->shiftreg_nr_bits = -pdp10fp->shiftreg_nr_bits;
pdp10fp->shiftreg = (octet_ch & 0xFF) >> (8 - pdp10fp->shiftreg_nr_bits);
}
pdp10fp->writing = 1;
pdp10fp->shiftreg = (pdp10fp->shiftreg << 9) | (nonet_ch & 0x1FF);
pdp10fp->shiftreg_nr_bits += 9;
if (pdp10_fputc_one_octet(pdp10fp) < 0)
return EOF;
if (pdp10fp->shiftreg_nr_bits == 8
&& pdp10_fputc_one_octet(pdp10fp) < 0)
return EOF;
pdp10fp->nonet_pos += 1;
return nonet_ch & 0x1FF;
}
int pdp10_fseeko(PDP10_FILE *pdp10fp, off_t offset, int whence)
{
off_t octet_pos, nonet_pos;
if (pdp10_flush_buffered_write(pdp10fp) == EOF)
return -1;
switch (whence) {
case PDP10_SEEK_SET:
nonet_pos = 0;
break;
case PDP10_SEEK_CUR:
nonet_pos = pdp10fp->nonet_pos;
break;
case PDP10_SEEK_END:
if (fseeko(pdp10fp->octet_fp, 0, SEEK_END) == -1)
return -1;
octet_pos = ftello(pdp10fp->octet_fp);
if (octet_pos == -1)
return -1;
/*
* Compute 'nonet_pos = (octet_pos * 8) / 9;' without
* overflowing the intermediate term.
*
* Let octet_pos = A * 9 + B, where A = octet_pos / 9 and B = octet_pos % 9.
*
* (octet_pos * 8) / 9
* == ((A * 9 + B) * 8) / 9
* == (A * 9 * 8 + B * 8) / 9
* == A * 8 + (B * 8) / 9
* == (octet_pos / 9) * 8 + ((octet_pos % 9) * 8) / 9
*/
nonet_pos = (octet_pos / 9) * 8 + ((octet_pos % 9) * 8) / 9;
break;
default:
errno = EINVAL;
return -1;
}
nonet_pos += offset;
/*
* Compute 'octet_pos = (nonet_pos * 9) / 8;' without
* overflowing the intermediate term.
*
* Let nonet_pos = C * 8 + D, where C = nonet_pos / 8 and D = nonet_pos % 8.
*
* (nonet_pos * 9) / 8
* == ((C * 8 + D) * 9) / 8
* == (C * 8 * 9 + D * 9) / 8
* == C * 9 + (D * 9) / 8
* == (nonet_pos / 8) * 9 + ((nonet_pos % 8) * 9) / 8
*/
octet_pos = (nonet_pos / 8) * 9 + ((nonet_pos % 8) * 9) / 8;
if (fseeko(pdp10fp->octet_fp, octet_pos, SEEK_SET) == -1)
return -1;
pdp10fp->nonet_pos = nonet_pos;
/*
* Now octet_pos will be from 0 to 7 bits before nonet_pos.
* Depending on whether the next I/O is a read or a write,
* different actions need to be taken. Set shiftreg_nr_bits
* to the negation of the number of "slack" bits to signal
* this case.
*/
pdp10fp->shiftreg = 0;
pdp10fp->shiftreg_nr_bits = -(nonet_pos % 8);
pdp10fp->writing = 0;
return 0;
}
off_t pdp10_ftello(PDP10_FILE *pdp10fp)
{
return pdp10fp->nonet_pos;
}
/*
* On an octet-based host, in-core data structures representing nonet-based
* target data will in fact contain oversize octet-based host data. For
* example, 9/18/36-bit target integers are typically stored in 16/32/64-bit
* host integers.
*
* This means that I/O of aggregate structures must be avoided, and instead
* be performed on each primitive data field individually, using explicit
* marshalling code for multi-nonet primitive data types.
*
* To detect mistakes in I/O, fread and fwrite only accept strings (size == 1)
* and single marshalled primitive data values (nmemb == 1, size == 1, 2, or 4).
*/
static int pdp10_freadwrite_bad_params(size_t size, size_t nmemb)
{
return !(size == 1 || (nmemb == 1 && (size == 2 || size == 4)));
}
size_t pdp10_fread(uint16_t *ptr, size_t size, size_t nmemb, PDP10_FILE *pdp10fp)
{
size_t i, nr_nonets;
int nonet_ch;
if (size == 0 || nmemb == 0)
return nmemb;
if (pdp10_freadwrite_bad_params(size, nmemb)) {
errno = EINVAL;
return 0;
}
nr_nonets = size * nmemb;
for (i = 0; i < nr_nonets; ++i) {
nonet_ch = pdp10_fgetc(pdp10fp);
if (nonet_ch == EOF)
break;
ptr[i] = nonet_ch & 0x1FF;
}
return i / size;
}
size_t pdp10_fwrite(const uint16_t *ptr, size_t size, size_t nmemb, PDP10_FILE *pdp10fp)
{
size_t i, nr_nonets;
if (size == 0 || nmemb == 0)
return nmemb;
if (pdp10_freadwrite_bad_params(size, nmemb)) {
errno = EINVAL;
return 0;
}
nr_nonets = size * nmemb;
for (i = 0; i < nr_nonets; ++i)
if (pdp10_fputc(ptr[i] & 0x1FF, pdp10fp) == EOF)
break;
return i / size;
}

View File

@@ -1,32 +0,0 @@
# nm/Makefile
# Copyright (C) 2013-2015 Mikael Pettersson
#
# This file is part of pdp10-tools.
#
# pdp10-tools is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pdp10-tools is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
CC=gcc
CFLAGS=-O2 -g -Wall
CPPFLAGS=-I../include
NMOBJS= nm.o
LIBOBJS=../lib/pdp10-elf36.o ../lib/pdp10-extint.o ../lib/pdp10-stdio.o
nm: $(NMOBJS) $(LIBOBJS)
$(LINK.c) -o $@ $^
nm.o: nm.c ../include/pdp10-elf36.h ../include/pdp10-inttypes.h ../include/pdp10-stdint.h ../include/pdp10-stdio.h
clean:
rm -f $(NMOBJS) nm a.out core.*

804
nm/nm.c
View File

@@ -1,804 +0,0 @@
/*
* nm.c -- nm clone for PDP10 Elf36 files
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This is essentially a copy of readelf.c, adjusted to
* process the symbol table differently.
*/
#define _GNU_SOURCE /* for getopt_long() */
#include <errno.h>
#include <getopt.h> /* for getopt_long() */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pdp10-elf36.h"
#include "pdp10-inttypes.h"
#include "pdp10-stdio.h"
#define VERSION "pdp10-tools nm version 0.1, built " __DATE__ " " __TIME__ "\n"
struct options {
unsigned char print_file_name;
unsigned char dynamic;
unsigned char format;
unsigned char extern_only;
unsigned char numeric_sort;
unsigned char no_sort;
unsigned char print_size;
unsigned char reverse_sort;
unsigned char radix;
unsigned char undefined_only;
unsigned char defined_only;
};
struct params {
const char *progname;
struct options opts;
int several_files;
const char *filename;
PDP10_FILE *pdp10fp;
Elf36_Ehdr ehdr;
Elf36_Shdr *shtab;
pdp10_uint36_t shnum;
pdp10_uint9_t *shstrtab;
pdp10_uint36_t shstrtablen;
Elf36_Sym *symtab;
pdp10_uint36_t symtabndx;
pdp10_uint36_t symnum;
pdp10_uint9_t *strtab;
pdp10_uint36_t strtablen;
};
static void params_init(struct params *params)
{
memset(params, 0, sizeof *params);
}
static void params_file_init(struct params *params)
{
params->pdp10fp = NULL;
params->shtab = NULL;
params->shnum = 0;
params->shstrtab = NULL;
params->shstrtablen = 0;
params->symtab = NULL;
params->symtabndx = 0;
params->symnum = 0;
params->strtab = NULL;
params->strtablen = 0;
}
static void params_file_fini(struct params *params)
{
free(params->strtab);
free(params->symtab);
free(params->shstrtab);
free(params->shtab);
pdp10_fclose(params->pdp10fp);
}
static int check_ehdr(struct params *params)
{
Elf36_Ehdr *ehdr = &params->ehdr;
Elf36_Uchar *e_ident = ehdr->e_ident;
if (e_ident[EI_MAG0] != ELFMAG0
|| e_ident[EI_MAG1] != ELFMAG1
|| e_ident[EI_MAG2] != ELFMAG2
|| e_ident[EI_MAG3] != ELFMAG3) {
fprintf(stderr, "%s: %s: not an ELF file: wrong magic\n", params->progname, params->filename);
return -1;
}
if (e_ident[EI_CLASS] != ELFCLASS36) {
fprintf(stderr, "%s: %s: not an ELF36 file: wrong class %u\n",
params->progname, params->filename, e_ident[EI_CLASS]);
return -1;
}
if (e_ident[EI_DATA] != ELFDATA2MSB) {
fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong data %u\n",
params->progname, params->filename, e_ident[EI_DATA]);
return -1;
}
if (e_ident[EI_VERSION] != EV_CURRENT) {
fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong version %u\n",
params->progname, params->filename, e_ident[EI_VERSION]);
return -1;
}
switch (e_ident[EI_OSABI]) {
case ELFOSABI_NONE:
case ELFOSABI_LINUX:
break;
default:
fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong osabi %u\n",
params->progname, params->filename, e_ident[EI_OSABI]);
return -1;
}
if (e_ident[EI_ABIVERSION] != 0) {
fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong abiversion %u\n",
params->progname, params->filename, e_ident[EI_ABIVERSION]);
return -1;
}
switch (ehdr->e_type) {
case ET_REL:
case ET_EXEC:
case ET_DYN:
case ET_CORE:
break;
default:
fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong type %u\n",
params->progname, params->filename, ehdr->e_type);
return -1;
}
if (ehdr->e_machine != EM_PDP10) {
fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong machine %u\n",
params->progname, params->filename, ehdr->e_machine);
return -1;
}
if (ehdr->e_version != EV_CURRENT) {
fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong version %" PDP10_PRIu36 "\n",
params->progname, params->filename, ehdr->e_version);
return -1;
}
if (ehdr->e_ehsize != ELF36_EHDR_SIZEOF) {
fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong ehsize %u\n",
params->progname, params->filename, ehdr->e_ehsize);
return -1;
}
if (ehdr->e_shoff != 0 && ehdr->e_shentsize != ELF36_SHDR_SIZEOF) {
fprintf(stderr, "%s: %s: not a PDP10 ELF36 file: wrong shentsize %u\n",
params->progname, params->filename, ehdr->e_shentsize);
return -1;
}
return 0;
}
static int read_strtab(struct params *params, pdp10_uint36_t i, pdp10_uint9_t **strtab_ptr, pdp10_uint36_t *strtablen_ptr, const char *kind)
{
pdp10_uint9_t *strtab;
pdp10_uint36_t strtablen;
if (i == 0 || i >= params->shnum) {
fprintf(stderr, "%s: %s: invalid index %" PDP10_PRIu36 " for %s string table\n",
params->progname, params->filename, i, kind);
return -1;
}
if (params->shtab[i].sh_type != SHT_STRTAB) {
fprintf(stderr, "%s: %s: %s string table at index %" PDP10_PRIu36 " has wrong type %" PDP10_PRIu36 "\n",
params->progname, params->filename, kind, i, params->shtab[i].sh_type);
return -1;
}
*strtablen_ptr = strtablen = params->shtab[i].sh_size;
*strtab_ptr = strtab = malloc(strtablen * sizeof(pdp10_uint9_t));
if (!strtab) {
fprintf(stderr, "%s: %s: failed to allocate %zu bytes for %s string table: %s\n",
params->progname, params->filename, strtablen * sizeof(pdp10_uint9_t), kind, strerror(errno));
return -1;
}
if (pdp10_fseeko(params->pdp10fp, params->shtab[i].sh_offset, PDP10_SEEK_SET) < 0) {
fprintf(stderr, "%s: %s: failed to seek to %s string table at %" PDP10_PRIu36 ": %s\n",
params->progname, params->filename, kind, params->shtab[i].sh_offset, strerror(errno));
return -1;
}
for (i = 0; i < strtablen; ++i)
if (pdp10_elf36_read_uint9(params->pdp10fp, &strtab[i]) < 0) {
fprintf(stderr, "%s: %s: failed to read %s string table at index %" PDP10_PRIu36 ": %s\n",
params->progname, params->filename, kind, i, strerror(errno));
return -1;
}
return 0;
}
static int read_shtab(struct params *params)
{
Elf36_Shdr shdr0;
pdp10_uint36_t i;
if (params->ehdr.e_shoff == 0)
return 0;
params->shnum = params->ehdr.e_shnum;
if (pdp10_fseeko(params->pdp10fp, params->ehdr.e_shoff, PDP10_SEEK_SET) < 0) {
fprintf(stderr, "%s: %s: failed to seek to section header table at %" PDP10_PRIu36 ": %s\n",
params->progname, params->filename, params->ehdr.e_shoff, strerror(errno));
return -1;
}
if (pdp10_elf36_read_shdr(params->pdp10fp, &shdr0) < 0) {
fprintf(stderr, "%s: %s: failed to read section header index 0: %s\n",
params->progname, params->filename, strerror(errno));
return -1;
}
if (params->shnum == 0)
params->shnum = shdr0.sh_size;
params->shtab = malloc(params->shnum * sizeof(Elf36_Shdr));
if (!params->shtab) {
fprintf(stderr, "%s: %s: failed to allocate %zu bytes for section header table: %s\n",
params->progname, params->filename, params->shnum * sizeof(Elf36_Shdr), strerror(errno));
return -1;
}
params->shtab[0] = shdr0;
for (i = 1; i < params->shnum; ++i)
if (pdp10_elf36_read_shdr(params->pdp10fp, &params->shtab[i]) < 0) {
fprintf(stderr, "%s: %s: failed to read section header index %" PDP10_PRIu36 ": %s\n",
params->progname, params->filename, i, strerror(errno));
return -1;
}
i = params->ehdr.e_shstrndx;
if (i == SHN_UNDEF)
return 0;
if (i == SHN_XINDEX)
i = shdr0.sh_link;
if (read_strtab(params, i, &params->shstrtab, &params->shstrtablen, "section header") < 0)
return -1;
return 0;
}
static int print_name(struct params *params, pdp10_uint9_t *strtab, pdp10_uint36_t strtablen, pdp10_uint36_t name, int say_empty)
{
pdp10_uint36_t i;
if (name >= strtablen) {
fprintf(stderr, "%s: %s: name index %" PDP10_PRIu36 " is larger than the string table\n",
params->progname, params->filename, name);
return -1;
}
i = name;
while (strtab[i] != '\0') {
printf("%c", strtab[i]);
++i;
if (i >= strtablen) {
fprintf(stderr, "%s: %s: name string at index %" PDP10_PRIu36 " is not NUL-terminated\n",
params->progname, params->filename, name);
return -1;
}
}
if (i == name && say_empty)
printf("(empty)");
return 0;
}
static int read_symtab(struct params *params)
{
pdp10_uint36_t i;
for (i = 1; i < params->shnum; ++i)
if (params->shtab[i].sh_type == SHT_SYMTAB)
break;
if (i >= params->shnum)
return 0;
params->symtabndx = i;
if (read_strtab(params, params->shtab[i].sh_link, &params->strtab, &params->strtablen, "symtab") < 0)
return -1;
if (params->shtab[i].sh_entsize != ELF36_SYM_SIZEOF) {
fprintf(stderr, "%s: %s: bogus sh_entsize %" PDP10_PRIu36 " in symbol table section header at index %" PDP10_PRIu36 "\n",
params->progname, params->filename, params->shtab[i].sh_entsize, i);
return -1;
}
if ((params->shtab[i].sh_size % ELF36_SYM_SIZEOF) != 0) {
fprintf(stderr, "%s: %s: bogus sh_size %" PDP10_PRIu36 " in symbol table section header at index %" PDP10_PRIu36 "\n",
params->progname, params->filename, params->shtab[i].sh_size, i);
return -1;
}
params->symnum = params->shtab[i].sh_size / ELF36_SYM_SIZEOF;
if (params->symnum == 0)
return 0;
params->symtab = malloc(params->symnum * sizeof(Elf36_Sym));
if (!params->symtab) {
fprintf(stderr, "%s: %s: failed to allocate %zu bytes for symbol table: %s\n",
params->progname, params->filename, params->symnum * sizeof(Elf36_Sym), strerror(errno));
return -1;
}
if (pdp10_fseeko(params->pdp10fp, params->shtab[i].sh_offset, PDP10_SEEK_SET) < 0) {
fprintf(stderr, "%s: %s: failed to seek to symbol table at %" PDP10_PRIu36 ": %s\n",
params->progname, params->filename, params->shtab[i].sh_offset, strerror(errno));
return -1;
}
for (i = 0; i < params->symnum; ++i)
if (pdp10_elf36_read_sym(params->pdp10fp, &params->symtab[i]) < 0) {
fprintf(stderr, "%s: %s: failed to read symbol table index %" PDP10_PRIu36 ": %s\n",
params->progname, params->filename, i, strerror(errno));
return -1;
}
return 0;
}
static int print_sym_name(struct params *params, Elf36_Sym *sym)
{
return print_name(params, params->strtab, params->strtablen, sym->st_name, 1);
}
static char sym_type_letter(struct params *params, Elf36_Sym *sym)
{
unsigned int st_type, st_bind;
Elf36_Shdr *shdr;
st_type = ELF36_ST_TYPE(sym->st_info);
st_bind = ELF36_ST_BIND(sym->st_info);
if (sym->st_shndx == SHN_ABS) {
switch (st_type) {
case STT_NOTYPE:
case STT_OBJECT:
case STT_FUNC:
if (st_bind == STB_GLOBAL)
return 'A';
if (st_bind == STB_LOCAL)
return 'a';
}
return '\0';
}
if (sym->st_shndx == SHN_UNDEF) {
if (st_bind == STB_GLOBAL)
return 'U';
return '\0';
}
if (sym->st_shndx == SHN_COMMON) {
switch (st_type) {
case STT_NOTYPE:
case STT_OBJECT:
if (st_bind == STB_GLOBAL)
return 'C';
if (st_bind == STB_LOCAL)
return 'c';
}
return '\0';
}
if (st_type == STT_GNU_IFUNC)
return 'i';
if (sym->st_shndx >= params->shnum)
return '\0';
shdr = &params->shtab[sym->st_shndx];
if (shdr->sh_type == SHT_NOBITS
&& ((shdr->sh_flags & (SHF_ALLOC | SHF_WRITE)) == (SHF_ALLOC | SHF_WRITE))) {
if (st_bind == STB_GLOBAL)
return 'B';
if (st_bind == STB_LOCAL)
return 'b';
return '\0';
}
if (shdr->sh_type == SHT_PROGBITS) {
if ((shdr->sh_flags & (SHF_ALLOC | SHF_EXECINSTR)) == (SHF_ALLOC | SHF_EXECINSTR)) {
if (st_bind == STB_GLOBAL)
return 'T';
if (st_bind == STB_LOCAL)
return 't';
return '\0';
}
if ((shdr->sh_flags & (SHF_ALLOC | SHF_WRITE)) == (SHF_ALLOC | SHF_WRITE)) {
if (st_bind == STB_GLOBAL)
return 'D';
if (st_bind == STB_LOCAL)
return 'd';
return '\0';
}
if (shdr->sh_flags & SHF_ALLOC) {
if (st_bind == STB_GLOBAL)
return 'R';
if (st_bind == STB_LOCAL)
return 'r';
return '\0';
}
return '\0';
}
return '\0';
}
static pdp10_uint36_t sym_value(const struct params *params, const Elf36_Sym *sym)
{
pdp10_uint36_t base;
base = 0;
if (sym->st_shndx < params->shnum && sym->st_shndx != SHN_ABS && sym->st_shndx != SHN_COMMON) {
Elf36_Shdr *shdr = &params->shtab[sym->st_shndx];
if (shdr->sh_type == SHT_PROGBITS
&& (shdr->sh_flags & SHF_ALLOC))
base = shdr->sh_addr;
}
return base + sym->st_value;
}
static int print_sym(struct params *params, pdp10_uint36_t i)
{
Elf36_Sym *sym;
char type;
pdp10_uint36_t value;
sym = &params->symtab[i];
type = sym_type_letter(params, sym);
if (type == '\0') /* ignored */
return 0;
/* XXX: handle --extern-only, --undefined-only, --defined-only */
/* XXX: handle --format={bsd,sysv,posix} */
if (params->opts.print_file_name)
printf("%s:", params->filename);
value = sym_value(params, sym);
switch (params->opts.radix) {
case 'x':
printf("%0*" PDP10_PRIx36, 9, value);
break;
case 'd':
printf("%0*" PDP10_PRIu36, 11, value);
break;
case 'o':
printf("%0*" PDP10_PRIo36, 12, value);
break;
}
printf(" %c ", type);
if (print_sym_name(params, sym) < 0)
return -1;
printf("\n");
return 0;
}
static int sym_cmp_value(const struct params *params, const Elf36_Sym *sym1, const Elf36_Sym *sym2)
{
pdp10_uint36_t val1, val2;
val1 = sym_value(params, sym1);
val2 = sym_value(params, sym2);
if (val1 < val2)
return -1;
if (val1 > val2)
return 1;
return 0;
}
static int sym_cmp_name(const struct params *params, const Elf36_Sym *sym1, const Elf36_Sym *sym2)
{
pdp10_uint36_t i;
i = 0;
for (;; ++i) {
pdp10_uint9_t c1, c2;
if (sym1->st_name + i >= params->strtablen)
c1 = 0;
else
c1 = params->strtab[sym1->st_name + i];
if (sym2->st_name + i >= params->strtablen)
c2 = 0;
else
c2 = params->strtab[sym2->st_name + i];
if (c1 < c2)
return -1;
else if (c1 > c2)
return 1;
else if (c1 == 0)
return 0;
}
}
static struct params *the_params; /* XXX: kludge */
static int sym_cmp(const void *p1, const void *p2)
{
Elf36_Sym *sym1 = (Elf36_Sym*)p1;
Elf36_Sym *sym2 = (Elf36_Sym*)p2;
int cmp;
if (the_params->opts.numeric_sort)
cmp = sym_cmp_value(the_params, sym1, sym2);
else
cmp = sym_cmp_name(the_params, sym1, sym2);
if (the_params->opts.reverse_sort) {
if (cmp < 0)
cmp = 1;
else if (cmp > 0)
cmp = -1;
}
return cmp;
}
static void symtab_sort(struct params *params)
{
if (params->opts.no_sort)
return;
/* We need access to `params' in the comparison routines.
Ideally qsort() should take an optional context parameter,
but it doesn't. A function closure could be used instead,
but that's non-standard C. So temporarily store `params'
in a global variable. */
the_params = params;
qsort(params->symtab, params->symnum, sizeof params->symtab[0], sym_cmp);
the_params = NULL;
}
static int print_symtab(struct params *params)
{
pdp10_uint36_t i;
if (params->several_files)
printf("\n%s:\n", params->filename);
symtab_sort(params);
for (i = 0; i < params->symnum; ++i)
if (print_sym(params, i) < 0) {
fprintf(stderr, "%s: %s: failed to print symbol table entry %" PDP10_PRIu36 "\n",
params->progname, params->filename, i);
return -1;
}
return 0;
}
static int nm1(struct params *params)
{
if (pdp10_elf36_read_ehdr(params->pdp10fp, &params->ehdr) < 0) {
fprintf(stderr, "%s: %s: failed to read ELF header: %s\n",
params->progname, params->filename, strerror(errno));
return -1;
}
if (check_ehdr(params) < 0)
return -1;
if (read_shtab(params) < 0) {
fprintf(stderr, "%s: %s: failed to read section header table\n",
params->progname, params->filename);
return -1;
}
if (read_symtab(params) < 0) {
fprintf(stderr, "%s: %s: read to read symbol table\n",
params->progname, params->filename);
return -1;
}
return print_symtab(params);
}
static int nm(struct params *params, char **files, int nrfiles)
{
char fake_file[6];
char *fake_files[1];
int i, status;
if (nrfiles <= 0) {
fake_file[0] = 'a';
fake_file[1] = '.';
fake_file[2] = 'o';
fake_file[3] = 'u';
fake_file[4] = 't';
fake_file[5] = '\0';
fake_files[0] = fake_file;
files = fake_files;
nrfiles = 1;
}
if (nrfiles > 1)
params->several_files = 1;
for (i = 0; i < nrfiles; ++i) {
params_file_init(params);
params->filename = files[i];
params->pdp10fp = pdp10_fopen(params->filename, "rb");
if (!params->pdp10fp) {
fprintf(stderr, "%s: %s: failed to open: %s\n",
params->progname, params->filename, strerror(errno));
return -1;
}
status = nm1(params);
params_file_fini(params);
if (status < 0)
return -1;
}
return 0;
}
/*
* Command-line interface.
*/
enum lopt {
LOPT_no_demangle = 1,
LOPT_special_syms = 2,
LOPT_defined_only = 3,
};
static const struct option long_options[] = {
/*
* Long-only options:
*/
{ "no-demangle", no_argument, 0, LOPT_no_demangle },
{ "special-syms", no_argument, 0, LOPT_special_syms },
{ "defined-only", no_argument, 0, LOPT_defined_only },
/*
* Long aliases for short options:
*/
{ "print-file-name", no_argument, 0, 'A' },
{ "dynamic", no_argument, 0, 'D' },
{ "format", required_argument, 0, 'f' },
{ "extern-only", no_argument, 0, 'g' },
{ "numeric-sort", no_argument, 0, 'v' },
{ "no-sort", no_argument, 0, 'p' },
{ "portability", no_argument, 0, 'P' },
{ "print-size", no_argument, 0, 'S' },
{ "reverse-sort", no_argument, 0, 'r' },
{ "radix", required_argument, 0, 't' },
{ "undefined-only", no_argument, 0, 'u' },
{ "version", no_argument, 0, 'V' },
/*
* NYI options:
* -a / --debug-syms
* --demangle
* --plugin <name>
* -l / --line-numbers
* --size-sort
* -s / --print-armap [TODO]
* --target=<bfdname>
* -X 32_64
* --help [TODO?]
* @file
*/
{ 0, 0, 0, 0 }
};
static void usage(const char *progname)
{
fprintf(stderr, "Usage: %s [options..] [files..]\n", progname);
}
int main(int argc, char **argv)
{
struct params params;
params_init(&params);
params.progname = argv[0];
params.opts.radix = 'x';
for (;;) {
int ch;
ch = getopt_long(argc, argv, "AoBDf:gnvpPSrt:uV", long_options, NULL);
switch (ch) {
case 'A':
case 'o':
params.opts.print_file_name = 1;
continue;
case 'B':
params.opts.format = 'b';
continue;
case LOPT_no_demangle:
/* default */
continue;
case 'D':
params.opts.dynamic = 1;
continue;
case 'f':
switch (optarg[0]) {
case 'b':
case 's':
case 'p':
params.opts.format = optarg[0];
continue;
default:
fprintf(stderr, "%s: invalid format '%s'\n", params.progname, optarg);
return 1;
}
case 'g':
params.opts.extern_only = 1;
continue;
case 'n':
case 'v':
params.opts.numeric_sort = 1;
params.opts.no_sort = 0;
continue;
case 'p':
params.opts.no_sort = 1;
params.opts.numeric_sort = 0;
params.opts.reverse_sort = 0;
continue;
case 'P':
params.opts.format = 'p';
continue;
case 'S':
params.opts.print_size = 1;
continue;
case 'r':
params.opts.reverse_sort = 1;
params.opts.no_sort = 0;
continue;
case LOPT_special_syms:
/* nothing to do, ignore */
continue;
case 't':
switch (optarg[0]) {
case 'd':
case 'o':
case 'x':
if (optarg[1] == '\0') {
params.opts.radix = optarg[0];
continue;
}
/*FALLTHROUGH*/
default:
fprintf(stderr, "%s: invalid radix '%s'\n", params.progname, optarg);
return 1;
}
case 'u':
params.opts.undefined_only = 1;
continue;
case LOPT_defined_only:
params.opts.defined_only = 1;
continue;
case 'V':
printf(VERSION);
return 0;
case -1:
break;
default:
usage(params.progname);
return 1;
}
break;
}
if (nm(&params, &argv[optind], argc - optind) < 0)
return 1;
return 0;
}

View File

@@ -1,32 +0,0 @@
# od/Makefile
# Copyright (C) 2013-2015 Mikael Pettersson
#
# This file is part of pdp10-tools.
#
# pdp10-tools is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pdp10-tools is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
CC=gcc
CFLAGS=-O2 -g -Wall
CPPFLAGS=-I../include
ODOBJS= od.o
LIBOBJS=../lib/pdp10-extint.o ../lib/pdp10-stdio.o
od: $(ODOBJS) $(LIBOBJS)
$(LINK.c) -o $@ $^
od.o: od.c ../include/pdp10-extint.h ../include/pdp10-inttypes.h ../include/pdp10-stdint.h ../include/pdp10-stdio.h
clean:
rm -f $(ODOBJS) od a.out core.*

569
od/od.c
View File

@@ -1,569 +0,0 @@
/*
* od.c -- od clone for binary files with 9-bit bytes
* Copyright (C) 2013-2015, 2018 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* getopt() */
#include "pdp10-extint.h"
#include "pdp10-inttypes.h"
#include "pdp10-stdio.h"
#define VERSION "pdp10-tools od version 0.2, built " __DATE__ " " __TIME__ "\n"
struct options {
/* user options: */
char address_radix; /* -A/--address-radix= */
unsigned long skip_bytes; /* -j/--skip-bytes= */
unsigned long read_bytes; /* -N/--read-bytes= */
char output_type; /* 'c', 'd', 'o', 'u', 'x'; 'a' and 'f' are NYI */
unsigned char output_z; /* type has trailing 'z' */
unsigned int bytes_per_datum; /* 1, 2, or 4 */
unsigned long width; /* -w/--width= */
unsigned char version; /* -V */
/* compiled options: */
char numfmt[8]; /* "%0*{,l,ll}[doux]\0" */
int chars_per_datum;
unsigned int datums_per_line;
};
struct input {
unsigned long read_bytes;
char **files;
unsigned int nrfiles;
PDP10_FILE *pdp10fp;
};
static void input_init(struct input *input, unsigned long read_bytes, char **files, unsigned int nrfiles)
{
input->read_bytes = read_bytes;
input->files = files;
input->nrfiles = nrfiles;
input->pdp10fp = NULL;
}
static void input_fini(struct input *input)
{
if (input->pdp10fp)
pdp10_fclose(input->pdp10fp);
}
static int input_fgetc_raw(struct input *input, const char *progname)
{
int ch;
const char *filename;
for (;;) {
if (input->pdp10fp) {
ch = pdp10_fgetc(input->pdp10fp);
if (ch != EOF)
return ch;
pdp10_fclose(input->pdp10fp);
input->pdp10fp = NULL;
}
if (input->nrfiles == 0)
return EOF;
filename = input->files[0];
++input->files;
--input->nrfiles;
/* XXX: call pdp10_fdopen() if filename is "-" */
if (strcmp(filename, "-") == 0)
filename = "/dev/stdin";
input->pdp10fp = pdp10_fopen(filename, "rb");
if (!input->pdp10fp) {
fprintf(stderr, "%s: %s: failed to open: %s\n", progname, filename, strerror(errno));
input->nrfiles = 0;
return EOF;
}
}
}
static int input_fgetc_limited(struct input *input, const char *progname)
{
int ch;
if (input->read_bytes == 0)
return EOF;
ch = input_fgetc_raw(input, progname);
if (ch == EOF)
return ch;
if (input->read_bytes != -1UL)
--input->read_bytes;
return ch;
}
static int od1(const char *progname, struct options *options, struct input *input)
{
pdp10_uint36_t offset;
const unsigned int bytes_per_line = options->bytes_per_datum * options->datums_per_line;
pdp10_uint9_t line_bytes[bytes_per_line];
unsigned int nrbytes, b;
int ch;
pdp10_uint36_t datum;
offset = 0;
for (; options->skip_bytes > 0; ++offset, --options->skip_bytes) {
if (input_fgetc_raw(input, progname) == EOF) {
fprintf(stderr, "%s: cannot skip past end of combined input\n", progname);
return 1;
}
}
for (;;) {
switch (options->address_radix) {
case 'o':
printf("%011" PDP10_PRIo36, offset);
break;
case 'd':
printf("%010" PDP10_PRIu36, offset);
break;
case 'x':
printf("%09" PDP10_PRIx36, offset);
break;
}
for (nrbytes = 0; nrbytes < bytes_per_line; ++nrbytes) {
ch = input_fgetc_limited(input, progname);
if (ch == EOF)
break;
line_bytes[nrbytes] = ch;
}
for (b = nrbytes; b < bytes_per_line; ++b)
line_bytes[b] = 0;
if (nrbytes == 0) {
printf("\n");
break;
}
for (b = 0; b < nrbytes; b += options->bytes_per_datum) {
if (options->output_type == 'c') {
if ((unsigned char)line_bytes[b] == line_bytes[b]
&& isprint(line_bytes[b])) {
printf(" %c", line_bytes[b]);
continue;
}
switch (line_bytes[b]) {
case '\0':
printf(" \\0");
break;
case '\t':
printf(" \\t");
break;
case '\r':
printf(" \\r");
break;
case '\n':
printf(" \\n");
break;
case '\f':
printf(" \\f");
break;
case '\e':
printf(" \\e");
break;
default:
printf(" %03o", line_bytes[b]);
break;
}
continue;
}
switch (options->bytes_per_datum) {
default:
case 1:
datum = line_bytes[b];
if (options->output_type == 'd') {
const pdp10_uint36_t PDP10_UINT9_SBIT = ~(PDP10_UINT9_MAX >> 1) & PDP10_UINT9_MAX;
datum = ((datum & PDP10_UINT9_MAX) ^ PDP10_UINT9_SBIT) - PDP10_UINT9_SBIT;
}
break;
case 2:
{
struct pdp10_ext_uint18 ext18;
ext18.nonet[0] = line_bytes[b + 0];
ext18.nonet[1] = line_bytes[b + 1];
datum = pdp10_uint18_from_ext(&ext18);
if (options->output_type == 'd') {
const pdp10_uint36_t PDP10_UINT18_SBIT = ~(PDP10_UINT18_MAX >> 1) & PDP10_UINT18_MAX;
datum = ((datum & PDP10_UINT18_MAX) ^ PDP10_UINT18_SBIT) - PDP10_UINT18_SBIT;
}
break;
}
case 4:
{
struct pdp10_ext_uint36 ext36;
ext36.nonet[0] = line_bytes[b + 0];
ext36.nonet[1] = line_bytes[b + 1];
ext36.nonet[2] = line_bytes[b + 2];
ext36.nonet[3] = line_bytes[b + 3];
datum = pdp10_uint36_from_ext(&ext36);
if (options->output_type == 'd') {
const pdp10_uint36_t PDP10_UINT36_SBIT = ~(PDP10_UINT36_MAX >> 1) & PDP10_UINT36_MAX;
datum = ((datum & PDP10_UINT36_MAX) ^ PDP10_UINT36_SBIT) - PDP10_UINT36_SBIT;
}
break;
}
}
printf(" ");
printf(options->numfmt, options->chars_per_datum, datum);
}
while (b < bytes_per_line) {
printf("%*s", options->chars_per_datum + 1, "");
b += options->bytes_per_datum;
}
if (options->output_z) {
printf(" >");
for (b = 0; b < nrbytes; ++b) {
if ((unsigned char)line_bytes[b] == line_bytes[b]
&& isprint(line_bytes[b]))
printf("%c", line_bytes[b]);
else
printf(".");
}
printf("<");
}
printf("\n");
offset += nrbytes;
}
return 0;
}
static int od(const char *progname, struct options *options, char **files, int nrfiles)
{
struct input input;
char fake_file[2];
char *fake_files[1];
int i;
int status;
/* getopt() doesn't diagnose invalid short options, so we'll do that here */
for (i = 0; i < nrfiles; ++i) {
if (files[i][0] == '-' && files[i][1] != '\0') {
fprintf(stderr, "%s: invalid option '%s'\n", progname, files[i]);
return 1;
}
}
if (options->version)
printf(VERSION);
if (nrfiles <= 0) {
fake_file[0] = '-';
fake_file[1] = '\0';
fake_files[0] = fake_file;
files = fake_files;
nrfiles = 1;
}
input_init(&input, options->read_bytes, files, nrfiles);
status = od1(progname, options, &input);
input_fini(&input);
return status;
}
/*
* Command-line interface.
*/
static void usage(const char *progname)
{
fprintf(stderr,
"Usage: %s [-V] [-bcdDiloOsSxX] [-t [bcdoux][1248][z]] [-A RADIX] [-j BYTES] [-N BYTES] [-w [BYTES]] [files..]\n",
progname);
}
static int parse_radix(const char *progname, struct options *options, const char *string)
{
switch (string[0]) {
case 'd':
case 'o':
case 'x':
case 'n':
if (string[1] == '\0') {
options->address_radix = string[0];
return 0;
}
/*FALLTHROUGH*/
default:
fprintf(stderr, "%s: invalid radix '%s'\n", progname, string);
return -1;
}
}
static int parse_bytes(const char *progname, unsigned long *dst, const char *string)
{
unsigned long val;
char *end;
errno = 0;
val = strtoul(string, &end, 0);
if ((val == 0 || val == ULONG_MAX) && errno != 0) {
fprintf(stderr, "%s: invalid number '%s': %s\n", progname, string, strerror(errno));
return -1;
}
switch (*end) {
case 'b':
val *= 512;
++end;
break;
case 'K':
val *= 1024;
++end;
break;
case 'M':
val *= 1024 * 1024;
++end;
break;
case 'G':
val *= 1024 * 1024 * 1024;
++end;
break;
}
if (*end != '\0') {
fprintf(stderr, "%s: invalid multiplier in '%s'\n", progname, string);
return -1;
}
*dst = val;
return 0;
}
static int parse_type(const char *progname, struct options *options, const char *string)
{
const char *s;
s = string;
switch (*s) {
case 'c':
case 'd':
case 'o':
case 'u':
case 'x':
options->output_type = *s;
break;
default:
fprintf(stderr, "%s: invalid type letter '%c' in type specifier '%s'\n", progname, *s, string);
return -1;
}
if (*s == 'c') {
++s;
options->bytes_per_datum = 1;
} else {
++s;
switch (*s) {
case '1':
options->bytes_per_datum = 1;
++s;
break;
case '2':
options->bytes_per_datum = 2;
++s;
break;
case '4':
options->bytes_per_datum = 4;
++s;
break;
case 'z':
case '\0':
options->bytes_per_datum = 4;
break;
default:
fprintf(stderr, "%s: invalid type size '%c' in type specifier '%s'\n", progname, *s, string);
return -1;
}
}
if (*s == 'z') {
options->output_z = 1;
++s;
}
if (*s != '\0') {
fprintf(stderr, "%s: invalid suffix '%c' in type specifier '%s'\n", progname, *s, string);
return -1;
}
return 0;
}
static int compile_options(const char *progname, struct options *options)
{
pdp10_uint36_t maxval;
char tmpbuf[16];
options->datums_per_line = options->width / options->bytes_per_datum;
if (options->datums_per_line * options->bytes_per_datum != options->width) {
fprintf(stderr, "%s: line width %lu is not a multiple of the input datum size %u\n",
progname, options->width, options->bytes_per_datum);
return -1;
}
switch (options->output_type) {
case 'd':
sprintf(options->numfmt, "%% *%s", PDP10_PRId36);
break;
case 'u':
sprintf(options->numfmt, "%% *%s", PDP10_PRIu36);
break;
case 'o':
sprintf(options->numfmt, "%%0*%s", PDP10_PRIo36);
break;
case 'x':
sprintf(options->numfmt, "%%0*%s", PDP10_PRIx36);
break;
default:
options->chars_per_datum = 3; /* for -c */
return 0;
}
maxval = PDP10_UINT36_MAX;
if (options->bytes_per_datum < 4)
maxval >>= 18;
if (options->bytes_per_datum < 2)
maxval >>= 9;
sprintf(tmpbuf, options->numfmt, 1, maxval);
options->chars_per_datum = strlen(tmpbuf);
return 0;
}
int main(int argc, char **argv)
{
struct options options;
memset(&options, 0, sizeof options);
options.address_radix = 'o';
options.read_bytes = -1UL;
options.output_type = 'o';
options.bytes_per_datum = 2;
options.width = 16;
for (;;) {
int ch;
ch = getopt(argc, argv, "VbcdDiloOsxXA:j:N:t:w::");
switch (ch) {
case 'V':
options.version = 1;
continue;
case 'b': /* == -t o1 */
options.output_type = 'o';
options.output_z = 0;
options.bytes_per_datum = 1;
break;
case 'c': /* == -t c */
options.output_type = 'c';
options.output_z = 0;
options.bytes_per_datum = 1;
continue;
case 'd': /* == -t u2 */
options.output_type = 'u';
options.output_z = 0;
options.bytes_per_datum = 2;
continue;
case 'D': /* == -t u4 */
options.output_type = 'u';
options.output_z = 0;
options.bytes_per_datum = 4;
continue;
case 'o': /* == -t o2 */
options.output_type = 'o';
options.output_z = 0;
options.bytes_per_datum = 2;
continue;
case 'O': /* == -t o4 */
options.output_type = 'o';
options.output_z = 0;
options.bytes_per_datum = 4;
continue;
case 's': /* == -t d2 */
options.output_type = 'd';
options.output_z = 0;
options.bytes_per_datum = 2;
continue;
case 'i': /* == -t d<sizeof(int)> */
case 'l': /* == -t d<sizeof(long)> */
options.output_type = 'd';
options.output_z = 0;
options.bytes_per_datum = 4;
continue;
case 'x': /* == -t x2 */
options.output_type = 'x';
options.output_z = 0;
options.bytes_per_datum = 2;
continue;
case 'X': /* == -t x4 */
options.output_type = 'x';
options.output_z = 0;
options.bytes_per_datum = 4;
continue;
case 't':
if (parse_type(argv[0], &options, optarg) < 0)
goto do_usage;
continue;
case 'A':
if (parse_radix(argv[0], &options, optarg) < 0)
goto do_usage;
continue;
case 'j':
if (parse_bytes(argv[0], &options.skip_bytes, optarg) < 0)
goto do_usage;
continue;
case 'N':
if (parse_bytes(argv[0], &options.read_bytes, optarg) < 0)
goto do_usage;
continue;
case 'w':
if (!optarg)
options.width = 32;
else if (parse_bytes(argv[0], &options.width, optarg) < 0)
goto do_usage;
continue;
case -1:
break;
default:
do_usage:
usage(argv[0]);
return 1;
}
break;
}
if (compile_options(argv[0], &options) < 0)
return 1;
return od(argv[0], &options, &argv[optind], argc - optind);
}

View File

@@ -1,32 +0,0 @@
# readelf/Makefile
# Copyright (C) 2013-2015 Mikael Pettersson
#
# This file is part of pdp10-tools.
#
# pdp10-tools is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pdp10-tools is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
CC=gcc
CFLAGS=-O2 -g -Wall
CPPFLAGS=-I../include
READELFOBJS= readelf.o
LIBOBJS= ../lib/pdp10-elf36.o ../lib/pdp10-extint.o ../lib/pdp10-opcodes.o ../lib/pdp10-stdio.o
readelf: $(READELFOBJS) $(LIBOBJS)
$(LINK.c) -o $@ $^
readelf.o: readelf.c ../include/pdp10-elf36.h ../include/pdp10-inttypes.h ../include/pdp10-opcodes.h ../include/pdp10-stdint.h ../include/pdp10-stdio.h
clean:
rm -f $(READELFOBJS) readelf a.out core.*

View File

@@ -1,254 +0,0 @@
/*
* gen-test1.c -- generate test1.o for readelf
* Copyright (C) 2013-2015 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "pdp10-elf36.h"
#include "pdp10-stdio.h"
/*
* Layout (mirroring a minimal x86 ELF32 file with empty .data and .bss omitted):
*
* 0:
* - ELF Header (52 nonets, 13 words)
* 52:
* - Contents of .text (12 nonets, 3 words)
* 64:
* - Contents of .shstrtab: "", ".symtab", ".strtab", ".shstrtab", ".text"
* (33 nonets padded to 36 nonets, 9 words)
* 100:
* - Section headers:
* + [0] empty
* + [1] .text
* + [2] .shstrtab
* + [3] .symtab
* + [4] .strtab
* (200 (5 * 40) nonets, 50 words)
* 300:
* - Contents of .symtab: (undef), function global .text "start"
* (32 (2 * 16) nonets, 8 words)
* 332:
* - Contents of .strtab: "", "start"
* (7 nonets padded to 8 nonets, 2 words)
* 340:
* - end of file
*/
static int write_elf(PDP10_FILE *pdp10fp)
{
enum {
/* size of start and .text */
TEXT_SIZE_start = 12,
TEXT_SIZE = TEXT_SIZE_start,
/* .shstrtab indices and size */
SHSTRTAB_IX_symtab = 1,
SHSTRTAB_IX_strtab = 9,
SHSTRTAB_IX_shstrtab = 17,
SHSTRTAB_IX_text = 27,
SHSTRTAB_SIZE = 36,
/* .strtab indices and size */
STRTAB_IX_start = 1,
STRTAB_SIZE = 8,
/* section header indices and size */
SHTAB_IX_text = 1,
SHTAB_IX_shstrtab = 2,
SHTAB_IX_strtab = 3,
SHTAB_NR = 5,
/* .symtab indices and size */
SYMTAB_IX_LAST_LOCAL = 0,
SYMTAB_NR = 2,
SYMTAB_SIZE = SYMTAB_NR * ELF36_SYM_SIZEOF,
/* file offsets */
FILE_OFFSET_TEXT = ELF36_EHDR_SIZEOF,
FILE_OFFSET_SHSTRTAB = FILE_OFFSET_TEXT + TEXT_SIZE,
FILE_OFFSET_SHTAB = FILE_OFFSET_SHSTRTAB + SHSTRTAB_SIZE,
FILE_OFFSET_SYMTAB = FILE_OFFSET_SHTAB + (SHTAB_NR * ELF36_SHDR_SIZEOF),
FILE_OFFSET_STRTAB = FILE_OFFSET_SYMTAB + SYMTAB_SIZE,
};
static const pdp10_uint36_t text[3] = {
/* start: */
PDP10_UINT36_C(0201040000000), /* MOVEI 1,0 ; exit status = 0 */
PDP10_UINT36_C(0104000000136), /* JSYS 0136 ; SYS_exit_group */
PDP10_UINT36_C(0254200000000), /* HALT */
};
static const pdp10_uint9_t shstrtab[36] = {
'\0', '.', 's', 'y', 'm', 't', 'a', 'b', '\0', '.', 's', 't', 'r', 't', 'a', 'b',
'\0', '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', '\0', '.', 't', 'e', 'x', 't',
'\0', '\0', '\0', '\0',
};
static const pdp10_uint9_t strtab[8] = {
'\0', 's', 't', 'a', 'r', 't', '\0', '\0'
};
static const Elf36_Shdr shtab[5] = {
[0] = { /* (empty) */
.sh_name = 0,
.sh_type = SHT_NULL,
.sh_flags = 0,
.sh_addr = 0,
.sh_offset = 0,
.sh_size = 0,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 0,
.sh_entsize = 0,
},
[1] = { /* .text */
.sh_name = SHSTRTAB_IX_text,
.sh_type = SHT_PROGBITS,
.sh_flags = SHF_ALLOC | SHF_EXECINSTR,
.sh_addr = 0,
.sh_offset = FILE_OFFSET_TEXT,
.sh_size = TEXT_SIZE,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 4,
.sh_entsize = 0,
},
[2] = { /* .shstrtab */
.sh_name = SHSTRTAB_IX_shstrtab,
.sh_type = SHT_STRTAB,
.sh_flags = 0,
.sh_addr = 0,
.sh_offset = FILE_OFFSET_SHSTRTAB,
.sh_size = SHSTRTAB_SIZE,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 1,
.sh_entsize = 0,
},
[3] = { /* .strtab */
.sh_name = SHSTRTAB_IX_strtab,
.sh_type = SHT_STRTAB,
.sh_flags = 0,
.sh_addr = 0,
.sh_offset = FILE_OFFSET_STRTAB,
.sh_size = STRTAB_SIZE,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = 1,
.sh_entsize = 0,
},
[4] = { /* .symtab */
.sh_name = SHSTRTAB_IX_symtab,
.sh_type = SHT_SYMTAB,
.sh_flags = 0,
.sh_addr = 0,
.sh_offset = FILE_OFFSET_SYMTAB,
.sh_size = SYMTAB_SIZE,
.sh_link = SHTAB_IX_strtab,
.sh_info = SYMTAB_IX_LAST_LOCAL + 1,
.sh_addralign = 4,
.sh_entsize = ELF36_SYM_SIZEOF,
},
};
static const Elf36_Sym symtab[2] = {
[0] = { /* (empty) */
.st_name = 0,
.st_value = 0,
.st_size = 0,
.st_info = ELF36_ST_INFO(STB_LOCAL, STT_NOTYPE),
.st_other = 0,
.st_shndx = SHN_UNDEF,
},
[1] = { /* start */
.st_name = STRTAB_IX_start,
.st_value = 0,
.st_size = TEXT_SIZE_start,
.st_info = ELF36_ST_INFO(STB_GLOBAL, STT_FUNC),
.st_other = STV_DEFAULT,
.st_shndx = SHTAB_IX_text,
},
};
static const Elf36_Ehdr ehdr = {
.e_ident[EI_MAG0] = ELFMAG0,
.e_ident[EI_MAG1] = ELFMAG1,
.e_ident[EI_MAG2] = ELFMAG2,
.e_ident[EI_MAG3] = ELFMAG3,
.e_ident[EI_CLASS] = ELFCLASS36,
.e_ident[EI_DATA] = ELFDATA2MSB,
.e_ident[EI_VERSION] = EV_CURRENT,
.e_ident[EI_OSABI] = ELFOSABI_NONE,
.e_ident[EI_ABIVERSION] = 0,
.e_ident[EI_PAD ... EI_NIDENT - 1] = 0,
.e_type = ET_REL,
.e_machine = EM_PDP10,
.e_version = EV_CURRENT,
.e_entry = 0,
.e_phoff = 0,
.e_shoff = FILE_OFFSET_SHTAB,
.e_flags = 0,
.e_ehsize = ELF36_EHDR_SIZEOF,
.e_phentsize = 0,
.e_phnum = 0,
.e_shentsize = ELF36_SHDR_SIZEOF,
.e_shnum = SHTAB_NR,
.e_shstrndx = SHTAB_IX_shstrtab,
};
unsigned int i;
if (pdp10_elf36_write_ehdr(pdp10fp, &ehdr) < 0)
return 1;
for (i = 0; i < 3; ++i)
if (pdp10_elf36_write_uint36(pdp10fp, text[i]) < 0)
return -1;
for (i = 0; i < 36; ++i)
if (pdp10_elf36_write_uint9(pdp10fp, shstrtab[i]) < 0)
return -1;
for (i = 0; i < 5; ++i)
if (pdp10_elf36_write_shdr(pdp10fp, &shtab[i]) < 0)
return -1;
for (i = 0; i < 2; ++i)
if (pdp10_elf36_write_sym(pdp10fp, &symtab[i]) < 0)
return -1;
for (i = 0; i < 8; ++i)
if (pdp10_elf36_write_uint9(pdp10fp, strtab[i]) < 0)
return -1;
return 0;
}
int main(void)
{
PDP10_FILE *pdp10fp;
pdp10fp = pdp10_fopen("test1.o", "wb");
if (!pdp10fp) {
fprintf(stderr, "failed to open %s: %s\n", "test1.o", strerror(errno));
return 1;
}
if (write_elf(pdp10fp) < 0) {
fprintf(stderr, "failed to write ELF data: %s\n", strerror(errno));
return 1;
}
pdp10_fclose(pdp10fp);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,32 +0,0 @@
# sim/Makefile
# Copyright (C) 2018 Mikael Pettersson
#
# This file is part of pdp10-tools.
#
# pdp10-tools is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pdp10-tools is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
CC=gcc
CFLAGS=-O2 -g -Wall
CPPFLAGS=-I../include
SIMOBJS=sim.o pdp10-virt-mem.o pdp10-ea.o
LIBOBJS=../lib/pdp10-elf36.o ../lib/pdp10-extint.o ../lib/pdp10-stdio.o
sim: $(SIMOBJS) $(LIBOBJS)
$(LINK.c) -o $@ $^
sim.o: sim.c ../include/pdp10-elf36.h ../include/pdp10-inttypes.h ../include/pdp10-stdint.h ../include/pdp10-stdio.h
clean:
rm -f $(SIMOBJS) sim a.out core.*

View File

@@ -1,113 +0,0 @@
/*
* pdp10-core.h -- core definitions for PDP10 simulation
* Copyright (C) 2018 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PDP10_CORE_H
#define PDP10_CORE_H
#include <assert.h>
#include "pdp10-stdint.h"
#include "pdp10-virt-mem.h"
/*
* Words are 36 bits wide. The bits are numbered 0-35, left to right (most
* significant to least significant). The left (more significant) half word
* is bits 0-17, and the right (less significant) half word is bits 18-36.
* Numbers use twos-complement representation, with bit 0 as the sign.
*
* A double word is two adjacent words treated as a single 72-bit entity, where
* the word with the lower address is the more significant.
*
* Bits are numbered in decimal, most other numbers are in octal, in particular
* accumulator numbers, addresses, and instruction codes are in octal.
*
* A virtual address on a fully extended processor is 30 bits, composed of a 12
* bit section number (upper 12 bits) and an 18-bit section offset (lower 18
* bits). Paging hardware divides each section into 512 pages of 512 words each.
* The address bits are numbered according to the right-justified position of an
* address in a word. Thus bits 6-17 contain the section number, and bits 18-35
* the section offset.
*
* Single-section processors (PDP6, KA10, KI10, non-extended KL10, KS10) have no
* section number in their virtual addresses, while the extended KL10 (KL10B)
* only has 5 bit section numbers (bits 13-17).
*
* The program counter register, PC, contains a virtual address. Incrementing PC
* increments its segment offset without propagating any carry into the section
* number.
*
* Instructions are words. In the basic instruction format, bits 0-8 specify the
* operation, and bits 9-12 (A) address an accumulator. The rest of the word
* specifies how to calculate the effective address (E). Bit 13 (I) specifies the
* type of addressing (indirect or not), bits 14-17 (X) specify an index register,
* and bits 18-35 (Y) specify a memory location. Some instructions use bits 9-12
* to address flags or as extension of the instruction code.
*
* If an instruction does not use some part of the instruction word, that part is
* reserved and MUST BE ZERO, unless otherwise specified.
*/
/*
* BITS36(X, LEFT, RIGHT)
*
* Extract bits LEFT through RIGHT (inclusive) from a 36-bit number X.
* Requires 0 <= LEFT <= RIGHT <= 35.
*/
static inline pdp10_uint36_t BITS36(pdp10_uint36_t X, unsigned int LEFT, unsigned int RIGHT)
{
assert(0 <= LEFT && LEFT <= RIGHT && RIGHT <= 35);
return (X >> (35 - RIGHT)) & ((1UL << (1 + RIGHT - LEFT)) - 1);
}
static inline uint32_t BITS36LOW18(pdp10_uint36_t X)
{
return BITS36(X, 18, 35);
}
/*
* BIT36(X, BIT)
*
* Extract bit BIT from a 36-bit number X.
* Requires 0 <= BIT <= 35.
*/
static inline unsigned int BIT36(pdp10_uint36_t X, unsigned int BIT)
{
return BITS36(X, BIT, BIT);
}
typedef uint32_t pdp10_vaddr_t; /* 30 bits: 12-bit section number, 18-bit section offset */
struct pdp10_cpu {
pdp10_vaddr_t PC;
pdp10_uint36_t AC[017]; /* copy of ACS[CAB] */
pdp10_uint36_t ACS[8][017];
unsigned int flags:13;
unsigned int CAB:3; /* Current AC Block */
/*
* Previous Context
*/
unsigned int PCS:12; /* Previous Context Section */
unsigned int PCU:1; /* Previous Context User */
unsigned int PAB:3; /* Previous AC Block */
/*
* Memory
*/
struct pdp10_vmem vmem;
};
#endif /* PDP10_CORE_H */

View File

@@ -1,173 +0,0 @@
/*
* pdp10-ea.c -- PDP10 Effective-Address Calculation
* Copyright (C) 2018 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pdp10-core.h"
#include "pdp10-arith.h"
/* c.f. Figure 1.9 in the Toad-1 Architecture Manual */
static
uint64_t pdp10_section_zero_ea(struct pdp10_cpu *cpu, uint64_t MB)
{
/* Instruction Fetch (not done here)
*
* MB := C(PC)
* IR := MB_<0:12>
*/
for (;;) {
uint32_t Y = BITS36(MB, 18, 35); /* Y := MB_<18:35> */
unsigned int X = BITS36(MB, 14, 17); /* X := MB_<14:17> */
unsigned int I = BIT36(MB, 13); /* I := MB_<13> */
uint32_t E; /* 18 bits */
if (X == 0) {
E = Y;
} else {
E = BITS36LOW18(Y + BITS36LOW18(cpu->AC[X])); /* E := Y + C(X)_<18:35> */
}
if (I == 0) {
return E;
}
/* MB := C(E), but handle ACs */
if (E <= 017) {
MB = cpu->AC[E];
} else {
MB = pdp10_vmem_read(&cpu->vmem, E);
if (MB == (uint64_t)-1)
return MB; /* propagate page fault */
}
}
}
/* c.f. Figure 1.11 in the Toad-1 Architecture Manual */
static
uint64_t pdp10_extended_ea(struct pdp10_cpu *cpu, uint64_t MB)
{
uint32_t E; /* 30 bits */
/* Instruction Fetch (not done here)
*
* if PC_<18:31> == 0 then MB := C(PC_<32:35>)
* else MB := C(PC_<6:35>)
* IR := MB_<0:12>
*/
E = BITS36(cpu->PC, 6, 17) << 18; /* E_<6:17> := PC_<6:17> */
/* Local-Format Address Word */
/* A Local Address is in the same section as this Address Word */
for (;;) {
unsigned int I = BIT36(MB, 13); /* I := MB_<13> */
{
uint32_t Y = BITS36(MB, 18, 35); /* Y_<18:35> := MB_<18:35> */
unsigned int X = BITS36(MB, 14, 17); /* X := MB_<14:17> */
/* Indexed Address? Test X field. */
if (X == 0) {
/* No Indexing */
E = BITS36(E, 6, 17) | Y; /* E_<18:35> := Y_<18:35> */
} else {
/* X field != 0 */
pdp10_uint36_t CX = cpu->AC[X];
/* Test Section Number in E_<6:17> */
if (BITS36(E, 6, 17) == 0) { /* Section 0 */
/* Local Index */
E = BITS36(E, 6, 17) | BITS36LOW18(CX + Y); /* E_<18:35> := C(X)_<18:35> + Y_<18:35> */
} else {
/* Section != 0 */
/* Test C(X). Global Index when (C(X)_<0> == 0) && (C(X)_<6:17> != 0) */
if (!(BIT36(CX, 0) == 0 && BITS36(CX, 6, 17) != 0)) {
/* Local Index */
E = BITS36(E, 6, 17) | BITS36LOW18(CX + Y); /* E_<18:35> := C(X)_<18:35> + Y_<18:35> */
} else {
/* Global Index */
Y = pdp10_sext_uint18(Y); /* Y_<6:17> := 07777 * Y_<18> */
E = BITS36((CX + Y), 6, 35); /* E_<6:35> := C(X)_<6:35> + Y_<6:35> */
}
}
}
}
for (;;) {
/* Indirect Addressing? Test I bit. */
if (I == 0) { /* Done! */
/* E is the Effective Address */
/* The "XCT Continues" loop is implemented by the caller. */
return E;
}
/* Fetch the Indirect Word: MB := C(E) */
/* FIXME: handle ACs? */
MB = pdp10_vmem_read(&cpu->vmem, E);
if (MB == (uint64_t)-1)
return MB; /* propagate page fault */
/* Non-Zero Section? Test E_<6:17> */
if (BITS36(E, 6, 17) == 0) {
/* Section 0 */
break;
} else {
/* Section != 0 */
/* Decode Indirect Word MB_<0:1> */
switch (BITS36(MB, 0, 1)) {
case 2:
/* Local Indirect */
break;
case 3:
/* Page Failure */
return (uint64_t)-1;
case 0:
case 1: {
/* Global Indirect Word */
uint32_t Y = BITS36(MB, 6, 35); /* Y := MB_<6:35> */
unsigned int X = BITS36(MB, 2, 5); /* X := MB_<2:5> */
I = BIT36(MB, 1); /* I := MB_<1> */
/* Indexed Address? Test X field. */
if (X == 0) {
E = Y; /* E_<6:35> := Y_<6:35> */
} else {
E = BITS36((cpu->AC[X] + Y), 6, 35); /* E_<6:35> := C(X)_6:35 + Y_<6:35> */
}
continue;
}
}
}
break;
}
}
}
static
int pdp10_section_zero_p(struct pdp10_cpu *cpu)
{
/* My interpretation is that the choice of EA procedure is only based on
* whether the CPU is extended or not, so an extended CPU should always
* use the extended EA procedure, regardless of which section PC is in.
*/
return 0;
}
uint64_t pdp10_ea(struct pdp10_cpu *cpu, uint64_t MB)
{
if (pdp10_section_zero_p(cpu))
return pdp10_section_zero_ea(cpu, MB);
else
return pdp10_extended_ea(cpu, MB);
}

View File

@@ -1,42 +0,0 @@
/*
* pdp10-ea.h -- PDP10 Effective-Address Calculation
* Copyright (C) 2018 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PDP10_EA_H
#define PDP10_EA_H
#include "pdp10-core.h"
/* This performs Effective Address Calculation, but not Instruction Fetch
* or looping on XCT instructions; the caller is assumed to handle that.
* Returns (uint64_t)-1 on failure (page fault), otherwise a pdp10_vaddr_t
* (30 bits) and a 1-bit local(0)/global(1) flag in the MSB (2^30).
*/
uint64_t pdp10_ea(struct pdp10_cpu *cpu, uint64_t MB);
static inline int pdp10_ea_is_page_fault(uint64_t ea)
{
return ea == (uint64_t)-1;
}
static inline int pdp10_ea_is_global(uint64_t ea)
{
return ea & (1UL << 30);
}
#endif /* PDP10_EA_H */

View File

@@ -1,76 +0,0 @@
/*
* pdp10-virt-mem.c -- virtual memory simulation for PDP10
* Copyright (C) 2018 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "pdp10-virt-mem.h"
int pdp10_vmem_init(struct pdp10_vmem *vmem)
{
memset(vmem, 0, sizeof *vmem);
return 0;
}
static inline pdp10_uint36_t pdp10_mword_read(uint64_t *mword)
{
return *mword;
}
static inline void pdp10_mword_write(uint64_t *mword, pdp10_uint36_t word)
{
/* TODO: assert high bits are clear */
*mword = word;
}
static inline uint64_t *deref(struct pdp10_vmem *vmem, uint32_t address)
{
struct pdp10_section *section;
struct pdp10_page *page;
section = vmem->section[address >> 18];
if (section) {
page = section->page[(address >> 9) & ((1 << 9) - 1)];
if (page)
return &page->mword[address & ((1 << 9) - 1)];
}
return NULL;
}
uint64_t pdp10_vmem_read(struct pdp10_vmem *vmem, uint32_t address)
{
uint64_t *mword;
mword = deref(vmem, address);
if (!mword)
return (uint64_t)-1;
return pdp10_mword_read(mword);
}
int pdp10_vmem_write(struct pdp10_vmem *vmem, uint32_t address, pdp10_uint36_t word)
{
uint64_t *mword;
mword = deref(vmem, address);
if (!mword)
return -1;
pdp10_mword_write(mword, word);
return 0;
}

View File

@@ -1,60 +0,0 @@
/*
* pdp10-virt-mem.h -- virtual memory simulation for PDP10
* Copyright (C) 2018 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PDP10_VIRT_MEM_H
#define PDP10_VIRT_MEM_H
#include <stdint.h>
#include "pdp10-stdint.h"
/*
* A fully-extended PDP10 has 30-bit addresses, divided into
* - 12 bit section number (4096 sections)
* - 9 bit page number (512 pages per section)
* - 9 bit page offset (512 36-bit words per page)
*
* Each 36-bit word is currently stored in the low 36 bits of an uint64_t.
*
* (Other options that pack the 36-bit words more tightly have drawbacks
* such as more complex address arithmetic, requiring multiple loads or stores
* per access, or requiring writes to perform read-modify-write operations.)
*/
struct pdp10_page {
uint64_t mword[512];
};
struct pdp10_section {
struct pdp10_page *page[512];
};
struct pdp10_vmem {
struct pdp10_section *section[4096];
};
/* Returns non-zero on failure, zero on success. */
int pdp10_vmem_init(struct pdp10_vmem *vmem);
/* Returns (uint64_t)-1 on failure (page fault), a pdp10_uint36_t word on success. */
uint64_t pdp10_vmem_read(struct pdp10_vmem *vmem, uint32_t address);
/* Returns non-zero on failure, zero on success. */
int pdp10_vmem_write(struct pdp10_vmem *vmem, uint32_t address, pdp10_uint36_t word);
#endif /* PDP10_VIRT_MEM_H */

View File

@@ -1,24 +0,0 @@
/*
* sim.c -- simulator for PDP10 Elf36 files
* Copyright (C) 2018 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
int main(void)
{
return 1;
}