ftp.nice.ch/pub/next/unix/music/clm.d.tar.gz#/next56.c

This is next56.c in view mode; [Download] [Up]

/* 56000 - nExt communication            */
/* compiled: cc next56.c -c -O           */


/* changed relatively drastically during Feb-94 for port to Intel and so on
 * Main change: TRDY => TXDE at DAJ's request to make future device drivers simpler
 *                 (the MusicKit uses TXDE, I originally used TRDY)
 * Related change: removed all "l" series functions -- these were debugging conveniences
 * Also: removed calls on DSPOpenNoBoot and DSPClose and substituted lower level snddriver calls.
 */


#include "clmdsp.h"       /* dsp.h and hostInterface declaration */

#include <sound/sound.h>
#include <sound/sounddriver.h>
#include <mach/mach.h>
#include <sys/file.h>
#include <sys/mman.h>     /* protection bits etc */

/* for a Turbo NeXT, delete the word "inline" here and in get_cpu_rx below */
inline put_cpu_tx(int x)
{
#ifdef ARIEL_PC_56D
  unsigned char hi = (x >> 16);
  unsigned char med = ((x >> 8) & 0xff);
  unsigned char low = (x & 0xff);
  dsp_putTXRaw(current_active_dsp,hi,med,low);
#else
  cpu_HI->data.tx.h = ((x >> 16) & 0xff);
  cpu_HI->data.tx.m = ((x >> 8) & 0xff);
  cpu_HI->data.tx.l = (x & 0xff);
#endif
}

inline get_cpu_rx(int *x)
{
#ifdef ARIEL_PC_56D
  unsigned char hi,med,low;
  dsp_getRXRaw(current_active_dsp,&hi,&med,&low);
  *x = hi;
  *x = (*x << 8) | med;
  *x = (*x << 8) | low;
#else
  /* byte-wise order should be high middle low (RXDF cleared when low read -- 10-23) */
  *x = ((cpu_HI->data.rx.h) << 16);
  *x = *x | ((cpu_HI->data.rx.m) << 8);
  *x = *x | (cpu_HI->data.rx.l);
#endif
}

static int dsp_fd = -1;        /* "static" here apparently means "internal" */

#ifndef ARIEL_PC_56D
static int current_active_dsp = -1;
#endif

int wait_time = 1000000;

#ifndef ARIEL_PC_56D
DSPRegs *getDSPRegs() 
/* from (system 1.0) /NextLibrary/Documentation/NeXT/SysRefMan/14_ProgDSP.wn */
/* not documented (or guaranteed to work) in system 2.0, but will work at least another year... */
/* see /usr/include/nextdev/snd_dspreg.h */
/* 
 * The following function memory-maps the DSP host interface.
 * Memory-mapped access can interfere with the Mach Sound/DSP 
 * driver, so normally the driver is kept unaware during 
 * memory-mapped control by zeroing RREQ and TREQ in the 
 * Interrupt Control Register (ICR) of the host interface;
 * this ensures that the DSP never interrupts the host, which 
 * would cause the driver to read and possibly write the DSP.
 */
{
    char *alloc_addr;	                /* page address for DSP memory map */

    dsp_fd = open("/dev/dsp",O_RDWR);	/* need <sys/file.h> */
    if (dsp_fd == -1) 
      return(NULL);
 
     if (( alloc_addr = (char *)valloc(getpagesize()) ) == NULL) 
      return(NULL);
     if ( -1 == mmap(alloc_addr,
	 getpagesize(),			/* Must map a full page */
	 PROT_READ|PROT_WRITE,	        /* rw access <sys/mman.h> */
	 MAP_SHARED,			/* shared access (of course) */
	 dsp_fd,			/* This device */
	 0) )				/* 0 offset */
      return(NULL);
 
     return (DSPRegs *)alloc_addr; 	/* <dsp/dsp_structs.h> */
} 
#endif

/* the following are the indices to direct lisp (from C) function calls (a sort of case statement) */
#define SERVICE_BREAK 0
#define READ_INPUT 1
#define LOCSIZ_SERVICE_BREAK 2
#define AWAIT_GET_SERVICE_BREAK 3
#define AWAIT_PUT_SERVICE_BREAK 4
#define AWAIT_OUTPUT_SERVICE_BREAK 6

wait_a_while (int ticks)
{
  int i;
  for (i=0;i<=ticks;i++);
}

