Pab Posted March 31, 2014 Author Share Posted March 31, 2014 That was what I thought. There were other bugs that I found, but if you can't load a file under MyDOS or SpartaDOS on the Atari, there's no point in creating it. Quote Link to comment Share on other sites More sharing options...
Alfred Posted March 31, 2014 Share Posted March 31, 2014 I don't understand your bankswitching code, it's a mess. I think your first mistake is saving $D301 from within the DOS call. Under DOS 2.0 or MyDos this should not be an issue, but I can see where it might cause trouble under SpartaDos. I think you need to have a loader stub that saves $D301 itself and then loads the banks itself since I don't recall DOS 2.0 having the XIO #40 to do a binary load. I would swap banks before invoking any DOS function. I also don't see where you interrogate the hardware to determine just what banks are available. Unless you've set a minimum standard, I would think that would have to be the first order of business, determining what hardware is available. Quote Link to comment Share on other sites More sharing options...
Mathy Posted March 31, 2014 Share Posted March 31, 2014 Hello guys I don't know much about it, but why not use MEM.SAV (or the way it works) as a way to save data into the RAMdisk? Sincerely Mathy Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted March 31, 2014 Share Posted March 31, 2014 How does this sound for an option? Segments that need to be loaded into banked RAM will actually be loaded into memory starting at $8000 and moved after the segment is loaded. This would mean that any code destined to be compiled into the area from $8000-$BFFF would have to come in a later MODULE than the routines destined for the banks. Or, if you plan on having the main program in cartridge RAM at $A000-$BFFF (including the runtime), you just have to make sure you're not putting more than 8K in any MODULE. Sound like a reasonable restriction? Yes, but remember you can make the transient buffer smaller if need be and make the segments correspondingly smaller too (for example, copying four contiguous 4KB code blocks into an extended bank). This might relieve some knock-on restrictions. Quote Link to comment Share on other sites More sharing options...
Pab Posted March 31, 2014 Author Share Posted March 31, 2014 Right now I don't interrogate the hardware. At this stage I'm still only playing with the 4 "XE" banks, which are pretty standard. In the language's logic, bank 0 is the main RAM bank. Any address referenced without a bank number or as being in bank 0 is assumed to be in main RAM. Instead of higher banks being addressed through the bits switched in PORTB, however, I apply a bit of logic to calculate which bits to turn on based on a bank number from 1-32. First, I query what's in PORTB at the moment and do an AND #01 so I don't go swapping out OSRAM if it's active. Then I calculate which bank we are swapping in. Banks 1-4 are the XE banks, set through bits 2 and 3 of PORTB. (The language subtracts 1 from the bank number specified before calling routines, so "Bank 1" becomes XE Bank 0. 0160 LDA BANK 0170 AND #$03 ; Check the 4 lowest banks 0171 ASL A 0172 ASL A 0180 STA SCRATCH Banks 5-8 (internally 4-7) are presumed (at this moment) to be part of a 320XE upgrade, addressed through bit 5 of PORTB. 0190 LDA BANK 0200 AND #$04 ; Check the bit for 256K upgrades 0210 ASL A 0211 ASL A 0212 ASL A 0220 ORA SCRATCH 0230 STA SCRATCH Banks 9 through 16 (internally 8-15) are treated as a 576K upgrade addressed through bit 1 of PORTB 0240 LDA BANK 0250 AND #$08 ; Check for 576K upgrade banks 0260 LSR A 0261 LSR A 0270 ORA SCRATCH ; In the BASIC bit 0280 STA SCRATCH And if we have a 1Mb upgrade, banks 17-32 are assumed to be addressed through bit 6 of PORTB. 0290 LDA BANK 0300 AND #$10 ; A megabyte upgrade? 0301 ASL A 0302 ASL A 0303 ORA SCRATCH 0305 STA SCRATCH ; We have set all the bits This value is then OR'd with the old value of PORTB and stored. So, if you have a 1Mb upgrade and want to access the highest bank of RAM (Bank 32), the bank selection routine would turn on bits 2, 3, 5, 1, and 6 of PORTB. If you tried accessing bank 31, it would turn on 3, 5, 1, and 6. I know there has to be a better way, but this is what I have for now. It's easy to pull that code out and replace it however. The first segment of the file is a quickie stashed in the cassette buffer which copies the current value of PORTB into $CA. I did that only so I have a value to use when I want to force my way back into the main bank after loading data into a bank. Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted March 31, 2014 Share Posted March 31, 2014 Yep: I think I already posted a link to a good generic RAM detection routine you might use. But the method for getting code into extended memory is the same regardless of how many banks are present. Bank 0 for main bank makes perfect sense, as does caching the original PORTB value. Quote Link to comment Share on other sites More sharing options...
Pab Posted March 31, 2014 Author Share Posted March 31, 2014 My thinking is that most developers are going to want to develop for the lowest common denominator, so there isn't really a need for detection at the language level. They aren't going to stash variables or procedures anywhere other than the four banks they can be assured every machine with extended memory has. The place for detection is at the RTL level, so at runtime a program can decide where it wants to or can stash data. So if it wants to put buffers, tables, etc. in extended RAM it can make calls to routines like "CheckAvailableBanks" or "IsBankAvailable" or some such. For example, the bootstrap compiler uses a 16k code buffer to minimize writing, which would be a natural for an empty bank in the native Atari version. Those RTL routines could also detect if the program is running under SpartaDOS X so it would only use banks left free at the DOS level. Quote Link to comment Share on other sites More sharing options...
Alfred Posted March 31, 2014 Share Posted March 31, 2014 What is the binary supposed to do ? When I run it under Altirra as a 128K XL it enters the self-test code. When you say crashes, what are you seeing ? Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted March 31, 2014 Share Posted March 31, 2014 (edited) My thinking is that most developers are going to want to develop for the lowest common denominator, so there isn't really a need for detection at the language level. They aren't going to stash variables or procedures anywhere other than the four banks they can be assured every machine with extended memory has. The place for detection is at the RTL level, so at runtime a program can decide where it wants to or can stash data. So if it wants to put buffers, tables, etc. in extended RAM it can make calls to routines like "CheckAvailableBanks" or "IsBankAvailable" or some such. For example, the bootstrap compiler uses a 16k code buffer to minimize writing, which would be a natural for an empty bank in the native Atari version. Those RTL routines could also detect if the program is running under SpartaDOS X so it would only use banks left free at the DOS level. Well quite: the idea was that the detection routine runs at application run time and thus the BANK values the user hard-coded into the source become mapped to an array of arbitrary PORTB values which the coder can't know in advance and doesn't have to worry about (at least as far as code blocks are concerned). Edited March 31, 2014 by flashjazzcat Quote Link to comment Share on other sites More sharing options...
Pab Posted March 31, 2014 Author Share Posted March 31, 2014 Alfred: originally it was supposed to load a procedure into each of the four standard XE banks which called a PrintE routine, then the main procedure would call each of the four procedures in turn in each bank. Trying to use DOS to load directly into each bank proved to be a mistake as was pointed out by flashjazzcat upthread, so I've abandoned that approach for now in favor of a load-move routine. flashjazzcat: I've decided to go with your approach and build a bank table. Will just need to decide on a safe place to stash it. Quote Link to comment Share on other sites More sharing options...
Alfred Posted March 31, 2014 Share Posted March 31, 2014 Well you're free to implement what you like, but I disagree that direct bank loading via DOS is a mistake. I've used it myself in the past, so I know it works. Load and copy is going to be pretty slow. Quote Link to comment Share on other sites More sharing options...
Pab Posted March 31, 2014 Author Share Posted March 31, 2014 Just realized one of my other problems with SpartaDOS. Along the way I somehow ended up with two DEVICE RAMDISK statements in my CONFIG,SYS, so I had the main RAMDISK installed, and then another one in the XE banks that I had assumed were available. That was my own stupid fault. Quote Link to comment Share on other sites More sharing options...
Pab Posted March 31, 2014 Author Share Posted March 31, 2014 Well you're free to implement what you like, but I disagree that direct bank loading via DOS is a mistake. I've used it myself in the past, so I know it works. Load and copy is going to be pretty slow. Under Sparta? Well, I'm rewriting my banking code from the ground up, so I'll try it again with the new code. I agree that direct loading is much preferable to load-and-move. Quote Link to comment Share on other sites More sharing options...
Alfred Posted March 31, 2014 Share Posted March 31, 2014 Yes, under SpartaDos, although 3.2 and not SDX. My approach wasn't exactly like yours however. A kernel loaded first and then it switched to each bank in succession and loaded a program into each bank of memory. Your approach is sound however, and if it doesn't work either there is a bug in the PrintE bank code, or (my guess) is that there is a bug in the bank switching code; either a bad mask or an invalid bank # is being used. Quote Link to comment Share on other sites More sharing options...
Pab Posted March 31, 2014 Author Share Posted March 31, 2014 The PrintE is the same as I've been using and is sound. I posted the object code here a while back. It has to be in the bank code. Like I said, I'm tearing it down and rebuilding it from the ground up, so we shall see. Banks outside of the original 4 were never my specialty. I didn't have an expanded system until late in the game and never wrote a program that used anything other than the original 4, leaving the rest for ramdisks. Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted March 31, 2014 Share Posted March 31, 2014 (edited) Well you're free to implement what you like, but I disagree that direct bank loading via DOS is a mistake. I've used it myself in the past, so I know it works. Load and copy is going to be pretty slow. I just don't think it's safe and reliable, and therefore it's inadvisable. I'd have to use the Altirra debugger to verify this, but I suspect that (for example) when DOS 2.5 grabs a sector from the RAMdisk (requiring writes to PORTB), it won't necessarily restore the banking register's original state (it may simply be hard-coded to restore the base bank). Whether this is the case, I'm not completely certain, but I can't say it isn't the case, and unless it's written somewhere that direct binary loads into extended RAM are guaranteed to work with all widely used DOS packages, then my advice would be: don't assume it will work. As for load and copy being slow: I don't get that at all. Apparently we're talking about a supported maximum of four extended banks here, amounting to no more than 64KB of code (which is obviously an extreme case: I know of few people churning out executables of half that size). My word processor The Last Word loads 14KB of itself under the OS, which is necessarily a (two stage) load and copy operation, and frankly you can't perceive it happening. The 6502 can (I guess) shift around 40-50KB/s, so I would not regard load and copy as a significant overhead. Banks outside of the original 4 were never my specialty. I didn't have an expanded system until late in the game and never wrote a program that used anything other than the original 4, leaving the rest for ramdisks. This was my experience when I developed all my applications on a 130XE back in the 90s. When I came back to the Atari in 2008 and released some stuff, one of the first things I was asked to do was support more than the measly 128KB of yesteryear. Even 320KB seemed like unimaginable luxury back in the day: something I just read about in magazine ads. First thing I noticed in 2008 is that lots of people had 1MB Ataris. It took a few days of research to support these upgrades, but once it's done, it's done, and you have your re-usable code library. Or - to reiterate - you can use something pre-written which works: This is a good one which I use: http://atariki.krap.pl/index.php/Obsługa_rozszerzenia_pamięci_RAM Edited March 31, 2014 by flashjazzcat 1 Quote Link to comment Share on other sites More sharing options...
Pab Posted March 31, 2014 Author Share Posted March 31, 2014 Am I correct in my assumption that the largest upgrades out there right now are 64 banks? Or has someone managed a 2MB upgrade somehow? Quote Link to comment Share on other sites More sharing options...
Pab Posted March 31, 2014 Author Share Posted March 31, 2014 GAH! Shows how stupid I can be some times. I adapted flashjazzcat's routine for identifying and counting available banks, but I'd only allocated 64 bytes for the bank table. Then when it identified 65 banks (I had forgotten about $FF for the main bank) it overwrote the first byte of my routine to actually switch banks. Writing self-modifying code is cool. Writing accidentally self-modifying code is not. 1 Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted March 31, 2014 Share Posted March 31, 2014 I did something very similar the other day when I added an extra display line to a text editor and forgot to enlarge the line length table. Anyway, I wouldn't worry about 2MB upgrades right now, although a generic detection routine should theoretically find as many banks as are accessible through PORTB. You can just stop looking after you find 64 banks. If you need to know how to read the SDX banking tables (which you should do if you detect SpartaDOS X) and calculate free banks, banking masks, etc, let me know, although IIRC there are also some code samples on the same site as the RAM detection routine. Quote Link to comment Share on other sites More sharing options...
Pab Posted April 1, 2014 Author Share Posted April 1, 2014 Tested under SDX 4.46, SD 3.2f, BW DOS, MyDOS 4.53, and even DOS 2.5. (I have discovered through this process that Altirra does not like DOS 3. That's how thorough I wanted to be.) Under SDX, all routines that use banked RAM are disabled. (USE OSRAM/DEVICE SPARTA OSRAM, no RAMDISK, DOSKEY, etc.) Under DOS 2.5, RAMDISK.COM renamed to RAMDISK.SYS to keep it from running. Observable behavior: First segment, the "return to main RAM" routine, loads. Second segment, the rest of the banking runtime. Loads 65 bytes after the end of "return to main RAM" to leave room for the bank table. Third segment loads and runs at $480. This is the adaptation of flashjazzcat's code to detect banks and builds a bank table at $1F08 (right after "return from bank"), Next, the "Hello from bank 1" routine loads at $8000. A relocator runs at $480, switching in bank #1 and moving the code. Monitored in Altirra's debug mode, seems to work fine. "Hello from bank 2" loads at $8000 Relocator swaps in bank 2 and seems to move everything okey-dokey. "Hello from bank 3" loads Relocator seems to successfully swap it into bank #3. "Hello from bank 4" loads. Relocator seems to successfully swap it into bank #4. "Main" segment loads RUNAD starts program at $21CC "0" (for bank 1) stored into $CF Bank selection routine JSR'd at $1F49. Appropriate value loaded into PORTB. Selected bank swaps in. Bank selection routine RTS's. Program JSR's to $4000, where the "Hello from bank 1" procedure lives. System freezes. Same situation appears under each DOS. I am at a loss. test16.bin Quote Link to comment Share on other sites More sharing options...
Pab Posted April 1, 2014 Author Share Posted April 1, 2014 I did something very similar the other day when I added an extra display line to a text editor and forgot to enlarge the line length table. Anyway, I wouldn't worry about 2MB upgrades right now, although a generic detection routine should theoretically find as many banks as are accessible through PORTB. You can just stop looking after you find 64 banks. If you need to know how to read the SDX banking tables (which you should do if you detect SpartaDOS X) and calculate free banks, banking masks, etc, let me know, although IIRC there are also some code samples on the same site as the RAM detection routine. I will certainly get to you down the road for that. As for the site with the RAM detection routine, I can't read Polish and Babelfish only goes so far. Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted April 1, 2014 Share Posted April 1, 2014 (edited) The program crashes because you JSR to bank switching code at $1F00 from inside the banking window (at $4023 to be precise). The subroutine's return address immediately becomes invalid (in fact you RTS into a bunch of zeros). Note I did not write the RAM detection routine. Regarding wiki content: I used Google Translate or similar, although I did have prior tuition on the subject of SDX bank handling from Drac030. Now: I'm really curious to know why you think Altirra won't run DOS 3??? Edited April 1, 2014 by flashjazzcat 1 Quote Link to comment Share on other sites More sharing options...
+David_P Posted April 1, 2014 Share Posted April 1, 2014 Now: I'm really curious to know why you think Altirra won't run DOS 3??? Because it has taste 3 Quote Link to comment Share on other sites More sharing options...
Pab Posted April 1, 2014 Author Share Posted April 1, 2014 (edited) lda #$40 ; A9 40 sta L00A1 ; 85 A1 lda #$02 ; A9 02 sta L00A2 ; 85 A2 jsr L1F00 ; 20 00 1F jsr L215E ; 20 5E 21 pha ; 48 lda #$01 ; A9 01 sta L00CF ; 85 CF jsr L1F49 ; 20 49 1F pla ; 68 rts ; 60 How the hell did that get in there? Everything between the STA $A1 and the RTS should not have been there, except for the JSR $215E. Going to be a long night stepping through Pascal source, it looks like. Edited April 1, 2014 by Pab Quote Link to comment Share on other sites More sharing options...
Pab Posted April 1, 2014 Author Share Posted April 1, 2014 Not that it does anyone any good, but for the curious this is the source that I'm trying to compile right now. For the curious and the strong of stomach. MODULE ORG=$1F00 USES PRINT MODULE ORG=$4000:1 PROC Bank1 PrintE("Hello from bank #1!") RETURN MODULE ORG=$4000:2 PROC Bank2 PrintE("Hello from bank #2!") RETURN MODULE ORG=$4000:3 PROC Bank3 PrintE("Hello from bank #3!") RETURN MODULE ORG=$4000:4 PROC Bank4 PrintE("Hello from bank #4!") RETURN MODULE // Return to where we left off in main bank. PROC MAIN Bank1 Bank2 Bank3 Bank4 RETURN Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.