1
0
mirror of https://github.com/aap/pdp6.git synced 2026-03-05 19:09:59 +00:00

emu: rewrote 551, still rough

This commit is contained in:
aap
2019-02-24 20:41:25 +01:00
parent 7935d618f0
commit 4909e1bfd9
13 changed files with 869 additions and 263 deletions

View File

@@ -14,3 +14,6 @@ pdp6: $(SRC) $(H)
test_dc: test_dc.c dc.c $(H)
$(CC) -o $@ $(CFLAGS) test_dc.c dc.c
test_dt: test_dt.c dc.c dt.c $(H)
$(CC) -o $@ $(CFLAGS) test_dt.c dc.c dt.c

View File

@@ -230,11 +230,8 @@ makeapr(int argc, char *argv[])
apr->dev.type = apr_ident;
apr->dev.name = "";
apr->dev.attach = nil;
apr->dev.ioconnect = nil;
apr->dev.examine = ex_apr;
apr->dev.deposit = dep_apr;
apr->dev.next = nil;
apr->iobus.dev[CPA] = (Busdev){ apr, wake_cpa, 0 };
apr->iobus.dev[PI] = (Busdev){ apr, wake_pi, 0 };

View File

@@ -260,6 +260,27 @@ c_attach(int argc, char *argv[])
dev->attach(dev, argv[2]);
}
static void
c_detach(int argc, char *argv[])
{
Device *dev;
if(argc < 2){
printf("Not enough arguments\n");
return;
}
dev = getdevice(argv[1]);
if(dev == nil){
printf("No device: %s\n", argv[1]);
return;
}
if(dev->detach == nil){
printf("No detach for device type %s\n", dev->type);
return;
}
dev->detach(dev);
}
/* ioconnect dev busdev */
static void
c_ioconnect(int argc, char *argv[])
@@ -615,6 +636,8 @@ struct {
"make a device: mkdev name type [args]" },
{ "attach", c_attach,
"attach a file to a devie: attach name filename" },
{ "detach", c_detach,
"detach a file from a devie: attach name" },
{ "connectio", c_ioconnect,
"connect device to IO bus: connectio devname procname" },
{ "connectmem", c_memconnect,

View File

@@ -244,7 +244,6 @@ makedc(int argc, char *argv[])
dc->dev.type = dc_ident;
dc->dev.name = "";
dc->dev.attach = nil;
dc->dev.ioconnect = dcioconnect;
return &dc->dev;

646
emu/dt.c
View File

@@ -10,11 +10,14 @@ char *dx_ident = DX_IDENT;
enum
{
DTSIZE = 922512
// DTSIZE = 922512
// 01102 blocks, 2700 word for start/end each + safe zone
DTSIZE = 987288 + 1000
};
/* Transport */
#if 0
static uchar
dxread(Dx555 *dx)
{
@@ -32,6 +35,25 @@ dxwrite(Dx555 *dx, uchar d)
else
*dx->cur = d;
}
#endif
static uchar
dxread_(Dx555 *dx)
{
if(dx->dt->ut_rev)
return *dx->cur ^ 017;
else
return *dx->cur;
}
static void
dxwrite_(Dx555 *dx, uchar d)
{
if(dx->dt->ut_rev)
*dx->cur = d ^ 017;
else
*dx->cur = d;
}
static void
dxmove(Dx555 *dx)
@@ -48,19 +70,31 @@ dxmove(Dx555 *dx)
}
}
static void
dxdetach(Device *dev)
{
Dx555 *dx;
dx = (Dx555*)dev;
if(dx->fd < 0)
return;
lseek(dx->fd, 0, SEEK_SET);
write(dx->fd, dx->start, dx->size);
close(dx->fd);
dx->fd = -1;
memset(dx->start, 0, dx->size);
}
static void
dxattach(Device *dev, const char *path)
{
Dx555 *dx;
int fd;
dx = (Dx555*)dev;
fd = dx->fd;
if(fd >= 0){
dx->fd = -1;
close(dx->fd);
}
memset(dx->start, 0, DTSIZE);
dxdetach(dev);
memset(dx->start, 0, dx->size);
// TODO: resize
dx->fd = open(path, O_RDWR | O_CREAT, 0666);
if(dx->fd < 0)
fprintf(stderr, "couldn't open file %s\n", path);
@@ -88,12 +122,14 @@ makedx(int argc, char *argv[])
dx->dev.type = dx_ident;
dx->dev.name = "";
dx->dev.attach = dxattach;
dx->dev.ioconnect = nil;
dx->dev.detach = dxdetach;
dx->start = malloc(DTSIZE);
dx->fd = -1;
dx->size = DTSIZE;
dx->start = malloc(dx->size);
dx->cur = dx->start;
dx->end = dx->start + DTSIZE;
memset(dx->start, 0, DTSIZE);
dx->end = dx->start + dx->size;
memset(dx->start, 0, dx->size);
return &dx->dev;
}
@@ -105,8 +141,10 @@ enum
TapeEndF = 022,
TapeEndR = 055,
/* block mark high half */
BlockSpace = 025,
/* block mark low half */
BlockEndF = 026,
BlockEndR = 045,
@@ -126,19 +164,17 @@ enum
#define DATA_SYNC (dt->tmk == (0600|DataSync))
#define END_ZONE (dt->tmk == (0600|TapeEndF))
#define BM_SPACE (dt->tmk == (0400|BlockSpace) ||\
dt->tmk == (0500|BlockSpace) ||\
dt->tmk == (0600|BlockSpace) ||\
dt->tmk == (0700|BlockSpace))
#define BM_SPACE ((dt->tmk&0477) == (0400|BlockSpace))
#define BM_END (dt->tmk == (0500|BlockEndF))
#define DATA_SYNC (dt->tmk == (0600|DataSync))
#define BM_SYNC (dt->tmk == (0700|BlockSync))
#define REV_BM (dt->tmk == (0500|BlockEndR))
#define FWD_DATA_END (dt->tmk == (0400|DataEndF) ||\
dt->tmk == (0700|DataEndF))
#define REV_DATA_END (dt->tmk == (0400|DataEndR) ||\
dt->tmk == (0600|DataEndR))
#define DATA (dt->tmk == (0400|Data))
#define STOP (dt->tdata == 0 || dt->tdata == 1)
#define SYNC (dt->tdata == 0200)
#define REV_CKS (dt->tdata == 0100)
@@ -146,6 +182,7 @@ enum
#define PRE_FINAL (dt->tdata == 004)
#define FWD_CKS (dt->tdata == 002)
#define UT_WRITE ((dt->ut_fcn & 04) == 04)
#define UT_READ ((dt->ut_fcn & 04) == 0)
#define UT_ALL ((dt->ut_fcn & 03) == 01)
@@ -154,26 +191,33 @@ enum
#define UT_DN (dt->ut_fcn == 0)
#define UT_WRTM (dt->ut_fcn == 04)
#define DC_SELECT1 (dt->dc->devp[dt->dc->device] == dt)
#define UTE_DC_DISCONNECT (!(DC_SELECT1 && !dt->dc->da_rq))
#define UT_WRITE_PREVENT (dt->seldx->wrlock)
#define UT_WRITE_PREVENT (UT_WRITE && dt->seldx->wrlock)
#define UT_WREN_DATA (UT_WRITE && dt->ut_wren && !UT_WRITE_PREVENT)
#define RW_ODD (!dt->tct && dt->rw_state == RW_ACTIVE)
#define UT_WREN_BTM (UT_WREN_DATA && dt->ut_btm_switch && UT_WRTM) // 3-14
#define RW_ODD (!dt->tct && dt->rw_state == RW_ACTIVE) // 3-6
#define RW_EVEN (dt->tct && dt->rw_state == RW_ACTIVE)
#define RW_BM_DONE (UT_BM && BM_END)
#define RW_DATA_CONT (DC_SELECT1 && !dt->dc->da_rq && UT_DATA && dt->rw_state == RW_ACTIVE)
#define RW_DATA_STOP (UTE_DC_DISCONNECT && UT_DATA && dt->rw_state == RW_ACTIVE)
#define RW_DATA_CONT (DC_SELECT1 && !dt->dc->da_rq && UT_DATA && prev.rw_state == RW_ACTIVE)
// TODO: what is RW_DATA_WR_CONT?
// TODO: this is really RW_DATA_WR_STOP
#define RW_DATA_STOP (UTE_DC_DISCONNECT && UT_DATA && prev.rw_state == RW_ACTIVE)
#define TBM0 (dt->tbm == 10)
#define TBM3 (dt->tbm == 1)
// all but block space
#define UTE_UNIT_OK (nunits == 1)
#define UTE_DC_DISCONNECT (!(DC_SELECT1 && !dt->dc->da_rq))
// all but block space and rev block mark
#define UTE_MK (DATA_SYNC || END_ZONE || BM_END ||\
DATA_SYNC || BM_SYNC || FWD_DATA_END || REV_DATA_END || DATA)
#define UTE_ERROR (dt->uteck && (dt->utek == 040) != UTE_MK)
// not sure if BM SYNC || DATA SYNC is correct
#define UTE_ACTIVE_ERROR (!UT_ALL && dt->rw_state == RW_ACTIVE && (BM_SYNC || DATA_SYNC))
BM_SYNC || FWD_DATA_END || REV_DATA_END || DATA)
#define UTE_ERROR (dt->uteck && (prev.utek == 040) != UTE_MK)
// TODO: not sure if BM SYNC || DATA SYNC is correct
#define UTE_ACTIVE_ERROR (!UT_ALL && prev.rw_state == RW_ACTIVE && (BM_SYNC || DATA_SYNC))
//#define debug(...) printf(__VA_ARGS__)
#define debug(...) 0
#define PRINT1 \
printf("%c%02o(%o,%02o,%d)", dt->rw_state == RW_ACTIVE ? '+' : dt->rw_state == RW_RQ ? '-' : ' ', \
@@ -194,21 +238,23 @@ enum
#define PRINT2 \
if(END_ZONE) \
printf("TapeEndF "); \
debug("%c%d %02o TapeEndF ", state, dt->tct, dt->lb); \
else if(BM_SPACE) \
printf("BlockSpace %o ", dt->tbm); \
debug("%c%d %02o BlockSpace %o ", state, dt->tct, dt->lb, dt->tbm); \
else if(BM_END) \
printf("BlockEndF "); \
debug("%c%d %02o BlockEndF %o ", state, dt->tct, dt->lb, dt->tbm); \
else if(REV_BM) \
debug("%c%d %02o BlockEndR %o ", state, dt->tct, dt->lb, dt->tbm); \
else if(DATA_SYNC) \
printf("DataSync "); \
debug("%c%d %02o DataSync %o ", state, dt->tct, dt->lb, dt->tdata); \
else if(BM_SYNC) \
printf("BlockSync "); \
debug("%c%d %02o BlockSync %o ", state, dt->tct, dt->lb, dt->tbm); \
else if(FWD_DATA_END) \
printf("DataEndF "); \
debug("%c%d %02o DataEndF %o ", state, dt->tct, dt->lb, dt->tdata); \
else if(REV_DATA_END) \
printf("DataEndR "); \
debug("%c%d %02o DataEndR %o ", state, dt->tct, dt->lb, dt->tdata); \
else if(DATA) \
printf("Data ");
debug("%c%d %02o Data %o ", state, dt->tct, dt->lb, dt->tdata);
static void
recalc_dt_req(Dt551 *dt)
@@ -225,14 +271,278 @@ recalc_dt_req(Dt551 *dt)
setreq(dt->bus, UTC, req);
}
#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)
word dtbuf;
char state = 'n';
#define REV (dt->ut_rev && !UT_BM)
static void
dt_tp0(Dt551 *dt)
{
dt->sense = dxread_(dt->seldx);
// 3-7
if(UT_WRITE && dt->rw_state == RW_ACTIVE)
dt->ut_wren = 1;
// 3-7
if(UT_WRITE){ // TODO
int c;
c = REV ? 7 : 0;
if(dt->tct)
dt->wb = dt->rwb&7 ^ c;
else
dt->wb = dt->rwb>>3&7 ^ c;
/* copy to mark track; 3-13/14 */
if(UT_WREN_BTM)
dt->wb |= dt->wb<<1 & 010;
else
dt->wb = dt->wb&7 | dt->sense&010;
if(UT_WRITE_PREVENT)
dt->ut_illegal_op = 1; // 3-16
if(UT_WREN_DATA){
dxwrite_(dt->seldx, dt->wb);
debug("writing %02o\n", dt->wb);
}
}
}
static void
dt_tp1(Dt551 *dt)
{
/* complement WB here, totally useless */
//dt->wb = ~dt->wb & 07;
/* advance mark track window */
if(!UT_WRTM)
dt->tmk = ((dt->tmk << 1) | LDB(3, 1, dt->sense)) & 0777 |
dt->tmk&0400;
/* Strobe sensors into RWB */
// 3-12
if(dt->rw_state == RW_ACTIVE && UT_READ){
int c = REV ? 7 : 0;
if(dt->tct)
dt->rwb |= (dt->sense^c)&07;
else
dt->rwb |= ((dt->sense^c)&07) << 3;
}
}
static void
dt_tp2(Dt551 *dt)
{
Dt551 prev;
int tbedge, tdedge;
prev = *dt;
if(END_ZONE){
dt->ut_go = 0;
dt->ut_tape_end_flag = 1;
/* TODO: is this right? */
dt->rw_state = RW_NULL;
}
/* Block mark timing.
* Shift down starting at block sync,
* shifts to 10 before rev block number,
* shifts to 01 before fwd block number. */
// 3-5
if(BM_SYNC)
dt->tbm |= 020;
if(BM_SYNC || BM_SPACE)
dt->tbm >>= 1;
tbedge = ~prev.tbm & dt->tbm;
/* Data timing.
* Shift down starting at data sync.
* shifts to 100 before reverse check sum,
* shifts to 001 after forward check sum */
// 3-8, 3-9
if(DATA_SYNC)
dt->tdata = 0400;
if(FWD_DATA_END || REV_DATA_END || DATA_SYNC)
dt->tdata >>= 1;
tdedge = ~prev.tdata & dt->tdata;
/* Send 6 bit byte to DC every two steps when reading */
if(UT_READ && RW_EVEN)
/* except checksums */
if((prev.tdata & 0102) == 0){
int rwb = dt->rwb;
if(REV)
rwb = rwb>>3 & 07 | rwb<<3 & 070;
dcgv(dt->dc, DEVNO, rwb, REV);
if(UTE_DC_DISCONNECT)
dt->ut_incomp_block = 1; // 3-17
}
/* Clear LB before reading the reverse checksum */
if(tdedge & 0100)
dt->lb = 0; // 3-9
/* Keep track of checksum */
if(dt->tct)
// Manual says XOR, but also talks of parity of zeros
// dt->lb ^= dt->rwb;
dt->lb ^= ~dt->rwb & 077;
if(prev.rw_state != RW_ACTIVE)
dt->tct = 0;
else
dt->tct ^= 1;
/* Ring count UTEK */
if(!BM_SPACE){
if(dt->utek == 1)
dt->utek = 0100;
dt->utek >>= 1;
}
/* Go into active state */
if(prev.rw_state == RW_RQ)
if(UT_BM && tbedge & 1 || // 3-6
UT_DATA && tdedge & 0100 || // 3-9
UT_ALL && tbedge & 010) // 3-11
dt->rw_state = RW_ACTIVE;
/* What to do after block */
if(tdedge & 1){
if(RW_DATA_CONT) // 3-10
dt->rw_state = RW_RQ;
if(RW_DATA_STOP) // 3-11
dt->ut_jb_done_flag = 1;
/* test checksum. NB: manual says should be 0
* TODO: not sure about ACTIVE */
if(prev.rw_state == RW_ACTIVE && dt->lb != 077)
debug("CHECKSUM ERR\n"),
dt->ut_info_error = 1; // 3-13
}
/* Job done after block mark */
if(prev.rw_state == RW_ACTIVE && RW_BM_DONE) // 3-8
dt->ut_jb_done_flag = 1;
/* Catch wrongly set active state; 3-16 */
if(UTE_ACTIVE_ERROR){
dt->ut_info_error = 1;
dt->rw_state = RW_NULL;
}
/* Catch invalid mark code */
if(UTE_ERROR)
debug("TRACK ERROR\n"),
dt->ut_info_error = 1; // 3-15
/* Stop activity once job gets done */
if(!prev.ut_jb_done_flag && dt->ut_jb_done_flag) // 3-8
dt->rw_state = RW_NULL;
}
static void
dt_tp3(Dt551 *dt)
{
// 3-6
if(RW_ODD)
dt->rwb = 0;
// 3-15
/* before fwd block mark */
if(dt->tbm & 1){
if(BM_SPACE)
dt->utek = 040; // UTE PRESET 100000
else
dt->uteck = 1;
}
if(BM_SYNC)
dt->uteck = 0;
}
static void
dt_tp4(Dt551 *dt)
{
/* stop writing WB here */
if(dt->rw_state != RW_ACTIVE)
dt->ut_wren = 0;
/* get 6 bit byte from DC every two steps when writing */
if(UT_WRITE && RW_ODD){
/* except checksums */
if((dt->tdata & 0102) == 0){
dt->rwb |= dctk(dt->dc, DEVNO, REV);
if(UTE_DC_DISCONNECT)
dt->ut_incomp_block = 1; // 3-17
}else
debug("Getting LB\n"),
dt->rwb |= dt->lb;
// 3-6
if(REV)
dt->rwb = dt->rwb>>3 & 07 | dt->rwb<<3 & 070;
}
}
/* count dialled transports and select last */
static int
selectdx(Dt551 *dt)
{
int i, n, nunits;
n = dt->ut_units == 0 ? 8 : dt->ut_units;
nunits = 0;
dt->seldx = nil;
if(dt->ut_units_select)
for(i = 0; i < 8; i++)
if(dt->dx[i] && dt->dx[i]->unit == n){
dt->seldx = dt->dx[i];
nunits++;
}
return nunits;
}
/* Read one line of bits and move the tape.
* This should occur once every 33.33μs */
static void
dtcycle(void *p)
{
Dt551 *dt;
dt = (Dt551*)p;
uchar l, wb;
int data1edge, data7edge;
int bm0edge, bm3edge;
if(dt->delay){
if(--dt->delay == 0){
// UT_START goes to 0 here
int nunits;
dt->time_flag = 1;
/* check for legal selection */
nunits = selectdx(dt);
// UTE_SW_ERROR; 3-16
if(!UTE_UNIT_OK ||
dt->ut_btm_switch != UT_WRTM)
debug("ILL op %d %d %d\n", nunits, dt->ut_btm_switch, UT_WRTM),
dt->ut_illegal_op = 1;
if(!UTE_UNIT_OK){
dt->ut_go = 0; // 3-3
return;
}
if(UT_WRTM) // 3-14
dt->rw_state = RW_ACTIVE;
else if(!UT_DN) // TODO: is this right?
dt->rw_state = RW_RQ;
}else
/* Don't move during delay.
* TODO: is this right? */
return;
}
// TODO: maybe do something else here?
if(dt->seldx == nil)
@@ -241,166 +551,33 @@ dtcycle(void *p)
if(!dt->ut_go)
return;
// sense; start writing
dt_tp0(dt);
if(dt->rw_state != RW_ACTIVE)
dt->tct = 0;
l = dxread(dt->seldx);
dtbuf = dtbuf<<3 & FW;
dtbuf |= dt->sense & 07;
/* TP0 */
// read strobe
dt_tp1(dt);
if(dt->rw_state == RW_ACTIVE)
dt->ut_wren = 1;
// interpret mark code
dt_tp2(dt);
if(UT_WRITE){
if(UT_WRITE_PREVENT)
dt->ut_illegal_op = 1;
if(dt->tct)
wb = l&010 | dt->rwb&07;
else
wb = l&010 | dt->rwb>>3 & 07;
}
if(UT_WREN_DATA)
dxwrite(dt->seldx, wb);
// clear rwb; mark track error sync
dt_tp3(dt);
/* TP1 */
// get next rwb from DC to write
dt_tp4(dt);
//**/ PRINT1
//**/ PRINT2
dt->tmk = ((dt->tmk << 1) | !!(l&010)) & 0377 |
dt->tmk&0400 | (dt->tmk<<1)&0400;
if(UT_READ){
if(dt->tct != dt->ut_rev)
dt->rwb |= l&07;
else
dt->rwb |= (l&07) << 3;
}
/* TP2 */
///**/ printf("%2o%c%c%c ", dt->utek, UTE_MK ? 'M' : ' ', UTE_ERROR ? 'E' : ' ', dt->uteck ? 'C' : ' ');
if(UTE_ERROR || UTE_ACTIVE_ERROR)
printf("UT INFO ERROR\n"),
dt->ut_info_error = 1;
if(!BM_SPACE){
if(dt->utek == 1)
dt->utek = 040;
else
dt->utek >>= 1;
}
if(dt->tct)
dt->lb ^= ~dt->rwb & 077;
//**/ if(dt->rw_state == RW_ACTIVE && dt->tct)
//**/ printf("(%02o, %02o) ", dt->rwb, dt->lb);
if(UT_READ && dt->rw_state == RW_ACTIVE && dt->tct){
// before tct complement
if(!(UT_DATA && dt->tdata & 0102)){
dcgv(dt->dc, DEVNO, dt->rwb, dt->ut_rev);
if(UTE_DC_DISCONNECT)
dt->ut_incomp_block = 1;
}
}
if(END_ZONE){
dt->ut_tape_end_flag = 1;
dt->ut_go = 0;
}
bm0edge = 0;
bm3edge = 0;
if(BM_SYNC)
dt->tbm |= 020; // shifted to 010 (TBM0) now
if(BM_SPACE || BM_SYNC){
dt->tbm >>= 1;
if(TBM0)
bm0edge = 1;
else if(TBM3)
bm3edge = 1;
}
data1edge = 0; // goes up before rev checksum is expected
data7edge = 0; // goes up when checksum is seen
if(DATA_SYNC)
dt->tdata |= 0400; // shifted to 0200 now
if(FWD_DATA_END || REV_DATA_END || DATA_SYNC){
dt->tdata >>= 1;
if(dt->tdata == 0100)
data1edge = 1;
else if(dt->tdata == 1)
data7edge = 1;
}
if(data1edge)
dt->lb = 0;
// TODO: not sure about rw_active
if(data7edge && dt->rw_state == RW_ACTIVE)
if(dt->lb != 077)
printf("UT INFO ERROR\n"),
dt->ut_info_error = 1;
// before active is set below
if(dt->rw_state == RW_ACTIVE)
dt->tct = !dt->tct;
// manual mentions tdata6(0) going to 0???
if(dt->rw_state == RW_ACTIVE){
if(data7edge && RW_DATA_STOP ||
RW_BM_DONE){
printf("FINISHING JOB\n");
dt->ut_jb_done_flag = 1;
dt->rw_state = RW_NULL;
}
if(UTE_ACTIVE_ERROR)
dt->rw_state = RW_NULL;
if(data7edge && RW_DATA_CONT)
dt->rw_state = RW_RQ;
}else if(dt->rw_state == RW_RQ){
if(UT_BM && bm3edge ||
UT_DATA && data1edge ||
UT_ALL && bm0edge)
dt->rw_state = RW_ACTIVE;
}
/* TP3 */
if(RW_ODD)
dt->rwb = 0;
if(TBM3 && BM_SPACE)
dt->utek = 040;
if(BM_SYNC)
dt->uteck = 0;
if(TBM3 && !BM_SPACE)
dt->uteck = 1;
/* TP4 */
if(UT_WRITE && RW_ODD){
/* Take checksum data from LB */
if(UT_DATA && dt->tdata & 0102)
dt->rwb = dt->lb;
else{
dt->rwb |= dctk(dt->dc, DEVNO, dt->ut_rev);
if(UTE_DC_DISCONNECT)
dt->ut_incomp_block = 1;
}
if(dt->ut_rev)
dt->rwb = dt->rwb>>3 & 07 | dt->rwb<<3 & 070;
}
if(dt->rw_state == RW_ACTIVE)
dt->ut_wren = 0;
//**/ printf("\n");
state = dt->rw_state == RW_NULL ? 'n' :
dt->rw_state == RW_RQ ? 'r' :
dt->rw_state == RW_ACTIVE ? 'a' : 'x';
PRINT2
else
debug("%c%d -- ", state, dt->tct);
debug(" %012lo %02o %d.%02o\n", dtbuf, dt->rwb, dt->uteck, dt->utek);
dxmove(dt->seldx);
recalc_dt_req(dt);
}
static void
@@ -444,7 +621,7 @@ wake_dt(void *dev)
if(bus->devcode == UTS){
if(IOB_STATUS){
//printf("UTS STATUS\n");
// we have no delays (yet?) F25
if(dt->delay) bus->c12 |= F25;
if(dt->rw_state == RW_RQ) bus->c12 |= F26;
if(dt->rw_state == RW_ACTIVE) bus->c12 |= F27;
if(dt->rw_state == RW_NULL) bus->c12 |= F28;
@@ -459,7 +636,7 @@ wake_dt(void *dev)
}
if(bus->devcode == UTC){
if(IOB_STATUS){
//printf("UTC STATUS\n");
printf("UTC STATUS\n");
if(dt->ut_units_select) bus->c12 |= F19;
if(dt->ut_tape_end_enable) bus->c12 |= F20;
if(dt->ut_jb_done_enable) bus->c12 |= F21;
@@ -481,12 +658,11 @@ wake_dt(void *dev)
dt->ut_tape_end_flag = 0;
dt->ut_jb_done_flag = 0;
// 3-5
dt->rw_state = RW_NULL;
}
if(IOB_CONO_SET){
//printf("UTC CONO SET\n");
int i, n, nunits;
dt->ut_pia = bus->c12 & 07;
dt->ut_units = bus->c12>>3 & 07;
dt->ut_fcn = bus->c12>>6 & 07;
@@ -498,42 +674,37 @@ wake_dt(void *dev)
dt->ut_tape_end_enable = bus->c12>>15 & 1;
dt->ut_units_select = bus->c12>>16 & 1;
// UT CONO SET LONG
// UT CONO SET LONG, 1ms after UT CONO SET
// triggers UT START level until end of delay
// find selected transport unit
n = dt->ut_units == 0 ? 8 : dt->ut_units;
dt->seldx = nil;
nunits = 0;
if(dt->ut_units_select)
for(i = 0; i < 8; i++)
if(dt->dx[i] && dt->dx[i]->unit == n){
dt->seldx = dt->dx[i];
nunits++;
}
/* update selection, also done after delay */
selectdx(dt);
dt->delay = 0;
if(dt->ut_time){
// wait delay
dt->time_flag = 1;
dt->uteck = 0;
if(nunits != 1){
dt->ut_go = 0;
dt->ut_illegal_op = 1;
goto ret;
switch(dt->ut_time){
case 1: // 20ms
dt->delay = 600;
break;
case 2: // 160ms
dt->delay = 4800;
break;
case 3: // 300ms
dt->delay = 9000;
break;
}
if(dt->ut_btm_switch != UT_WRTM)
dt->ut_illegal_op = 1;
}
// T CLEAR; 3-4
dt->tmk = 0;
dt->uteck = 0; // 3-15
if(!UT_DN){
if(UT_WRTM)
dt->rw_state = RW_ACTIVE;
else
dt->time_flag = 0;
// now wait
}else
if(!UT_DN && // TODO: is this right?
!UT_WRTM) // 3-14
dt->rw_state = RW_RQ;
}
}
}
ret:
recalc_dt_req(dt);
}
@@ -555,6 +726,27 @@ dtconn(Dc136 *dc, Dt551 *dt)
dc->devp[DEVNO] = dt;
}
int
dtdep(Device *dev, const char *reg, word data)
{
Dt551 *dt;
dt = (Dt551*)dev;
if(strcmp(reg, "btm_wr") == 0) dt->ut_btm_switch = data&1;
else return 1;
return 0;
}
word
dtex(Device *dev, const char *reg)
{
Dt551 *dt;
dt = (Dt551*)dev;
if(strcmp(reg, "btm_wr") == 0) return dt->ut_btm_switch;
return ~0;
}
Device*
makedt(int argc, char *argv[])
{
@@ -566,11 +758,13 @@ makedt(int argc, char *argv[])
dt->dev.type = dt_ident;
dt->dev.name = "";
dt->dev.attach = nil;
dt->dev.ioconnect = dtioconnect;
dt->dev.deposit = dtdep;
dt->dev.examine = dtex;
// should have 30000 cycles per second
th = (Thread){ nil, dtcycle, dt, 1000, 0 };
// should have 30000 cycles per second, so one every 33μs
// APR at 1 has an approximate cycle time of 200-300ns
th = (Thread){ nil, dtcycle, dt, 150, 0 };
addthread(th);
return &dt->dev;

View File

@@ -12,10 +12,11 @@ mkdev cmem1 cmem161C mem_1
mkdev cmem2 cmem161C mem_2
mkdev cmem3 cmem161C mem_3
#mkdev netmem netmem its.pdp10.se 10006
mkdev netmem netmem localhost 10006
#mkdev netmem netmem localhost 10006
mkdev netmem netmem maya 10006
connectdev dc dt0
connectdev dt0 dx0 8
connectdev dt0 dx0 1
connectio tty apr
connectio ptr apr
connectio ptp apr
@@ -34,4 +35,3 @@ attach ptr ../code/test.rim
attach ptp ../code/ptp.out
#attach dx0 ../test/out.dt6
attach dx0 ../test/test.dt6

View File

@@ -621,7 +621,26 @@ dofile(const char *path)
void
quit(int code)
{
//SDL_Quit();
int i;
Device *dev;
Membus *mbus;
/* Detach all files */
for(dev = devlist; dev; dev = dev->next)
if(dev->detach)
dev->detach(dev);
/* Sync memory to disk */
for(dev = devlist; dev; dev = dev->next){
if(strcmp(dev->type, apr_ident) != 0)
continue;
mbus = &((Apr*)dev)->membus;
for(i = 0; i < 16; i++)
if(mbus->cmem[i] && mbus->cmem[i]->sync)
mbus->cmem[i]->sync(mbus->cmem[i]);
}
putchar('\n');
exit(code);
}

View File

@@ -33,6 +33,36 @@ readmem(const char *file, word *mem, word size)
fclose(f);
}
void
writemem(const char *file, word *mem, word size)
{
FILE *f;
hword i, a;
if(f = fopen(file, "w"), f == nil)
return;
a = 0;
for(i = 0; i < size; i++)
if(mem[i] != 0){
if(a != i){
a = i;
fprintf(f, "%06o:\n", a);
}
fprintf(f, "%012lo\n", mem[a++]);
}
fclose(f);
}
static void
synccore(Mem *mem)
{
CMem *core;
core = mem->module;
writemem(core->filename, core->core, 040000);
}
/* Both functions below are very confusing. I'm sorry.
* The schematics cannot be converted to C in a straightfoward way
* but I tried my best. */
@@ -245,11 +275,9 @@ makecoremem(const char *file)
memset(core, 0, sizeof(CMem));
core->filename = strdup(file);
mem = malloc(sizeof(Mem));
memset(mem, 0, sizeof(Mem));
mem->dev.type = cmem_ident;
mem->dev.name = "";
mem->dev.attach = nil;
mem->dev.ioconnect = nil;
mem->dev.next = nil;
mem->module = core;
mem->bus[0] = &memterm;
@@ -258,6 +286,7 @@ makecoremem(const char *file)
mem->bus[3] = &memterm;
mem->wake = wakecore;
mem->poweron = powercore;
mem->sync = synccore;
return mem;
}
@@ -274,11 +303,9 @@ makefastmem(int p)
ff->fmc_p_sel = p;
mem = malloc(sizeof(Mem));
memset(mem, 0, sizeof(Mem));
mem->dev.type = fmem_ident;
mem->dev.name = "";
mem->dev.attach = nil;
mem->dev.ioconnect = nil;
mem->dev.next = nil;
mem->module = ff;
mem->bus[0] = &memterm;

