1
0
mirror of https://github.com/aap/pdp6.git synced 2026-01-11 23:53:31 +00:00
2024-04-19 11:06:17 +02:00

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);
}