cleararray(int beg, int end, int *arr)
{
  int *i,*j;
  j=arr+end;        /* C compiler on Next doesn't optimize these expressions out of the loop, so... */
  for (i=arr+beg;i<=j;i++) *i=0; /* for (i=beg;i<=end;i++) arr[i]=0; */
}


arrtran (int beg1, int end1, int *arr1, int beg2, int *arr2)
{
  int *i,*j,*k;
  k=arr1+end1;
  for (i=arr1+beg1,j=arr2+beg2;i<=k;i++,j++) *j=*i;  /* arr2[beg2 by j]=arr1[beg1 to end1 by i] */
}


cloadfarr(float *tbl, int siz, int beg, int *mem)
{
  int i,j,fix,exp23;
  exp23=8388608;       /* 1 << 23 may be C's way of saying this */
  for (i=0,j=beg;i<siz;i++,j++)
    {
      if (tbl[i] != 1.0)
	{
	  fix=(tbl[i]*exp23);
	  mem[j]=(fix & 0xffffff);
	}
      else mem[j]=0x7fffff;    /* two's complement 24-bit max pos num -- "fractional" one */
    }
}


/* Now some very unfortunate duplication of code -- in system 1.0 this was unnecessary */

/* -------------------------------------- AwaitData ---------------------------------- */

inline int Await_cpu_Data(int ms)
{
    int i;
    if (CPU_ISR&1) return 0;
    i=0;
    while ((!(CPU_ISR&1)) && (i<ms)) ++i;
    if (CPU_ISR&1) return 0;
    return -1;
}

inline int Await_qp_Data(int ms)
{
    int i;
    if (QP_ISR&1) return 0;
    i=0;
    while ((!(QP_ISR&1)) && (i<ms)) ++i;
    if (QP_ISR&1) return 0;
    return -1;
}

inline int AwaitData(int ms)
{
  int i;
  i = 0;
  if (current_active_dsp != -1)
    {
      if (current_active_dsp == 0)
	i = Await_cpu_Data(ms);
      else i = Await_qp_Data(ms);
    }
  return i;
}

/* -------------------------------------- AwaitTRDY ---------------------------------- */
/* changed to TXDE at DAJ's request 16-Feb-94 */

inline int Await_cpu_TRDY(int ms)
{
    int i;
    if (CPU_ISR&2) return 0;
    i=0;
    while ((!(CPU_ISR&2)) && (i<ms)) ++i;
    if (CPU_ISR&2) return 0;
    return -1;
}

inline int Await_qp_TRDY(int ms)
{
    int i;
    if (QP_ISR&2) return 0;
    i=0;
    while ((!(QP_ISR&2)) && (i<ms)) ++i;
    if (QP_ISR&2) return 0;
    return -1;
}

inline int AwaitTRDY(int ms)
{
  int i;
  i = 0;
  if (current_active_dsp != -1)
    {
      if (current_active_dsp == 0)
	i = Await_cpu_TRDY(ms);
      else i = Await_qp_TRDY(ms);
    }
  return i;
}


/* -------------------------------------- HF2 --------------------------------------- */

inline int cpu_HF2 (void) 
{
  return (CPU_ISR&8);
}

inline int qp_HF2 (void) 
{
  return (QP_ISR&8);
}

inline int HF2 (void)
{
  int i;
  i = -1;
  if (current_active_dsp != -1)
    {
      if (current_active_dsp == 0)
	i = cpu_HF2();
      else i = qp_HF2();
    }
  return i;
}


/* -------------------------------------- HF3 --------------------------------------- */

inline int cpu_HF3 (void) 
{
  return (CPU_ISR&16);
}

inline int qp_HF3 (void) 
{
  return (QP_ISR&16);
}

inline int HF3 (void)
{
  int i;
  i = -1;
  if (current_active_dsp != -1)
    {
      if (current_active_dsp == 0)
	i = cpu_HF3();
      else i = qp_HF3();
    }
  return i;
}

/* -------------------------------------- ISR et al ------------------------------------- */

int get_ISR (void)
{
  int i;
  i = -1;
  if (current_active_dsp != -1)
    {
      if (current_active_dsp == 0)
	i = CPU_ISR;
      else i = QP_ISR;
    }
  return i;
}

int get_ICR (void)
{
  int i;
  i = -1;
  if (current_active_dsp != -1)
    {
      if (current_active_dsp == 0)
	i = CPU_ICR;
      else i = QP_ICR;
    }
  return i;
}

