delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2009/05/15/00:46:27

X-Authentication-Warning: delorie.com: mail set sender to djgpp-bounces using -f
Newsgroups: comp.os.msdos.djgpp
Date: Fri, 15 May 2009 04:37:54 GMT
From: "A. Wik" <root AT dynamite DOT narpes DOT com>
Subject: Re: An interrupt drived uart program dead
In-Reply-To: <dcff139d-32b8-4f22-ab4a-6f7e78f81324@c18g2000prh.googlegroups.com>
Message-ID: <Pine.LNX.4.60.0905150327230.1746@narpes.com>
References: <dcff139d-32b8-4f22-ab4a-6f7e78f81324 AT c18g2000prh DOT googlegroups DOT com>
Organization: DOS Research Labs
Mail-To-News-Contact: abuse AT dizum DOT com
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp
Reply-To: djgpp AT delorie DOT com
Errors-To: nobody AT delorie DOT com
X-Mailing-List: djgpp AT delorie DOT com
X-Unsubscribes-To: listserv AT delorie DOT com

On Thu, 14 May 2009, [ISO-2022-JP]  wrote:

> I wrote a program under djgpp to drive PC UART. the program is
> interrupt-drived. When run the program, the data has sent, but then
> the PC halt. I can't find any bug in the program. So ask for help.
> below is the program code.
> 
> #include <dos.h>
> #include <stdio.h>
> #include <stddef.h>
> #include <pc.h>
> #include <dpmi.h>
> #include <go32.h>
> 
> #define LOCK_VARIABLE(x)    _go32_dpmi_lock_data((void *)&x,(long)
> sizeof(x));
> #define LOCK_FUNCTION(x)    _go32_dpmi_lock_code(x,(long)sizeof(x));

The smallest object you can lock with DPMI lock is
a page, which on the x86 is never smaller than 4096
bytes in size (the VAX, which has the smallest pages
as far as I know, uses 512).  I don't know how these
_go32.*lock*() routines react if you specify sizes
that aren't a multiple of 4096, so you might want to
verify that.

Anyway, looking further down, you don't seem to be
calling the locking routines mentioned above.  If
you're working under an environment that does page
swapping, demand paging, etc. you should lock all
code and data needed at interrupt time (including
the stack).

Based on the code below, I presume that you're
working in a plain DOS environment with a non-paging
DPMI host, in which case the above locking issue is
unlikely to be of relevance.

> const unsigned int baseAddress = 0x3f8;
> const byte commIrq = 0x04;
> const byte commIntr = 0x0c;
> bool txIdle = true;
> 
> _go32_dpmi_seginfo OldISR, NewISR;
> byte oldIMR;
> 
> void commISR();

I'm not certain that the above is sufficient to declare
an interrupt handler.  You may have to add some attribute
that informs the compiler not to make any assumptions
about the values of different registers upon entry to the
procedure, and furthermore, to comply with all
requirements applicable to an interrupt handler, such as
saving and restoring all registers modified.  Stacks may
have to be switched as well.  Perhaps the DJGPP routines
(_go32_dpmi.* etc.) that you use to install the handler
also makes the necessary arrangements, so that you don't
have to worry, but you need to verify that.

Furthermore, it is important to instruct the compiler not
to make certain optimisations, such as reordering
statements that interact with the hardware, as that may
produce unpredictable results.

> 
>    _go32_dpmi_get_protected_mode_interrupt_vector(commIntr, &OldISR);
>    NewISR.pm_offset = (int)commISR;
>    NewISR.pm_selector = _go32_my_cs();
>    _go32_dpmi_allocate_iret_wrapper(&NewISR);
>    _go32_dpmi_set_protected_mode_interrupt_vector(commIntr, &NewISR);
> 
>    oldIMR = inportb(0x21);
>    byte newIMR = oldIMR & (~(0x01 << 4));
>    outportb(0x21, newIMR);
> }

I'm assuming that you're familiar with the runtime
enviroment in which your code runs.  It is possible for
a DPMI host or other system code to reprogram interrupt
controller so that the IRQ no longer go to the same
vectors normally assumed.  This is another matter you
may have to investigate.

> 
> 
> #define QUEUE_CAPABILITY 16
> byte writeQueue[QUEUE_CAPABILITY];
> uint16_t queueHead = 0, queueTail = 0;
> uint16_t queueSize = 0;
> 
> int asyWriteComm()
> {
>    for(int count = 0; count < QUEUE_CAPABILITY; count ++)
>    {
>       writeQueue[queueTail] = 'a' + count;
>       queueTail = (queueTail + 1) % QUEUE_CAPABILITY;
>       queueSize ++;
>    }
> 
>    byte data = writeQueue[queueHead];
[...]
> 
> void commISR()
> {
[...]
>             byte data = writeQueue[queueHead];
>             queueHead = (queueHead + 1) % QUEUE_CAPABILITY;
>             queueSize --;
>             outportb(baseAddress + OFFSET_THR, data);
>             txIdle = false;

You may have to declare these data structures you're
accessing from the interrupt handler and from normal
code "volatile" to inform the compiler not to make
certain assumptions that may be hazardous in the
context of asynchronous, real-time events.

Also, regarding the loop:
   do {
   } while(queueSize != 0);

It may be a good idea to look into the HLT
instruction or the DPMI idle call, in order to
reduce heat generation and power consumption.
HLT causes the processor to halt until it
receives an interrupt.

One other thing: the interrupt may have to be
acknowledged (e.g. a Specific EOI for the IRQ in
question, or the more popular non-specific EOI).
Either your handler or the wrappers installed by
DJGPP/DPMI will have to acknowledge, or you may
receive no further interrupts (including any
unrelated interrupts with lower priority).  There
are some exceptions, such as the rarely used
automatic EOI mode of the PIC (I think Plan9
uses it).   (And of course, there's the IO-APIC.)

-aw

- Raw text -


  webmaster     delorie software   privacy  
  Copyright 2019   by DJ Delorie     Updated Jul 2019