Jump to content
IGNORED

Action! Bank Selection


Recommended Posts

Im trying to learn how to use bank switching in Action!

; PORTB banking bit scheme
; SLF,NA,ANT,CPU,BNK,BNK,BAS,OS = FLDS
;   7, 6,  5,  4,  3,  2,  1, 0 = BNUM
; 128,64, 32, 16,  8,  4,  2, 1 = BVAL
;   1, 1,  1,  1,  0,  0,  1, 1 = 243 M
;   1, 1,  1,  0,  0,  0,  1, 1 = 227 1
;   1, 1,  1,  0,  0,  1,  1, 1 = 231 2
;   1, 1,  1,  0,  1,  0,  1, 1 = 235 3
;   1, 1,  1,  0,  1,  1,  1, 1 = 239 4

MODULE

; Bank switch defines
DEFINE PORTB = "$D301"
DEFINE BANKM = "243"
DEFINE BANK1 = "227"
DEFINE BANK2 = "231"
DEFINE BANK3 = "235"
DEFINE BANK4 = "239"


PROC Main()
BYTE ARRAY bMem(16384)=$4000

; Set bank 1 memory
Poke(PORTB,BANK1)
SetBlock(bMem,16384,50)

; Set bank 2 memory
Poke(PORTB,BANK2)
SetBlock(bMem,16384,51)

; Set bank 3 memory 
Poke(PORTB,BANK3)
SetBlock(bMem,16384,52)

; Set bank 4 memory 
Poke(PORTB,BANK4)
SetBlock(bMem,16384,53)

; Set bank M memory
Poke(PORTB,BANKM)
SetBlock(bMem,16384,49)

RETURN

When I compile and run this in the Action! monitor, it works fine. PORTB is correctly set at 243, and 4000 to 7FFF is filled with 49.

 

When I include it in a larger program, with the Action! runtime, it crashes the machine. At crash, PORTB is 227, and 4000 to 7FFF is filled with 0. I think its crashing on the SetBlock for bank 1 "SetBlock(bMem,16384,50)".

 

So two questions. 1) Am I doing this right? 2) What could be causing it to crash when in a larger program using the runtime?

Link to comment
Share on other sites

It looks like you are swapping banks correctly. If it's crashing in the larger program, when the first swap occurs I would start thinking that some piece of interrupt code is missing. Also check to make sure that the runtime itself is not falling in the bank window. The fact that it crashes says something goes missing when the bank swaps, so it's just figuring out what the missing part is.

Link to comment
Share on other sites

Emulation or real? Working stuff like this out is much easeier in emulation since you can at least find out what the PORTB state is when it crashes.

 

When doing banking via PORTB no matter what the reason it's always a good idea to do so by masking and setting bits rather than storing absolute values.

Potentially a Dos, driver, utility or something resident that also uses banking to keep anything in extended memory could be upset by another program doing the same.

 

Also, the Ram window sits @ $4000-$7FFF which will be the middle chunk of any medium/large program in a language environment. If you return from your program with a different bank presented to the CPU then it's potential for real problems. If you return with the OS switched off and no valid OS in the Ram then 100% crash certainty.

 

Action was released well before the 130XE and it's extended memory scheme was devised so has no inbuilt mechnism to know or preserve Ram bank settings.

 

 

At the least it's a good idea to keep a copy of PORTB when your program starts then restore the value just before exiting.

Edited by Rybags
Link to comment
Share on other sites

Your routine is probably switching part of itself out. If any part of your program exists in the bank you are switching out, and you happen either be directly in that or use a library call that has code in that bank, then BOOM. Running it differently with different amounts of code present can re-arrange the way its laid out in memory, and that is why it works one way and not the other.

  • Like 1
Link to comment
Share on other sites

Basically, get the byte from PORTB, bitwise AND it with hex C3, and then bitwise OR it with the values in lines 2-6 below, depending on what bank you want. You can put them in an array (30,20,23,28,2C) and index them with 0 for normal bank, 1 for first extended bank, etc.

  0xC3,                            //banking_mask    11000011 
  0x30,                            //main_bank       00110000 
  0x20,                            //first_bank      00100000
  0x24,                            //second_bank     00100100       
  0x28,                            //third_bank      00101000          
  0x2C                             //fourth_bank     00101100
These values are for an unmodified 130XE. Edited by danwinslow
Link to comment
Share on other sites

Quick answer, save all your code to disk and use compile from disk while in the MONITOR! to test your code. If it works, you were using the memory into banked. If it doesn't work, probably a problem with your code.

 

Expanding on what is being said by the previous posters, it comes down to the way Action works. Let's say you are using a DOS with a mem lo of ~8k. From somewhat faulty memory :) The text buffer for Action is set at mem lo and grows from there. If your main program takes up 8k, that puts the start of your compiled program at 16k. The included runtime will add ~3-5k depending on things like editing out routines you don't need and added ones that you wrote yourself or got from other people. Add in the compiled code from your program, lets say 12k, and you have now totaled 32k+ or gone into banked memory. Note that in this example, your actual program will load at ~mem lo + text buffer + compiled runtime or around 20k! The area between DOS memlo and the start of the runtime package is not used! Runtime will start at ~16k and your code will be appended/compiled there.

 

