Release 2.0  Copyright ã1991 by NeXT Computer, Inc.  All Rights Reserved.

Chapter 7
Programming the DSP

This chapter explains how to access the DSP from software on a NeXT computer.  A brief review of the hardware is presented, followed by a description of ways to access the DSP.  Familiarity with the DSP56001, especially the host interface port, is assumed.

DSP details, including the D-15 connector pinouts, DSP memory map, and DSP instruction summary, can be found in Reference.

DSP Hardware

The hardware associated with the DSP includes:

·	The Motorola DSP56001 clocked at 25 MHz 
·	8K 24-bit words of zero-wait-state RAM, private to the DSP 
·	Memory-mapped and DMA access (5 megabytes/sec) to the DSP host interface 
·	A D-15 connector that provides access to the DSP SSI and SCI serial ports

Booting the DSP

The DSP is in the reset state while not in use by some task.  When first accessed, it exits the reset state awaiting a bootstrap program.  You can write a DSP program to be fed to the DSP during the bootstrap sequence.  This and the following sections describe how to create, load, and communicate with your own DSP bootstrap program.

The DSP bootstrap program must be a single contiguous program segment starting at location p:0 in on-chip program memory, and it must not exceed 512 words in length (the size of on-chip program RAM).  Below is an example DSP bootstrap program:

; boot56k.asm - Example DSP bootstrap program that goes into an 
; infinite loop as it reads HRX, right-shifts one place, and
; writes HTX

         org p:0 
reset  jmp >rcv_buz

         dup $40-2  ; output must be a contiguous segment 
         nop
         endm

         org p:$40  ; typical starting address

rcv_buz jclr #0,x:$FFE9,rcv_buz  ; wait for data from host 
         move x:$FFEB,A1

         LSR A  ; right-shift one place

xmt_buz jclr #1,x:$FFE9,xmt_buz  ; send shifted word to host
         move A1,x:$FFEB

         jmp rcv_buz

    end $40

DSP Assembly

To assemble this file (named boot56k.asm) and create the object file boot56k.lod, type

asm56000 -b -a -l -os,so boot56k

in a Terminal window.  asm56000 is the Motorola DSP assembler program.  The command-line arguments used in the example are:

·	-b option tells the program to create an object file.

·	-a indicates that the object file should be absolute, or nonrelocatable.  Absolute files are indicated by the extension ª.lodº.  If -a is omitted, a relocatable file (extension ª.lnkº) is created.  You can convert a ª.lnkº file to a ª.lodº file by using the DSP linker program, lnk56000.

·	-l produces a listing file (extension ª.lstº).  The file contains a script of the operations performed by the assembler and is useful while debugging.

·	-os,so causes the assembler to put symbol information in the object file.  This information is used by Bug56Ô, the DSP symbolic debugger.  Bug56 can be found in the directory /NextDeveloper/Apps.

DSP Tools Documentation

There are three UNIX manual pages documenting the DSP assembler asm56000, linker lnk56000, and librarian lib56000.  Complete documentation of these tools is also provided in the directory /NextLibrary/Documentation/Motorola.  The Bug56 application has an extensive help facility (available in the main menu), and is documented in the directory /NextLibrary/Documentation/Ariel.

Binary DSP Object File Format

The ª.lodº object file written by the assembler is in a machine-independent ASCII format.  NeXT supports a more efficient binary ª.dspº format.  A ª.lodº file can be converted to a ª.dspº file using the program dspimg.  For example,

dspimg boot56k.lod boot56k.dsp

converts boot56k.lod to ª.dspº format.  As a convenience, the extension of the input file name defaults to ª.lod,º and the output file name, when omitted, is derived from the input file name, so this example can also appear as

dspimg boot56k

Loading the DSP Bootstrap Program

After you've prepared the bootstrap program boot56k.lod or boot56k.dsp, you can load it into the DSP from a C program by calling the DSPBootFile() function.  As shown in the following example, the function takes the name of the bootstrap program file as its single argument.

/*
 * test_boot56k.c - read and load boot56k.dsp (bootstrap file)
 * To compile and link:  
 *     cc test_boot56k.c -ldsp_s -lsys_s
 */
#include <dsp/dsp.h>   /* needed by programs that use the DSP */
main()
{
    DSPBootFile("boot56k.dsp");  /* "boot56k.lod" works, too */
    /* Communicate with DSP program here */
}

After the call to DSPBootFile(), the DSP remains open and can be accessed via the Mach driver or by simple host interface programming, as discussed in the next section.

Software Access to the DSP

There are two basic ways to access the DSP:

·	Reading and writing the host interface registers
·	Sending and receiving Mach messages to and from the sound/DSP driver

These access modes are described below.

Host Interface Access