View File

@@ -9,16 +9,14 @@
720200000000
254200000300
777600000277
0
0
0
0
0
000020:
710600000060
710740000010
254000000021
710440000026
710740000010
254000000024
0
000027:
254000000021
000200:
000000000567

View File

@@ -32,9 +32,10 @@ netmemcycle(void *dev)
}
len = buf[0]<<8 | buf[1];
if(len > 9){
fprintf(stderr, "netmem botch, closing\n");
fprintf(stderr, "netmem botch(%d), closing\n", len);
close(nm->fd);
nm->fd = -1;
return;
}
memset(buf, 0, sizeof(buf));
readn(nm->fd, buf, len);
@@ -96,9 +97,6 @@ makenetmem(int argc, char *argv[])
memset(nm, 0, sizeof(Netmem));
nm->dev.type = netmem_ident;
nm->dev.name = "";
nm->dev.attach = nil;
nm->dev.ioconnect = nil;
nm->dev.next = nil;
// TODO: don't hardcode;
apr = getdevice("apr");

View File

@@ -103,8 +103,10 @@ struct Device
char *name;
/* attach file to device */
void (*attach)(Device *dev, const char *path);
void (*detach)(Device *dev);
/* connect device to iobus */
void (*ioconnect)(Device *dev, IOBus *bus);
/* manipulate device registers */
word (*examine)(Device *dev, const char *reg);
int (*deposit)(Device *dev, const char *reg, word data);
};
@@ -146,10 +148,11 @@ enum {
struct Mem
{
Device dev;
void *module;
void *module; /* CMem, FMem */
Membus *bus[4];
int (*wake)(Mem *mem, Membus *bus);
void (*poweron)(Mem *mem);
void (*sync)(Mem *mem); /* sync file to disk */
};
struct Membus
@@ -554,6 +557,7 @@ struct Dx555
uchar *start;
uchar *cur;
uchar *end;
uint size;
};
#define DX_IDENT "dx555"
extern char *dx_ident;
@@ -598,17 +602,21 @@ struct Dt551
int ut_info_error;
int ut_incomp_block;
int tmk; /* 9 bits */
int rwb; /* 6 bits */
int lb; /* 6 bits */
int tbm; /* 4 bits */
int tdata; /* 8 bits */
int tct; /* 1 bit */
int tmk; /* mark track window, 9b */
int rwb; /* read write buffer, 6b */
int lb; /* longitudinal buffer, computes check sum, 6b */
int tbm; /* block mark timing, 4b */
int tdata; /* data timing, 8b */
int tct; /* selects half of 6 bit rwb, 1b */
/* error check */
int utek; /* 6 bits */
int uteck;
int rw_state; /* null, rq, active */
int delay;
int sense;
int wb;
// int req;
};
@@ -616,11 +624,6 @@ struct Dt551
extern char *dt_ident;
Device *makedt(int argc, char *argv[]);
void dtconn(Dc136 *dc, Dt551 *dt);
/*
void dtcono(Dt551 *dt, word iob);
void dtcycle(Dt551 *dt);
*/
typedef struct Netmem Netmem;
struct Netmem

