1
0
mirror of https://github.com/aap/pdp6.git synced 2026-01-13 15:27:46 +00:00
aap.pdp6/tools/ld6.c
2016-12-11 17:23:06 +01:00

481 lines
7.3 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <assert.h>
#include "pdp6common.h"
#include "pdp6bin.h"
#include "args.h"
#define nil NULL
enum
{
MAXSYM = 1000
};
typedef struct Add Add;
struct Add
{
word name;
int l;
hword addr;
Add *next;
};
char *argv0;
FILE *in;
hword itemsz;
word mem[01000000];
hword rel, loc;
hword locmax, locmin;
hword start;
Add *addlist;
int error;
char **files;
int nfiles;
FILE*
mustopen(const char *name, const char *mode)
{
FILE *f;
if(f = fopen(name, mode), f == NULL){
fprintf(stderr, "couldn't open file: %s\n", name);
exit(1);
}
return f;
}
void
err(int n, char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "error: ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
error |= n;
}
/*
* debugging helpers
*/
void
printinst(hword p)
{
printf("%06o: %06o %06o %s\n", p, left(mem[p]), right(mem[p]), disasm(mem[p]));
}
void
disasmrange(hword start, hword end)
{
for(; start < end; start++)
printinst(start);
}
/* emulate PDP-6 IBP instruction */
word
ibp(word bp)
{
word pos, sz, p;
pos = (bp>>30)&077;
sz = (bp>>24)&077;
p = right(bp);
if(pos >= sz)
return point(pos-sz, sz, p);
return point(36-sz, sz, p+1);
}
/* emulate PDP-6 LDB instruction */
word
ldb(word bp)
{
word pos, sz, p;
pos = (bp>>30)&077;
sz = (bp>>24)&077;
p = right(bp);
return (mem[p]>>pos) & (1<<sz)-1;
}
/* print an ASCII string in memory */
void
printascii(hword loc)
{
word bp;
char c;
bp = point(36, 7, loc);
for(;;){
c = ldb(bp = ibp(bp));
if(c == 0)
break;
putchar(c);
}
putchar('\n');
}
word symtab[MAXSYM*2];
word symp;
/* Get symbol by name */
word*
findsym(word name)
{
word p;
word mask;
mask = 0037777777777;
for(p = 0; p < symp; p += 2)
if((symtab[p]&mask) == (name&mask))
return &symtab[p];
return NULL;
}
/* Extend a global request chain by writing hw at the end of
* the chain beginning at p */
void
extendreq(hword p, hword hw)
{
while(right(mem[p]))
p = right(mem[p]);
mem[p] = fw(left(mem[p]), hw);
}
/* Resolve a global request chain by writing hw to all locations */
void
resolvereq(hword p, hword hw)
{
hword next;
do{
next = right(mem[p]);
mem[p] = fw(left(mem[p]), hw);
p = next;
}while(next);
}
/* Perform additive external fixup */
void
fixadd(void)
{
Add *a;
word *s;
char name[8];
for(a = addlist; a; a = a->next){
s = findsym(a->name);
if(s == nil){
unrad50(a->name, name);
fprintf(stderr, "Need symbol %s\n", name);
continue;
}
if(a->l)
mem[a->addr] += fw(right(s[1]), 0);
else
mem[a->addr] += fw(0, right(s[1]));
}
}
/* Insert a symbol into the symbol table. Handle linking. */
void
loadsym(word *newsym)
{
word *sym;
int type, newtype;
char name[8];
newtype = (newsym[0]>>30)&074;
if(newtype == SymUndef && left(newsym[1]) & 0400000){
/* Additive fixup */
Add *a;
a = malloc(sizeof(Add));
a->name = newsym[0];
a->l = !!(left(newsym[1]) & 0200000);
a->addr = right(newsym[1]);
a->next = addlist;
addlist = a;
return;
}
sym = findsym(newsym[0]);
if(sym == NULL){
/* Symbol not in table yet.
* TODO: ignore locals? */
// if(newtype == SymGlobal || newtype == SymGlobalH ||
// newtype == SymUndef){
assert(symp < MAXSYM);
symtab[symp++] = newsym[0];
symtab[symp++] = newsym[1];
// }
return;
}
type = unrad50(sym[0], name);
if(type == SymUndef){
/* global request is in table */
if(newtype == SymGlobal || newtype == SymGlobalH){
/* found definition, resolve request chain
* and insert definition into table */
resolvereq(right(sym[1]), right(newsym[1]));
sym[0] = newsym[0];
sym[1] = newsym[1];
}else if(newtype == SymUndef)
/* extend request chain */
extendreq(right(sym[1]), right(newsym[1]));
}else if(type == SymGlobal || type == SymGlobalH){
/* global definition is in table */
if(newtype == SymGlobal || newtype == SymGlobalH){
if(newtype == type &&
newsym[1] == sym[1])
return;
err(1, "multiple definitions: %s", name);
}else if(newtype == SymUndef)
/* just resolve request */
resolvereq(right(newsym[1]), right(sym[1]));
}
}
/* print symbol table, not needed */
void
dumpsym(void)
{
int type;
char name[8];
word p;
for(p = 0; p < symp; p += 2){
type = unrad50(symtab[p], name);
printf(" %02o %s %012lo\n", type, name, symtab[p+1]);
}
}
/* Make sure there are no undefined symbols left */
void
checkundef(void)
{
int type;
char name[8];
word p;
for(p = 0; p < symp; p += 2){
type = unrad50(symtab[p], name);
if(type != SymUndef)
continue;
err(1, "undefined: %s %012lo", name, symtab[p+1]);
}
}
word block[18];
hword blocksz;
void
readblock(int doreloc)
{
word reloc;
hword i;
int bits;
blocksz = 0;
if(itemsz == 0)
return;
reloc = readw(in);
i = 18;
while(itemsz && i--){
block[blocksz++] = readw(in);
itemsz--;
}
/* relocate block */
for(i = 0; i < 18; i++){
bits = (reloc >> 34) & 03;
reloc <<= 2;
if(doreloc){
if(bits & 1)
block[i] += fw(0, rel);
if(bits & 2)
block[i] += fw(rel, 0);
}
}
}
void
skipitem(void)
{
while(itemsz)
readblock(0);
}
void
handlecode(void)
{
int i;
readblock(1);
loc = right(block[0]);
i = 1;
if(i < blocksz) // hacky
goto loop;
while(itemsz){
readblock(1);
for(i = 0; i < blocksz; i++){
loop:
mem[loc] = block[i];
if(loc < locmin) locmin = loc;
if(loc > locmax) locmax = loc;
loc++;
}
}
}
void
handlesym(void)
{
int i;
while(itemsz){
readblock(1);
i = 0;
while(i < blocksz){
loadsym(&block[i]);
i += 2;
}
}
}
void
handleend(void)
{
word abs;
char name[8];
readblock(1);
rel = block[0];
/* not sure what to do with this... */
abs = block[1];
while(itemsz)
readblock(0);
}
void
handlename(void)
{
word w;
int id;
char name[8];
readblock(0);
w = block[0];
while(itemsz)
readblock(0);
id = unrad50(w, name);
}
void
handlestart(void)
{
readblock(1);
start = right(block[0]);
while(itemsz)
readblock(1);
}
/* Saves in RIM format. Read with this:
* LOC 20
* CONO PTR,60
* A: CONSO PTR,10
* JRST .-1
* DATAI PTR,B
* CONSO PTR,10
* JRST .-1
* B: 0
* JRST A
*/
void
saverim(const char *filename)
{
FILE *out;
hword i;
out = mustopen(filename, "wb");
for(i = locmin; i <= locmax; i++){
writew(fw(0710440, i), out); /* DATAI PTR,i */
writew(mem[i], out);
}
writew(fw(0254200, start), out); /* HALT start */
writew(0, out);
fclose(out);
}
void
usage(void)
{
fprintf(stderr, "usage: %s\n", argv0);
exit(1);
}
int
main(int argc, char *argv[])
{
word w;
hword type;
int i;
char *outfile;
void (*typesw[8])(void) = {
skipitem,
handlecode,
handlesym,
skipitem,
skipitem,
handleend,
handlename,
handlestart,
};
outfile = "a.rim";
ARGBEGIN{
case 'r':
rel = strtol(EARGF(usage()), NULL, 8);
break;
case 'o':
outfile = EARGF(usage());
break;
default:
usage();
}ARGEND;
nfiles = argc;
files = argv;
locmax = 0;
locmin = 0777777;
for(i = 0; i < nfiles; i++){
in = mustopen(files[i], "rb");
while(w = readw(in), w != ~0){
type = left(w);
itemsz = right(w);
typesw[type]();
}
fclose(in);
}
fixadd();
// dumpsym();
checkundef();
if(error)
return 1;
printf("%06o %06o\n", locmin, locmax);
// disasmrange(findsym(rad50(0, "LINKSR"))[1],
// findsym(rad50(0, "LINEP"))[1]);
// disasmrange(0600+rel, 0603+rel);
// disasmrange(0200+rel, 0212+rel);
saverim(outfile);
return 0;
}