Received: from uknet by cix.compulink.co.uk id aa23944; 21 Jan 93 7:15 GMT
Received: from sun4nl.nluug.nl by ben.uknet.ac.uk via EUnet with SMTP (PP) 
          id <sg.02778-0@ben.uknet.ac.uk>; Thu, 21 Jan 1993 06:52:36 +0000
Received: from targon by sun4nl.nluug.nl via EUnet id AA26297 (5.65b/CWI-3.3);
          Thu, 21 Jan 1993 07:52:33 +0100
Received: by targon.UUCP (5.61/smail2.5/01-24-90) id AA15594;
          Thu, 21 Jan 93 07:31:33 +0100
Date: Thu, 21 Jan 93 07:31:33 +0100
From: Marc Dierikx <marc@targon.uucp>
Message-Id: <9301210631.AA15594@targon.UUCP>
To: apelled@cix.compulink.co.uk
Subject: DMA
Apparently-To: apelled

To: apelled@cix.compulink.co.uk
Subject: Re: DMA chip and ACSI/SCSI
Newsgroups: comp.sys.atari.st.tech
In-Reply-To: <memo.881374@cix.compulink.co.uk>
Organization: Siemens Nixdorf Informatiesyst. ,dep.SWZ,Postbus 29,4130 EA Vianen,Netherlands
Cc: 
Bcc: 

In article <memo.881374@cix.compulink.co.uk> you write:
>
>    Can someone point me toward some decent documentation on ACSI and also
>exhaustive details on the dma chip ?
>    What i am doing is working on Alan Hourihane's Tapebios software. Mostly
>things are going well. i have superb documents on SCSI but very little on the
>ACSI protocol. There is one very old text file on umich.edu that is quite
>impressive considering the little the guy had to go on, but still leaves me
>with a lot of questions and few answers.
>    If someone could mail me good documentation i would be extremely grateful.
>
>Regards,
>    Adam.   apelled@cix.compulink.co.uk

Hello,

