🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: alt.msdos.programmer
3 messages
3 total messages Started by Merkosh Mon, 17 Aug 1998 00:00
oop in pascal - help needed!
#1454
Author: Merkosh
Date: Mon, 17 Aug 1998 00:00
33 lines
2027 bytes
Hi,

I want to program an object that allows an easy installation of a keyboard
interrupt handler. The whole thing should look something like this:

Type	PKeyboard	= ^TKeyboard;
	TKeyboard	= Object
		Scan	: Byte;
		Control	: Byte;

		Constructor Init(Scan, Control : Byte);
		Destructor Done;		Virtual;
		Procedure ActionProcedure;	Virtual;
	End;

Were Scan is the scancode of the key which has to be pressed to start the
procedure ActionProcedure and Control is the control key (shift, alt, etc)
which has to be pressed.
The following implementation is invalid:

	Procedure TKeyoard.ActionProcedure; Interrupt;
	Begin
	...
	End;


If anybody has a CLUE how something like this can be implemented with
virtual mehtods or can explain why this is impossible, please contact me:
<merkosh@iwwn.com.na>

Thanx

Uwe
Re: oop in pascal - help needed!
#1455
Author: Christopher Eltschka
Date: Wed, 19 Aug 1998 00:00
52 lines
3490 bytes
[Mailed and posted]

Merkosh wrote:
> 
> Hi,
> 
> I want to program an object that allows an easy installation of a keyboard
> interrupt handler. The whole thing should look something like this:
> 
> Type    PKeyboard       = ^TKeyboard;
>         TKeyboard       = Object
>                 Scan    : Byte;
>                 Control : Byte;
> 
>                 Constructor Init(Scan, Control : Byte);
>                 Destructor Done;                Virtual;
>                 Procedure ActionProcedure;      Virtual;
>         End;
> 
> Were Scan is the scancode of the key which has to be pressed to start the
> procedure ActionProcedure and Control is the control key (shift, alt, etc)
> which has to be pressed.
> The following implementation is invalid:
> 
>         Procedure TKeyoard.ActionProcedure; Interrupt;
>         Begin
>         ...
>         End;
> 
> If anybody has a CLUE how something like this can be implemented with
> virtual mehtods or can explain why this is impossible, please contact me:
> <merkosh@iwwn.com.na>

The problem is that interrupt procedures are a very special thing,
and methods are another very special thing. The speciality
of interrupt procedures is that they save the complete register set;
the pseudo arguments which you can give on the definition just
reference the saved registers on stack.
Methods OTOH have a hidden extra parameter, the self parameter.
This parameter tells the method on which object it was invoked.
Now, an interrupt is never invoked on an object, it's invoked
on the system (one could, of course, view the system as an object
with the interrupt table being the virtual method table).
So there's no self parameter on an interrupt, and therefore an
interrupt handler cannot be a method.

However, there's one way you can get your effect anyway:
Maintain a global pointer to the current Keyboard object,
and let the interrupt procedure call your method on that
object. Functions called from interrupt functions may be
just normal functions (except for some limitations due to
non-reentrancy of DOS), including methods.
Re: oop in pascal - help needed!
#1456
Author: Michael Tippach
Date: Wed, 19 Aug 1998 00:00
230 lines
7578 bytes
In article <35DAD0FB.1E9CCA28@physik.tu-muenchen.de>, Christopher
Eltschka <celtschk@physik.tu-muenchen.de> writes
>Merkosh wrote:
>> 
>> Hi,
>> 
>> I want to program an object that allows an easy installation of a keyboard
>> interrupt handler. The whole thing should look something like this:
>> 
>> Type    PKeyboard       = ^TKeyboard;
>>         TKeyboard       = Object
>>                 Scan    : Byte;
>>                 Control : Byte;
>> 
>>                 Constructor Init(Scan, Control : Byte);
>>                 Destructor Done;                Virtual;
>>                 Procedure ActionProcedure;      Virtual;
>>         End;
>> 
>> Were Scan is the scancode of the key which has to be pressed to start the
>> procedure ActionProcedure and Control is the control key (shift, alt, etc)
>> which has to be pressed.
>> The following implementation is invalid:
>> 
>>         Procedure TKeyoard.ActionProcedure; Interrupt;
>>         Begin
>>         ...
>>         End;
>> 
>> If anybody has a CLUE how something like this can be implemented with
>> virtual mehtods or can explain why this is impossible, please contact me:
>> <merkosh@iwwn.com.na>
>
>The problem is that interrupt procedures are a very special thing,
>and methods are another very special thing. The speciality
>of interrupt procedures is that they save the complete register set;
>the pseudo arguments which you can give on the definition just
>reference the saved registers on stack.
>Methods OTOH have a hidden extra parameter, the self parameter.
>This parameter tells the method on which object it was invoked.
>Now, an interrupt is never invoked on an object, it's invoked
>on the system (one could, of course, view the system as an object
>with the interrupt table being the virtual method table).
>So there's no self parameter on an interrupt, and therefore an
>interrupt handler cannot be a method.
>
>However, there's one way you can get your effect anyway:
>Maintain a global pointer to the current Keyboard object,
>and let the interrupt procedure call your method on that
>object. Functions called from interrupt functions may be
>just normal functions (except for some limitations due to
>non-reentrancy of DOS), including methods.

