Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

TopSpeed-Borland-Windows-DLLs

2 views
Skip to first unread message

Bengt-Inge DalenbŠck

unread,
Sep 7, 1995, 3:00:00 AM9/7/95
to
Hi all,

Now, after having ported a comparatively large project from TopSpeed
3.10 to Windows 3.1 (merging 30 Xtd, and large model programs to one
MDI app), I can report the following.

Once you get the hang of it (and have fixed some things reported in
my earlier longer postings half a year ago) it all works very well!

*** Except for one thing ***

MATHLIB has a problem if e.g. Sin() or, for what it seems, any other
MATHLIB function is called repeatedly in a loop. In such cases a
register is trashed (the one used for the loop variable) and the loop
is terminated prematurely. However, if MATHLIB functions are called one
at a time in the middle of the code it all works fine, and even after
an huge amount of flotating point calculations (and I mean hours worth
of it) the final results are identical to the Xtd DOS program's (also
the speed is nearly identical). If debug is turned on the problem
disapears since the code then changes but of course the execution
speed also goes down, and I can't have that.

So, what to do? In the FIXES.DOC document at the UK BBS there is
*one* problem mentioned with Windows and floats. That did not help.

So, then what to do? I stripped down the code and sent a very simple
program to TopSpeed and they recognized the bug. And, hold your hats,
I received a bugfix! Good news! Well, not quite. After a rebuild of the
libraries it still did not work (also that was recognized by TopSpeed
but no more help to get). It has something to do with which registers
are preserved and not by CoreMath.a under Windows. I don't know enough
assembler to sort it out myself. I know this group has several that
know more low-level ("TopSpeed and assembler" thread...).

So, then what to do? I wrapped all the MATHLIB functions in a DLL and
that obviously changed some function prologs (or whatever) so that it
worked - almost. Now in some very few cases (but still too many...) I
get strange results and e.g. the Str.RealToStr does not give the
correct results (Str calls MATHLIB).

So then what to do? I bought Borland Pascal 7.0 to get some more
Windows documentation and planned to make the same DLL using BP instead.
To create a DLL in BP *without* floating point and call it from
TopSpeed works fine, but as soon as I try the real thing with the BP
Double floats (N+ compiler directive that should be the same as LONGREAL),
I get a GPF. Does anybody with a better low-level understanding have
some advice. The low-level docs for BP are thin and the map-file it
generates for the DLL is not much. E.g. I can't spot the WEP or LibMain
procedures (that are suppose to be named exactly like that and WEP is to
be exported in the EXP-file, in BP it is not explicitly exported but
hidden somewhere) but it works anyway to use the DLL from TopSpeed (i.e.
without floating-point). Borland does seem to do things in an
unorthodox manner.

Some thoughts I have:

1) Can maybee a LONGREAL be passed differently in BP? From what it seems,
it is on the stack as it is supposed to be for a DLL (pragma assures
that in the TS DLL DEF-file). Or is the result returned differently?

2) Can the double float formats be different. Should not be if they both
use the coprocessor 8-byte type? Anyway, it ought not cause a GPF.

3) Is it the init procedures for the math processor that are different
and clashes between TS and BP? I can call the BP DLL from a BP program
without problem but I get GPFs both when calling the TS DLL in BP and
when calling the BP DLL in TS.

4) TS don't use the coprosessor stack but BP does. That should be able
to fix with pragmas but maybe a rebuild of the TS libs are required for
that. I tried some promising prgma settings but no luck since it is
fixed in the LIB anyway.

5) I could create the same DLL with a C-compiler but I may run into the
same problems again if I don't understand the reason.

6) I could make my own versions of some of the math functions if I can
pinpoint the problem functions (not easy to debug since the problem
goes away with debug code on) but that would probably be much slower.

A note: as I am sure you all have experienced, it may be tricky with
DLLs under Windows since if something goes wrong the old DLL may stay
loaded. I am aware of this so for each error I have had to restart
Windows to clean up (is that a mess, or is that a mess?)

I am sure I can find some kind of solution (a patch rather) to this but
I would much appreciate you low-level guys' opinion on this.

TS will not make any new pure compilers until maybe next year sometime.
You can buy Modula-2 support for Clarion for Windows but it is still the
same old 16-bit libraries were the bugs are not even fixed. It is anyway
a messy solution since I already have the full code in Modula which also
makes it pointless to use e.g. Delphi and TS DLLs at this stage.

I plan to finnish the 3.1 version with TS (it is nearly finnsihed) and
then switch to StonyBrook and Windows 95 (the information I have on the
new compiler makes it look very very good). October is latest stated
release month.

