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:
@@ -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
|
||||
|
||||
@@ -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 };
|
||||
|
||||
23
emu/cmd.c
23
emu/cmd.c
@@ -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,
|
||||
|
||||
1
emu/dc.c
1
emu/dc.c
@@ -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
646
emu/dt.c
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
21
emu/main.c
21
emu/main.c
@@ -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);
|
||||
}
|
||||
|
||||
39
emu/mem.c
39
emu/mem.c
@@ -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;
|
||||
|
||||
10
emu/mem_0
10
emu/mem_0
@@ -9,16 +9,14 @@
|
||||
720200000000
|
||||
254200000300
|
||||
777600000277
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
000020:
|
||||
710600000060
|
||||
710740000010
|
||||
254000000021
|
||||
710440000026
|
||||
710740000010
|
||||
254000000024
|
||||
0
|
||||
000027:
|
||||
254000000021
|
||||
000200:
|
||||
000000000567
|
||||
|
||||
@@ -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");
|
||||
|
||||
27
emu/pdp6.h
27
emu/pdp6.h
@@ -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
345
emu/test_dt.c
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user