error for small data model

45 views
Skip to first unread message

Paul Edwards

unread,
Nov 13, 2022, 9:42:53 PM11/13/22
to
What is the best way of producing an error here?

; push the psp now, ready for calling start

if @DataSize
push ds
else
error you must use a model with far data pointers
endif


Also, is there something like:

if not @DataSize
error ...
endif

???

Thanks. Paul.

R.Wieser

unread,
Nov 14, 2022, 3:13:11 AM11/14/22
to
Paul,

> What is the best way of producing an error here?

That depends on 1) what kind of error you want (run or assmble time) 2) the
assembler you're using.

Looking at the example code it looks to me you want #2. In that case you
could check if your assember has something like "@err" (for errors) and
"@out" (for warnings).

And a suggestion : when one of the blocks contains an program (error) exit
than you do not need to use an "else". Just make sure that the error-exit
is in the first, main block :
- - - - - - - - - -
if not @DataSize
error you must use a model with far data pointers
endif
push ds
- - - - - - - - - -
notice the "not" after the "if"

Regards,
Rudy Wieser


Paul Edwards

unread,
Nov 15, 2022, 12:47:34 AM11/15/22
to
Hi Rudy, thanks for your reply.

Yes, I am after an assembly error.

But neither @err nor not seem to work on masm or wasm.

@err gives an error and "not" seems to be used as a variable
which is false.

However, I now accept small data pointers so I no longer
need to produce an error so it doesn't matter any more.

On the subject of small and medium memory model -
how is it possible for them to work? Functions can
accept pointers that originated from either the stack
or the data segment, or potentially even the code
section if literals are stored there.

Those are different address spaces. How did DOS compiler
vendors manage to get a sensible result?

Did they define the buffer in fwrite etc to be "far" to force
an override? That would work for the C library, but fall down
when it comes to user code.

Thanks. Paul.

R.Wieser

unread,
Nov 15, 2022, 4:17:47 AM11/15/22
to
Paul,

> Yes, I am after an assembly error.
>
> But neither @err nor not seem to work on masm or wasm.
>
> @err gives an error and "not" seems to be used as a variable
> which is false.

My suggestions where based on Borlands Tasm32 (yeah I know, ancient). But
now you've specified which assembler you're using you stand a chance that
someone here uses the same and knows the answer to all three of the above.

Though you could try using "ifn" instead of "if not". Bottom line, take a
peek at your assemblers documentation.

> On the subject of small and medium memory model -
> how is it possible for them to work?
...
> Those are different address spaces.

I had the same thoughts/problem. Its almost impossible to use stack-based
structures/strings when DS and SS are not the same. As such they are most
always (made) the same.

If you want to store data in / retrieve from the code segment of your
program (you should not, but its your choice) than you have no other option
than to make sure that all three segment registers are the same (locking you
into the smaller memory models).

That, or special functions that override the pointers default segment with
one of your own choice (for example, mov al,[cs:si] ).

Regards,
Rudy Wieser


Paul Edwards

unread,
Nov 15, 2022, 9:03:43 PM11/15/22
to
On Tuesday, November 15, 2022 at 5:17:47 PM UTC+8, R.Wieser wrote:

> > On the subject of small and medium memory model -
> > how is it possible for them to work?
> ...
> > Those are different address spaces.

> I had the same thoughts/problem. Its almost impossible to use stack-based
> structures/strings when DS and SS are not the same. As such they are most
> always (made) the same.
>
> If you want to store data in / retrieve from the code segment of your
> program (you should not, but its your choice) than you have no other option
> than to make sure that all three segment registers are the same (locking you
> into the smaller memory models).

What do you mean by "smaller memory models"?

The only ones that conceivably work are tiny, compact,
large and huge.

The ones that don't are small and medium.

> That, or special functions that override the pointers default segment with
> one of your own choice (for example, mov al,[cs:si] ).

But from memory small was the default memory model for
DOS C compilers.

How did they manage to make it work?

Thanks. Paul.

R.Wieser

unread,
Nov 16, 2022, 3:04:02 AM11/16/22
to
Paul,

> What do you mean by "smaller memory models"?

The ones that keep DS and SS (and possibly CS) the same.

> But from memory small was the default memory model for
> DOS C compilers.
>
> How did they manage to make it work?

As long as they kept SS the same as DS that one is easy - as long as you do
not put (directly accessed) data in the CS segment. No extra work is
needed

If not ? Well, they would have to use segment-register overrides a lot.

Assume that SS differs from DS and you have some "local string variable" (on
the stack) which you want to display. You can't use INT 21h AH=09h
directly, as it expects the string to be in the data segment.

So, you have to either write funtions which grab a byte a time while
overriding the default segment for that register (mov dl,[ss:dx]), or wrap
the call into a bit of code which sets DS to be the same as SS and
afterwards restores it. (push ds | mov ax,ss | mov ds,ax | .... | pop ds).