int get_CVR (void)
{
  int i;
  i = -1;
  if (current_active_dsp != -1)
    {
      if (current_active_dsp == 0)
	i = CPU_CVR;
      else i = QP_CVR;
    }
  return i;
}

put_CVR (int word)
{
  if (current_active_dsp != -1)
    {
      if (current_active_dsp == 0)
	put_cpu_cvr(word);
      else put_qp_cvr(word);
    }
}

put_ICR (int word)
{
  if (current_active_dsp != -1)
    {
      if (current_active_dsp == 0)
	put_cpu_icr(word);
      else put_qp_icr(word);
    }
}


/* -------------------------------------- checkHF3 ------------------------------------- */

int check_cpu_HF3 (void)
{    
    int i;
    long lisp_call(int index);
    if ((cpu_HF3() != 0) && (cpu_HF3() != 0))
      {

/* see Motorola DSP56000 manual section 10.2.6.5 -- when HF2 and 3 used as a pair (as here) */
/* you may see indeterminate states during a transition, so you have to read twice */

	if ((cpu_HF2() == 0) && (cpu_HF2() == 0))
	  {
	    i=0;
	    while ((cpu_HF3() != 0) && (cpu_HF2() == 0) && (i<wait_time)) ++i;
	    if ((cpu_HF2() == 0) && (cpu_HF3() != 0)) 
	      lisp_call(SERVICE_BREAK);
	    else 
	      if ((cpu_HF2() != 0) && (cpu_HF3() != 0))
		{
		  lisp_call(READ_INPUT);
		  return 1;
		}
	    
/* all of this paranoia is an attempt to deal with an apparent race condition where we jump in */
/* to look for both flags on, and see only one on */

	    return 0;
	  }
                                  /* clservicebreak in next56.lisp -- HF3 used as signal for forced break */
                                  /* if returned lisp value ever used, remember it is << 3              */
	else 
	  {
	    lisp_call(READ_INPUT);
	    return 1;
	  }
      }
    return 0;
}

int check_qp_HF3 (void)
{   
    int i;
    long lisp_call(int index);
    if ((qp_HF3() != 0) && (qp_HF3() != 0)) /* see note above */
      {
	if ((qp_HF2() == 0) && (qp_HF2() == 0))
	  {
	    i=0;
	    while ((qp_HF3() != 0) && (qp_HF2() == 0) && (i<wait_time)) ++i;
	    if ((qp_HF2() == 0) && (qp_HF3() != 0)) 
	      lisp_call(SERVICE_BREAK);
	    else 
	      if ((qp_HF2() != 0) && (qp_HF3() != 0))
		{
		  lisp_call(READ_INPUT);
		  return 1;
		}
	    return 0;
	  }
	else 
	  {
	    lisp_call(READ_INPUT);
	    return 1;
	  }
      }
    return 0;
}


int checkHF3 (void)
{   
    int i;
    long lisp_call(int index);
    if ((HF3() != 0) && (HF3() != 0)) /* see note above */
      {
	if ((HF2() == 0) && (HF2() == 0))
	  {
	    i=0;
	    while ((HF3() != 0) && (HF2() == 0) && (i<wait_time)) ++i;
	    if ((HF2() == 0) && (HF3() != 0)) 
	      lisp_call(SERVICE_BREAK);
	    else 
	      if ((HF2() != 0) && (HF3() != 0))
		{
		  lisp_call(READ_INPUT);
		  return 1;
		}
	    return 0;
	  }
	else 
	  {
	    lisp_call(READ_INPUT);
	    return 1;
	  }
      }
    return 0;
}


/* -------------------------------------- put and get ------------------------------------- */

#ifdef ARIEL_PC_56D
inline void arielpc56d_putoneword(int word)
{
  unsigned char hi = (word >> 16);
  unsigned char med = ((word >> 8) & 0xff);
  unsigned char low = (word & 0xff);
  dsp_putTX(current_active_dsp,hi,med,low);
}  

inline void arielpc56d_getoneword(int *reply)
{
  unsigned char hi,med,low;
  unsigned int ho;
  dsp_getRX(current_active_dsp,&hi,&med,&low);
  ho = hi;
  ho = (ho << 8) | med;
  ho = (ho << 8) | low;
  *reply = ho;
}
#endif
 

