home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sound Sensations!
/
sound_sensations.iso
/
midifile
/
midily
/
mpu401.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1989-08-30
|
8KB
|
225 lines
Unit MPU401;
{
****************************************************************************
This Unit is derived from an article written in the May 1989 issue of
Electronic Musician Magazine entitled 'Handling MPU-401 Interrupts with
Turbo Pascal' by William Millar. The Code was coded into Unit form by
John Sloan CIS. 71310,2267.
****************************************************************************
}
Interface
Uses DOS;
Const
MPU_reset = $ff;
MPU_UART_Mode = $3f;
MPU_ack = $fe;
MPU_Dataport =$330;
MPU_Statport =$331;
MPU_Comport =$331;
MPU_Data_Available_Mask = $80;
MPU_Data_Ready_Mask = $40;
MPU_Interrupt_Number = 10;
Buffer_start = 1;
Buffer_End =512; {increase this if there appears to be data loss with
long messages ie. make it 1024, 2048 etc.}
Type
MPU_Comdata_Send_Buffer = ARRAY[1..128] of Byte;
Data_Buffer = Array[Buffer_Start..Buffer_End] of Byte;
Var
MPU_Indata_Buffer : Data_Buffer;
MPU_in_UART_mode : Boolean;
buffer_Head, Buffer_Tail : Word;
Old_Int_Vec : Pointer;
ExitSave:pointer;
Procedure Disable_CPU_Interrupts;
INLINE($FA);{CLI}
Procedure Enable_CPU_Interrupts;
INLINE($FB); {STI}
Procedure Disable_MPU_Interrupts;
INLINE($FA/$BA/$21/$00/$EC/$0C/$04/$EE/$FB);
Procedure Enable_MPU_Interrupts;
INLINE($FA/$BA/$21/$00/$EC/$24/$FB/$EE/$FB);
Procedure Ack_Int_to_PIC;
INLINE($BA/$20/$00/$B0/$20/$EE);
Function Get_Data_From_MPU(Var data:Byte):Boolean;
Procedure Send_Command_to_MPU(Command:Byte);
Implementation
Procedure MPU_Interrupt_Handler;
{***************************************************************************
This routine is called every time the hardware IRQ2 toggles as a result of
data being received by the MPU-401. The hardware vector to this routine is
entered into the PC's interrupt vector table in the initialization section
of this Unit. The pseudocode is something like:
Disable any further interrupts from bothering us
If the status port data available bit is reset then
Write the data to the next location in the buffer
If the pointer to this data location hasn't reached the
end of the buffer then increment it, otherwise make
it point to the beginning of the buffer
Enable the CPU interrupt system
Acknowledge to the PIC chip that we responded to this IRQ
*****************************************************************************
}
Interrupt;
Begin
Disable_MPU_Interrupts;
While((Port[MPU_statport] AND MPU_Data_Available_Mask)=0) DO
Begin
MPU_Indata_BUffer[Buffer_Head]:=Port[MPU_DataPort];
If(Buffer_Head < Buffer_End) Then
Inc(buffer_Head) Else
Buffer_Head:=Buffer_Start
End;
Enable_MPU_Interrupts;
ack_Int_to_PIC;
End;
Function Get_Data_From_MPU;
{
****************************************************************************
Disable CPU interrupts
If the buffer beginning pointer and the end pointer are different then we
must have data therefore:
Renable interrupts so we don't lose any data
Get the data from the buffer
If the pointer to this data isn't at the end of buffer increment it
otherwise reset it to point to the buffer's beginning
If data was available, pass the data back to the calling routine
as well as a boolean true (data available) otherwise
pass a boolean false (data not available)
*****************************************************************************
}
Var
Valid:boolean;
Begin
Disable_MPU_Interrupts;
Valid:=(Buffer_Head <> Buffer_Tail);
Enable_MPU_Interrupts;
If (Valid) then
begin
Data:=MPU_Indata_Buffer[buffer_Tail];
If (Buffer_Tail < Buffer_End)
Then Inc(buffer_Tail)
Else buffer_Tail:=Buffer_Start;
end;
Get_data_From_MPU:=valid
end;{Get..}
Procedure Send_Command_to_MPU;
{
*****************************************************************************
Wait until there is no data in the MPU's buffer then:
Disable interrupts
Send a command byte (ie. MPU reset) to the MPU
If the command was a reset and the MPU was in UART mode
Then set UART_MODE flag false otherwise
Get data from MPU, buffer it as in Get_Data_From_MPU function
until an ACK byte from the MPU comes in
If the command was to put the MPU in UART mode then set UART_MODE flag true;
Enable interrupts
Get out of here
*****************************************************************************
}
Var
Data:Byte;
a:byte;
Begin
Repeat
Until((Port[MPU_Statport] And MPU_Data_Ready_Mask)=0);
Disable_MPU_Interrupts;
Port[MPU_Comport]:=Command;
If (Command = MPU_Reset) and (MPU_in_UART_Mode)
Then MPU_in_UART_Mode:=False
Else Repeat
Repeat
a:=port[mpu_statport];
Until ((Port[MPU_Statport] and MPU_Data_Available_Mask)=0);
Data:=Port[MPU_Dataport];
If (Data <> MPU_ack) Then
Begin
MPU_Indata_buffer[buffer_head]:=data;
If(Buffer_head < buffer_end)
Then Inc(buffer_Head)
Else Buffer_head:=buffer_start;
End;
Until (Data = MPU_ack);
If (Command = MPU_UART_Mode) then MPU_in_UART_Mode:=True;
Enable_MPU_Interrupts
end; {Send_Command..}
{$F+} Procedure Uninstall_MPU401; {$F-}
{
****************************************************************************
This procedure gains control when the program terminates, normal or otherwise
The code is:
Disable interrupts
Put the old IRQ2 interrupt back where it was before we started
Put the pointer to the next exit procedure (if any) back
in Turbo's internal ExitProc pointer
*****************************************************************************
}
Begin
Disable_MPU_Interrupts;
SetIntVec(MPU_Interrupt_Number,Old_Int_Vec);
ExitProc:=ExitSave;
End;
{
*****************************************************************************
This code gets called at the Begin statement of the Main program. The code is
as follows:
Save any Previously stored Exit code address
Put our exit procedure's code into Turbo's intrinsic pointer
Initialize our data buffer to empty
Get the existing IRQ2 interrupt vector and save it
Put in its place the address to our Interrupt service routine
(MPU_Interrupt_Handler)
Enable from the MPU
Set the UART_Mode flag to false
Go and execute the Main Program
*****************************************************************************
}
Begin {initialization Code}
ExitSave:=ExitProc;
ExitProc:=@Uninstall_MPU401;
{Procedure Install_MPU401;}
Buffer_Head := Buffer_Start;
Buffer_Tail := Buffer_Start;
GetIntVec(MPU_Interrupt_Number,Old_Int_Vec);
SetIntVec(MPU_Interrupt_Number,@MPU_Interrupt_Handler);
Enable_MPU_Interrupts;
MPU_In_UART_Mode := False;
End. {Init Code}