VOGONS


First post, by mac57mac57

User metadata
Rank Newbie
Rank
Newbie

Hi All, I have been struggling to understand whether a DOS program compiled with DJGPP can address more than 1 MB of RAM. Since DJGPP programs are 32 bit and run in protected mode, it stands to reason that they should be able to address all the RAM available on the machine, including any Extended Memory that might be present. Is this so? Are there any special compile-time or link-time parameters that have to be specified?

I do know that CWSDPMI5's stub must be added to the program after linking, and that this provides the program with a full DPMI server capability. I am just wondering if this is enough...

Thanks for any and all insights!

Reply 1 of 5, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie

Yes, it absolutely can address more than 1mb.

The default compiler options to GCC should build you a 32bit protected mode binary that can access as much memory as you have in your system.

You do need a copy of cwsdpmi in the path, at runtime, as you state.

My collection database and technical wiki:
https://www.target-earth.net

Reply 2 of 5, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie

For reference I am using:

$ /opt/toolchains/x86/djgpp/bin/i586-pc-msdosdjgpp-gcc -v Using built-in specs. COLLECT_GCC=/opt/toolchains/x86/djgpp/bin/i586-p […]
Show full quote

$ /opt/toolchains/x86/djgpp/bin/i586-pc-msdosdjgpp-gcc -v
Using built-in specs.
COLLECT_GCC=/opt/toolchains/x86/djgpp/bin/i586-pc-msdosdjgpp-gcc
COLLECT_LTO_WRAPPER=/opt/toolchains/x86/djgpp/bin/../libexec/gcc/i586-pc-msdosdjgpp/12.1.0/lto-wrapper
Target: i586-pc-msdosdjgpp
Configured with: ../gnu/gcc-12.10/configure --target=i586-pc-msdosdjgpp --program-prefix=i586-pc-msdosdjgpp- --prefix=/usr/local/djgpp --disable-nls --disable-plugin --disable-lto --enable-lto --enable-libstdcxx-filesystem-ts --enable-libquadmath-support --with-gmp=/home/vagrant/build-djgpp/build/djcross-gcc-12.1.0/tmpinst --with-mpfr=/home/vagrant/build-djgpp/build/djcross-gcc-12.1.0/tmpinst --with-mpc=/home/vagrant/build-djgpp/build/djcross-gcc-12.1.0/tmpinst --enable-version-specific-runtime-libs --enable-languages=c,c++
Thread model: single
Supported LTO compression algorithms: zlib
gcc version 12.1.0 (GCC)

... my compiler command line is:

gcc -O3 -mtune=i386 -march=i386 -fgnu89-inline -c source1.c -o objfile1.o

... the -fgnu89-inline is purely to have compatability with the Allegro libraries I use, which have older style inlines.

Linker in use is:

$ /opt/toolchains/x86/djgpp/bin/i586-pc-msdosdjgpp-ld -V GNU ld (GNU Binutils) 2.30 Supported emulations: i386go32 […]
Show full quote

$ /opt/toolchains/x86/djgpp/bin/i586-pc-msdosdjgpp-ld -V
GNU ld (GNU Binutils) 2.30
Supported emulations:
i386go32

... no special options to ld, just called via the gcc front end as:

gcc -o target.exe objfile1.o objfile2.o libraryX.a libraryY.a

This gets you one of these binaries:

$ file bin/scrolls.exe
bin/scrolls.exe: MS-DOS executable, COFF for MS-DOS, DJGPP go32 DOS extender

I'm not doing any big malloc calls in my code, but the exe is already >1MB, and is happy to run on Dosbox or real >= 386 systems with a copy of cwsdpmi.exe in the same folder. Without it you will get a missing dos extender error when attempting to start the binary.

