🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.modula2
Article #2877

Re: PLEASE HELP: M2 AND INTERRUPTS

#2877
From: "Mark Morgan Lloyd "
Date: Wed, 04 Oct 1995 15:26
181 lines
6819 bytes
> Hello!
> 
>        I am using TopSpeed M2 compiler v3.10. I am trying to program
> Synchronous Modem Card in PC (on DOS).  I have an Interrupt 
> service routine for the SCC on the card. I have two coroutines: one for
> implementing BISYNC protocol and one for User Interface. Reading the 
> TopSpeed manuals, I figure that there are two ways to write ISR's in M2 
> :

Righty-ho. I'll email this in case Usenet folds up, but will also leave 
this in the newsgroup since it may be of general interest.

The first thing that has to be asked is whether you are using coroutines 
elsewhere in the program (apparently yes), since the priority (i.e. 
16-bit PIC mask) is held (IIRC) on a per-coroutine basis. If this is 
happening then you will need to artificially pass the priority between 
coroutines (which is cheating) or adjust the PIC mask by direct hardware 
access (which is worse than cheating).

> (1) (*# save, call(interrupt => on, reg_param=>(), same_ds =>off) *) 

You may also find check(stack=>off) to be a good idea. I'm not condoning 
running with checks disabled, but TopSpeed (in fact almost all) 
stack-checking code gets confused inside an ISR (often also inside 
coroutines particularly if stack sizes differ).

>      PROCEDURE IntHandler;
>       BEGIN
>                :
>                :
>               Out(020H, 020H);  (* eoi *)
>       END IntHandler;
>       (*#restore*)

This looks fairly decent and is, in fact, the method I normally use. Note 
that, depending on the hardware, you may find it advisable not to assume 
that there will be precisely one interrupting condition per invocation of 
the ISR, i.e. use WHILE or LOOP.

> (2) PROCEDURE IntHandler;
>      BEGIN
>              LOOP
>                    IOTRANSFER(IntProc, MainProc, 0BH);
>                    :
>                    :
>              END;
>      END IntHandler;
> 
> The software runs fine as long as I have no coroutines (ie. i implement
> the protocol and User Interface in a single thread). When I start
> using coroutines ie TRANSFER(), my machine locks up.   

See my comment on coroutines/priorities above. When you say locks up, is 
it the program that lock up, or the entire computer (i.e. does <Caps 
Lock> still change the state of the LED?)

>  What I want to know is 
> (1)    what is the difference between two methods shown above ?

Your method (1) does not fiddle with the PIC.

> (2)    Is there a special method to implement ISR's when using 
> MultiThreading ?

I do this a lot, with the coroutine mechanism encapsulated within a 
non-preemptive portable microkernel. I use your method (1) with the ISR 
transferring data to/from a microkernel queue (all code is reentrant or 
locked) with non-preemptive processes handling the other side of the 
queue. As an example, this code fragment is from a (non-PC) 16450 handler 
(I'm also driving SCCs but do not have a mature ISR for them at present), 
note that the ISR entry points are declared in the definition module 
hence this is where the pragmas are located:

Definition module:

(*# save, call(seg_name=>DatagramIsr, interrupt=>on, reg_param=>())     *)
(*# call(same_ds=>off), check(stack=>off)                               *)

PROCEDURE AceIrq1;
PROCEDURE AceIrq2;

(* Interrupt entry points for SCPU PC-compatible serial ports A and B.  *)

(*# restore                                                             *)

Implementation module:

(*# save, call(seg_name=>DatagramIsr)                                   *)

PROCEDURE aceIrq(port: CARDINAL);

(* Common IRQ code.                                                     *)

CONST   iir= 2;
        msr= 6;
        lsr= 5;

VAR     intType, scratch: SHORTCARD;

BEGIN
  WITH PortArray[port] DO
    intType:= In(base + iir);
    WHILE NOT ODD(intType) DO
      CASE (intType >> 1) MOD 8 OF
        0:    scratch:= In(base + msr) |                (* Modem status *)
        1:    LOOP                                      (* Tx empty     *)
                IF NOT ODD(In(base + lsr) >> 5) THEN
                  EXIT
                END;
                IF ReadQueueConditional(out, scratch) THEN
                  Out(base, scratch)
                ELSE
                  EXIT
                END
              END |
        2, 6: WHILE ODD(In(base + lsr)) DO              (* Rx buffer    *)
                scratch:= In(base);
                IF WriteQueueConditional(in, scratch) THEN
                END
              END |
        3:    scratch:= In(base + lsr)                  (* Line status  *)
      ELSE
      END;
      intType:= In(base + iir)
    END
  END;

(* Interrupt handling is complete, issue EOI to the master and slave    *)
(* PICs.                                                                *)

  NonSpecificEoi
END aceIrq;

(*# restore                                                             *)


PROCEDURE AceIrq1;

(* Interrupt entry points for SCPU PC-compatible serial ports A and B.  *)

BEGIN
  aceIrq(1)
END AceIrq1;


PROCEDURE AceIrq2;

(* Interrupt entry points for SCPU PC-compatible serial ports A and B.  *)

BEGIN
  aceIrq(2)
END AceIrq2;

These are not, in fact, hooked directly onto the appropriate vectors, 
instead IDT entries are set up (but this is left as an exercise... :-)

> I have even tried using TopSpeed's PROCESS Library with no luck. My 
> ISR's are fine because they wrk when I don't use any TRANSFER() calls.

The process module is fine within its limitations. It's a long time since 
I've used it. One thing that might be of use to you would be to get a 
copy of the Comms toolkit (NOT the RS modules that come with some 
variants of the TopSpeed system) since this was written by Don Milne who 
Knows What He Is Doing :-) and, among other things, wrote the Odyssey 
comms program; credit is due to him for originally pointing out the 
priority problem discussed above.

> Any hints, suggestions would be appreciated.  Please help before I am 
> forced to switch to using C.

Go wash your mouth out :-)

But seriously, if you switched to C you would not have access to 
coroutines so any technique you used there would also be applicable to 
Modula-2.

Mark Morgan Lloyd
mark_tbu@cix.compulink.co.uk

[Opinions above are the author's, not those of his employers or 
colleagues]
Technical Details
Message-ID: <DFxK8C.549@cix.compulink.co.uk>
Path: arc1-ca.pugleaf.net!cix.compulink.co.uk!usenet
References: <cmuxdv1.3.00C0F061@primenet.com>

Show Full Headers
Complete Article Headers
Newsgroups: comp.lang.modula2
Path: arc1-ca.pugleaf.net!cix.compulink.co.uk!usenet
From: mark_tbu@cix.compulink.co.uk ("Mark Morgan Lloyd ")
Subject: Re: PLEASE HELP: M2 AND INTERRUPTS
Message-ID: <DFxK8C.549@cix.compulink.co.uk>
Organization: KDG Mobrey Telemetry
References: <cmuxdv1.3.00C0F061@primenet.com>
Date: Wed, 4 Oct 1995 15:26:36 GMT
X-News-Software: Ameol