With hopes of a better future for Modula-2 (-3 and Oberon now when
Windows 95 finally has arrived).

Cheers

Bengt-Inge

--------------------------------
Bengt-Inge Dalenback, CATT
also at:
Department of Applied Acoustics
Chalmers University of Technology
Gothenburg, SWEDEN
e-mail: b...@ta.chalmers.se
fax : +46 31 145154

David Collier

unread,
Sep 8, 1995, 3:00:00 AM9/8/95
to
Loops and floating-point.

I know this sounds silly, but maybe if you just wrote out the FOR loops
as explicit code, A:=1 ; ..... ; INC(A) ; IF A< n THEN GOTO L1: ....

Perhaps that would keep less in registers, and avoid your problem?

Do you have the mathlib source?

David

Bengt-Inge DalenbŠck

unread,
Sep 11, 1995, 3:00:00 AM9/11/95
to

> Loops and floating-point.

Hi David,

I tried that (INC() etc.) because I had the same thought but it is not
only when loops are executed. That problem went away when I made a DLL
calling MATHLIB (and I also have a lot of loops).

There are in a few other cases, e.g. with Str.RealToStr, that calls
MATHLIB.IntPow and a few others and gives the wrong results. Since I have
the source to Str.MOD and, when I look closer into it, it has different
versions for _XTD amd _WINDOWS so *that* particular bug may be in the
source of the function. I will look into that.

The MATHLIB source is basically in CoreMath.A and it is included in
the SourceKit. In CoreMath.A is where one official fix was for a push-pop
mismatch under Windows. The second fix I got was in the form of a changed
pragma setting in the MATHLIB.DEF file "call(reg_saved..." but I don't
have the settings here.

Even if no obvious solution appears in the news-group the possibility
to discuss this may even make me find a solution myself. You know how it
is, sometimes it even helps telling your cat about the problem. And when
you have told him about it you say. Wait a second...Aaaha!

We all suffer from that M2 is not as spread as C/C++. If more had
tried programming for Windows using TSM2, the bug would probably have
been fixed while TS were still interested in it.

If anything comes up, I will post it here. Thanks so far.

Peter Moylan

unread,
Sep 12, 1995, 3:00:00 AM9/12/95
to
Bengt-Inge DalenbŠck (b...@ta.chalmers.se) wrote:
>Hi all,

> Now, after having ported a comparatively large project from TopSpeed
>3.10 to Windows 3.1 (merging 30 Xtd, and large model programs to one
>MDI app), I can report the following.

> Once you get the hang of it (and have fixed some things reported in
>my earlier longer postings half a year ago) it all works very well!

> *** Except for one thing ***

I don't know how to fix this problem, but perhaps I can give some
insight into what's going on.

> MATHLIB has a problem if e.g. Sin() or, for what it seems, any other
> MATHLIB function is called repeatedly in a loop. In such cases a
>register is trashed (the one used for the loop variable) and the loop
>is terminated prematurely. However, if MATHLIB functions are called one
>at a time in the middle of the code it all works fine, and even after
>an huge amount of flotating point calculations (and I mean hours worth
>of it) the final results are identical to the Xtd DOS program's (also
>the speed is nearly identical). If debug is turned on the problem
>disapears since the code then changes but of course the execution
>speed also goes down, and I can't have that.

[snip]

> So then what to do? I bought Borland Pascal 7.0 to get some more
>Windows documentation and planned to make the same DLL using BP instead.
>To create a DLL in BP *without* floating point and call it from
>TopSpeed works fine, but as soon as I try the real thing with the BP
>Double floats (N+ compiler directive that should be the same as LONGREAL),
>I get a GPF. Does anybody with a better low-level understanding have
>some advice. The low-level docs for BP are thin and the map-file it
>generates for the DLL is not much. E.g. I can't spot the WEP or LibMain
>procedures (that are suppose to be named exactly like that and WEP is to
>be exported in the EXP-file, in BP it is not explicitly exported but
>hidden somewhere) but it works anyway to use the DLL from TopSpeed (i.e.
>without floating-point). Borland does seem to do things in an
>unorthodox manner.