345
emu/test_dt.c Normal file
View File

@@ -0,0 +1,345 @@
#include "pdp6.h"
Dc136 *dc;
Dt551 *dt;
Dx555 *dx;
IOBus iobus;
IOBus *bus = &iobus;
int pireq;
Thread dtthread;
void
setreq(IOBus *bus, int dev, u8 pia)
{
if(dev == DC)
pireq = pia;
}
void
addthread(Thread th)
{
dtthread = th;
}
void
wakedev(IOBus *bus, int d)
{
Busdev *dev;
bus->devcode = d;
dev = &bus->dev[d];
if(dev->wake)
dev->wake(dev->dev);
}
void
bus_reset(IOBus *bus)
{
int d;
bus->c34 |= IOBUS_IOB_RESET;
for(d = 0; d < 128; d++)
wakedev(bus, d);
bus->c34 &= ~IOBUS_IOB_RESET;
}
void
cono(IOBus *bus, int d, hword w)
{
bus->c34 |= IOBUS_CONO_CLEAR;
wakedev(bus, d);
bus->c34 &= ~IOBUS_CONO_CLEAR;
bus->c34 |= IOBUS_CONO_SET;
bus->c12 = w;
wakedev(bus, d);
bus->c34 &= ~IOBUS_CONO_SET;
bus->c12 = 0;
}
void
datao(IOBus *bus, int d, word w)
{
bus->c34 |= IOBUS_DATAO_CLEAR;
wakedev(bus, d);
bus->c34 &= ~IOBUS_DATAO_CLEAR;
bus->c34 |= IOBUS_DATAO_SET;
bus->c12 = w;
wakedev(bus, d);
bus->c34 &= ~IOBUS_DATAO_SET;
bus->c12 = 0;
}
word
coni(IOBus *bus, int d)
{
word w;
bus->c34 |= IOBUS_IOB_STATUS;
wakedev(bus, d);
bus->c34 &= ~IOBUS_IOB_STATUS;
w = bus->c12;
bus->c12 = 0;
return w;
}
word
datai(IOBus *bus, int d)
{
word w;
bus->c34 |= IOBUS_IOB_DATAI;
wakedev(bus, d);
bus->c34 &= ~IOBUS_IOB_DATAI;
w = bus->c12;
bus->c12 = 0;
return w;
}
void
printdc(Dc136 *dc)
{
printf("DB/%012lo DA/%012lo CCT/%o SCT/%o CHMOD/%o\n",
dc->db, dc->da, dc->cct, dc->sct, dc->ch_mode);
printf(" CLBD/%o DBDAMOVE/%o DARQ/%o DBRQ/%o INOUT/%o DEV/%o PIA/%o\n",
dc->data_clbd, dc->dbda_move, dc->da_rq, dc->db_rq,
dc->inout, dc->device, dc->pia);
}
// DC controls
enum {
CLBD = 010000,
DBDAMOVE = 04000,
DARQ = 02000,
DBRQ = 01000,
IN = 0000,
OUT = 0400,
CHMOD_6 = 0000,
CHMOD_36 = 0100,
CHMOD_12 = 0200,
CHMOD_18 = 0300,
DEV1 = 010,
DEV2 = 020,
DEV3 = 030,
DEV4 = 040,
DEV5 = 050,
DEV6 = 060,
};
enum {
SEL = 0200000,
GO = 0020000,
FWD = 0000000,
REV = 0010000,
DLY0 = 0000000,
DLY1 = 0001000,
DLY2 = 0002000,
DLY3 = 0003000,
FN_DN = 0000000,
FN_RA = 0000100,
FN_RBN = 0000200,
FN_RD = 0000300,
FN_WTM = 0000400,
FN_WA = 0000500,
FN_WBN = 0000600,
FN_WD = 0000700
};
word writebuf[133*01102 + 6000];
word *bufp;
int bufsz;
void
fillbuf(int n)
{
bufp = writebuf;
bufsz = n;
while(n--)
bufp[n] = n | 0112200000000;
}
void
fillbuf_fmt(void)
{
int i, j;
bufp = writebuf;
for(i = 0; i < 6; i++)
*bufp++ = 0707707707707; // 55 55
for(i = 0; i < 01102; i++){
*bufp++ = 0070707070770; // 25 26
*bufp++ = 0077070007000; // 32 10
*bufp++ = 0007000007000; // 10 10
*bufp++ = 0007000777000; // 10 70
for(j = 0; j < 125; j++)
*bufp++ = 0777000777000; // 70 70
*bufp++ = 0777000777077; // 70 73
*bufp++ = 0777077777077; // 73 73
*bufp++ = 0777077707007; // 73 51
*bufp++ = 0700707070707; // 45 25
}
for(i = 0; i < 6; i++)
*bufp++ = 0070070070070; // 22 22
bufsz = bufp - writebuf;
bufp = writebuf;
}
void
fwdtest_w(void)
{
word w;
printf("forward test:\n\n");
dx->cur = dx->start;
fillbuf(128);
cono(bus, DC, DARQ|DBRQ|OUT|CHMOD_6|DEV1|7);
cono(bus, UTC, SEL|GO|FWD|DLY3|FN_WBN|DEV1|0);
while(dt->ut_go){
dtthread.f(dt);
if(pireq == 7){
if(bufsz > 0){
w = bufp[--bufsz];
datao(bus, DC, w);
printf("DC send: %012lo\n", w);
}
// break;
}
}
// printdc(dc);
}
void
revtest_w(void)
{
word w;
printf("reverse test:\n\n");
dx->cur = dx->end-1;
fillbuf(128);
cono(bus, DC, DARQ|DBRQ|OUT|CHMOD_6|DEV1|7);
cono(bus, UTC, SEL|GO|REV|DLY3|FN_WD|DEV1|0);
while(dt->ut_go){
dtthread.f(dt);
if(pireq == 7){
if(bufsz > 0){
w = bufp[--bufsz];
datao(bus, DC, w);
printf("DC send: %012lo\n", w);
}
// break;
}
}
// printdc(dc);
}
void
fwdtest_r(void)
{
word w;
printf("forward test:\n\n");
dx->cur = dx->start;
cono(bus, DC, DBDAMOVE|IN|CHMOD_6|DEV1|7);
cono(bus, UTC, SEL|GO|FWD|DLY3|FN_RD|DEV1|0);
while(dt->ut_go){
dtthread.f(dt);
if(pireq == 7){
w = datai(bus, DC);
printf("DC got: %012lo\n", w);
// break;
}
}
// printdc(dc);
}
void
revtest_r(void)
{
word w;
printf("reverse test:\n\n");
dx->cur = dx->end-1;
cono(bus, DC, DBDAMOVE|IN|CHMOD_6|DEV1|7);
cono(bus, UTC, SEL|GO|REV|DLY3|FN_RD|DEV1|0);
while(dt->ut_go){
dtthread.f(dt);
if(pireq == 7){
w = datai(bus, DC);
printf("DC got: %012lo\n", w);
// break;
}
}
// printdc(dc);
}
void
fmttest(void)
{
word w;
printf("format test:\n\n");
dx->cur = dx->start;
fillbuf_fmt();
cono(bus, DC, DARQ|DBRQ|OUT|CHMOD_6|DEV1|7);
cono(bus, UTC, SEL|GO|FWD|DLY3|FN_WTM|DEV1|0);
while(dt->ut_go){
dtthread.f(dt);
if(pireq == 7){
if(bufsz > 0){
--bufsz;
w = *bufp++;
datao(bus, DC, w);
// printf("DC send: %012lo\n", w);
}else
cono(bus, UTC, SEL|DLY2|DEV1|0);
// break;
}
}
// printdc(dc);
}
void
dxstore(Dx555 *dx, const char *file)
{
FILE *f;
f = fopen(file, "wb");
if(f == nil)
return;
fwrite(dx->start, 1, dx->size, f);
fclose(f);
}
int
main()
{
dc = (Dc136*)makedc(0, nil);
dc->dev.ioconnect((Device*)dc, bus);
dt = (Dt551*)makedt(0, nil);
dt->dev.ioconnect((Device*)dt, bus);
dtconn(dc, dt);
dx = (Dx555*)makedx(0, nil);
dxconn(dt, dx, 1);
dx->dev.attach((Device*)dx, "../test/out.dt6");
bus_reset(bus);
assert(coni(bus, DC) == 0);
printdc(dc);
// fmttest();
// fwdtest_r();
dxstore(dx, "foo.dt6");
return 0;
}

View File

@@ -44,7 +44,7 @@ readn(int fd, void *data, int n)
while(n > 0){
m = read(fd, data, n);
if(m == -1)
if(m <= 0)
return -1;
data += m;
n -= m;