Ofcourse, if you have DS different from CS and put strings into the code
segment which you want to display you would have the same problem. Heck,
the same happens when you allocate memory and want to access it : you mostly
have to juggle DS and ES around to get the "movs" instruction to do its
thing. :-)

In other words : Its not a rocket science needing problem, but its solution
is one that needs to be applied rigorously and correctly *all the time*.

Which is the reason that, when I'm writing Assembly, I seldom (if ever) feel
the need to pick a memory model where SS is different from DS. :-)

Regards,
Rudy Wieser


Paul Edwards

unread,
Nov 16, 2022, 3:49:07 AM11/16/22
to
On Wednesday, November 16, 2022 at 4:04:02 PM UTC+8, R.Wieser wrote:
> Paul,
> > What do you mean by "smaller memory models"?
> The ones that keep DS and SS (and possibly CS) the same.

There is no choice in that case - tiny is the only one.

> Which is the reason that, when I'm writing Assembly, I seldom (if ever) feel
> the need to pick a memory model where SS is different from DS. :-)

So long as you use far data pointers, ie compact, large and
huge, it should all be fine. Otherwise you only have the one
choice, above.

Unless I'm missing something.

BFN. Paul.

R.Wieser

unread,
Nov 16, 2022, 4:49:12 AM11/16/22
to
Paul,

> There is no choice in that case - tiny is the only one.

As you have not mentioned anything about your requirements there is no way
for me to agree or disagree with the above I'm afraid ...

> So long as you use far data pointers, ie compact, large and
> huge, it should all be fine.

And create the replacement or wrapper functions for INT 21h (and other) "one
segment only" calls.

As I said, its not rocket science. But you might find programming Assembly
in those models becoming tiresome rather quickly.

Regards,
Rudy Wieser


Terje Mathisen

unread,
Nov 16, 2022, 7:19:22 AM11/16/22
to
For my word count code I needed a 64 KB lookup table, so I put that in a
separate ES segment, then I could put another largish table in the SS
segment and access it with BP, leaving disk buffers etc in DS.

Terje


--
- <Terje.Mathisen at tmsw.no>
"almost all programming can be viewed as an exercise in caching"

Paul Edwards

unread,
Nov 16, 2022, 8:34:28 AM11/16/22
to
On Wednesday, November 16, 2022 at 5:49:12 PM UTC+8, R.Wieser wrote:
> Paul,
> > There is no choice in that case - tiny is the only one.
> As you have not mentioned anything about your requirements there is no way
> for me to agree or disagree with the above I'm afraid ...

I was trying to implement my C library (PDPCLIB) for MSDOS
when I encountered this issue.

> > So long as you use far data pointers, ie compact, large and
> > huge, it should all be fine.
> And create the replacement or wrapper functions for INT 21h (and other) "one
> segment only" calls.
>
> As I said, its not rocket science. But you might find programming Assembly
> in those models becoming tiresome rather quickly.

I'm not trying to program in assembly, except for the minimal
wrappers.

I'm wondering how a C "hello world" could have worked in small
memory model C compiler (any vendor) when the "hello world"
string could come from either a buffer on the stack or a data
variable.

It somehow magically worked.

I didn't need to stuff around in my hello world application program -
someone else magically dealt with that.

Now I'm trying to understand magic.

Thanks. Paul.

R.Wieser

unread,
Nov 16, 2022, 11:19:40 AM11/16/22
to
Paul,

> I'm wondering how a C "hello world" could have worked in small
> memory model C compiler (any vendor) when the "hello world"
> string could come from either a buffer on the stack or a data
> variable.
>
> It somehow magically worked.

:-) Thats the problem when you use a compiler, it hides a lot of the "magic"
from you.

When using a compiler it just silently switches to the library matching the
chosen memory model and "upgrades" your involved pointers accordingly.

Maybe you can tell your compiler to generate an assembly listing of the
program you're compiling, and see how it works ?

Regards,
Rudy Wieser


George Neuner

unread,
Nov 16, 2022, 12:34:48 PM11/16/22
to
On Wed, 16 Nov 2022 05:33:51 -0800 (PST), Paul Edwards
<muta...@nospicedham.gmail.com> wrote:

>I'm wondering how a C "hello world" could have worked in small
>memory model C compiler (any vendor) when the "hello world"
>string could come from either a buffer on the stack or a data
>variable.
>
>It somehow magically worked.

I may be mis-remembering [it has been a long time], but I believe the
"small" model was 64K code, 64K data, DS = SS.

"tiny" was 64K code + data, CS = DS = SS.
"compact" was 64K code, 1MB data, DS != SS
"medium" was 1MB code, 64K data, DS = SS
"large" was 1MB code, 1MB data, DS != SS, 4:16 pointers
"huge" was 1MB code, 1MB data, DS != SS, 16:4 pointers


