Работа с DSP и DMA

unit DSP_DMA;
interface

procedure DspOut(val:byte);         {выводит байт на DSP} 
procedure SetupDMA(dmach,page,ofs,DMAcount,dmacmd:word);
                                   {установка режима DMA}
procedure SetupDSP(dspcmd, mode, DSPcount, tc:word);
                                   {установка режима DSP}
procedure SetMixer;       
                  {сброс платы и выбор источника сигнала}
procedure EnableInterrupt(newvect:pointer);
                          {установка векторов прерываний}
procedure DisableInterrupt;
                     {восстановление векторов прерываний}

implementation
uses getsbinf,crt,dos;

var
   intvecsave      :pointer;  { старый вектор прерывания}
   intrnum         :integer;  { номер прерывания        }
   intrmask        :integer;  { маска прерывания        }

{ структура, содержащая данные контроллера DMA }
type
   DmaPortRec = record
      addr,count,page : byte;
   end;
const
   DmaPorts : array[0..7]of DmaPortRec = (
    (addr:$00; count:$01; page:$87),  {0}
    (addr:$02; count:$03; page:$83),  {1}
    (addr:$04; count:$05; page:$81),  {2 не используется}
    (addr:$06; count:$07; page:$82),  {3}
    (addr:$00; count:$00; page:$00),  {4 не используется}
    (addr:$C4; count:$C6; page:$8B),  {5}
    (addr:$C8; count:$CA; page:$89),  {6}
    (addr:$CC; count:$CE; page:$8A)); {7}

procedure DspOut(val:byte);{выводит байт в DSP}
begin
   while (Port[base + $0C] and $80) <> 0 do;
   Port[base + $0C] := val;
end;

function DspIn:byte;{читает байт из DSP}
begin
   while (Port[base + $0E] and $80) = 0 do;
   dspin := Port[base + $0A];
end;

procedure SetupDMA(dmach,page,ofs,DMAcount,dmacmd:word);
                          { Программирует контроллер DMA}
                       { для 8- или 16-разрядного канала}
var
   mask,mode,ff : byte;
begin
   if (dmach < 4) then begin
      mask := $0A;
      mode := $0B;
      ff   := $0C;
   end else begin
      mask := $D4;
      mode := $D6;
      ff   := $D8;
      ofs := (ofs shr 1) + ((page and 1) shl 15);
   end;
   Port[mask]  := 4 or dmach;  { маскируем DMA}
   Port[FF]    := 0;        { сбрасываем триггер-защелку}
   Port[mode]  := dmacmd or (dmach and 3);
                                        { уст.режима DMA}
   Port[dmaports[dmach].addr]  := lo(ofs);
                                   { младший байт адреса}
   Port[dmaports[dmach].addr]  := hi(ofs);{ старший байт}
   Port[dmaports[dmach].page]  := page; { номер страницы}
   Port[dmaports[dmach].count] := lo(DMAcount-1);
                                 { младший байт счетчика}
   Port[dmaports[dmach].count] := hi(DMAcount-1);
                                          { старший байт}
   Port[mask]  := (dmach and 3);   { сброс бита маски}
end;

procedure SetupDSP(dspcmd, mode, DSPcount, tc:word);
                      { Программирует DSP звуковой платы}
begin
   DspOut($40);             {установка константы времени}
      DspOut(tc);
   DspOut(dspcmd);                        {команда Bx/Cx}
      DspOut(mode);
      DspOut(lo(DSPcount-1));
      DspOut(hi(DSPcount-1));
end;

procedure SetMixer;{сброс платы и выбор источника сигнала}
var
   val:byte;
begin
   Port[base + $06] := 1; {сброс DSP}
   delay(1);
   Port[base + $06] := 0;
   if (dspin <> $AA) then {проверка готовности}
         writeln(?Sound Blaster не готов.?);
   Port[base + $04] := $3D;
   Port[base + $05] := 1;
               { левый канал:источник сигнала — микрофон}
{   Port[base + $04] := $3E;  {для моно — не обязательно}
{   Port[base + $05] := 1; }
              { правый канал:источник сигнала — микрофон}
   Port[base + $04] := $3C;
   Port[base + $05] := 0;
                    { на выходе отключаем все, что можно}
end;

procedure EnableInterrupt(newvect:pointer);        
                   {установка векторов прерываний}
var intrmask1:word;
begin
   if (irq < 8) then {вычисляем номера прерывания}
      intrnum := irq + 8  { для IRQ 0-7 прерывания 8-15.}
   else
      intrnum := irq - 8 + $70;
                      { для IRQ 8-15 прерывания 70H-78H.}
   intrmask := 1 shl irq; {маска}
   GetIntVec(intrnum,intvecsave);
                               { сохраняем старый вектор}
   SetIntVec(intrnum, newvect);
                            { устанавливаем новый вектор}
   intrmask1 := intrmask;          
{разрешаем прерывания}
   Port[$21] := Port[$21] and not intrmask1;
   intrmask1 := intrmask1 shr 8;
   Port[$A1] := Port[$A1] and not intrmask1;
end;

procedure DisableInterrupt;
                     {восстановление векторов прерываний}
var  intrmask1:word;
begin
   intrmask1 := intrmask; {запрещаем прерывания}
   Port[$21] := Port[$21] or intrmask1;
   intrmask1 := intrmask1 shr 8;
   Port[$A1] := Port[$A1] or intrmask1;
   SetIntVec(intrnum,intvecsave);{восстанавливаем вектор}
end;

end.