Reading and writing the eight bytes of the DSP host interface is the simplest and most general way to access the DSP.  In this access mode, you have complete control over the DSP software.  There are no programming conventions to obey and no reserved DSP resources.  The disadvantages are that you must write your own DSP communication services, and the DSP can't interrupt the host processor.  Lack of interrupt capability implies lack of direct memory access (DMA) transfer between the DSP and host memory.  The Mach driver interface must be used to field DSP device interrupts.

Host Interface Programming Example

The following example illustrates communication with the example bootstrap program boot56k.asm given above.

/* To compile and link: cc test_getput.c -ldsp_s -lsys_s */
#include <dsp/dsp.h>
main() {
    int tval,reply;

    DSPBootFile("boot56k");

    DSPSetHF0();  /* Set HF0 */
    DSPSetHF1();  /* Set HF1 */
    DSPReadICR(&reply);       /* 8 bits, right-justified */
    printf("\n\ticr = 0x%X\n",reply);

    DSPReadISR(&reply);       /* 8 bits, right-justified */
    printf("\tisr = 0x%X\n",reply);

    tval = 0xBBCCDD;          /* test value */
    DSPWriteTX(tval);         /* 24 bits, right-justified in 32 */

    /* Wait for the data to become ready (RXDF on). */
    while (!DSPDataIsAvailable());
    while (DSPDataIsAvailable()) {
        DSPReadRX(&reply); /* 24 bits, right-justified */
        printf("\trx = 0x%X\n",reply); }

    if (reply != tval>>1)
        printf("ERROR: rx should be = 0x%X\n",tval>>1);

    DSPClose();
}

The output of this program should be

icr = 0x18
isr = 0x6
rx = 0x5DE66E

Note:  Since IVR isn't used in the DSP host interface, there are no functions for reading and writing that register.

For convenience (and efficiency), whole arrays can be written to the transmit registers using

	DSPWriteTXArray(intArray, numberOfInts)

and read from the receive registers of the DSP using

	DSPReadRXArray(intArray, numberOfInts)

Each word of the transfer is conditioned on TXDE for DSPWriteTXArray() and on RXDF for DSPReadRXArray().

DSP Error Handling

Most of the DSP system functions (prefix ªDSPº) return an integer error code, where 0 indicates success and nonzero indicates failure.  These functions also write a string describing the error to the file name passed as the single argument to DSPEnableErrorFile().

Restrictions on Host Interface Programming

Certain restrictions apply to the operation of the write/read primitives (which are implemented using the Mach driver):

·	To write the ICR, you use the functions DSPSetHF1(), DSPSetHF0(), DSPClearHF1(), and DSPClearHF0().  

·	To write the CVR, you pass a host command identifier (an integer) to the DSPHostCommand() function.  The host commands are described in the Motorola DSP56001 User's Manual.

These restrictions are necessary because the DSP driver uses TREQ and HREQ for its own purposes.  In particular, HREQ causes an interrupt that causes the driver to read all available words from the DSP into a kernel buffer.  A call to DSPGetRX() actually fetches words from this buffer rather than from the DSP directly.

Host Interface Access Functions

Functions that support simple host interface programming, such as DSPReadRX(), are currently documented in the procedure prototypes defined in the following header files in the directory /usr/include/dsp:

·	dsp.h is a master header file that pulls in all function prototypes for the DSP library (libdsp_s.a).

·	DSPError.h contains prototypes for the DSP error handling functions.

·	DSPConversion.h prototypes the functions that convert data between type DSPFix24 and int, float, and double.

·	DSPObject.h prototypes the low-level DSP interface functions.

DSPObject.h contains many functions that are useful only in conjunction with the array processing or Music Kit monitors.  The following sections list the functions that are useful regardless of the DSP monitor that you use.

Orienting the Host

·	DSPGetDSPCount() returns the number of DSPs in your cube.

·	DSPSetCurrentDSP(int index) and DSPGetCurrentDSP() set and return, respectively, the zero-based index of the DSP upon which subsequent DSP functions will act.

·	DSPSetMessagePriority(int priority) and DSPGetMessagePriority() set and return, respectively, the priority of messages sent to the current DSP.  There are three priorities, represented as the constants DSP_MSG_HIGH, DSP_MSG_MED, and DSP_MSG_LOW.

·	DSPSetOpenPriority(int priority) and DSPGetOpenPriority() set and return, respectively, the priority with which a subsequent call to DSPOpenNoBoot() opens the DSP.  There are two priorities:  0 is low and 1 is high.  With high priority, a process can gain access to the DSP even if it has already been opened by another process.  This is used mostly by the DSP debugger.  The original process should be frozen while the new process steps in and looks around.

·	DSPEnableHostMsg() and DSPDisableHostMsg() enable and disable, respectively, DSP host message protocol.  DSPHostMsgIsEnabled() returns the current state of the protocol.  With this protocol, DSP error messages are sent on the DSP error port.  Otherwise, all messages arrive on the DSP message port.

