/* ibm1130_ptrp.c: IBM 1130 paper tape reader/punch emulation | |
Based on the SIMH simulator package written by Robert M Supnik | |
Brian Knittel | |
Revision History | |
2004.10.22 - Written. | |
* (C) Copyright 2004, Brian Knittel. | |
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN | |
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the | |
* usual yada-yada. Please keep this notice and the copyright in any distributions | |
* or modifications. | |
* | |
* This is not a supported product, but I welcome bug reports and fixes. | |
* Mail to simh@ibm1130.org | |
*/ | |
#include "ibm1130_defs.h" | |
/*************************************************************************************** | |
* 1134 Paper Tape Reader device PTR | |
* 1055 Paper Tape Punch device PTP (shares DSW with PTR) | |
***************************************************************************************/ | |
#define PTR1134_DSW_READER_RESPONSE 0x4000 | |
#define PTR1134_DSW_PUNCH_RESPONSE 0x1000 | |
#define PTR1134_DSW_READER_BUSY 0x0800 | |
#define PTR1134_DSW_READER_NOT_READY 0x0400 | |
#define PTR1134_DSW_PUNCH_BUSY 0x0200 | |
#define PTR1134_DSW_PUNCH_NOT_READY 0x0100 | |
#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT) | |
static t_stat ptr_svc (UNIT *uptr); | |
static t_stat ptr_reset (DEVICE *dptr); | |
static t_stat ptr_attach (UNIT *uptr, char *cptr); | |
static t_stat ptr_detach (UNIT *uptr); | |
static t_stat ptr_boot (int unitno, DEVICE *dptr); | |
static t_stat ptp_svc (UNIT *uptr); | |
static t_stat ptp_reset (DEVICE *dptr); | |
static t_stat ptp_attach (UNIT *uptr, char *cptr); | |
static t_stat ptp_detach (UNIT *uptr); | |
static int16 ptr_dsw = 0; /* device status word */ | |
static int32 ptr_wait = 1000; /* character read wait */ | |
static uint8 ptr_char = 0; /* last character read */ | |
static int32 ptp_wait = 1000; /* character punch wait */ | |
UNIT ptr_unit[1] = { | |
{ UDATA (&ptr_svc, UNIT_ATTABLE, 0) }, | |
}; | |
REG ptr_reg[] = { | |
{ HRDATA (DSW, ptr_dsw, 16) }, /* device status word */ | |
{ DRDATA (WTIME, ptr_wait, 24), PV_LEFT }, /* character read wait */ | |
{ DRDATA (LASTCHAR, ptr_char, 8), PV_LEFT }, /* last character read */ | |
{ NULL } }; | |
DEVICE ptr_dev = { | |
"PTR", ptr_unit, ptr_reg, NULL, | |
1, 16, 16, 1, 16, 16, | |
NULL, NULL, ptr_reset, | |
ptr_boot, ptr_attach, ptr_detach}; | |
UNIT ptp_unit[1] = { | |
{ UDATA (&ptp_svc, UNIT_ATTABLE, 0) }, | |
}; | |
REG ptp_reg[] = { | |
{ HRDATA (DSW, ptr_dsw, 16) }, /* device status word (this is the same as the reader's!) */ | |
{ DRDATA (WTIME, ptp_wait, 24), PV_LEFT }, /* character punch wait */ | |
{ NULL } }; | |
DEVICE ptp_dev = { | |
"PTP", ptp_unit, ptp_reg, NULL, | |
1, 16, 16, 1, 16, 16, | |
NULL, NULL, ptp_reset, | |
NULL, ptp_attach, ptp_detach}; | |
/* xio_1134_papertape - XIO command interpreter for the 1134 paper tape reader and 1055 paper tape punch */ | |
void xio_1134_papertape (int iocc_addr, int iocc_func, int iocc_mod) | |
{ | |
char msg[80]; | |
switch (iocc_func) { | |
case XIO_READ: /* read: return last character read */ | |
M[iocc_addr & mem_mask] = (uint16) (ptr_char << 8); | |
break; | |
case XIO_WRITE: /* write: initiate punch operation */ | |
if ((ptr_dsw & PTR1134_DSW_PUNCH_NOT_READY) == 0 && IS_ONLINE(ptp_unit)) { | |
putc((M[iocc_addr & mem_mask] >> 8) & 0xFF, ptp_unit->fileref); | |
ptp_unit->pos++; | |
} | |
sim_activate(ptp_unit, ptp_wait); /* schedule interrupt */ | |
SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY | PTR1134_DSW_PUNCH_BUSY); | |
break; | |
case XIO_SENSE_DEV: /* sense device status */ | |
ACC = ptr_dsw; | |
if (iocc_mod & 0x01) { /* reset interrupts */ | |
CLRBIT(ptr_dsw, PTR1134_DSW_READER_RESPONSE | PTR1134_DSW_PUNCH_RESPONSE); | |
CLRBIT(ILSW[4], ILSW_4_1134_TAPE); | |
} | |
break; | |
case XIO_CONTROL: /* control: initiate character read */ | |
sim_activate(ptr_unit, ptr_wait); /* schedule interrupt */ | |
SETBIT(ptr_dsw, PTR1134_DSW_READER_BUSY | PTR1134_DSW_READER_NOT_READY); | |
break; | |
default: | |
sprintf(msg, "Invalid 1134 reader/1055 punch XIO function %x", iocc_func); | |
xio_error(msg); | |
} | |
} | |
// ptr_svc - emulated timeout - 1134 read operation complete | |
static t_stat ptr_svc (UNIT *uptr) | |
{ | |
CLRBIT(ptr_dsw, PTR1134_DSW_READER_BUSY); /* clear reader busy flag */ | |
SETBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY); /* assume at end of file */ | |
if (IS_ONLINE(uptr)) { /* fetch character from file */ | |
ptr_char = getc(uptr->fileref); | |
uptr->pos++; | |
if (! feof(uptr->fileref)) /* there's more left */ | |
CLRBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY); | |
} | |
SETBIT(ptr_dsw, PTR1134_DSW_READER_RESPONSE); /* indicate read complete */ | |
SETBIT(ILSW[4], ILSW_4_1134_TAPE); /* initiate interrupt */ | |
calc_ints(); | |
return SCPE_OK; | |
} | |
// ptp_svc - emulated timeout -- 1055 punch operation complete | |
static t_stat ptp_svc (UNIT *uptr) | |
{ | |
CLRBIT(ptr_dsw, PTR1134_DSW_PUNCH_BUSY); /* clear punch busy flag */ | |
if (IS_ONLINE(uptr)) /* update punch ready status */ | |
CLRBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY); | |
else | |
SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY); | |
SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_RESPONSE); /* indicate punch complete */ | |
SETBIT(ILSW[4], ILSW_4_1134_TAPE); /* initiate interrupt */ | |
calc_ints(); | |
return SCPE_OK; | |
} | |
/* ptr_reset - reset emulated paper tape reader */ | |
static t_stat ptr_reset (DEVICE *dptr) | |
{ | |
sim_cancel(ptr_unit); | |
CLRBIT(ptr_dsw, PTR1134_DSW_READER_BUSY | PTR1134_DSW_READER_RESPONSE); | |
SETBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY); | |
if (IS_ONLINE(ptr_unit) && ! feof(ptr_unit->fileref)) | |
CLRBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY); | |
if ((ptr_dsw & PTR1134_DSW_PUNCH_RESPONSE) == 0) { /* punch isn't interrupting either */ | |
CLRBIT(ILSW[4], ILSW_4_1134_TAPE); | |
calc_ints(); | |
} | |
return SCPE_OK; | |
} | |
/* ptp_reset - reset emulated paper tape punch */ | |
static t_stat ptp_reset (DEVICE *dptr) | |
{ | |
sim_cancel(ptp_unit); | |
CLRBIT(ptr_dsw, PTR1134_DSW_PUNCH_BUSY | PTR1134_DSW_PUNCH_RESPONSE); | |
SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY); | |
if (IS_ONLINE(ptp_unit)) | |
CLRBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY); | |
if ((ptr_dsw & PTR1134_DSW_READER_RESPONSE) == 0) { /* reader isn't interrupting either */ | |
CLRBIT(ILSW[4], ILSW_4_1134_TAPE); | |
calc_ints(); | |
} | |
return SCPE_OK; | |
} | |
/* ptr_attach - attach file to simulated paper tape reader */ | |
static t_stat ptr_attach (UNIT *uptr, char *cptr) | |
{ | |
t_stat rval; | |
SETBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY); /* assume failure */ | |
if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) /* use standard attach */ | |
return rval; | |
if ((ptr_dsw & PTR1134_DSW_READER_BUSY) == 0 && ! feof(uptr->fileref)) | |
CLRBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY); /* we're in business */ | |
return SCPE_OK; | |
} | |
/* ptr_attach - detach file from simulated paper tape reader */ | |
static t_stat ptr_detach (UNIT *uptr) | |
{ | |
SETBIT(ptr_dsw, PTR1134_DSW_READER_NOT_READY); | |
return detach_unit(uptr); | |
} | |
/* ptr_attach - perform paper tape initial program load */ | |
static t_stat ptr_boot (int unitno, DEVICE *dptr) | |
{ | |
int ch, nch, val, addr; | |
t_bool leader = TRUE, start = FALSE; | |
t_stat rval; | |
addr = 0; | |
nch = 0; | |
val = 0; | |
for (;;) { | |
if ((ch = getc(ptr_unit->fileref)) == EOF) { | |
printf("EOF on paper tape without finding Channel 5 end-of-load mark\n"); | |
break; | |
} | |
if (leader) { | |
if ((ch & 0x7F) == 0x7F) // ignore leading rubouts or "delete" characters | |
continue; | |
leader = FALSE; // after first nonrubout, any punch in channel 5 terminates load | |
} | |
// this is untested -- not sure of actual byte ordering | |
val = (val << 4) | (ch & 0x0F); // get next nybble | |
if (++nch == 4) { // if we now have four nybbles, store the word | |
M[addr & mem_mask] = (uint16) val; | |
addr++; // prepare for next word | |
nch = 0; | |
val = 0; | |
} | |
if (ch & 0x10) { // channel 5 punch terminates load | |
start = TRUE; | |
break; | |
} | |
} | |
if (! start) // if we didn't get a valid load, report EOF error | |
return SCPE_EOF; | |
if ((rval = reset_all(0)) != SCPE_OK) // force a reset | |
return rval; | |
IAR = 0; // start running at address 0 | |
return SCPE_OK; | |
} | |
/* ptp_attach - attach file to simulated paper tape punch */ | |
static t_stat ptp_attach (UNIT *uptr, char *cptr) | |
{ | |
t_stat rval; | |
SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY); /* assume failure */ | |
if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) /* use standard attach */ | |
return rval; | |
fseek(uptr->fileref, 0, SEEK_END); /* if we opened an existing file, append to it */ | |
uptr->pos = ftell(uptr->fileref); | |
if ((ptr_dsw & PTR1134_DSW_PUNCH_BUSY) == 0) | |
CLRBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY); /* we're in business */ | |
return SCPE_OK; | |
} | |
/* ptp_detach - detach file from simulated paper tape punch */ | |
static t_stat ptp_detach (UNIT *uptr) | |
{ | |
SETBIT(ptr_dsw, PTR1134_DSW_PUNCH_NOT_READY); | |
return detach_unit(uptr); | |
} |