Jump to content
IGNORED

New Atari BBS software.


tschak909

Recommended Posts

I don't know if you've sen this example yet, but:

 

http://www.cc65.org/doc/atari-9.html

 

Depending on the sizes of various bits, I would put the runtime or some common routines (user data API, console/serial I/O) in RAMLO -> $3FFF, CC65 runtime lib in $8000 -> xxxx and use xxxx -> $BC1F for the stack/heap. This leaves $4000-$7FFF open for banking in modules (on a 130XE) or reading them from disk (on systems with <=64K). As an overlay model, this gives you the best flexibility between different models, IMHO.

 

Now that I'm done moving, I'll see if I have time to grab a copy from github and see the various sizes of the resulting code.

Link to comment
Share on other sites

You are targeting SpartaDOS? I'd try to use the Sparta way to enumerate/allocate/reserve memory banks then. I have no idea how that works, but there are several people on Atariage who do (Draco030, flashjazzcat to name a couple). I would also vote for the extended memory method... dealing with chain-loading a bunch of stand-alone executables sounds like a nightmare kludge.

Link to comment
Share on other sites

Here is a zip file containing a demo of one way to do banking. There are 5 banks set up : main, bank 0, bank 1, bank 2, bank 3. The startup code and the c library and any non banked code starts at $8000, and there is a 'lowcode' section set up for the $2000-$3FFF area, with some data loaded into it. This should give you all you need to see how to do it for your own situation. The build script is a dos batch file : build.bat.

banktest.zip

  • Like 1
Link to comment
Share on other sites

Unfortunately, you'll have to do a pretty serious reorganization of your code, most likely. If you've been relying on malloc and the global heap you'll find you have much less of it in this situation, because its squeezed up in the $8000+ area along with all of the non banked code and the C library. You'll have to set up your own blocks of data memory and manage them yourself. But thats kind of the way it goes with C on the atari, you just can't write a large program in regular C code and not expect to run out of memory. You have to write your code specifically to work around the machine limitations. You can also use the memory underneath the OS in this way, but you'll have to manage interrupts by preventing them from occurring while you are in the OS memory area, I think. I've never done it but that's what I have heard about it.

Link to comment
Share on other sites

I'm specifically wanting to use SpartaDOS X's memory allocation calls. They are documented in the SpartaDOS X Programming guide, but it's in Polish, and nobody has the supposed english version except Flashjazzcat, who has sworn to Drac030 that it be kept under lock, key, and gun turret.

 

I WANNA USE IT! :P :)

Link to comment
Share on other sites

I'm specifically wanting to use SpartaDOS X's memory allocation calls. They are documented in the SpartaDOS X Programming guide, but it's in Polish, and nobody has the supposed english version except Flashjazzcat, who has sworn to Drac030 that it be kept under lock, key, and gun turret.

 

I WANNA USE IT! :P :)

I'm sure if you ask very nicely and in an "NDA" type fashion, he(Drac030) will help you out. He did mention that you could get a beta version of sdx4.47 just by asking.

  • Like 1
Link to comment
Share on other sites