Opening and Closing the DSP

·	DSPInit() opens the DSP and loads a minimal, generic DSP boot program.  This is the function that's most commonly called to open the DSP.

·	DSPOpenNoBoot() opens the DSP without loading a boot program.

·	DSPOpenNoBootHighPriority() performs a high-priority open without loading a boot program.  This is normally used only by the DSP debugger.

·	DSPReset() resets the DSP (which must already be open).  A reset DSP is awaiting a bootstrap program.

·	DSPBootFile(char *filename) opens (if necessary) and boots the DSP from the given program file.

·	DSPBoot(DSPLoadSpec *system) opens (if necessary) and boots the DSP from the given program.  DSPLoadSpec is defined in /usr/lib/include/dsp_structs.h.

·	DSPClose() and DSPRawClose() close the DSP; the Raw close doesn't clean up the device.

·	DSPCloseSaveState() and DSPRawCloseSaveState() are like the previous functions, but the state of the open modes are retained and used in a subsequent reopening of the DSP.

DSP Ownership Information

·	DSPIsOpen() returns nonzero if the DSP is open.

·	DSPGetOwnerString() returns a pointer to a string that contains information about the process that currently owns the DSP.  It's in a form exemplified by the following:

DSP opened in PID 351 by me on Sun Jun 18 17:50:46 1989

·	DSPOpenWhoFile() registers the current owner of the DSP in the DSP log file.  This is called implicitly by the functions that open the DSP.

·	DSPCloseWhoFile() deletes the DSP log file.  This is called implicitly by the functions that close the DSP.

Reading and Writing DSP/Host Interface Flags

·	DSPSetHF0(), DSPClearHF0(), and DSPGetHF0() set, clear, and return the state of HF0 (host flag 0), respectively.

An analogous set of functions is provided for HF1, and a DSPGet... function (only) is provided for HF2 and HF3.

Reading and Writing Interface Registers

·	DSPReadICR(int *registerValuePtr) reads the DSP Interrupt Control Register into the integer pointed to by the argument (8 bits, right-justified).

·	DSPGetICR() returns the ICR register.

An analogous set of functions is provided for the Command Vector Register (CVR), and the Interrupt Status Register (ISR).

Reading and Writing Commands and Data

·	DSPHostCommand(int cmd) issues the given host command.

·	DSPWriteTX(DSPFix24 word) writes the low-order 24 bits of word into the DSP Transmit Byte registers.

·	DSPWriteTXArray(DSPFix24 *dataPtr, int n) writes n words from dataPtr into the DSP Transmit Byte registers.

·	DSPWriteTXArrayB(DSPFix24 *dataPtr, int n) writes the data backwards.

·	DSPReadRX(DSPFix24 *wordPtr) reads the next word from the DSP Receive Byte registers into the 24-bit word (right-justified) pointed to by the argument.  The function waits for the time limit returned by DSPDefaultTimeLimit() to expire before giving up (and returning an error code).

·	DSPReadRXArray(DSPFix24 *dataPtr, int n) reads the next n words from the RX registers into dataPtr.

·	DSPGetRX() returns the RX register.

Synchronization

·	DSPAwaitHC(int msTimeLimit) waits for the HC bit to clear.  This happens when the next instruction to be executed on the DSP is the first word of the Host Command interrupt vector.  msTimeLimit is the maximum wait time; 0 means wait forever.

·	DSPAwaitTRDY(int msTimeLimit) waits for the TRDY bit to be set.

·	DSPAwaitData(int msTimeLimit) waits for the DSP to send data to the host.

·	DSPDataIsAvailable() returns nonzero if data from the DSP is available.

Ports

The following functions return a port_t value; the port_t data type is defined in /usr/include/sys/message.h.  The DSP must be open before you call any of these functions.

·	DSPGetOwnerPort() returns the port that conveys DSP and sound-out ownership.

·	DSPGetHostMessagePort() returns the port that's used to send host messages to the DSP.

·	DSPGetDSPMessagePort() returns the port that's used to receive DSP messages sent from the DSP to the host.

·	DSPGetErrorPort() returns the port that receives error messages from the DSP.

The Simulator 

The Motorola DSP56001 simulator, sim56000, isn't provided by NeXT; it can be obtained directly from Motorola.

·	DSPIsSimulated() returns nonzero if the DSP is being simulated.

·	DSPIsSimulatedOnly() returns nonzero if the DSP simulator output is open while the DSP is closed.

·	DSPOpenSimulatorFile(char *filename) opens filename for simulator output.

·	DSPCloseSimulatorFile() closes the simulator output file.

·	DSPStartSimulatorFP(FILE *filePtr) starts the simulator, with output filePtr.

·	DSPGetSimulatorFP() returns a pointer to the simulator output file.

·	DSPStopSimulator() stops the simulator.