mirror of
https://github.com/aap/pdp6.git
synced 2026-01-13 15:27:46 +00:00
428 lines
7.7 KiB
C
428 lines
7.7 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
|
|
#define nil NULL
|
|
typedef unsigned char uchar;
|
|
typedef unsigned int uint;
|
|
typedef uint64_t word;
|
|
|
|
enum
|
|
{
|
|
TapeEndF = 022,
|
|
TapeEndR = 055,
|
|
|
|
BlockSpace = 025,
|
|
|
|
BlockEndF = 026,
|
|
BlockEndR = 045,
|
|
|
|
DataSync = 032, /* rev guard */
|
|
BlockSync = 051, /* guard */
|
|
|
|
DataEndF = 073, /* pre-final, final, ck, rev lock */
|
|
DataEndR = 010, /* lock, rev ck, rev final, rev pre-final */
|
|
|
|
Data = 070,
|
|
|
|
NUMBLOCKS = 01102,
|
|
|
|
// DTSIZE = 922512
|
|
// 01102 blocks, 2700 word for start/end each + safe zone
|
|
DTSIZE = 987288 + 1000
|
|
};
|
|
|
|
FILE*
|
|
mustopen(const char *name, const char *mode)
|
|
{
|
|
FILE *f;
|
|
if(f = fopen(name, mode), f == nil){
|
|
fprintf(stderr, "couldn't open file: %s\n", name);
|
|
exit(1);
|
|
}
|
|
return f;
|
|
}
|
|
|
|
/* Read raw tape data (forward) */
|
|
void
|
|
readf(uchar **dtp, uchar *mark, word *wrd)
|
|
{
|
|
int i;
|
|
uchar l;
|
|
uchar m;
|
|
word w;
|
|
|
|
m = 0;
|
|
w = 0;
|
|
for(i = 0; i < 6; i++){
|
|
l = *(*dtp)++;
|
|
m = (m << 1) | !!(l&010);
|
|
w = (w << 3) | l&7;
|
|
}
|
|
*mark = m;
|
|
*wrd = w;
|
|
}
|
|
|
|
/* Write raw tape data (forwad */
|
|
void
|
|
writef(uchar **p, int mark, int *ck, int data)
|
|
{
|
|
int i;
|
|
uchar d;
|
|
if(ck){
|
|
*ck ^= ~data & 077;
|
|
*ck ^= ~data>>6 & 077;
|
|
*ck ^= ~data>>12 & 077;
|
|
}
|
|
for(i = 0; i < 6; i++){
|
|
if(mark)
|
|
d = !!(mark & 040) << 3;
|
|
else
|
|
d = !!(**p & 010) << 3;
|
|
if(data & 01000000)
|
|
d |= **p & 07;
|
|
else{
|
|
d |= (data & 0700000) >> 15;
|
|
data = (data << 3) & 0777777;
|
|
}
|
|
mark <<= 1;
|
|
**p = d;
|
|
(*p)++;
|
|
}
|
|
}
|
|
|
|
#define LDB(p, s, w) ((w)>>(p) & (1<<(s))-1)
|
|
#define XLDB(ppss, w) LDB((ppss)>>6 & 077, (ppss)&077, w)
|
|
#define MASK(p, s) ((1<<(s))-1 << (p))
|
|
#define DPB(b, p, s, w) ((w)&~MASK(p,s) | (b)<<(p) & MASK(p,s))
|
|
#define XDPB(b, ppss, w) DPB(b, (ppss)>>6 & 077, (ppss)&077, w)
|
|
|
|
void
|
|
writesimh(FILE *f, word w)
|
|
{
|
|
uchar c[8];
|
|
uint l, r;
|
|
|
|
r = LDB(0, 18, w);
|
|
l = LDB(18, 18, w);
|
|
c[0] = LDB(0, 8, l);
|
|
c[1] = LDB(8, 8, l);
|
|
c[2] = LDB(16, 8, l);
|
|
c[3] = LDB(24, 8, l);
|
|
c[4] = LDB(0, 8, r);
|
|
c[5] = LDB(8, 8, r);
|
|
c[6] = LDB(16, 8, r);
|
|
c[7] = LDB(24, 8, r);
|
|
fwrite(c, 1, 8, f);
|
|
}
|
|
|
|
word
|
|
readsimh(FILE *f)
|
|
{
|
|
uchar c[8];
|
|
word w[2];
|
|
if(fread(c, 1, 8, f) != 8)
|
|
return ~0;
|
|
w[0] = c[3]<<24 | c[2]<<16 | c[1]<<8 | c[0];
|
|
w[1] = c[7]<<24 | c[6]<<16 | c[5]<<8 | c[4];
|
|
return (w[0]<<18 | w[1]) & 0777777777777;
|
|
}
|
|
|
|
char*
|
|
tostr(int m)
|
|
{
|
|
return m == TapeEndF ? "End Zone Fwd" :
|
|
m == TapeEndR ? "End Zone Rev" :
|
|
m == BlockSpace ? "Block Space" :
|
|
m == BlockEndF ? "Block End Fwd" :
|
|
m == BlockEndR ? "Block End Rev" :
|
|
m == DataSync ? "Data Sync" :
|
|
m == BlockSync ? "Block Sync" :
|
|
m == DataEndF ? "Data End Fwd" :
|
|
m == DataEndR ? "Data End Rev" :
|
|
m == Data ? "Data" :
|
|
"Unknown";
|
|
}
|
|
|
|
void
|
|
rawdump(uchar *dtp)
|
|
{
|
|
uchar mark;
|
|
word w;
|
|
uchar *end;
|
|
end = dtp + DTSIZE;
|
|
while(dtp < end){
|
|
readf(&dtp, &mark, &w);
|
|
printf("%02o[%-13s] %06o\n", mark, tostr(mark), w);
|
|
}
|
|
}
|
|
|
|
#define CHKWORD(exp) \
|
|
readf(&dtp, &mark, &w); \
|
|
if(mark != exp){ \
|
|
fprintf(stderr, "expected %s(%02o) got %s(%02o)\n", \
|
|
tostr(exp), exp, tostr(mark), mark); \
|
|
return 0; \
|
|
} \
|
|
|
|
int
|
|
validate(uchar *dtp)
|
|
{
|
|
uchar mark;
|
|
word w;
|
|
int i, j;
|
|
|
|
CHKWORD(TapeEndR);
|
|
CHKWORD(TapeEndR);
|
|
for(i = 0; i < NUMBLOCKS; i++){
|
|
CHKWORD(BlockSpace);
|
|
CHKWORD(BlockEndF);
|
|
CHKWORD(DataSync);
|
|
CHKWORD(DataEndR);
|
|
CHKWORD(DataEndR);
|
|
CHKWORD(DataEndR);
|
|
CHKWORD(DataEndR);
|
|
for(j = 1; j < 127; j++){
|
|
CHKWORD(Data);
|
|
CHKWORD(Data);
|
|
}
|
|
CHKWORD(DataEndF);
|
|
CHKWORD(DataEndF);
|
|
CHKWORD(DataEndF);
|
|
CHKWORD(DataEndF);
|
|
CHKWORD(BlockSync);
|
|
CHKWORD(BlockEndR);
|
|
CHKWORD(BlockSpace);
|
|
}
|
|
CHKWORD(TapeEndF);
|
|
CHKWORD(TapeEndF);
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
dumpdta(uchar *dtp, FILE *f)
|
|
{
|
|
uchar mark;
|
|
word w, w2;
|
|
int i, j;
|
|
|
|
readf(&dtp, &mark, &w);
|
|
readf(&dtp, &mark, &w);
|
|
for(i = 0; i < NUMBLOCKS; i++){
|
|
readf(&dtp, &mark, &w);
|
|
readf(&dtp, &mark, &w2);
|
|
w = w << 18 | w2;
|
|
|
|
// data unused
|
|
readf(&dtp, &mark, &w);
|
|
readf(&dtp, &mark, &w2);
|
|
w = w << 18 | w2;
|
|
|
|
readf(&dtp, &mark, &w);
|
|
for(j = 0; j < 128; j++){
|
|
readf(&dtp, &mark, &w);
|
|
readf(&dtp, &mark, &w2);
|
|
writesimh(f, w<<18 | w2);
|
|
}
|
|
readf(&dtp, &mark, &w);
|
|
|
|
// data unused
|
|
readf(&dtp, &mark, &w);
|
|
readf(&dtp, &mark, &w2);
|
|
w = w << 18 | w2;
|
|
|
|
// reverse block mark
|
|
readf(&dtp, &mark, &w);
|
|
readf(&dtp, &mark, &w2);
|
|
w = w << 18 | w2;
|
|
}
|
|
readf(&dtp, &mark, &w);
|
|
readf(&dtp, &mark, &w);
|
|
}
|
|
|
|
void
|
|
wrf(FILE *f, int mark, int *ck, int data)
|
|
{
|
|
uchar buf[6], *p;
|
|
p = buf;
|
|
writef(&p, mark, ck, data);
|
|
fwrite(buf, 1, 6, f);
|
|
};
|
|
|
|
void
|
|
dumpdtr(word *wp, word *bmp, word *ibp, FILE *f)
|
|
{
|
|
word w;
|
|
int i, j;
|
|
int ck;
|
|
|
|
wrf(f, TapeEndR, nil, 0);
|
|
wrf(f, TapeEndR, nil, 0);
|
|
|
|
for(i = 0; i < NUMBLOCKS; i++){
|
|
w = *bmp++;
|
|
wrf(f, BlockSpace, nil, LDB(18, 18, w)); // block mark
|
|
wrf(f, BlockEndF, nil, LDB(0, 18, w)); // block mark
|
|
|
|
w = *ibp++;
|
|
wrf(f, DataSync, nil, LDB(18, 18, w));
|
|
wrf(f, DataEndR, nil, LDB(0, 18, w));
|
|
|
|
ck = 0;
|
|
wrf(f, DataEndR, &ck, 0007777); // rev check
|
|
|
|
/* the data */
|
|
w = *wp++;
|
|
wrf(f, DataEndR, &ck, LDB(18, 18, w));
|
|
wrf(f, DataEndR, &ck, LDB(0, 18, w));
|
|
for(j = 1; j < 127; j++){
|
|
w = *wp++;
|
|
wrf(f, Data, &ck, LDB(18, 18, w));
|
|
wrf(f, Data, &ck, LDB(0, 18, w));
|
|
}
|
|
w = *wp++;
|
|
wrf(f, DataEndF, &ck, LDB(18, 18, w));
|
|
wrf(f, DataEndF, &ck, LDB(0, 18, w));
|
|
|
|
wrf(f, DataEndF, nil, (ck & 077) << 12 | 07777); // check
|
|
|
|
w = *ibp++;
|
|
wrf(f, DataEndF, nil, LDB(18, 18, w));
|
|
wrf(f, BlockSync, nil, LDB(0, 18, w));
|
|
|
|
w = *bmp++;
|
|
wrf(f, BlockEndR, nil, LDB(18, 18, w)); // rev block mark
|
|
wrf(f, BlockSpace, nil, LDB(0, 18, w)); // rev block mark
|
|
}
|
|
|
|
wrf(f, TapeEndF, nil, 0);
|
|
wrf(f, TapeEndF, nil, 0);
|
|
}
|
|
|
|
uchar*
|
|
findstart(uchar *buf)
|
|
{
|
|
uchar *t;
|
|
int i;
|
|
word w;
|
|
uchar m;
|
|
|
|
for(i = 0; i < 1000; i++){
|
|
t = buf;
|
|
readf(&t, &m, &w);
|
|
if(m == TapeEndR)
|
|
goto found;
|
|
buf++;
|
|
}
|
|
return nil;
|
|
found:
|
|
while(readf(&buf, &m, &w), m == TapeEndR);
|
|
return buf-18;
|
|
}
|
|
|
|
uchar dtbuf[DTSIZE], *dtp;
|
|
word blockbuf[NUMBLOCKS*0200];
|
|
word bmbuf[NUMBLOCKS*2];
|
|
word ibbuf[NUMBLOCKS*2];
|
|
|
|
/* Fill block mark and interblock word buffers */
|
|
void
|
|
makefmt(void)
|
|
{
|
|
int i, j;
|
|
word co;
|
|
|
|
for(i = 0; i < NUMBLOCKS; i++){
|
|
/* forward and reverse block number */
|
|
bmbuf[i*2] = i;
|
|
// last one is 700707070707 really because it can't be written easily
|
|
co = 0;
|
|
for(j = 0; j < 12; j++)
|
|
co |= ((bmbuf[i*2]>>j*3) & 07) << (11-j)*3;
|
|
co ^= 0777777777777;
|
|
bmbuf[i*2+1] = co;
|
|
|
|
/* interblock words - used to find block 75 which contains the loader */
|
|
|
|
/* forward word */
|
|
if(i < 075)
|
|
ibbuf[i*2] = 0721200220107; // move forward
|
|
else if(i == 075)
|
|
ibbuf[i*2] = 0577777777777; // nop
|
|
else
|
|
ibbuf[i*2] = 0721200233107; // move backward
|
|
|
|
/* reverse word */
|
|
// last one is 777077707007 really because it can't be written easily
|
|
if(i < 073)
|
|
ibbuf[i*2+1] = 0721200223107; // move forward
|
|
else
|
|
ibbuf[i*2+1] = 0721200230107; // move backward
|
|
}
|
|
|
|
/* Last block isn't written quite correctly. To simulate: */
|
|
// ibbuf[01101*2 + 0] = 0077070007000;
|
|
// ibbuf[01101*2 + 1] = 0777077707007;
|
|
// bmbuf[01101*2 + 1] = 0700707070707;
|
|
}
|
|
|
|
int
|
|
readdtr(FILE *f)
|
|
{
|
|
fread(dtbuf, 1, DTSIZE, f);
|
|
fclose(f);
|
|
dtp = findstart(dtbuf);
|
|
if(dtp == nil){
|
|
fprintf(stderr, "no start\n");
|
|
return 1;
|
|
}
|
|
if(!validate(dtp)){
|
|
fprintf(stderr, "invalid file format\n");
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
readdta(FILE *f)
|
|
{
|
|
word w;
|
|
int n;
|
|
|
|
n = 0;
|
|
while(w = readsimh(f), w != ~0 && n < NUMBLOCKS*0200)
|
|
blockbuf[n++] = w;
|
|
return n != NUMBLOCKS*0200;
|
|
}
|
|
|
|
int
|
|
dtr2dta(void)
|
|
{
|
|
if(readdtr(stdin))
|
|
return 1;
|
|
dumpdta(dtp, stdout);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
dta2dtr(void)
|
|
{
|
|
if(readdta(stdin))
|
|
return 1;
|
|
makefmt();
|
|
dumpdtr(blockbuf, bmbuf, ibbuf, stdout);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
|
|
if(strstr(argv[0], "dtr2dta")) return dtr2dta();
|
|
else if(strstr(argv[0], "dta2dtr")) return dta2dtr();
|
|
else fprintf(stderr, "Unknown %s\n", argv[0]);
|
|
|
|
return 0;
|
|
}
|