inline int cpu_putoneword(int word)
{
#ifdef ARIEL_PC_56D
  arielpc56d_putoneword(word);
#else
  if (CPU_ISR&2) put_cpu_tx(word);
  else
    {
      if (Await_cpu_TRDY(wait_time) != 0) lisp_call(AWAIT_PUT_SERVICE_BREAK);
      put_cpu_tx(word);
    }
#endif
  return 0;
}

inline int qp_putoneword(int word)
{
  if (QP_ISR&2) put_qp_tx(word);
  else
    {
      if (Await_qp_TRDY(wait_time) != 0) lisp_call(AWAIT_PUT_SERVICE_BREAK);
      put_qp_tx(word);
    }
  return 0;
}

inline int dspputoneword (int word)
{
  int i;
  i = 0;
  if (current_active_dsp != -1)
    {
      if (current_active_dsp == 0)
	i = cpu_putoneword(word);
      else i = qp_putoneword(word);
    }
  return i;
}


inline int cpu_getoneword(void)
{
  int reply;
#ifdef ARIEL_PC_56D
  arielpc56d_getoneword(&reply);
#else
  if (CPU_ISR&1) get_cpu_rx(&reply);
  else
    {
      if (Await_cpu_Data(wait_time) != 0) lisp_call(AWAIT_GET_SERVICE_BREAK);
      get_cpu_rx(&reply);
    }
#endif
  return reply;
}

inline int qp_getoneword(void)
{
  int reply;
  if (QP_ISR&1) get_qp_rx(&reply);
  else
    {
      if (Await_qp_Data(wait_time) != 0) lisp_call(AWAIT_GET_SERVICE_BREAK);
      get_qp_rx(&reply);
    }
  return reply;
}

inline int dspgetoneword(void)
{
  int i;
  i = 0;
  if (current_active_dsp != -1)
    {
      if (current_active_dsp == 0)
	i = cpu_getoneword();
      else i = qp_getoneword();
    }
  return i;
}

inline int cpu_putarray(int beg, int end, int *arr)
{
#ifdef ARIEL_PC_56D
    dsp_putArray(current_active_dsp,arr+beg,end-beg+1);
#else
    int *i,*last;
    last=arr+end;
    for (i=(arr+beg);i<=last;i++)
      {
	cpu_putoneword(*i);
      }
#endif
    return (end-beg+1);
}

inline int qp_putarray(int beg, int end, int *arr)
{
    int *i,*last;
    last=arr+end;
    for (i=(arr+beg);i<=last;i++)
      {
	qp_putoneword(*i);
      }
    return (end-beg+1);
}

inline int dspputarray(int beg, int end, int *arr)
{
  int i;
  i = 0;
  if (current_active_dsp != -1)
    {
      if (current_active_dsp == 0)
	i = cpu_putarray(beg,end,arr);
      else i = qp_putarray(beg,end,arr);
    }
  return i;
}


inline int cpu_getarray(int beg, int end, int *arr)
{
#ifdef ARIEL_PC_56D
    dsp_getArray(current_active_dsp,arr+beg,end-beg+1);
#else
    int *i,*last;
    last=arr+end;
    for (i=(arr+beg);i<=last;i++)
      {
	if (CPU_ISR&1) get_cpu_rx(i);
	else (*i)=cpu_getoneword();
      }
#endif
    return (end-beg+1);
}

inline int qp_getarray(int beg, int end, int *arr)
{
    int *i,*last;
    last=arr+end;
    for (i=(arr+beg);i<=last;i++)
      {
	if (QP_ISR&1) get_qp_rx(i);
	else (*i)=qp_getoneword();
      }
    return (end-beg+1);
}

inline int dspgetarray(int beg, int end, int *arr)
{
  int i;
  i = 0;
  if (current_active_dsp != -1)
    {
      if (current_active_dsp == 0)
	i = cpu_getarray(beg,end,arr);
      else i = qp_getarray(beg,end,arr);
    }
  return i;
}

void clear_host_interfaces (void)
{
  cpu_HI = NULL;
  qp_HI = NULL;
}

#ifdef ARIEL_PC_56D
static void resetPC56d(void)
{
  dsp_resetOn(current_active_dsp);
  /* usleep(10000); */  
  wait_a_while(10000); /* usleep in the past has caused lisp to hang -- will try it later */ /* 100000 ok */
  dsp_resetOff(current_active_dsp);
}
#endif