Of course it would be even worse if instead of including your runtime from disk, you loaded it into the program editor with your code. I mean it is possible to actually run out of memory JUST WITH CODE IN THE EDITOR!

 

Eventually everything on the Atari becomes compile from disk. I am including assemblers in the mix for the same reason, you can't have both the source code and compiled code in memory at the same time, just not enough room on what is essentially a machine with ~30k of free memory.

 

It is actually a good thing on some levels. Encourages good programming practices. Eventually you may have huge data arrays and Action doesn't have a short form for including them. I recall once including three uncompressed MicroIllustrator pics in a program and the byte arrays alone were something like 72k. At some time you may want or need the full memory available which means you will need the cart space too.

Link to comment
Share on other sites

Your routine is probably switching part of itself out. If any part of your program exists in the bank you are switching out, and you happen either be directly in that or use a library call that has code in that bank, then BOOM. Running it differently with different amounts of code present can re-arrange the way its laid out in memory, and that is why it works one way and not the other.

 

I should have thought of this... it's probably what's happening.

But can it be avoided? If you put bank switch and extended access at the start of your program will it be the first thing compiled and so end up living somewhere in low memory safely under $4000 ?

Link to comment
Share on other sites

Yep. You have to arrange things carefully. Obviously the bank switch routine must be outside the $4000-$7FFF boundary, but so must all library functions that get called during the time the original bank is switched out. If you are using the banked memory just as data storage, it's somewhat easier to handle, but if you are switching to code that runs in extended then you need to make sure any functions that get called are either completely within the bank or completely outside the bank. A development environment that allows code segments to be placed as desired is really helpful, I don't recall whether Action gives you that kind of control or not.

Link to comment
Share on other sites

Yep. You have to arrange things carefully. Obviously the bank switch routine must be outside the $4000-$7FFF boundary, but so must all library functions that get called during the time the original bank is switched out. If you are using the banked memory just as data storage, it's somewhat easier to handle, but if you are switching to code that runs in extended then you need to make sure any functions that get called are either completely within the bank or completely outside the bank. A development environment that allows code segments to be placed as desired is really helpful, I don't recall whether Action gives you that kind of control or not.

IIRC, there is some compiler directive ('SET' perhaps?), which works similar to *=/.ORG in assembler.

Link to comment
Share on other sites

IIRC, there is some compiler directive ('SET' perhaps?), which works similar to *=/.ORG in assembler.

 

These threads are exposing some of the things I never tried. :)

 

I believe you can use the compile to disk operation along with the INIT/RUN vectors to over lap assembly programs. For example you can use the directive *=$2000 with the INIT vector to run multiple routines from a single contiguous file. The first one runs, returns to DOS, DOS then loads and RUNs the next block, ad infinitum. There is the compile to disk hack/program and I'm not sure I have ever tried to run multiple Action programs chained together with that method. Of course you can only do it with the original version of the cart as it was patched by FTE to use the RUN vs. INIT vector in later production runs. I still have two of the original carts floating around my house somewhere so it doesn't apply to me. :)

Link to comment
Share on other sites

Great responses. Thanks.

 

The banks will be used for data, not program code.

 

I set this variable as 16K and defined at $4000:

BYTE ARRAY bMem(16384)=$4000

 

I thought this would reserved that 16K block at $4000 for this variable. Then switching the banks out would allow the variable to reference data in that bank from the same address. At least I think thats how it would work based on my reading.

 

 

I will try the compile from disk. Even that simple program listed above craps out when run from disk (compiled from memory).

 

I've been using SpartDOS 3.2g under emulation. The use of the emulator is how I found the status of PORTB. Next question, does it matter which DOS is in use when the program is written to disk from from the monitor using WRITE?

Link to comment
Share on other sites

Great responses. Thanks.

 

The banks will be used for data, not program code.

 

I set this variable as 16K and defined at $4000:

BYTE ARRAY bMem(16384)=$4000

 

I thought this would reserved that 16K block at $4000 for this variable. Then switching the banks out would allow the variable to reference data in that bank from the same address. At least I think thats how it would work based on my reading.

 

 

I will try the compile from disk. Even that simple program listed above craps out when run from disk (compiled from memory).

 

I've been using SpartDOS 3.2g under emulation. The use of the emulator is how I found the status of PORTB. Next question, does it matter which DOS is in use when the program is written to disk from from the monitor using WRITE?

 

Nothing wrong with your plan, but you need to keep any executing code out of the window. If you are including the Action! runtime package this pretty much means you have to compile from disk. When the compile is done, use the monitor to peek at location 14; this will tell you where the end of code is. Location $491 is where the code starts.

 

It doesn't matter what DOS you use to write the binary file.

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...