Article View: alt.msdos.programmer
Article #1456Re: oop in pascal - help needed!
From: Michael Tippach
Date: Wed, 19 Aug 1998 00:00
Date: Wed, 19 Aug 1998 00:00
230 lines
7578 bytes
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
Technical Details
Message-ID:
<HLPFRAALAz21Ews6@wuschel.demon.co.uk>Path:
arc1-ca.pugleaf.net!unknown!not-for-mailReferences:
<01bdca19$cb831300$640c1bc4@Merkosh.iwwn.com.na> <35DAD0FB.1E9CCA28@physik.tu-muenchen.de>Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: f8a86,87a99d11cf64563f X-Google-Attributes: gidf8a86,public X-Google-Thread: f9e32,87a99d11cf64563f X-Google-Attributes: gidf9e32,public X-Google-Thread: 13ed84,87a99d11cf64563f X-Google-Attributes: gid13ed84,public X-Google-Thread: 111659,87a99d11cf64563f X-Google-Attributes: gid111659,public X-Google-Thread: 110467,87a99d11cf64563f X-Google-Attributes: gid110467,public X-Google-Thread: 10261c,87a99d11cf64563f X-Google-Attributes: gid10261c,public X-Google-Thread: 102bfa,87a99d11cf64563f X-Google-Attributes: gid102bfa,public X-Google-Thread: 10cc59,87a99d11cf64563f X-Google-Attributes: gid10cc59,public From: Michael Tippach <Spammer.Drop.Dead@wuschel.demon.co.uk> Subject: Re: oop in pascal - help needed! Date: 1998/08/19 Message-ID: <HLPFRAALAz21Ews6@wuschel.demon.co.uk> X-Deja-AN: 382751777 Distribution: world X-NNTP-Posting-Host: wuschel.demon.co.uk:212.228.176.171 References: <01bdca19$cb831300$640c1bc4@Merkosh.iwwn.com.na> <35DAD0FB.1E9CCA28@physik.tu-muenchen.de> X-Complaints-To: abuse@demon.net X-Trace: news.demon.co.uk 903558051 nnrp-02:18475 NO-IDENT wuschel.demon.co.uk:212.228.176.171 Organization: really bad, I mean it! MIME-Version: 1.0 Newsgroups: alt.msdos.programmer,comp.lang.pascal,comp.lang.pascal.borland,comp.lang.pascal.misc,comp.msdos.programmer,fido.ger.pascal,fido.pascal_ger,fido.pascal-ger,fidonet.pascal