#define ARIEL_PC_IS_OPEN (-2)


static port_t dev_port, owner_port, cmd_port;
static int clm_dsp_error;

int get_clm_dsp_error(void) {return clm_dsp_error;}

int cpu_boot(int end, int *program)             /* get Next built-in 56000, reset and load it */
{
#ifdef ARIEL_PC_56D
    dsp_open(0);
    resetPC56d();
    dsp_selectMemoryMap(current_active_dsp,1);
    dsp_fd = ARIEL_PC_IS_OPEN;  
    cpu_putarray(0,end,program);
#else
    int i,err;
    int *j,*pend;
    dev_port = 0; owner_port = 0; cmd_port = 0;
    err = SNDAcquire(SND_ACCESS_DSP, 10, 0, 0, NULL_NEGOTIATION_FUN, 0, &dev_port, &owner_port);
    if (err == 0)
      {
        err = snddriver_get_dsp_cmd_port(dev_port,owner_port,&cmd_port);
	if (err == 0)
	  {
	    err = snddriver_dsp_reset(cmd_port,SNDDRIVER_LOW_PRIORITY);
	  }
      }
    clm_dsp_error = err;
    i=err;
    if (i != 0) return -2;
    cpu_HI = getDSPRegs();                       /* get memory-mapped host interface */
    if (cpu_HI == NULL) return -1;
    pend=program+end; 
    for (j=program;j<=pend;j++)
      put_cpu_tx(*j);                            /* load program -- see lib56.lisp for the monitor code     */
#endif
    put_cpu_icr(8);                              /* set HF0 to signal boot done -- see 56000 manual 10-43 */
    return 0;
}

int cpu_close(void)
{
    int err;

#ifdef ARIEL_PC_56D
    if (dsp_fd == ARIEL_PC_IS_OPEN) dsp_close(current_active_dsp);
    dsp_fd = -1;
    return 0;
#else
    if (cmd_port != 0) clm_dsp_error=port_deallocate(task_self(),cmd_port);
    /* the close code in DSPObject.c deallocates the command port before calling SNDRelease */
    /* if we call it afterwards, port_deallocate returns 4 */
    err=SNDRelease(SND_ACCESS_DSP,dev_port,owner_port);
    clm_dsp_error = ((clm_dsp_error << 16) | err);

    if (cpu_HI != NULL)
      free((char *)cpu_HI);
    else err = -2;
    cpu_HI = NULL;
    if (dsp_fd != -1)
      close(dsp_fd);
    else err = -3;
    dsp_fd = -1;
    return err;
#endif
}

inline int checkhostInterface (void)
{
#ifdef ARIEL_PC_56D
    return (dsp_fd == ARIEL_PC_IS_OPEN) ? 0 : -1;
#else
    if ((cpu_HI == NULL) && (qp_HI == NULL)) return -1;
    return 0;
#endif
}

int hival(void)
{
  int i;
  i = 0;
  if (current_active_dsp != -1)
    {
      if (current_active_dsp == 0)
	i = (int)cpu_HI;
      else i = (int)qp_HI;
    }
  return i;
}

inline int dspisopen (void)
{
#ifdef ARIEL_PC_56D
    return (dsp_fd == ARIEL_PC_IS_OPEN) ? 1 : 0;
#else
  if (dsp_fd == -1) return(0);
  return(1);
#endif
}


/* on chip, output results are collected in buffers to be flushed out when full.     */
/* The HF2 bit is set when the dsp has filled its output buffers.  We build a list   */
/* at run time on the lisp side of the locations and sizes of these buffers, and     */
/* here we read the contents.  If needed, input data is also sent to the chip at     */
/* this time.  Then, the dsp sets out on its next buffer, while we merge the results */
/* into the respective files.  Once that is finished, we return to lisp awaiting HF2 */
/* External delay lines change this scenario a bit.                                  */

/* #define DATSIZ 32768 */
#define DATSIZ 131072
/* static int datbuf[DATSIZ]; */     /* dump dsp's "external memory" here (16K for QP) (32K for exp mem) (65536*2 for SFSU mem) */
                                     /* If we ever take advantage of SFSU P mem for delay lines, change this to 65536*3 */
#ifdef ARIEL_PC_56D
  #define ZERO_SIZE 4096
  static int *zero_buf;
#endif

static int *datbuf;
static int data_ok = -1;