There are peculiarities when dealing with stuff that lives within the <1MB area (IO ports, video memory ranges, etc), but the last time I checked I think these use cases were documented on the djgpp info pages. For memory mapped devices that live in high memory ranges, there are also some rules that need to be followed (you can't just read/write to them using things like memcpy). It's an edge case (accessing VESA linear frame buffers directly is probably the most common example), but is definitely possible: https://www.delorie.com/djgpp/v2faq/faq18_7.html

BTW, I tend to get pre-built cross-compiler versions of djgpp from: https://github.com/andrewwutw/build-djgpp - these come with gcc, binutils, ld etc... but generally not with make and other supporting tools. I find these are kept much more up to date than the ancient dos-native versions available from djgpp.com; which is probably your only place if you want to run gcc on dos. That's pretty hardcore these days; a cross compiler environment is much more productive.

My collection database and technical wiki:
https://www.target-earth.net

Reply 3 of 5, by mac57mac57

User metadata
Rank Newbie
Rank
Newbie

Thanks @megatron-uk. I am running DJGPP on MS-DOS 6.22; I am a retro-software author and so I like to "eat my own dog food" - work in the environment I am writing for. When I had tested this months ago, I couldn't get above about 700K of allocated memory, but after the above post, I tried the test again, and today I got past 2 MB (I have 32 MB on the test system I was using). I think the difference is that between the first test and the one today, I have added CWSDPMI.EXE to my PATH and upgraded to CWSDPMI5b. Taken together, these two things seem to have allowed me to move beyond the 1MB barrier. I am almost sorry I made the past now; I should have tested again before I did so. My apologies for the online clutter.

There is one remaining question however...

All of this is related to my VE text editor (DOS), which makes one malloc call per line of text. For large files, that is a LOT of malloc calls. I had read somewhere that I might need to increase the heap size of CWSDPMI or else it might simply run out of segment allocation table space. Does this ring any bells? Is there anything I could do in terms of configuring CWSDPMI to increase its heap size? I have not been able to find anything online except for statements that I might wish to consider doing this.

Thanks!

Reply 4 of 5, by megatron-uk

User metadata
Rank Oldbie
Rank
Oldbie

I'm afraid I can't help there. In my case I do a little amount of malloc right at the start of my application, reserving some main memory as a video double buffer and scratch areas for sprite manipulation and some more structures for program state, but after that I am mostly static.

My collection database and technical wiki:
https://www.target-earth.net

Reply 5 of 5, by doshea

User metadata
Rank Member
Rank
Member
mac57mac57 wrote on 2023-11-27, 22:04:

I had read somewhere that I might need to increase the heap size of CWSDPMI or else it might simply run out of segment allocation table space. Does this ring any bells? Is there anything I could do in terms of configuring CWSDPMI to increase its heap size? I have not been able to find anything online except for statements that I might wish to consider doing this.

I don't know much about this but I found that https://github.com/brltty/locktones/blob/mast … mi/cwsparam.doc (which I don't think is like a canonical source for that document or anything) says:

Paragraphs of memory for extra CWSDPMI internal heap ? [128] […]
Show full quote

Paragraphs of memory for extra CWSDPMI internal heap ? [128]

CWSDPMI is built with an internal 4K heap. Each nested task consumes around
300 bytes, each memory zone takes 14 bytes, and each HW interrupt (nested)
takes around 850 bytes. If extra DOS memory is available, the additional
paragraphs specified here are added to the heap at execution time by DOS.
The r1 default of 4K was too little for programs which allocated over
around 12Mb of memory in very small requests. The 6K default should be good
for up to 21Mb in small requests. If you compile very large C++ programs
or allocate lots of memory in small pieces, you might need to bump this
parameter. If you are very tight on memory, you could decrease it to zero
and pick up another 2K of DOS memory. Each paragraph allows a little more
than one more memory zone (or in the worse case around 64K of memory).

http://www.delorie.com/djgpp/v2faq/faq3_9.html seems to have some more vague information about setting up DJGPP based on how much memory you have, I have no idea if it's up-to-date though. I didn't realise you could use CWSDPMI without a memory manager though, so that might have some useful information.

Good luck!