Probably the following article by Doug Collinge might help. I have
used it to make a software interface to my slm804 laser printer and
found the document to be correct, but quite hard to understand.
I used some other sources as well (A book about Atari internals (no,
not Atari Intern or whatever the Data Becker or Abacus version is
called, but some other one of which I don't remember the title) and
a piece of modula code from an early ST magazine from 'Stichting ST'
in Leiden (the Netherlands).


Regards, Marc
(marc@targon.UUCP)



From uucp Wed Oct 14 00:33 MET 1992
>From sun4nl!sol.UVic.CA!uvphys.phys.LOCAL!TAPP  Wed Oct 14 00:33:01 1992
Received: by targon.UUCP (5.61/smail2.5/01-24-90)
	id AA24113; Wed, 14 Oct 92 00:33:01 +0100
Received: from mcsun.EU.net by sun4nl.nluug.nl with SMTP
	id AA00177 (5.65b/CWI-3.3); Tue, 13 Oct 1992 23:34:02 +0100
Received: by mcsun.EU.net via EUnet
	id AA00506 (5.65b/CWI-2.180); Tue, 13 Oct 1992 23:33:57 +0100
From: uvphys.phys.LOCAL!TAPP@sol.UVic.CA
Received: from grolsch.cs.ubc.ca by relay2.UU.NET with SMTP 
	(5.61/UUNET-internet-primary) id AA26969; Tue, 13 Oct 92 18:25:39 -0400
Received: from sol.UVic.CA by grolsch.cs.ubc.ca with SMTP id AA01037
  (5.65c/IDA-1.3.5 for uunet!mcsun!sun4nl!targon!marc); Tue, 13 Oct 1992 14:38:06 -0700
Received: from uvphys.phys.UVic.CA by sol.UVic.CA (4.1/SMI-4.0.3-UVic-2.37TMX)
	id AA25930; Tue, 13 Oct 92 14:38:01 PDT
Date:    Tue, 13 Oct 1992 14:37:41 -0700 (PDT)
Message-Id: <921013143741.20206a05@uvphys.phys.UVic.CA>
Subject: dma, mfp
To: marc@targon.uucp
X-Vmsmail-To: SMTP%"marc@targon.UUCP"
Status: R


In your message of 13 Oct 92 07:17:48 GMT, you write:

> I'm looking for information on how to program in- and output from/to
> the st's dma port. I guess it has something to do with programming
> the mfp chip. Can anyone help?

Attached to the end of this message is a description of how to solve
this problem as written by Doug Collinge, formerly of the School of
Music at the University of Victoria.

Bob Tapp, University of Victoria
tapp@uvphys.phys.UVic.CA

-----------------------------------------------------------------------

INTERFACING THE ATARI ST HARD DISK PORT WITH FEWER TEARS
     
By Doug Collinge, collinge@uvicctr.BITNET uw-beaver!uvicctr!collinge
     
        When I set about to interface to the Hard Disk Port on my Atari
1040ST I assembled all the documentation I could find and discovered
that, though I found plenty, I still ended up without quite enough to
design the interface.  I attacked the problem with the Scientific
Method and now have a working one-megabyte-per-second interface.  This
article was written as a source of information for those who are (like
I was) frightened of using what has turned out to be a very simple and
easy-to-use port.
     
        Since much of the information in this article is based on
experiments with only one DMA chip it is possible that some of it will
not apply to other revisions of the chip.  A note in one of the
documents I used suggested that an earlier revision had certain
problems.  I have marked conjectures and guesses with "(?)".  Perhaps
someone at Atari will correct any misconceptions or outright errors.
Also, the interface I built only does DMA transfers into the ST (read
operations); therefore, while it is easy to infer the reverse protocol,
I haven't tested DMA transfers in the opposite direction.
     
DMA IN THE ST
     
        The same DMA channel is used for both the floppy disks and the
Hard Disk Port.  The floppies are controlled by a floppy disk
controller chip which is connected to the DMA chip.  The DMA chip is
capable of servicing data requests at about 1.25 MHz.  Data will be
lost if you attempt to transfer data at a rate greater than.  I have
been able to transfer data at very close to this rate without any
problems.  The DMA chip buffers 16 bytes of data before requesting the
memory bus then holds the bus until all buffered data has been
transfered.  Memory cycles used for DMA are taken from the processor;
since the memory bus makes 4 MByte/s available, 1 MByte/s of DMA should
take 25% of the cycles normally available to the processor, plus a
fudge factor to account for the time spent in memory bus arbitration.
     
THE HARD DISK PORT
     
        The Hard Disk Port is a 19-pin D connector - apparently
completely unavailable through normal commercial channels.  Make your
own from a metal-shelled male DB25 connector as follows:
     
        - remove and discard the metal shell revealing that the pins are
          held in place and insulated with two loose plastic retainers;
        - remove the pins from the retainers (for once you can lose a
          couple since you will end up with six spares);
        - using a fretsaw or a fine hacksaw remove one end of both
          retainers leaving 19 holes;
        - replace the pins and glue the retainers together.
     
You now have the connector you need.  It has no mounting ears but the
retaining force of 19 pins is quite substantial.  If this is not
adequate be ingenious and salvage the metal shell somehow.
     
        The pins on the Hard Disk Port are connected as follows (pin
one is at the upper right of the connector facing the rear of the
computer):
     
        1-8     DMA data bus bits 0-7 (bidirectional)
        9       Hard Disk Controller Chip Select (_HDCS) (output)
        10      Interrupt Request (_IRQ) (input, internal 1k pull-up)
        11      Ground
        12      Reset (bidirectional)
        13      Ground
        14      Acknowledge (_ACK) (output)
        15      Ground
        16      A1 (output)
        17      Ground
        18      Read/_Write (R/_W) (output)
        19      Data Request (_DRQ) (input, internal 1k pull-up)
     
        The Hard Disk Port is connected directly to the DMA chip
WITHOUT ANY BUFFERING on most pins - be careful, a small mistake (e.g.,
static) could blow your DMA chip.  The system reset line is also
directly connected to the port meaning that accidental shorts reset
your computer - very irritating and potentially dangerous to your
files.
     
        There are two ways to move data on this bus, which I will call
"processor cycles" and "DMA cycles".
     
        A processor cycle is initiated by the processor (as described
later) and transfers a byte of data on the data bus.  The R/_W line
reflects whether the processor is reading or writing the DMA bus.  A1
may be set by a mode bit in the DMA chip.  The transfer is strobed by
the _HDCS signal.  Apparently, a normal hard disk interface will
interrupt after each such cycle to indicate that it has processed the
data.  This was not necessary in my interface.
     
        A DMA cycle is initiated by the interface by asserting the
_HDRQ input.  The direction of the transfer is programmed in the DMA
chip.  R/_W HAS NOTHING TO DO WITH IT - it is used only in processor
cycles.  The DMA chip waits until it is ready to produce or receive the
data and asserts the _ACK output, with which you gate your data onto
the bus (a read) or strobe the data into a register (a write).  _HDCS,
R/_W, and A1 are irrelevant during a DMA transfer.  When the interface
decides the transfer is complete it tells the processor by asserting
the _IRQ input.
     
        A typical transfer goes something like:  the processor
configures the interface by writing a batch of data to it with
processor cycles.  Then it reprograms the DMA chip for DMA cycles and
does something else for a while.  The interface generates or receives
data until it is finished, then interrupts the processor.  The
processor programs the DMA chip for processor cycles and reads some
status from the interface.  The transfer is now complete.
     
INSIDE THE DMA CHIP
     
        The DMA chip is accessed through memory-mapped registers:
     
ff8604  R/W  16 bits    When bit 4 of the Mode register is zero a read or
                        write access to this word causes a read or write
                        cycle on the DMA bus.  If bit 3 is set the Hard
                        Disk Chip Select controls the cycle; otherwise,
                        the Floppy Disk Controller is selected.  R/_W is
                        set according to the type of the CPU access and
                        A1 is set according to bit 1 of the Mode register.
                        NOTA BENE: what is called A0 in the DMA chip is
                        called A1 on the Hard Disk Port.  For some reason,
                        if bit 7 is not set no DMA bus  cycle will take
                        place.
     
                        When bit 4 of the Mode register is one the internal
                        sector count register is selected.  This register
                        counts down the number of 512-byte blocks that have
                        been transferred.  When the sector count register
                        reaches zero the chip will cease to transfer data.
     
ff8606  R    16 bits    Status word:
                        bit 0: 1 if error.
                        bit 1: 1 if sector count is zero.
                        bit 2: 1 if _DRQ is active.
                        If this word is polled during a DMA operation the
                        transfer will be disrupted.  End of transfer must
                        be signalled with the _IRQ signal.  The status is
                        cleared by toggling bit 8 in the Mode register.
     
ff8606  W    16 bits    Mode register:
                        bit 0:  not used.
                        bit 1:  A0; state of Hard Disk Port line A1 (sic)
                                during a DMA bus cycle.
                        bit 2:  A1; used for Floppy Controller only.
                        bit 3:  HDC/_FDC chip select; if this bit is 1
                                the _HDCS chip select will be generated;
                                otherwise the Floppy Controller select.
                        bit 4:  If one, select the the internal sector
                                count register for access at ff8604.
                        bit 5:  Reserved; set to zero.
                        bit 6:  Disable DMA when set; this is not used by
                                Atari.
                        bit 7:  FDC/_HDC transfer select; if set DRQ from
                                the Floppy Controller is acknowledged;
                                otherwise, DRQ from the Hard Disk Port.
                                This bit must also be set to get a DMA bus
                                cycle for some reason.
                        bit 8:  Write/_Read; if set, data will be transferred
                                out of memory; otherwise, into.  Toggling
                                this bit also clears the DMA chip status.
     
ff8609  R/W  8 bits     DMA Address Counter High byte.
ff860b  R/W  8 bits     DMA Address Counter Mid byte.
ff860d  R/W  8 bits     DMA Address Counter Low byte.
                        The DMA Address Counter must be loaded in Low, Mid,
                        High order.
     
        There are two eight-word FIFOs in the chip; one for buffering
the DMA bus and one for buffering the memory bus. (?)  The FIFOs are
not flushed automatically so you can only transfer data in multiples of
16 bytes.  If possible, use 512-byte units like the sector count
register does.
     
        The DMA chip has no interrupt capability; This is ickky, but
cheap.  End-of-transfer interrupts must be generated by the external
controller and are masked and vectored by the 68901 MFP chip on the
General Purpose I/O Port, bit 5, interrupt level 7.  The MFP chip
interrupts are controlled with the XBIOS calls 'mfpinit', 'jdisint',
and 'jenabint'.  'jenabint(7)' and 'jdisint(7)' will enable and disable
the DMA interrupt. 'mfpint(7,dmahandler)' will initialize the vector to
'dmahandler', wiping out any earlier one.  If you want instead to
simply test the state of the interrupt request line, without taking any
interrupts you can test the MFP GPIP data register.  Read a byte from
fffa01 and mask with $20; if the result is zero there is no interrupt.
Atari gave us these nice XBIOS procedures but left out one very
important one:  the interrupt status of the MFP chip must be cleared
after each interrupt.  This is done by clearing bit 7 of the "interrupt
in-service register B":
     
        bclr    #7,$fffa11
     
If you don't do this you get into a hard interrupt loop with everything
locked out.  Reset.
     
        Because the floppy controller shares the DMA chip you have to
be very careful about two things: 1) do not leave DMA interrupts
enabled accidentally or floppy operations will call your DMA interrupt
handler; 2) turn off the floppy check routine while using DMA by
jamming a 1 into FLOCK=$43e to prevent this periodic operation from
screwing up your transfers by altering the DMA chip registers.
     