check_datbuf (void)
{
  int i;
  if (data_ok == -1)
    {
      datbuf = (int *)calloc((DATSIZ),sizeof(int)); 
#ifdef ARIEL_PC_56D
      zero_buf = (int *)calloc((ZERO_SIZE),sizeof(int));
      for (i=0;i<ZERO_SIZE;i++) zero_buf[i]=0;
#endif
    }
  data_ok = 0;

}



#define NO_IO -1
#define OUT_N 0
#define IN_N 1
#define EXT_DLY 2
/* RAN_IN_N = 3 and EXT_ZDLY = 4, but only used in debugging */

inn(int beg, int siz, int bufbeg, int *arr, int fsize)
{
    /* file data in ARR starts at file sample BEG, file size is FSIZE, we want SIZ samples, and */
    /* we are currently at BUFBEG within ARR */

  int num,zeros,k;

  num = fsize-beg-bufbeg;       /* max actual samples that could be read  (can be negative) */
  zeros = siz;                  /* in worst case (past eof), all samples are 0 */
     
  if (num>0)                    /* if there are samples in arr (not past eof) */
    {
      if (siz<num) 
	k=siz;
      else k=num;
      if (current_active_dsp == 0)
	{
	  cpu_putarray(bufbeg,bufbeg+k-1,arr);
	}
      else
	{
	  qp_putarray(bufbeg,bufbeg+k-1,arr);
	}
      zeros = zeros - k;
    }
  if (zeros>0)
    {
      if (current_active_dsp == 0)
	{
#ifdef ARIEL_PC_56D
	  for (k=0;k<zeros;k+=ZERO_SIZE)
	    {
	      if ((zeros-k) < ZERO_SIZE) { num=zeros-k; num-=1; } else num=ZERO_SIZE-1; 
              /* cc -O3 -DVOL=volatile -fwritable-strings  -DARIEL_PC_56D -O -c -I. akkcl-c56.c -w */
	      /* if ((zeros-k) < ZERO_SIZE) num=zeros-k-1; else num=ZERO_SIZE-1; */
	      /* on the Pentium this compiles num=zeros+k+1 */
	      cpu_putarray(0,num,zero_buf);
	    }
#else
	  for (k=0;k<zeros;k++)
	    cpu_putoneword(0);
#endif
	}
      else
	{
	  for (k=0;k<zeros;k++)
	    qp_putoneword(0);
	}
    }
}


inline outn (int outbeg, int outend, int *outa, int dspbeg, int *dspa)
{
  int *i,*j,*last;
  last=outa+outend;
  if (outa != 0)
    {
      for (i=(outa+outbeg),j=(dspa+dspbeg);i<=last;i++,j++)
	{
#ifdef ARIEL_PC_56D
	*i += *j;
#else	  
	  if ((*j) & 0x800000) 
	    *i += ((*j) | 0xffff0000);
	  else *i += *j;
#endif
	}
    }
}


/* outonebuf = dsp-merge-one-buffer and is used only in qplib56.lisp for partial DMEM flushes */

inline int cpu_outonebuf(int start, int stop, int *outloc)
{
  int *i,*last, *first;
  int val;
  first=outloc+start;
  last=outloc+stop;
  for (i=first;i<=last;i++)
    {
      if (CPU_ISR&1) get_cpu_rx(&val);
      else val=cpu_getoneword();
      if (val & 0x800000)
	*i += (val | 0xffff0000);
      else *i += val;
    }
return 0;
}

inline int qp_outonebuf(int start, int stop, int *outloc)
{
  int *i,*last, *first;
  int val;
  first=outloc+start;
  last=outloc+stop;
  for (i=first;i<=last;i++)
    {
      if (QP_ISR&1) get_qp_rx(&val);
      else val=qp_getoneword();
      if (val & 0x800000)
	*i += (val | 0xffff0000);
      else *i += val;
    }
return 0;
}

inline int outonebuf(int start, int stop, int *outloc)
{
  int i;
  i = -1;
  if (current_active_dsp != -1)
    {
      if (current_active_dsp == 0)
	i = cpu_outonebuf(start,stop,outloc);
      else i = qp_outonebuf(start,stop,outloc);
    }
  return i;
}



inline dspsendinput(int *beg, int cursiz, int *sigops, int *sigptrs, int **sigadrs, int *sigsizes, int sigsiz)
{
  int i;
  dspputoneword(cursiz);
  for (i=0;i<sigsiz;i++)
    {
      if (sigops[i] == IN_N)
	{
	  inn(beg[i],cursiz,sigptrs[i],sigadrs[i],sigsizes[i]);
	  sigptrs[i] += cursiz;
	}
    }
}

inline WaitForHF2_NotHF3 (void)
{
  /* be real patient here -- make the wait time out pretty excessive */
  int happy,i,waiting;
  happy = 1;
  waiting = 0;
  i = 0;
  while (happy)
    {
      i++;
      if (i>1000000) 
	{
	  put_CVR(0x96);  
	  while ((HF2() == 0) || (HF3() != 0)) 
	    {
	      waiting++;
	      if (waiting>2000) 
		{
		  lisp_call(AWAIT_OUTPUT_SERVICE_BREAK);
		}
	    }
	}
      if (HF2() != 0)
	{
	  if ((HF3() != 0) && (HF2() != 0))
	    {
	      lisp_call(READ_INPUT);
	      i = 0;
	    }
	  else if (HF3() == 0)
	    {
	      happy = 0;
	    }
	}
    }
}

inline cpu_WaitForHF3_NotHF2 (void)
{
  /* be real patient here -- make the wait time out pretty excessive */
  int happy,i;
  happy = 1;
  i = 0;
  while (happy)
    {
      if (cpu_HF3() != 0)
	{
	  if ((cpu_HF2() != 0) && (cpu_HF3() != 0))
	    {
	      lisp_call(READ_INPUT);
	      i = 0;
	    }
	  else if ((cpu_HF2() == 0) && (cpu_HF3() != 0))
	    {
	      happy = 0;
	    }
	}
      else
	{
	  i++;
	  if (i>1000000) 
	    lisp_call(AWAIT_GET_SERVICE_BREAK);
	}
    }
}

inline qp_WaitForHF3_NotHF2 (void)
{
  /* be real patient here -- make the wait time out pretty excessive */
  int happy,i;
  happy = 1;
  i = 0;
  while (happy)
    {
      if (qp_HF3() != 0)
	{
	  if ((qp_HF3() != 0) && (qp_HF2() != 0))
	    {
	      lisp_call(READ_INPUT);
	      i = 0;
	    }
	  else if (qp_HF2() == 0)
	    {
	      happy = 0;
	    }
	}
      i++;
      if (i>1000000) 
	lisp_call(AWAIT_GET_SERVICE_BREAK);
    }
}

inline WaitForHF3_NotHF2 (void)
{
  if (current_active_dsp == 0)
    cpu_WaitForHF3_NotHF2();
  else qp_WaitForHF3_NotHF2();
}

#define LOCSIZ 256
static int locs[LOCSIZ];

basicdspread (int beg, int end, int sigsiz, int dlys, int ins,
	      int *sigops, int **sigadrs, int *sigptrs,
	      int *sigbas, int *sigtop, int *sigsizes)
{
  int i,k,curdsploc,num,cursiz,readsize;
  if (sigsiz>LOCSIZ) lisp_call(LOCSIZ_SERVICE_BREAK);  
  check_datbuf();

  if (dlys != 0)                                        /* we have external delay lines in operation */
    {
      for (i=beg;i<=end;i++)
	{
	  for (k=0;k<sigsiz;k++)
	    {
	      if (sigops[k] == EXT_DLY)
		{
		  int *pt,*sp;
		  sp=sigptrs+k;
		  pt=sigadrs[k]+(*sp);
		  WaitForHF3_NotHF2();
		  dspputoneword(*pt);
		  (*pt)=dspgetoneword();
		  (*sp)++;
		  if ((*sp)>sigtop[k]) (*sp)=0;  /* sigbas is index into *clm-delay-lines* */
		}
	    }
	}
    }


  curdsploc=0;
  cursiz=(end-beg);
  readsize=cursiz+1;
  
  WaitForHF2_NotHF3();

  dspputoneword(readsize);

  for (i=0;i<sigsiz;i++)
    {
      if (sigops[i] == OUT_N)
	{
	  locs[i] = curdsploc;
	  num=dspgetarray(curdsploc,curdsploc+cursiz,datbuf); 
	  curdsploc += num;
	}
    }

  if (ins != 0)
    {
      dspsendinput(sigbas,readsize,sigops,sigptrs,sigadrs,sigsizes,sigsiz);
    }

  /* now the dsp should be running again -- merge current output into output buffers */
  for (i=0;i<sigsiz;i++)
    {
      if (sigops[i] == OUT_N) 
	{
	  outn(beg,end,sigadrs[i],locs[i],datbuf);
	}
    }
}

