• error for small data model

    From Paul Edwards@21:1/5 to All on Sun Nov 13 18:30:52 2022
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Mon Nov 14 09:03:17 2022
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Edwards@21:1/5 to R.Wieser on Mon Nov 14 21:45:26 2022
    On Monday, November 14, 2022 at 4:13:11 PM UTC+8, R.Wieser wrote:
    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"

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Tue Nov 15 10:03:03 2022
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Edwards@21:1/5 to R.Wieser on Tue Nov 15 18:01:29 2022
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Wed Nov 16 08:52:35 2022
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Edwards@21:1/5 to R.Wieser on Wed Nov 16 00:46:44 2022
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Wed Nov 16 10:45:50 2022
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Terje Mathisen@21:1/5 to R.Wieser on Wed Nov 16 13:09:43 2022
    R.Wieser wrote:
    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. :-)

    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"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Edwards@21:1/5 to R.Wieser on Wed Nov 16 05:33:51 2022
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Wed Nov 16 17:16:07 2022
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From George Neuner@21:1/5 to mutazilah@nospicedham.gmail.com on Wed Nov 16 12:14:03 2022
    On Wed, 16 Nov 2022 05:33:51 -0800 (PST), Paul Edwards <mutazilah@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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Edwards@21:1/5 to George Neuner on Thu Nov 17 17:36:24 2022
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Terje Mathisen@21:1/5 to Paul Edwards on Sat Nov 19 16:24:02 2022
    Paul Edwards wrote:
    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.

    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.

    Terje

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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Paul Edwards@21:1/5 to Terje Mathisen on Sat Nov 19 08:32:58 2022
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)