mirror of
https://github.com/aap/pdp6.git
synced 2026-01-11 23:53:31 +00:00
268 lines
4.9 KiB
C
268 lines
4.9 KiB
C
#include "common.h"
|
|
#include "pdp6.h"
|
|
|
|
#include <unistd.h>
|
|
|
|
#define IOB pdp->iob
|
|
#define PTP_DLY 15797788 // 63.3 chars per second
|
|
#define PTR_DLY 2500000 // 400 chars per second
|
|
|
|
|
|
|
|
/* PTP */
|
|
|
|
static void calc_ptp_req(PDP6 *pdp);
|
|
|
|
static void
|
|
handle_ptp(PDP6 *pdp, IOdev *dev, int cmd)
|
|
{
|
|
switch(cmd) {
|
|
case IOB_RESET:
|
|
case IOB_CONO_CLR:
|
|
pdp->ptp_b = 0;
|
|
pdp->ptp_busy = 0;
|
|
pdp->ptp_flag = 0;
|
|
pdp->ptp_pia = 0;
|
|
break;
|
|
|
|
case IOB_CONO_SET:
|
|
if(IOB & F30) pdp->ptp_b = 1;
|
|
if(IOB & F31) pdp->ptp_busy = 1;
|
|
if(IOB & F32) pdp->ptp_flag = 1;
|
|
pdp->ptp_pia |= IOB & 7;
|
|
break;
|
|
|
|
case IOB_STATUS:
|
|
if(pdp->ptp_b) IOB |= F30;
|
|
if(pdp->ptp_busy) IOB |= F31;
|
|
if(pdp->ptp_flag) IOB |= F32;
|
|
IOB |= pdp->ptp_pia;
|
|
return;
|
|
|
|
case IOB_DATAO_CLR:
|
|
pdp->ptp_busy = 1;
|
|
pdp->ptp_flag = 0;
|
|
pdp->ptp = 0;
|
|
return;
|
|
|
|
case IOB_DATAO_SET:
|
|
pdp->ptp |= IOB & 0377;
|
|
break;
|
|
}
|
|
calc_ptp_req(pdp);
|
|
}
|
|
|
|
static void
|
|
ptp_set_motor(PDP6 *pdp, int state)
|
|
{
|
|
if(pdp->ptp_motor_on == state)
|
|
return;
|
|
pdp->ptp_motor_on = state;
|
|
if(!pdp->ptp_motor_on)
|
|
pdp->ptp_motor_on_timer = NEVER;
|
|
else
|
|
pdp->ptp_punch_timer = simtime + PTP_DLY;
|
|
}
|
|
|
|
static void
|
|
cycle_ptp(PDP6 *pdp, IOdev *dev, int pwr)
|
|
{
|
|
u8 c;
|
|
bool go;
|
|
|
|
if(!pwr) {
|
|
pdp->ptp_motor_on = 0;
|
|
pdp->ptp_motor_on_timer = NEVER;
|
|
return;
|
|
}
|
|
|
|
go = pdp->ptp_busy || pdp->ptp_tape_feed;
|
|
if(go) {
|
|
pdp->ptp_motor_off_timer = simtime + 5000000000;
|
|
if(pdp->ptp_motor_on_timer == NEVER)
|
|
pdp->ptp_motor_on_timer = simtime + 1000000000;
|
|
}
|
|
|
|
if(!pdp->ptp_motor_on && pdp->ptp_motor_on_timer < simtime)
|
|
ptp_set_motor(pdp, 1);
|
|
if(pdp->ptp_motor_off_timer < simtime)
|
|
ptp_set_motor(pdp, 0);
|
|
|
|
if(!pdp->ptp_motor_on)
|
|
return;
|
|
if(pdp->ptp_punch_timer < simtime) {
|
|
// reluctance pickup
|
|
pdp->ptp_punch_timer = simtime + PTP_DLY;
|
|
if(pdp->ptp_busy) // PTP READY
|
|
c = (pdp->ptp_b ? pdp->ptp&077|0200 : pdp->ptp);
|
|
else if(pdp->ptp_tape_feed)
|
|
c = 0;
|
|
else
|
|
return;
|
|
|
|
if(pdp->ptp_fd >= 0)
|
|
if(write(pdp->ptp_fd, &c, 1) <= 0) {
|
|
close(pdp->ptp_fd);
|
|
pdp->ptp_fd = -1;
|
|
}
|
|
|
|
// PTP DONE
|
|
if(pdp->ptp_busy) {
|
|
pdp->ptp_busy = 0;
|
|
pdp->ptp_flag = 1;
|
|
calc_ptp_req(pdp);
|
|
}
|
|
}
|
|
}
|
|
|
|
static IOdev ptp_dev = { 0, 0100, handle_ptp, cycle_ptp };
|
|
|
|
static void
|
|
calc_ptp_req(PDP6 *pdp)
|
|
{
|
|
if(pdp->ptp_pia && pdp->ptp_flag)
|
|
setreq(pdp, &ptp_dev, 0200>>pdp->ptp_pia);
|
|
else
|
|
setreq(pdp, &ptp_dev, 0);
|
|
}
|
|
|
|
void
|
|
attach_ptp(PDP6 *pdp)
|
|
{
|
|
installdev(pdp, &ptp_dev);
|
|
}
|
|
|
|
/* PTR */
|
|
|
|
static void calc_ptr_req(PDP6 *pdp);
|
|
|
|
void
|
|
ptr_set_motor(PDP6 *pdp, int state)
|
|
{
|
|
if(pdp->ptr_motor_on == state)
|
|
return;
|
|
pdp->ptr_motor_on = state;
|
|
|
|
if(pdp->ptr_motor_on)
|
|
pdp->ptr_busy = 0;
|
|
pdp->ptr_flag = 1;
|
|
calc_ptr_req(pdp);
|
|
}
|
|
|
|
static void
|
|
ptr_set_busy(PDP6 *pdp)
|
|
{
|
|
if(!pdp->ptr_busy) {
|
|
// PTR CLR
|
|
pdp->ptr_sr = 0;
|
|
pdp->ptr = 0;
|
|
}
|
|
pdp->ptr_busy = 1;
|
|
}
|
|
|
|
static void
|
|
handle_ptr(PDP6 *pdp, IOdev *dev, int cmd)
|
|
{
|
|
switch(cmd) {
|
|
case IOB_RESET:
|
|
// hack for easier use. NB: this breaks diagnostics
|
|
ptr_set_motor(pdp, 1);
|
|
case IOB_CONO_CLR:
|
|
pdp->ptr_b = 0;
|
|
pdp->ptr_busy = 0;
|
|
pdp->ptr_flag = 0;
|
|
pdp->ptr_pia = 0;
|
|
break;
|
|
|
|
case IOB_CONO_SET:
|
|
if(IOB & F27) ptr_set_motor(pdp, 1); // not in schematics, can we turn it off too?
|
|
if(IOB & F30) pdp->ptr_b = 1;
|
|
if(IOB & F31) ptr_set_busy(pdp);
|
|
if(IOB & F32) pdp->ptr_flag = 1;
|
|
pdp->ptr_pia |= IOB & 7;
|
|
break;
|
|
|
|
case IOB_STATUS:
|
|
if(pdp->ptr_motor_on) IOB |= F27;
|
|
if(pdp->ptr_b) IOB |= F30;
|
|
if(pdp->ptr_busy) IOB |= F31;
|
|
if(pdp->ptr_flag) IOB |= F32;
|
|
IOB |= pdp->ptr_pia;
|
|
return;
|
|
|
|
case IOB_DATAI:
|
|
IOB |= pdp->ptr;
|
|
pdp->ptr_flag = 0;
|
|
// actually after DATAI negated
|
|
ptr_set_busy(pdp);
|
|
break;
|
|
}
|
|
calc_ptr_req(pdp);
|
|
}
|
|
|
|
static void
|
|
cycle_ptr(PDP6 *pdp, IOdev *dev, int pwr)
|
|
{
|
|
bool clutch;
|
|
u8 c;
|
|
|
|
if(!pwr) return;
|
|
|
|
if(pdp->sw_ptr_motor_on) ptr_set_motor(pdp, 1);
|
|
if(pdp->sw_ptr_motor_off) ptr_set_motor(pdp, 0);
|
|
|
|
clutch = pdp->ptr_motor_on && (pdp->ptr_busy | pdp->ptr_tape_feed);
|
|
if(clutch && !pdp->ptr_clutch) {
|
|
// start motion
|
|
pdp->ptr_timer = simtime + PTR_DLY;
|
|
}
|
|
pdp->ptr_clutch = clutch;
|
|
if(!pdp->ptr_clutch || pdp->ptr_fd.fd < 0 || pdp->ptr_timer >= simtime)
|
|
return;
|
|
pdp->ptr_timer = simtime + PTR_DLY;
|
|
|
|
if(!pdp->ptr_fd.ready)
|
|
return;
|
|
if(read(pdp->ptr_fd.fd, &c, 1) <= 0)
|
|
return;
|
|
waitfd(&pdp->ptr_fd);
|
|
if(pdp->ptr_busy && (c & 0200 || !pdp->ptr_b)) {
|
|
// PTR STROBE
|
|
// actually 400μs after feed hole edge
|
|
pdp->ptr_sr = (pdp->ptr_sr<<1) | 1;
|
|
pdp->ptr <<= 6;
|
|
if(pdp->ptr_b)
|
|
pdp->ptr |= c & 077;
|
|
else
|
|
pdp->ptr |= c;
|
|
|
|
// PTR TRAIL
|
|
// only if busy but that's guaranteed here
|
|
if(!pdp->ptr_b || pdp->ptr_sr & 040) {
|
|
pdp->ptr_busy = 0;
|
|
pdp->ptr_flag = 1;
|
|
calc_ptr_req(pdp);
|
|
}
|
|
}
|
|
}
|
|
|
|
static IOdev ptr_dev = { 0, 0104, nil, handle_ptr, cycle_ptr };
|
|
|
|
static void
|
|
calc_ptr_req(PDP6 *pdp)
|
|
{
|
|
if(pdp->ptr_pia && pdp->ptr_flag)
|
|
setreq(pdp, &ptr_dev, 0200>>pdp->ptr_pia);
|
|
else
|
|
setreq(pdp, &ptr_dev, 0);
|
|
}
|
|
|
|
void
|
|
attach_ptr(PDP6 *pdp)
|
|
{
|
|
pdp->ptr_fd.fd = -1;
|
|
pdp->ptr_fd.id = -1;
|
|
|
|
installdev(pdp, &ptr_dev);
|
|
}
|