There is a more generic way to solve this. The idea is that you
create some code in the private data area of your object and
make the interrupt vector point to that code. This code would
preload the argument list passed to the method to call with a
reference to self and it could also be used to save/restore
registers as necessary in an interrupt procedure.

I've written some code a while ago that does just this. Even
though it is Delphi 32 bit code, it should demonstrate the idea.


unit OOinterr;

{ 

   Allowes routing of hardware interrupts to object instance members.

   Usage Example:


type

   TMyEvenGreaterClass = class(MyGreatClass)

   private
      MyInterrupt: TInterrupt;
      procedure TheUltimateISR;register;

      ... blah blah blah

   
constructor TMyEvenGreaterClass.Create(MyArguments: TMyArguments);
begin

   ...

   MyInterrupt:=TInterrupt.Create(MyHardwareDevice.GetIRQ,self,@TheUltim
ateISR);

   ... 

end;

destructor TMyEvenGreaterClass.Destroy;
begin
   Nuke(SomeOtherStuff);
   MyInterrupt.Destroy;
end;

procedure TMyEvenGreaterClass.TheUltimateISR;register;
begin
   
   ... can access instance members now ...

   if NeedToChain then MyInterrupt.CallOldHandler else
MyInterrupt.Acknowledge;
end;

}

interface

type

   TClassInterruptGlueCode = packed record
      OpMovEAXImm: byte;
      ImmOperand: TObject;
      OpJmpNear: byte;
      Disp32: longint;
   end;

   TInterrupt = class(TObject)

      protected
         Wrapper: TClassInterruptGlueCode;
         OldHandler: pointer;
         IntNumber: byte;
         IntMask: byte;
         WasEnabled: boolean;
         PICPort: word;

      public
         procedure Acknowledge;
         procedure CallOldHandler; register;
         Constructor Create(IRQ: integer; Owner: TObject; Handler:
pointer);
         Destructor Destroy;

   end;

   { Usage example for a keyboard handler }

   TKeyboardInterrupt = class(TInterrupt)

      public
         Constructor Create(Owner: TObject; Handler: pointer);
         procedure Acknowledge;

   end;


implementation
uses dos;

Constructor TInterrupt.Create(IRQ: integer; Owner: TObject; Handler:
pointer);
begin
   if IRQ and 15 > 7 then begin
      IntNumber := (IRQ and 15) + $68;
      PICPort := $A0;
      IntMask := 1 shl (IRQ - 8);
   end else begin
      IntNumber := (IRQ and 15) + 8;
      PICPort := $20;
      IntMask := 1 shl IRQ;
   end;
   if IntNumber = 10 then begin
      IntNumber := $71;
      PICPort := $A0;
      IntMask := 2;
   end;
   WasEnabled := ((port[PICPort+1] and IntMask) = 0);

   { 

      Created code:

      mov  eax,Owner
      jmp  Handler

   }

   Wrapper.OpMovEAXImm := $B8;
   Wrapper.ImmOperand := Owner;
   Wrapper.OpJmpNear := $E9;
   Wrapper.Disp32 := longint(@Handler)-longint(@Wrapper.Disp32)+4;

   GetIntVec(IntNumber,OldHandler);
   SetIntVec(IntNumber,@Wrapper);
   if not WasEnabled then port[PICPort+1] := port[PICPort+1] and
not(IntMask);
   if IntNumber > 15 then port[$21] := port[$21] and $FB;
end;

Destructor TInterrupt.Destroy;
begin
   if not WasEnabled then port[PICPort+1] := port[PICPort+1] or IntMask;
   SetIntVec(IntNumber,OldHandler);
end;

procedure TInterrupt.Acknowledge;
begin
   if IntNumber > 15 then port[$A0]:=$20;
   port[$20]:=$20;
end;

procedure TInterrupt.CallOldHandler;register;assembler;
asm
   call dword ptr [eax][TInterrupt.OldHandler];
end;

Constructor TKeyboardInterrupt.Create(Owner: TOBject; Handler: pointer);
begin
   inherited Create(1, Owner, Handler);
end; 

procedure TKeyboardInterrupt.Acknowledge;
begin
   port[$61]:=port[$61] or $80;
   port[$61]:=port[$61] and $7F;
   inherited Acknowledge;
end;

end.

-- 
Michael Tippach
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads