Работа с 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.