>I didn't need to stuff around in my hello world application program -
>someone else magically dealt with that.
>
>Now I'm trying to understand magic.

No magic, just either saving/restoring the segment register around
code that messes with it. Or liberal use of segment overrides.

>Thanks. Paul.
George

Paul Edwards

unread,
Nov 17, 2022, 8:50:49 PM11/17/22
to
On Thursday, November 17, 2022 at 1:34:48 AM UTC+8, George Neuner wrote:

> >I'm wondering how a C "hello world" could have worked in small
> >memory model C compiler (any vendor) when the "hello world"
> >string could come from either a buffer on the stack or a data
> >variable.
> >
> >It somehow magically worked.

> I may be mis-remembering [it has been a long time], but I believe the
> "small" model was 64K code, 64K data, DS = SS.

Thanks, that was the secret!

Does this code look right to you (it is working, but that
doesn't necessarily mean I have adjusted sp correctly):

(btw, "ifn @DataSize" didn't work)

https://sourceforge.net/p/pdos/gitcode/ci/master/tree/pdpclib/dosstart.asm#l70

; It appears that in the tiny memory model, you are still required
; to set ds to the same as cs yourself, presumably because ds is
; pointing to the PSP while cs is probably pointing to the beginning
; of the executable. DGROUP may also get the correct value, presumably
; zero. es is set to ds a bit later. And you need to set ss to that
; value too

if @Model eq 1
mov dx, cs
else
mov dx,DGROUP
endif

mov ds,dx

; In tiny, small and medium memory models, you need to set
; ss to ds (MSDOS will have set them to different values
; when it loaded the executable).
; ds and ss are the same so that
; near pointers can refer to either stack or data and still work

if @DataSize
else

mov bx,ss
mov ax,ds
sub bx,ax
mov cl,4
shl bx,cl

mov bp, sp
sub bp, bx
mov ss, dx
mov sp, bp
; And that null PSP thing needs to be redone
mov ax, 0
push ax

endif


My testing suggests that there is a problem with tiny memory
model, but the other memory models seem to work.

Thanks. Paul.

Terje Mathisen

unread,
Nov 19, 2022, 10:37:49 AM11/19/22
to
Tiny is the one used by all .COM files, in those the binary has no
relocation info, it is just block copied into a newly allocated 64KB
block of memory, at offset 100h, and with those first 256 bytes (the
PSP) initialized by the OS.

In this model all segment registers are the same, i.e. CS=DS=ES=SS
because the OS and CPU are pretending to be a Z80 with no support for
extended/segmented memory addressing.

Paul Edwards

unread,
Nov 19, 2022, 11:37:54 AM11/19/22
to
On Saturday, November 19, 2022 at 11:37:49 PM UTC+8, Terje Mathisen wrote:

> > if @DataSize
> > else
> >
> > mov bx,ss
> > mov ax,ds
> > sub bx,ax
> > mov cl,4
> > shl bx,cl
> >
> > mov bp, sp
> > sub bp, bx

This should have been an add, not a subtract. :-)

> > mov ss, dx
> > mov sp, bp
> > ; And that null PSP thing needs to be redone
> > mov ax, 0
> > push ax
> >
> > endif
> >
> >
> > My testing suggests that there is a problem with tiny memory
> > model, but the other memory models seem to work.

> Tiny is the one used by all .COM files, in those the binary has no
> relocation info, it is just block copied into a newly allocated 64KB
> block of memory, at offset 100h, and with those first 256 bytes (the
> PSP) initialized by the OS.
>
> In this model all segment registers are the same, i.e. CS=DS=ES=SS
> because the OS and CPU are pretending to be a Z80 with no support for
> extended/segmented memory addressing.

That's only if you deliberately choose to produce a COM file,
and also you need an org 100h in the startup code.

Otherwise, tiny memory model produces a perfectly fine
normal MSDOS executable, and the entry point can be
anywhere.

My hello world program, linking in the whole C library
in tiny memory model is this size:

Memory size: e110 (57616.)

_TEXT CODE DGROUP 0000:0000 000053c6
CONST DATA DGROUP 053c:0006 000002be
CONST2 DATA DGROUP 0568:0004 00000000
_DATA DATA DGROUP 0569:0000 00000668
_BSS BSS DGROUP 05cf:0008 00006412
STACK STACK DGROUP 0c11:0000 00002000

Entry point address: 0000:02fa

Which is cool.

I have a lot of BSS because of 6144-byte buffers for files which
gave a great speedup on a real XT in the 1990s.

My tiny mode doesn't support malloc though, so you can't
do much. Doesn't support parameters either. :-) Large is
fine though. It was interesting to see.

PDOS/86 now has INT 3 and INT 1 support as a result of
debugging that.

BFN. Paul.

Reply all
Reply to author
Forward
0 new messages