TIMING
     
        These timing contraints are my interpretation of sketchy,
preliminary-looking Atari documents dated "27 September 1985".  If
someone at Atari can give better figures, please inform me.
     
        Processor cycles are controlled by the _HDCS, R/_W, and A1
lines as described earlier.  On a write cycle, the DMA chip gives you
60 ns of setup on A1, data, and R/_W before asserting _HDCS for about
250 ns, then holds for no more than 20 ns.  On a read cycle, you get
the same setup for A1 and R/_W, and you must give the DMA chip 100 ns
setup on the data before _HDCS is retracted.  Hold time should be less
than 80 ns.
     
        Data cycles are initiated by the external controller by
asserting _DRQ.  _ACK will be asserted by the DMA chip no more than 240
ns later.  _DRQ may then be retracted.  _ACK is asserted for about 250
ns.  In a read operation (data from controller to memory) data should
be setup 60(?) ns before _ACK is retracted and held for 50(?) ns.  In a
write operation (data from memory to controller) data is valid 60 ns
before _ACK is asserted until 60 ns after _ACK is retracted. _DRQ for
the next cycle may not be asserted earlier than 240 ns after _ACK has
been retracted.
     
INTERFACING IT
     
        This interface transfers a byte into the the DMA chip whenever
a rising edge is seen on the data strobe input.  It cannot coexist with
a hard disk because it will respond to commands intended for the hard
disk.  Bear with me, we'll tackle that issue later.
     
        Rather than attempt to render several schematics in ASCII I