I should imagine the English developer docs will be released when SDX 4.47 comes out... or in any case, once the docs are deemed ready (the translation won't have been a trivial task). The Polish version certainly doesn't come out of the other end of Bing or Google translate too well. Asking Konrad about it directly would be the most sensible course of action.

  • Like 1
Link to comment
Share on other sites

So...


Given that SDX calls require relocatable binaries, and that CC65 can't output the type that SDX wants, yet...I'll need to go with the approach that Shawn and Dan suggested.


To this end, I am putting in a new folder, banktest, as a sandbox to figure out a bank switching technique that will work.


Also, I will be fixing the regression in BBSCONF, so that configuration files will work again.


-Thom

Link to comment
Share on other sites

also, now with testing my terminal port routines with full 850 emulation turned on, and proper throttling, i've come to one conclusion:

 

MY SERIAL PORT ROUTINES SUCK!

 

fuck me.

 

It looks like i'm not flushing things sufficiently, and I need to completely re-think how I open and close the port.

 

This...is....depressing....

 

This may be the excuse to break out the terminal routines to their own library. Anybody wanna help make some serial port routines that DON'T SUCK? :)

 

I say this because fast serial port routines on the Atari 8-bit, source code on those is very carefully guarded...

 

-Thom

Link to comment
Share on other sites

Given that SDX calls require relocatable binaries, and that CC65 can't output the type that SDX wants, yet...I'll need to go with the approach that Shawn and Dan suggested.

Really? That seems strange that you can't make calls to SpartaDOS vectors unless your code has been compiled as a relocatable binary. Weird.

 

Maybe this post by flashjazzcat might be helpful:

 

http://atariage.com/forums/topic/136205-test-for-extended-ram/?p=1655132

Edited by Shawn Jefferson
Link to comment
Share on other sites

Yeah, I'm not sure that SDX calls require relocatable binaries, either. What makes you think that, Thom?

But either way ( SDX or homegrown ) you will have to restructure your code to be banked compatible. If you do use something like the demo I provided under SDX, make sure you ask SDX which banks it is using and avoid those. Best thing to do is to externalize the $D301 masks into a config file as an array of all possible banks and then index into free ones after you've asked SDX ( or run some other detection utility ). So, in general converting to banked is going to be a pain in the ass I think, but once you have a working banked system you can go nuts, you'll have all the room you need to write a totally kickass BBS.

 

About the serial routines...I could take a look at them. What exactly makes you say that they suck?

Edited by danwinslow
Link to comment
Share on other sites

I am referring to the CC65 cross platform serial driver, namely:

 

(1) they aren't flushing properly when being opened/closed (this becomes evident when switching to a real Atari 850 or using a 6502 850 handler in Altirra)

(2) No ability to assert DTR/RTS as is.

(3) No ability to sense DCD as is.

 

I need to refactor them so that they're also smaller, right now it takes up about 10K of resident RAM.

 

-Thom

Link to comment
Share on other sites

Ah. Well I'd at least consider writing my own calls to the device handler rather than going through the CC65 libraries. CC65 is written from a very general platform perspective and its support for specific machine hardware is not always that great. On the other hand, you can probably edit the CC65 serial library source and recompile to suit yourself, although its likely in 100% assembler.

Link to comment
Share on other sites

Yeah, I'm not sure that SDX calls require relocatable binaries, either.

This depends. Technically, there is no relationship between the system calls and the binary format. But most of the programming guide deals with the SDX Library calls, and the only way of doing these is via symbol references. In turn, the most convenient way of making symbol references is by using the relocatable file format, because the loader is then able to automatically resolve symbols and translate them to addresses.

 

Also, to use the library functions (like malloc), the library must be present in the memory. The library resides on the cartridge, so any program which requires disabling the cartridge (anything which requires X.COM to be executed) loses access to the library ROM. The library functions are not available then (or the access becomes complicated).

 

This problem however does not apply to the calls, structures and symbols, which are defined in RAM. A program which does not want / cannot use relocatable binary format and / or the Library calls, may still use kernel calls. One of the kernel calls, as it is explained in chapter 16, section 1 of the Programming Guide, is jfsymbol, which allows programs to search through the symbol list and find symbols.

 

Now sections 3.7.3 and 3.8 of the same manual explain the references necessary and provides code examples on how to access extended RAM without coming into conflict with other programs (drivers, ramdisks, DOS itself) occupying some ext RAM. The only thing necessary for this is the address symbolized by the symbol T_, and how to find out, what value the symbol T_ has, see above.

Edited by drac030
  • Like 1
Link to comment
Share on other sites

Ok, so there's a late binding facility to look up symbols. Very cool. Thanks Drac030. So it sounds like, technically at least, one can look up the malloc/free routines from a non-relocatable binary, provided that the cartridge is not disabled. I imagine, even if the cart was disabled, you could write a wrapper that would enable it and make the call, and the disable it again, which is what you were referring to when you said 'or the access becomes complicated'.

Link to comment
Share on other sites

The linker configuration has changed significantly with the newest builds of cc65, am going to have to piece together something between danwinslow's example and the cc65 overlay example:

 

 

FEATURES {
    STARTADDRESS: default = $2000;
}
SYMBOLS {
    __EXEHDR__:          type = import;
    __SYSTEM_CHECK__:    type = import;  # force inclusion of "system check" load chunk
    __AUTOSTART__:       type = import;  # force inclusion of autostart "trailer"
    __STACKSIZE__:       type = weak, value = $0800; # 2k stack
    __OVERLAYSIZE__:     type = weak, value = $1000; # 4k overlay
    __STARTADDRESS__:    type = export, value = %S;
    __RESERVED_MEMORY__: type = weak, value = $0000;
}
MEMORY {
    ZP:            file = "", define = yes, start = $0082, size = $007E;
 
# file header, just $FFFF
    HEADER:        file = %O,               start = $0000, size = $0002;
 
# "system check" load chunk
    SYSCHKHDR:     file = %O,               start = $0000, size = $0004;
    SYSCHKCHNK:    file = %O,               start = $2E00, size = $0300;
    SYSCHKTRL:     file = %O,               start = $0000, size = $0006;
 
# "main program" load chunk
    MAINHDR:       file = %O,               start = $0000, size = $0004;
    RAM:           file = %O, define = yes, start = %S + __OVERLAYSIZE__,
                                                           size = $BC20 - __OVERLAYSIZE__ - __STACKSIZE__ - __RESERVED_MEMORY__ - %S;
    TRAILER:       file = %O,               start = $0000, size = $0006;
 
    OVL1:          file = "%O.1",           start = %S,    size = __OVERLAYSIZE__;
    OVL2:          file = "%O.2",           start = %S,    size = __OVERLAYSIZE__;
    OVL3:          file = "%O.3",           start = %S,    size = __OVERLAYSIZE__;
    OVL4:          file = "%O.4",           start = %S,    size = __OVERLAYSIZE__;
    OVL5:          file = "%O.5",           start = %S,    size = __OVERLAYSIZE__;
    OVL6:          file = "%O.6",           start = %S,    size = __OVERLAYSIZE__;
    OVL7:          file = "%O.7",           start = %S,    size = __OVERLAYSIZE__;
    OVL8:          file = "%O.8",           start = %S,    size = __OVERLAYSIZE__;
    OVL9:          file = "%O.9",           start = %S,    size = __OVERLAYSIZE__;
}
SEGMENTS {
    EXEHDR:    load = HEADER,     type = ro;
    SYSCHKHDR: load = SYSCHKHDR,  type = ro,                optional = yes;
    SYSCHK:    load = SYSCHKCHNK, type = rw,  define = yes, optional = yes;
    SYSCHKTRL: load = SYSCHKTRL,  type = ro,                optional = yes;
    MAINHDR:   load = MAINHDR,    type = ro;
    STARTUP:   load = RAM,        type = ro,  define = yes;
    LOWCODE:   load = RAM,        type = ro,  define = yes, optional = yes;
    INIT:      load = RAM,        type = ro,                optional = yes;
    CODE:      load = RAM,        type = ro,  define = yes;
    RODATA:    load = RAM,        type = ro;
    DATA:      load = RAM,        type = rw;
    BSS:       load = RAM,        type = bss, define = yes;
    ZEROPAGE:  load = ZP,         type = zp;
    EXTZP:     load = ZP,         type = zp,                optional = yes;
    AUTOSTRT:  load = TRAILER,    type = ro;
    OVERLAY1:  load = OVL1,       type = ro,  define = yes, optional = yes;
    OVERLAY2:  load = OVL2,       type = ro,  define = yes, optional = yes;
    OVERLAY3:  load = OVL3,       type = ro,  define = yes, optional = yes;
    OVERLAY4:  load = OVL4,       type = ro,  define = yes, optional = yes;
    OVERLAY5:  load = OVL5,       type = ro,  define = yes, optional = yes;
    OVERLAY6:  load = OVL6,       type = ro,  define = yes, optional = yes;
    OVERLAY7:  load = OVL7,       type = ro,  define = yes, optional = yes;
    OVERLAY8:  load = OVL8,       type = ro,  define = yes, optional = yes;
    OVERLAY9:  load = OVL9,       type = ro,  define = yes, optional = yes;
}
FEATURES {
    CONDES: type    = constructor,
            label   = __CONSTRUCTOR_TABLE__,
            count   = __CONSTRUCTOR_COUNT__,
            segment = INIT;
    CONDES: type    = destructor,
            label   = __DESTRUCTOR_TABLE__,
            count   = __DESTRUCTOR_COUNT__,
            segment = RODATA;
    CONDES: type    = interruptor,
            label   = __INTERRUPTOR_TABLE__,
            count   = __INTERRUPTOR_COUNT__,
            segment = RODATA,
            import  = __CALLIRQ__;
}

 

It must be the stress of my day job, or i'm burning out, but am having trouble understanding how the different segments fit together and which ones are needed at a minimum for an atari binary. (e.g. I know I need at least the header, and one segment with a run and/or init address pointer...but what does CC65 need for its own housekeeping on top of that?)

 

-Thom

Link to comment
Share on other sites

I am referring to the CC65 cross platform serial driver, namely:

 

(1) they aren't flushing properly when being opened/closed (this becomes evident when switching to a real Atari 850 or using a 6502 850 handler in Altirra)

 

Is this actually occurring on a real 850? My understanding from reviewing the 850 technical manual is that R: is supposed to do a flush of the output buffer on close... which is probably a bug I need to fix in Altirra's 6502-based handler.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...