mirror of
https://github.com/aap/pdp6.git
synced 2026-01-13 15:27:46 +00:00
336 lines
5.2 KiB
C
336 lines
5.2 KiB
C
#include "pdp6.h"
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
|
|
/* TODO:
|
|
* implement motor delays
|
|
* get rid of waitdatao and use a delay
|
|
*/
|
|
|
|
char *ptr_ident = PTR_IDENT;
|
|
char *ptp_ident = PTP_IDENT;
|
|
|
|
static void
|
|
recalc_ptp_req(Ptp *ptp)
|
|
{
|
|
setreq(ptp->bus, PTP, ptp->flag ? ptp->pia : 0);
|
|
}
|
|
|
|
static void
|
|
recalc_ptr_req(Ptr *ptr)
|
|
{
|
|
setreq(ptr->bus, PTR, ptr->flag ? ptr->pia : 0);
|
|
}
|
|
|
|
/* We have to punch after DATAO SET has happened. But BUSY is set by
|
|
* DATAO CLEAR. So we use waitdatao to record when SET has happened */
|
|
|
|
static void
|
|
ptpcycle(void *p)
|
|
{
|
|
Ptp *ptp;
|
|
uchar c;
|
|
|
|
ptp = p;
|
|
if(ptp->busy && ptp->waitdatao){
|
|
if(ptp->fd >= 0){
|
|
if(ptp->b)
|
|
c = (ptp->ptp & 077) | 0200;
|
|
else
|
|
c = ptp->ptp;
|
|
write(ptp->fd, &c, 1);
|
|
}
|
|
ptp->busy = 0;
|
|
ptp->flag = 1;
|
|
recalc_ptp_req(ptp);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
wake_ptp(void *dev)
|
|
{
|
|
Ptp *ptp;
|
|
IOBus *bus;
|
|
|
|
ptp = dev;
|
|
bus = ptp->bus;
|
|
if(IOB_RESET){
|
|
ptp->pia = 0;
|
|
ptp->busy = 0;
|
|
ptp->flag = 0;
|
|
ptp->b = 0;
|
|
}
|
|
if(bus->devcode == PTP){
|
|
if(IOB_STATUS){
|
|
if(ptp->b) bus->c12 |= F30;
|
|
if(ptp->busy) bus->c12 |= F31;
|
|
if(ptp->flag) bus->c12 |= F32;
|
|
bus->c12 |= ptp->pia & 7;
|
|
}
|
|
if(IOB_CONO_CLEAR){
|
|
ptp->pia = 0;
|
|
ptp->busy = 0;
|
|
ptp->flag = 0;
|
|
ptp->b = 0;
|
|
}
|
|
if(IOB_CONO_SET){
|
|
if(bus->c12 & F30) ptp->b = 1;
|
|
if(bus->c12 & F31) ptp->busy = 1;
|
|
if(bus->c12 & F32) ptp->flag = 1;
|
|
ptp->pia |= bus->c12 & 7;
|
|
}
|
|
if(IOB_DATAO_CLEAR){
|
|
ptp->ptp = 0;
|
|
ptp->busy = 1;
|
|
ptp->flag = 0;
|
|
ptp->waitdatao = 0;
|
|
}
|
|
if(IOB_DATAO_SET){
|
|
ptp->ptp = bus->c12 & 0377;
|
|
ptp->waitdatao = 1;
|
|
}
|
|
}
|
|
recalc_ptp_req(ptp);
|
|
}
|
|
|
|
static void
|
|
ptr_setbusy(Ptr *ptr, int busy)
|
|
{
|
|
if(ptr->busy == busy)
|
|
return;
|
|
ptr->busy = busy;
|
|
if(ptr->busy){
|
|
// PTR CLR
|
|
ptr->ptr = 0;
|
|
ptr->sr = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
ptr_ic_clr(Ptr *ptr)
|
|
{
|
|
ptr->pia = 0;
|
|
ptr_setbusy(ptr, 0);
|
|
ptr->flag = 0;
|
|
ptr->b = 0;
|
|
}
|
|
|
|
void
|
|
ptr_setmotor(Ptr *ptr, int m)
|
|
{
|
|
if(ptr->motor_on == m)
|
|
return;
|
|
ptr->motor_on = m;
|
|
if(ptr->motor_on)
|
|
ptr_setbusy(ptr, 0);
|
|
ptr->flag = 1;
|
|
recalc_ptr_req(ptr);
|
|
}
|
|
|
|
static void
|
|
ptrcycle(void *p)
|
|
{
|
|
Ptr *ptr;
|
|
uchar c;
|
|
|
|
ptr = p;
|
|
|
|
// TODO: reader feed key
|
|
if(!(ptr->motor_on && ptr->busy))
|
|
return;
|
|
|
|
/* PTR LEAD */
|
|
if(!hasinput(ptr->fd))
|
|
return; /* no feed so no pulses */
|
|
|
|
read(ptr->fd, &c, 1);
|
|
|
|
if(!ptr->busy)
|
|
return;
|
|
|
|
/* skip invalid chars */
|
|
if(ptr->b && (c & 0200) == 0)
|
|
return;
|
|
|
|
/* PTR STROBE */
|
|
ptr->sr <<= 1;
|
|
ptr->ptr <<= 6;
|
|
ptr->sr |= 1;
|
|
if(ptr->b)
|
|
ptr->ptr |= c & 077;
|
|
else
|
|
ptr->ptr |= c;
|
|
|
|
/* TRAIL */
|
|
assert(ptr->busy);
|
|
if(!ptr->b || ptr->sr & 040){
|
|
ptr->flag = 1;
|
|
ptr_setbusy(ptr, 0);
|
|
}
|
|
|
|
recalc_ptr_req(ptr);
|
|
}
|
|
|
|
static void
|
|
wake_ptr(void *dev)
|
|
{
|
|
Ptr *ptr;
|
|
IOBus *bus;
|
|
|
|
ptr = dev;
|
|
bus = ptr->bus;
|
|
if(IOB_RESET)
|
|
ptr_ic_clr(ptr);
|
|
|
|
if(bus->devcode == PTR){
|
|
if(IOB_STATUS){
|
|
//printf("PTR STATUS\n");
|
|
if(ptr->motor_on) bus->c12 |= F27;
|
|
if(ptr->b) bus->c12 |= F30;
|
|
if(ptr->busy) bus->c12 |= F31;
|
|
if(ptr->flag) bus->c12 |= F32;
|
|
bus->c12 |= ptr->pia & 7;
|
|
}
|
|
if(IOB_DATAI){
|
|
//printf("PTR DATAI\n");
|
|
bus->c12 |= ptr->ptr;
|
|
ptr->flag = 0;
|
|
// actually when DATAI is negated again
|
|
ptr_setbusy(ptr, 1);
|
|
}
|
|
if(IOB_CONO_CLEAR)
|
|
ptr_ic_clr(ptr);
|
|
if(IOB_CONO_SET){
|
|
//printf("PTR CONO %012lo\n", bus->c12);
|
|
/* TODO: schematics don't have this, but code uses it */
|
|
if(bus->c12 & F27) ptr_setmotor(ptr, 1);
|
|
if(bus->c12 & F30) ptr->b = 1;
|
|
if(bus->c12 & F31) ptr_setbusy(ptr, 1);
|
|
if(bus->c12 & F32) ptr->flag = 1;
|
|
ptr->pia |= bus->c12 & 7;
|
|
}
|
|
}
|
|
recalc_ptr_req(ptr);
|
|
}
|
|
|
|
static void
|
|
ptpunmount(Device *dev)
|
|
{
|
|
Ptp *ptp;
|
|
|
|
ptp = (Ptp*)dev;
|
|
if(ptp->fd >= 0){
|
|
close(ptp->fd);
|
|
ptp->fd = -1;
|
|
}
|
|
}
|
|
|
|
static void
|
|
ptpmount(Device *dev, const char *path)
|
|
{
|
|
Ptp *ptp;
|
|
|
|
ptp = (Ptp*)dev;
|
|
ptpunmount(dev);
|
|
ptp->fd = open(path, O_WRONLY | O_CREAT, 0666);
|
|
if(ptp->fd < 0)
|
|
fprintf(stderr, "couldn't open file %s\n", path);
|
|
}
|
|
|
|
static void
|
|
ptrunmount(Device *dev)
|
|
{
|
|
Ptr *ptr;
|
|
|
|
ptr = (Ptr*)dev;
|
|
if(ptr->fd >= 0){
|
|
close(ptr->fd);
|
|
ptr->fd = -1;
|
|
}
|
|
}
|
|
|
|
static void
|
|
ptrmount(Device *dev, const char *path)
|
|
{
|
|
Ptr *ptr;
|
|
|
|
ptr = (Ptr*)dev;
|
|
ptrunmount(dev);
|
|
ptr->fd = open(path, O_RDONLY);
|
|
if(ptr->fd < 0)
|
|
fprintf(stderr, "couldn't open file %s\n", path);
|
|
}
|
|
|
|
static void
|
|
ptrioconnect(Device *dev, IOBus *bus)
|
|
{
|
|
Ptr *ptr;
|
|
ptr = (Ptr*)dev;
|
|
ptr->bus = bus;
|
|
bus->dev[PTR] = (Busdev){ ptr, wake_ptr, 0 };
|
|
}
|
|
|
|
static void
|
|
ptpioconnect(Device *dev, IOBus *bus)
|
|
{
|
|
Ptp *ptp;
|
|
ptp = (Ptp*)dev;
|
|
ptp->bus = bus;
|
|
bus->dev[PTP] = (Busdev){ ptp, wake_ptp, 0 };
|
|
}
|
|
|
|
static Device ptpproto = {
|
|
nil, nil, "",
|
|
ptpmount, ptpunmount,
|
|
ptpioconnect,
|
|
nil, nil
|
|
};
|
|
|
|
static Device ptrproto = {
|
|
nil, nil, "",
|
|
ptrmount, ptrunmount,
|
|
ptrioconnect,
|
|
nil, nil
|
|
};
|
|
|
|
|
|
Device*
|
|
makeptp(int argc, char *argv[])
|
|
{
|
|
Ptp *ptp;
|
|
Task t;
|
|
|
|
ptp = malloc(sizeof(Ptp));
|
|
memset(ptp, 0, sizeof(Ptp));
|
|
|
|
ptp->dev = ptpproto;
|
|
ptp->dev.type = ptp_ident;
|
|
ptp->fd = -1;
|
|
|
|
// 63.3 chars per second, value around 60000?
|
|
t = (Task){ nil, ptpcycle, ptp, 1000, 0 };
|
|
addtask(t);
|
|
return &ptp->dev;
|
|
}
|
|
|
|
Device*
|
|
makeptr(int argc, char *argv[])
|
|
{
|
|
Ptr *ptr;
|
|
Task t;
|
|
|
|
ptr = malloc(sizeof(Ptr));
|
|
memset(ptr, 0, sizeof(Ptr));
|
|
|
|
ptr->dev = ptrproto;
|
|
ptr->dev.type = ptr_ident;
|
|
ptr->fd = -1;
|
|
|
|
// 400 chars per second, value around 10000?
|
|
t = (Task){ nil, ptrcycle, ptr, 1000, 0 };
|
|
addtask(t);
|
|
return &ptr->dev;
|
|
}
|