+#include "MBA.h"
+#include "RP.h"
+#include "TM.h"
+# include "CON.h"
+# define BLKMAX 32768
+# define MIN(a,b) (a<b?a:b)
+#define MAXTER 10 /* max. no. consec. tape errors */
+/* */
+int blksiz , tfoff , tboff , dboff , tunit , dens ;
+int count , *tmMBA , *rpMBA , dblks , wsize ;
+unsigned int ins , outs ;
+unsigned int nread , bytoff , error ;
+int *RPptr , *TMptr ;
+int rpcyl,rptrk,rpsec;
+char input[150] , *bufptr , retry ;
+/* */
+main() {
+register int i ;
+/*
+* Stand-alone program to copy TM[23]/TE16 mag tape to
+* RP06/RM03 disk.
+* User specifies tape and disk MBA no.'s, tape and disk unit no.'s,
+* tape block size, tape file offset, tape block offset in file,
+* and disk sector offset.
+*/
+
+putlin("tdcopy : TM03 tape-to-disk copy") ;
+putnl() ;
+
+tmbno :
+count = getval("tape MBA #") ;
+if ((count < 0) || (count > MAXMBA-1)) goto tmbno ;
+tmMBA = TMptr = (int *)(M_BASE + (count*NEXSPC)) ; /* TM02 MBA addr */
+
+tuni :
+tunit = getval("tape unit #") ;
+if ((tunit < 0) || (tunit > 7)) goto tuni ;
+TMptr = (int *)((int)TMptr + (tunit*EXTSIZ) + M_extern) ; /* ptr. to MBA
+ ext. reg set for this TM02 unit */
+
+/*
+* ignore density prompt for tape read - TM02 recognizes and adjusts
+* for NRZ or PE input (800 or 1600 BPI)
+gden :
+dens = getval("tape density(8 or 16)") ;
+if (dens == 0) dens = TM_D800 ;
+else if ((dens != 8)&&(dens!=16)) goto gden ;
+*/
+dens = (dens==16?TM_D1600:TM_D800) ;
+
+toff :
+tfoff = getval("tape file offset") ;
+if (tfoff < 0) goto toff ;
+
+gtbo :
+tboff = getval("tape block offset") ;
+if (tboff < 0) goto gtbo ;
+putnl() ;
+
+gdm :
+count = getval("disk MBA #") ;
+if ((count < 0) || (count > MAXMBA-1)) goto gdm ;
+rpMBA = RPptr = (int *)(M_BASE + (count*NEXSPC)) ; /* RP06 MBA addr */
+
+dun :
+count = getval("disk unit") ;
+if ((count > 7) || (count < 0)) goto dun ;
+RPptr = (int *)((int)RPptr + (count*EXTSIZ) + M_extern) ; /* ptr to MBA ext reg set for
+ this RP06 unit */
+
+doff :
+dboff = getval("disk block offset") ;
+putnl() ;
+
+gknt :
+count = getval("no. of input blocks") ;
+if (count < 0) goto gknt ;
+
+if (init()) {
+ putlin("init() error") ;
+ return(-1) ;
+ }
+
+if ((dboff < 0) || (dboff > MAXSEC-1)) goto doff ;
+
+if (tapfil(TMptr,tfoff)) {
+ tioerr :
+ putlin("tape positioning error") ;
+ return(-1) ;
+ }
+if (tapfsp(TMptr,tboff)) goto tioerr ;
+
+/* read in 1st block of tape file to determine block size */
+nread = 1 ;
+blksiz = 65536 ;
+for (retry=0,i=10,error=0;i;i--) {
+ if ((tread()&TM_FCE) != TM_FCE) {
+ if (++error > MAXTER)
+ goto tioerr;
+ }
+ else break ;
+ }
+retry++;
+blksiz = (*(TMptr+TM_fc)) & 0xffff ;
+pdstr(" = tape block size",blksiz) ;
+nread = M_BCMAX/blksiz ; /* no. of tape reads to fill input buffer */
+wsize = nread * blksiz ; /* no. bytes each write to disc */
+dblks = wsize/512 ; /* no. of disc blocks on each write */
+*(TMptr+TM_cs1) = TM_DCLR | TM_GO ;
+twait(TMptr) ;
+if (tapbsp(TMptr,1)) goto tioerr ;
+putnl() ;
+
+for (error = 0 ; (error == 0) && (count > 0) ; count -= nread ) {
+ if (i=tread(TMptr)) {
+ putlin("tape i/o error") ;
+ TME_print(i) ;
+ goto ioerr ;
+ }
+ ins += nread ; /* count of tape blocks input */
+ if (i=dwrite(RPptr)) {
+ putlin("disk i/o error") ;
+ RPE_print(i) ;
+ ioerr :
+ error++ ;
+ continue ;
+ }
+ outs += dblks ; /* count of disk blocks output */
+}
+
+fini :
+/* no rewind on normal termination */
+if (error == 0) putlin("normal termination") ;
+else taprew(TMptr) ;
+pdstr(" input blocks read",ins) ;
+pdstr(" output blocks written",outs) ;
+return(0) ;
+}
+
+/* */
+
+init() {
+/*
+* Initialization.
+* Initialize MBA's and tape/disk units.
+* Initialize TM2/TE16 for drive 0 , 800 BPI, PDP11, etc.
+* Set up MBA map registers to map a max.
+* transfer of 'M_BCMAX' bytes.
+*/
+register int *mp0 , *mp1 , i , page ;
+extern char *end ;
+
+*(rpMBA+M_cr) = MBAinit ; /* init. RP06 MBA */
+if (rpMBA != tmMBA)
+ *(tmMBA+M_cr) = MBAinit ;
+if ((*(RPptr+RP_sr) & RP_MOL) == 0) {
+ putlin("disk unit not online") ;
+ return(-1) ;
+ }
+
+*(RPptr+RP_cr) = RP_RIP | RP_GO ; /* preset */
+dwait(RPptr) ;
+if (i=derror(RPptr)) {
+ putlin("disk init error") ;
+ RPE_print(i) ;
+ return(-1) ;
+ }
+*(RPptr+RP_off) = RP_FMT ; /* set format bit */
+
+i = *(RPptr+RP_dt)&0777 ; /* get disk type */
+if (i==RP6typ) { /* RP06 */
+ rpsec=RP6SEC; rpcyl=RP6CYL; rptrk=RP6TRK;
+ }
+else {
+ if (i==RM3typ) {
+ rpsec=RM3SEC; rpcyl=RM3CYL; rptrk=RM3TRK;
+ }
+ else return(-1);
+ }
+
+/* set TM03 unit no., density, PDP11 normal mode, odd parity
+ abort on error */
+*(TMptr+TM_tc) = tunit | dens | TM_PNOR | TM_EABO ;
+*(TMptr+TM_cs1) = TM_DCLR | TM_GO ;
+twait(TMptr) ;
+if (i=terror(TMptr)) {
+ tierr :
+ putlin("tape init error") ;
+ TME_print(i) ;
+ return(-1) ;
+ }
+if ((*(TMptr+TM_ds) & TM_MOL) == 0) {
+ putlin("tape unit not online") ;
+ return(-1) ;
+ }
+*(TMptr+TM_cs1) = TM_RWND | TM_GO ;
+twait(TMptr) ;
+if (i=terror(TMptr)) goto tierr ;
+
+bufptr = (char *)((((int)&end)+511)&017777777000) ;
+page = ((int)((int)bufptr>>9)&017777777) | 0x80000000 ; /* SBI page no. */
+mp0 = (int *)((int)tmMBA + (int)(M_map*4)) ;
+mp1 = (int *)((int)rpMBA + (int)(M_map*4)) ;
+for (i = ((M_BCMAX+511)/512)+1 ; i ; i--,page++) {
+ (*mp0++) = page ;
+ (*mp1++) = page ;
+ }
+return(0) ;
+}
+
+/* */
+
+tread()
+{
+/*
+* Function to read TM2/TE16 tape drive, 'blksiz' bytes each
+* read, and 'nread' reads.
+*/
+register int i, j , k , *t , *m , teknt ;
+
+m = tmMBA ;
+t = TMptr ;
+for (i=MIN(nread,count),j=0,teknt=0 ; i ; i--,j++) {
+ trloop :
+ *(m+M_var) = j * blksiz ;
+ *(m+M_bc) = (-blksiz) ; /* MBA byte count reg */
+ *(t+TM_cs1) = TM_REDF | TM_GO ; /* read forward */
+ twait(t) ; /* wait for ready */
+ if (k=terror(t)) {
+ if ((++teknt > MAXTER) || (retry == 0)) return(k);
+ *(t+TM_cs1) = TM_DCLR | TM_GO ;
+ twait(t);
+ if (k=tapbsp(t,1)) return(k);
+ goto trloop;
+ }
+ }
+return(0) ; /* normal return */
+}
+
+/* */
+
+dwrite()
+{
+/*
+* Function to write 'wsize' bytes to disc
+* from buffer '*bufptr'.
+*/
+register int i , j , *m , *d ;
+
+m = rpMBA ;
+d = RPptr ;
+*(d+RP_cr) = RP_DC | RP_GO ; /* drive clear */
+dwait(d) ;
+*(d+RP_cyl) = dboff/RP6ST ; /* cylinder no. */
+i = dboff%RP6ST ;
+j = (i/rpsec)<<8 ; /* track */
+*(d+RP_stk) = j | (i%rpsec) ; /* sector : track */
+*(m+M_bc) = (count<nread?-(count*512):(-wsize)) ; /* byte count */
+*(m+M_var) = 0 ; /* virt addr reg = map no. + byte off */
+*(d+RP_cr) = RP_WR | RP_GO ;
+dwait(d) ;
+if (i=derror(d)) return(i) ; /* error */
+dboff += dblks ; /* point to next disc sector */
+return(0) ; /* normal return */
+}