rpc_dsp_merge_all_output(int beg, int end, int **sigadrs, int *sigops, int sigsiz, int *ldatbuf)
{
  int cursiz,curloc,i;
  cursiz = (end-beg);
  curloc = 0;
  for (i=0;i<sigsiz;i++)
    {
      if (sigops[i] == OUT_N) 
	{
	  outn(beg,end,sigadrs[i],curloc,ldatbuf);
	  curloc += cursiz;
	}
    }
}

#define RTS_op 12
#define Clear_HF3 698372
#define Move_X_HTX 585899
#define No_op 0

int dspstartagain(int tag, int tagloc)
{
  return ( (checkhostInterface() == 0) &&          /*    it appears that we have a pointer to its registers               */
	   (HF3() != 0) && (HF3() != 0) &&         /*    it appears to be sitting at our breakpoint handler               */
	   (HF2() == 0) && (HF2() == 0) &&         /*    (not bug56...) (on repeat reads see note under hf3) and          */

	   (dspputoneword(Clear_HF3) != -1) &&     /*    BCLR M-HF3 X-IO M-HCR...                                         */
	   (dspputoneword(No_op) != -1) &&         /*    NOP (2 wrd command in breakpoint handler)...                     */
	   (HF3() == 0) &&                         /*    executed ok! -- we must be at .break and                         */

	   (dspputoneword(Move_X_HTX) != -1) &&    /*    MOVE X tag-loc X-IO M-HTX...                                     */
	   (dspputoneword(tagloc) != -1) &&        /*    (tag-loc)...                                                     */
	   (dspgetoneword() == tag) &&             /*    tag is the same -- current instrument must already be loaded and */

	   (dspputoneword(RTS_op) != -1) &&        /*    RTS (from .break)...                                             */
	   (dspputoneword(No_op) != -1));          /*    NOP (2nd word) -- we should now be awaiting the next note's data */
}                                                  /* Otherwise, reset chip and load everything                           */


int dspdataready (void)
{ 
  int i;
  i = 0;
  if (checkhostInterface() == 0) i = checkHF3();
  if (i == 1) return 0;
  return ( (checkhostInterface() == 0) &&
	   (HF2() != 0) && (HF2() != 0) &&         /* if we see .input's flags here by accident, endless trouble           */
	   (HF3() == 0) && (HF3() == 0) &&         /* so read everything twice -- if only we had more of these flags...    */
	   (HF2() != 0) && (HF3() == 0));
}


int dspsetupprogram(int ix, int iy, int ex, int ey, int ep, int xoff, int yoff, int poff, int *ixarr, int *iyarr, int *earr)
{
  if (dspputoneword(ix) != 0) return 1;
  if (ix != 0)
    {
      dspputoneword(0);
      if (dspputarray(0,ix-1,ixarr) != ix) return 2;
    }
  
  if (dspputoneword(iy) != 0) return 3;
  if (iy != 0)
    {
      dspputoneword(0);
      if (dspputarray(0,iy-1,iyarr) != iy) return 4;
    }
  
  if (dspputoneword(ex) != 0) return 5;
  if (ex != 0)
    {
      dspputoneword(xoff);
      if (dspputarray(0,ex-1,earr) != ex) return 6;
    }
  
  if (dspputoneword(ey) != 0) return 7;
  if (ey != 0)
    {
      dspputoneword(xoff);  /* xoff because we're asking here for the chip's notion of the start of Y memory, not our own */
                            /* then yoff in the put array call because there we're dealing with our offset into external-memory */
      if (dspputarray(yoff,yoff+ey-1,earr) != ey) return 8;
    }

  if (dspputoneword(ep) != 0) return 9;
  if (ep != 0)
    {
      dspputoneword(poff);
      if (dspputarray(poff,poff+ep-1,earr) != ep) return 10;
    }
  return 0;
}

set_active_dsp(int num) {current_active_dsp = num;}
int get_active_dsp(void) {return current_active_dsp;}

int set_wait_time (int ms)
{
  int old_wait;
  old_wait = wait_time;
  wait_time = ms;
  return old_wait;
}

int get_wait_time (void) {return wait_time;}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.