Jump to content

Photo

Action! Bank Selection

Action! Memory Bank Select

15 replies to this topic

#1 Ripdubski OFFLINE  

Ripdubski

    Stargunner

  • 1,246 posts

Posted Sat Jul 23, 2016 1:29 PM

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?



#2 Alfred OFFLINE  

Alfred

    Chopper Commander

  • 197 posts
  • Location:Elmwood, Ontario

Posted Sat Jul 23, 2016 7:59 PM

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.



#3 Rybags OFFLINE  

Rybags

    Quadrunner

  • 15,229 posts
  • Location:Australia

Posted Sat Jul 23, 2016 11:15 PM

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, Sat Jul 23, 2016 11:16 PM.


#4 danwinslow OFFLINE  

danwinslow

    River Patroller

  • 2,531 posts

Posted Sun Jul 24, 2016 5:42 AM

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.

#5 danwinslow OFFLINE  

danwinslow

    River Patroller

  • 2,531 posts

Posted Sun Jul 24, 2016 6:52 AM

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, Sun Jul 24, 2016 6:54 AM.


#6 ricortes OFFLINE  

ricortes

    Dragonstomper

  • 606 posts

Posted Sun Jul 24, 2016 9:08 AM

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.



#7 Rybags OFFLINE  

Rybags

    Quadrunner

  • 15,229 posts
  • Location:Australia

Posted Sun Jul 24, 2016 8:30 PM

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 ?



#8 Alfred OFFLINE  

Alfred

    Chopper Commander

  • 197 posts
  • Location:Elmwood, Ontario

Posted Sun Jul 24, 2016 9:45 PM

That would be easiest. Make sure anything that needs to be outside the bank window is first and compile from file rather than with a program in memory. That should put you well outside the window.



#9 danwinslow OFFLINE  

danwinslow

    River Patroller

  • 2,531 posts

Posted Mon Jul 25, 2016 6:35 AM

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.



#10 JoSch OFFLINE  

JoSch

    Moonsweeper

  • 425 posts
  • Location:Germany

Posted Mon Jul 25, 2016 7:02 AM

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.



#11 ricortes OFFLINE  

ricortes

    Dragonstomper

  • 606 posts

Posted Mon Jul 25, 2016 1:47 PM

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



#12 JoSch OFFLINE  

JoSch

    Moonsweeper

  • 425 posts
  • Location:Germany

Posted Mon Jul 25, 2016 2:27 PM

I looked it up in the Action manual.
Part VII, chapter 5 describes how to set where compiled code goes.

Edited by JoSch, Mon Jul 25, 2016 2:27 PM.


#13 Ripdubski OFFLINE  

Ripdubski

    Stargunner

  • Topic Starter
  • 1,246 posts

Posted Thu Jul 28, 2016 7:10 PM

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?  



#14 fujidude OFFLINE  

fujidude

    River Patroller

  • 4,732 posts
  • Location:United States of America

Posted Thu Jul 28, 2016 10:21 PM

You can easily compile from disk, but compiling to disk requires a special procedure and extra code, and can be tricky to make work sometimes.



#15 Alfred OFFLINE  

Alfred

    Chopper Commander

  • 197 posts
  • Location:Elmwood, Ontario

Posted Thu Jul 28, 2016 11:29 PM

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.



#16 Ripdubski OFFLINE  

Ripdubski

    Stargunner

  • Topic Starter
  • 1,246 posts

Posted Fri Jul 29, 2016 7:13 PM

You can easily compile from disk, but compiling to disk requires a special procedure and extra code, and can be tricky to make work sometimes.

 

OH, I didn't catch that the first time.  I will have to learn how to compile TO disk.  Thx for pointing this out.







Also tagged with one or more of these keywords: Action!, Memory, Bank Select

0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users