mirror of
https://github.com/mikpe/pdp10-tools.git
synced 2026-04-11 06:57:25 +00:00
remove obsolete C code
This commit is contained in:
94
8to9/8to9.c
94
8to9/8to9.c
@@ -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;
|
||||
}
|
||||
@@ -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.*
|
||||
4
Makefile
4
Makefile
@@ -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
12
TODO
@@ -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
|
||||
|
||||
32
ar/Makefile
32
ar/Makefile
@@ -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.*
|
||||
40
as/Makefile
40
as/Makefile
@@ -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.*
|
||||
106
as/assemble.c
106
as/assemble.c
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
167
as/hashtab.c
167
as/hashtab.c
@@ -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;
|
||||
}
|
||||
52
as/hashtab.h
52
as/hashtab.h
@@ -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 */
|
||||
279
as/input.c
279
as/input.c
@@ -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;
|
||||
}
|
||||
27
as/input.h
27
as/input.h
@@ -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 */
|
||||
72
as/main.c
72
as/main.c
@@ -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;
|
||||
}
|
||||
363
as/output.c
363
as/output.c
@@ -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(§ion_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, §ion_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, §ion_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, §ion_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(§ion0, "<fake section 0>");
|
||||
section0.sh_addralign = 0;
|
||||
if (output_section_header(&context, §ion0) < 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, §ion_symtab) < 0)
|
||||
return -1;
|
||||
}
|
||||
if (output_section_header(&context, &context.shstrtab.section) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
pdp10_fclose(context.pdp10fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
27
as/output.h
27
as/output.h
@@ -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 */
|
||||
467
as/parse.c
467
as/parse.c
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
28
as/parse.h
28
as/parse.h
@@ -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
435
as/scan.c
@@ -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;
|
||||
}
|
||||
}
|
||||
35
as/scan.h
35
as/scan.h
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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; }
|
||||
@@ -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
|
||||
58
as/token.c
58
as/token.c
@@ -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;
|
||||
}
|
||||
}
|
||||
103
as/token.def
103
as/token.def
@@ -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
|
||||
56
as/token.h
56
as/token.h
@@ -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 */
|
||||
302
as/tunit.c
302
as/tunit.c
@@ -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 = §ion->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, §ion->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)
|
||||
{
|
||||
}
|
||||
152
as/tunit.h
152
as/tunit.h
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
33
lib/Makefile
33
lib/Makefile
@@ -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.*
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
32
nm/Makefile
32
nm/Makefile
@@ -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
804
nm/nm.c
@@ -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 = ¶ms->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, ¶ms->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, ¶ms->shstrtab, ¶ms->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, ¶ms->strtab, ¶ms->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, ¶ms->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 = ¶ms->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 = ¶ms->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 = ¶ms->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, ¶ms->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(¶ms);
|
||||
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(¶ms, &argv[optind], argc - optind) < 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
32
od/Makefile
32
od/Makefile
@@ -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
569
od/od.c
@@ -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);
|
||||
}
|
||||
@@ -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.*
|
||||
@@ -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;
|
||||
}
|
||||
1029
readelf/readelf.c
1029
readelf/readelf.c
File diff suppressed because it is too large
Load Diff
32
sim/Makefile
32
sim/Makefile
@@ -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.*
|
||||
113
sim/pdp10-core.h
113
sim/pdp10-core.h
@@ -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 */
|
||||
173
sim/pdp10-ea.c
173
sim/pdp10-ea.c
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
24
sim/sim.c
24
sim/sim.c
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user