This sounds very much like a problem I had (and still haven't solved)
when trying to link TopSpeed modules with Borland C modules.
The problem arises because the coprocessor registers can be used
in two distinct ways: as a bank of numbered registers, or as a
stack. The first approach is superior in terms of code optimisation,
but can be very confusing because of some hardware quirks. (Certain
operations inevitably affect the top-of-stack pointer, and this
changes the way the hardware interprets register numbers.) The
"stack" approach is more consistent with the way the hardware works,
and therefore easier to get right, but it does mean that you get
inferior object code because you're failing to take advantage of
being able to leave some intermediate results in the floating
point registers.

Borland compilers use the "stack" approach, and in general they
adopt the rule that all procedures must clean up the stack before
they return. (Except for a function that returns a floating
point result on the top of the stack.) TopSpeed does better
code optimisation by using the "register" approach, but this does
mean that the TopSpeed code leaves stuff sitting in registers
after it's no longer needed. After a sufficiently long chain of
floating point operations, this unused rubbish either gets popped
off the top of the stack, or gets overwritten when the register
gets used for something else, or (more likely) gets pushed through
the bottom of the stack (and therefore lost because in reality
the stack is circular).

Another difference between Borland and Pascal is in their settings
of the hardware error masks. Certain things cause error interrupts
in one case but not the other, and this is related to the
stack/register bank dichotomy.

The bottom line is this: everything seems to work OK if all of
your code is Borland-generated code, or if all of your code is
TopSpeed-generated code (the language doesn't matter); but if
you try to combine the two then a spurious "stack overflow"
error will eventually occur while you're executing the TopSpeed
code. The precise cause of the error is difficult to determine
because of the way the coprocessor hardware works: the error
interrupt happens when you're already some way past the point
where the error was triggered. What seems to be happening is
that a stack overflow is caused by loading a floating point
number when the stack is already full, and the stack is full
because of some left-over rubbish that has been gradually been
pushed deeper and deeper into the stack. Logically this isn't
an error at all - all that's happening is that you're losing
the contents of a register that you weren't using anyway - but
the hardware detects it as an error because it thinks that the
register at the bottom of the stack is still in use.

In part this is a consequence of the fact that we're using the
stack the TopSpeed way but enabling the error flags the Borland
way, but I think there's also a deeper problem: a bug in the
TopSpeed floating point code generation that sometimes creates
a redundant stack push. This bug is harmless in most situations,
but fatal if you try to mix Borland and TopSpeed code. I'm not
sure whether the bug is confined to the core libraries, or is
also occurring in the compiler's code generator.

I've never tried to use TopSpeed with Windows, but I suspect that
pretty much the same problem is the cause of problems when
working under Windows.

A possible fix would be to specify that you don't have a
coprocessor when compiling. Of course this would hurt the
run-time efficiency.

The only good solution, I believe, would be to rewrite parts
of the TopSpeed floating point libraries. This could be a
very major job.

>3) Is it the init procedures for the math processor that are different
>and clashes between TS and BP? I can call the BP DLL from a BP program
>without problem but I get GPFs both when calling the TS DLL in BP and
>when calling the BP DLL in TS.

>4) TS don't use the coprosessor stack but BP does. That should be able
>to fix with pragmas but maybe a rebuild of the TS libs are required for
>that. I tried some promising prgma settings but no luck since it is
>fixed in the LIB anyway.

I think the above two are the source of the problem. Furthermore
I don't think you can fix the problem merely by changing pragma
settings - I've already tried all of the combinations I could
think of.

>5) I could create the same DLL with a C-compiler but I may run into the
>same problems again if I don't understand the reason.

I don't think language is an issue. The problem occurs with
both TopSpeed Modula-2 and TopSpeed C. The compilers use the
same back end, and pretty much the same libraries, though there
are some differences in terms of libraries.

>TS will not make any new pure compilers until maybe next year sometime.
>You can buy Modula-2 support for Clarion for Windows but it is still the
>same old 16-bit libraries were the bugs are not even fixed. It is anyway
>a messy solution since I already have the full code in Modula which also
>makes it pointless to use e.g. Delphi and TS DLLs at this stage.

Do you have any information that says that they will in fact
produce new compilers? I don't want to throw away TopSpeed, but
I'm not very interested in any upgrade which requires me to buy
Clarion and/or which requires me to run Windows.

--
Peter Moylan pe...@ee.newcastle.edu.au
file://ee.newcastle.edu.au/pub/www/Moylan.html

Bengt-Inge DalenbŠck

unread,
Sep 12, 1995, 3:00:00 AM9/12/95
to
Answer to Peter Moylan, pe...@ee.newcastle.edu.au.

Thanks for sharing your experiences that, in deed, go deeper into the
problem than mine.

Some more thoughts just to keep things boiling.