will describe the circuits and let you draw the schematics.  If the
instructions don't make any sense you probably should not attempt to
make the interface.  It's all very simple if you know exactly what you
are doing; if you don't - you're dead.
     
A SIMPLE, READ/WRITE INTERFACE
     
        If all you want to do is read and write bytes it is very
simple:  You simply use the Chip Select, R/_W, and A1 lines to select
two write registers and two read registers.  If you need more than that
all you have to do is use A1=0 to select an address register which
selects the register you get on a cycle with A1=1.  One thing that you
have to consider is that the ST writes to the Hard Disk Port several
times during its booting procedure, presumably to determine if there
are any hard disks connected.  Apparently, if no interrupt is received
in response to these writes the ROM assumes that no controller is
connected.
     
        In my interface there is a mode register which is accessed when
A1=0.  It has two control bits and two bits connected to a decoder
which determines which of three other registers are selected when
A1=1.
     
ADDING AN INTERRUPT
     
        If an interrupt is needed (probably why you want to use this
port) you need a flipflop to store the interrupt state and some way to
reset it.  I used a 74LS74 for the flipflop with a diode on the output
to get the open-collector action.  This diode is not needed if there is
no other device on the Hard Disk Port. (But don't scrimp on a diode...)
I reset the interrupt with any access to the mode register but other
methods would work as well.  Make sure that the circuit will always
leave reset with the interrupt cleared.  I arranged this by having a
circuit enable bit in the Mode register, which is cleared by system
reset.  If you screw up on this your floppy will not work because the
same interrupt is used for both floppy and hard disk controllers.  I
learned a little about the file system the hard way while debugging
this interface - I recommend getting the interrupt reset system right
the first time.
     
ADDING DMA
     
        Once you can write to your mode register adding DMA transfers
(at least for read operations) is very simple.  All you need is another
flipflop to do the Data Request synchronization and a 3-state octal
latch (74LS374) to hold the data.  Connect the output to the _DRQ line
with a diode as with the interrupt flipflop.  When data is available
clock it into the data register and clock a zero into the flipflop.
This generates a data request for the DMA chip.  When it gets around to
it the DMA chip will assert _ACK, which means it is ready to accept the
data.  Since you have the _ACK signal connected to the three-state
enable pin on the data register the data is driven onto the bus.  You
also use the _ACK signal to set the flipflop.  When the DMA chip no
longer needs the data it will retract _ACK and you can begin another
transfer.  Spurious data requests are not as nasty as spurious
interrupts because the DMA chip does not listen to hard disk data
requests if it is listening to the floppy disk controller.  Naturally,
if there is a real hard disk out there, there had better not be any
spurious data requests.
     
CO-EXISTING WITH A HARD DISK
     
        I do not own a hard disk; therefore, the suggestions in this
section are totally untested.
     
        The Atari-defined protocol allows eight different controllers
on the DMA bus.  In order to make an interface which will not interfere
with other controllers you must understand the protocol.  Each command
is initiated with a processor write cycle which sends out a Command
Byte (A1=0) on the DMA bus.  The most-significant three bits contain
the controller number and the remaining bits contain an operation
code.  The controller whose number matches the controller number in the
Command Byte responds to the operation code.  Some operations require
parameters, which are sent as Data Bytes (A1=1) following the Command
Byte.  The controller generates an interrupt after coping with each
byte.  After the last Data Byte is sent the controller takes over the
bus for the DMA transfer.  When the transfer is finished the controller
generates an interrupt.
     
        In order to keep out of the way of other controllers on the bus
it should only be necessary to select your interface with a Command
Byte with the proper format.  After that use data bytes as you wish,
since all other controllers will not be selected.
     
A DRIVER
     
        A sample driver is part of this article.  It is written in Mark
Williams C (plug: a most excellent product) in three parts "dma.h",
"dma.c", and "dmaint.s".  This driver contains knowledge of the DMA
chip only;  use it to write your own driver with knowledge of your own
interface.
     
CONCLUSIONS, OR, HAPPY HACKING!
     
        In spite of the intimidating lack of reasonable documentation
the Hard Disk Port is actually simple and easy to use.  Go to it: you
can now hook up almost anything to your ST.
     
=====================================================================
     
/***
* dma.h - Public interface to Hard Disk Port interface.
*
* See description of DMA chip for more details on these operations.
*
*** D.J. Collinge 88.05.01 ***/
     
/***
* Floppy check locking.
* The floppy is checked for media change frequently in the VBL
* interrupt handler.  This process uses the DMA chip.  To prevent
* this periodic operation from interfering with our DMA operations
* we must lock out the floppy with floff() then resume with flon()
* when finished.
***/
extern void flon();
extern void floff();
     
/***
* DMA buss processor cycles.
* Data is moved on the buss in one of two ways: processor cycles and
* DMA cycles.  These routines generate processor cycles.
***/
extern void dmawcmd(); /* (byte) char byte; */
        /* Write a byte to interface with A0=0. */
     
extern void dmawdat(); /* (byte) char byte; */
        /* Write a byte to interface with A0=1. */
     
extern char dmarcmd();
        /* Read a byte from interface with A0=0. */
     
extern char dmardat();
        /* Read a byte from interface with A0=1. */
     
/***
* Initiate DMA transfer.
* To do DMA we need to initialize the DMA chip address counter and to
* load the sector count register with the number of 512-byte blocks
* to transfer (at maximum).  If the interface tries to transfer exactly
* that many blocks, fine; if fewer, the sector count will not hit zero;
* if more, the DMA chip will not transfer the excess, thus protecting
* what lies beyond the buffer.
***/
extern void dmastart(); /* (buffer,blocks) char *buffer; short blocks; */
        /* Start DMA transfer loading DMA address counter to 'buffer'
         * and transferring 'blocks' 512 byte blocks.
         **/
     
/***
* Status requests.
* The DMA chip has a status register, whose contents are returned by
* dmastat().  This must not be done during a transfer or the transfer
* will be screwed up.
***/
extern short dmastat(); /* Return DMA chip status word. */
     
/***
* Interrupts.
* A DMA interrupt signals the end of a transfer.  Interrupts are handled
* by the 68901 MFP chip.  The interrupt can actually be taken if enabled
* or simply sniffed or polled with dmatirq().
***/
extern short dmatirq(); /* Return zero if no interrupt pending. */
     
extern void dmadis(); /* Disable DMA interrupts. */
     
extern void dmaena(); /* Enable DMA interrupts. */
     
extern void dmasetv(); /* (func) void (*func)(); */
        /* Set up interrupt handler so C function func() will be called. */
     
=====================================================================
     
/***
* dma.c - Driver for Hard Disk Port interface.
*
* See description of DMA chip for more details.
* For the function of these routines see dma.h.
*
*** D.J. Collinge 88.05.01 ***/
     
#include "dma.h"
#include <osbind.h>
     
/* These are for Mark Williams C. */
#define DMADWORD        long
#define DMAWORD         short
#define DMABYTE         char
     
/***
* Definitions of registers of DMA chip.  Done in this weird way
* to fool the compiler into accepting these as either r- or l-values.
***/
#define DMADATA (*(DMAWORD*)0xff8604L)
#define DMASTATUS       (*(DMAWORD*)0xff8606L)
#define DMAMODE (*(DMAWORD*)0xff8606L)
#define DMACOUNTH       (*(DMABYTE*)0xff8609L)
#define DMACOUNTM       (*(DMABYTE*)0xff860bL)
#define DMACOUNTL       (*(DMABYTE*)0xff860dL)
     
#define MFPGPIP  0xfffa01L              /* General purpose I/O port. */
#define GPIPMASK 0x20                   /* Which bit in the GPIP DMA ints
                                         * are hooked up to.
                                         */
#define MFPISRB (*(DMABYTE*)(0xfffa11L))        /* In-service reg B */
#define DMABIT 7                        /* mfp interrupt number. */
     
#define FLOCK   (*(DMAWORD*)0x43e)
     
void flon()
{       FLOCK = 0;
}
     
void floff()
{       FLOCK = 1;
}
     
void dmawcmd(byte)
DMABYTE byte;
{       DMAMODE = 0x88;         /* Select A0=0. */
        DMADATA = byte;
}
     
void dmawdat(byte)
DMABYTE byte;
{       DMAMODE = 0x8a;         /* Select A0=1. */
        DMADATA = byte;
}
     
DMABYTE dmarcmd()
{       DMAMODE = 0x88;         /* Select A0=0. */
        return DMADATA;
}
     
DMABYTE dmardat()
{       DMAMODE = 0x8a;         /* Select A0=1. */
        return DMADATA;
}
     
void dmastart(buffer,blocks)
char *buffer;
DMAWORD blocks;
{
        DMACOUNTL = ((DMADWORD)buffer)&0xff;            /* Load buffer addr. */
        DMACOUNTM = (((DMADWORD)buffer)>>8)&0xff;
        DMACOUNTH = (((DMADWORD)buffer)>>16)&0xff;
     
        DMAMODE = 0x190;                /* Toggle R/_W to clear DMA status. */
        DMAMODE = 0x090;
     
        DMADATA = blocks;               /* Load number of blocks to be sent. */
     
        DMAMODE = 0;            /* Tell chip to start listening to DRQ. */
}
     
DMAWORD dmastat()
{       return DMASTATUS&7;
}
     
int dmatirq()
{       return (MFPGPIP&GPIPMASK) == 0;
}
     
void dmadis()
{       Jdisint(DMABIT);
}
void dmaena()
{       Jenabint(DMABIT);
}
     
void (*dmavect)() = 0;
     
extern void dmairq();
     
void dmasetv(func)
void (*func)();
{       dmadis();               /* Make sure a nasty thing won't happen. */
        dmavect = func;
        Mfpint(DMABIT,dmairq);
}
     
=====================================================================
     
/ Essentially assembler parts of the DMA module.
/ Written in this stupid MWC assembler format, sorry.
/ D.J. Collinge 88.05.02
     
MFPISRB = 0xfffa11                      / In-service reg B
DMABIT  = 7                             / Bit number of DMA interrupt.
     
        .globl dmavect_                 / Pointer to what to call on interrupt.
        .globl dmawcmd_                 / Write a byte to interface.
     
        .shri
     
/ dmairq_
/ The machine interrupt handler, which returns via RTE.  It clears the
/ interrupt state of the MFP chip and calls what is pointed to by
/ dmavect_.
/
        .globl dmairq_
dmairq_:
/       Hardware vector for DMA interrupt.  Not C-callable.
     
        movem.l ${a0-a6,d0-d7},-(sp)
     
        bclr    $DMABIT,MFPISRB         / Clear mfp chip status.
     
        movea.l dmavect_,a0             / Get subroutine to call.
        jsr     (a0)
     
        movem.l (sp)+,${a0-a6,d0-d7}
        rte
     
===================================================================
     
END OF IT ALL