How about using the call(standard_float=>on) in some manner? It will
use the stack model for the 8087 but has to be used in the complete
program. It may fix the problem completely or the Borland DLL problem.
I tried to use stack calling and sandard_float but I lacked a library
(I hope I can find it on the TechKit disk so I'll try again).

Otherwise, to use a Borland DLL it would be needed to clear the TS way
of using the 8087 temporarily (like storing the stack and the status
bits) and then restore it again after the call since it seems to be only
when calling MATHLIB functions there is an error and not in the actual
code generation for a+b/c etc.

Has anybody used the TS Pascal compiler? It has some compatibilty mode
with Borland, maybee that can be used to create a Borland-friendly DLL
interface?

How about remaking the MATHLIB as a DLL? That seems to be one option
when remaking the libraries. The code will be slightly different and
may solve the probem. I am fortunate to have a well tested DOS version
to compare with so I'll know when it works. Anybody tried that?

Windows API have functions _FPInit and _FPTerm that should be used in a
DLL that does not itself init the FPU and install an exception handler.
Probably playing with these makes things even worse.

I may try some of the above but, fortunately, the bug does not stop me
developing further and there are still holes to fill in.


Peter says--------

coprocessor when compiling. Of course this would hurt the
run-time efficiency.

------------------
I must use floats, and under Windows the Windows FPU emulator runs or
the real one so I can't force to use the emulator only. Under Windows
you can force that you must have an FPU to run the program but the
TopSpeed code then locks some machines.


Peter says--------


The only good solution, I believe, would be to rewrite parts
of the TopSpeed floating point libraries. This could be a
very major job.

------------------
The CoreMath.a is available but not the compiler itself of course.
If the problem can be fixed inside of that module, it would be the
best solution. I have already had an offer from someone to look into
the code. With some joint effort we may be be to solve it. However,
if I am the only one writing with TS for Windows the interest may be
more of an academic nature.

Peter says--------
Do you have any information that says that they (TS) will in fact


produce new compilers? I don't want to throw away TopSpeed, but
I'm not very interested in any upgrade which requires me to buy
Clarion and/or which requires me to run Windows.

------------------
Same here. Mostly I have been treated well by those I have talked
to at TS. I know that some of them would like to go more for the
compilers but the word is out that Clarion is to be the money-maker
and then there may be a go for the compilers. Something like next
year...


The best option now is StonyBrook (some Oberon compilers may come
too now that 32-bits are (almost) here). I am sure StonyBrook have
been good all the time but it is always easier to remain with the
same compiler. The info I got on the StonyBrook compiler makes me
belive it is will be very capable. This was a personal info to me
upon request on differences frm TS so I will not provide any more
details, you have to trust me that it looked good. I don't know what
their official papers say. It is said to be available in Oct or so.

Martin Tom Brown

unread,
Sep 12, 1995, 3:00:00 AM9/12/95
to
In article <42mhgl$j...@nyheter.chalmers.se>
b...@ta.chalmers.se "Bengt-Inge Dalenbck" writes:

> Once you get the hang of it (and have fixed some things reported in
> my earlier longer postings half a year ago) it all works very well!
>
> *** Except for one thing ***
>
> MATHLIB has a problem if e.g. Sin() or, for what it seems, any other
> MATHLIB function is called repeatedly in a loop. In such cases a
> register is trashed (the one used for the loop variable) and the loop
> is terminated prematurely.

Sounds similar to a problem I once had with FOR loops in OS/2 IOPL code.
I've had a quick look at coremath.a and noemul.a and have a tentative
explanation - sorry I don't have time to try any experiments.
Standard DOS code for Sin goes on the stack something like this
BP ____ BP set to point here
reserved -2
CX -4
AX -6
where fstsw [BP][-2] will store into "reserved"

The Windows version calls an external routine __FloatStoreSW() in noemul.a
The only thing that seems to be wrong is that it doesn't issue an
fwait to sync the NDP & CPU before reading the value in [BP][-2]
(This routine has it's own temporary copies & returns result in AX)
Whilst this might give the wrong answer sometimes, I can't see
how that would mangle the stack or the for loop variable.

There is some evidence of panic measures inside the (*%T _WIN*) code
with attempts to preserve AX only to use it again for the same value.
Since the code appears to preserve all the registers it uses,
I think it's most likely that something is trashing the stack.

FWIW The OS/2 compiled version of mathlib seems to work OK.
There is a bug in the initiallisation of the x87 rounding rule
in threads which causes TRUNC() to give the wrong answer (fixable).

Regards,
--
Martin Brown <mar...@nezumi.demon.co.uk> __ CIS: 71651,470
Scientific Software Consultancy /^,,)__/

Mark Morgan Lloyd

unread,
Sep 18, 1995, 3:00:00 AM9/18/95
to
There is still Modula-2 work at TopSpeed, since this is what (large parts
of?) the compilers are written in.

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

[Opinions above are the author's, not those of his employers or
colleagues]

0 new messages