14

If I was to write an Amiga game, what would be the best/most reliable way to detect how much RAM is actually available?

Looking at Action's Guide to AGA-Fixing!, he mentions Faulty Memory Detection:

   move.l   #0,$0
   move.l   #$aaaaaaaa,$200000  ;Poke in $200000
   cmp.l    #$aaaaaaaa,$200000  ;Re-read to check valid address
   bne      NoFastAt200000
   cmp.l    $0,$200000          ;Test the mirror effect
   beq      NoFastAt200000

I do wonder though if that's a good way to work across all Amigas, from an original A1000 with 256k Chip RAM to an A4000 with 2MB Chip and 4MB Fast RAM. Also, I don't see how that would tell me how much Fast RAM is available.

I saw AvailMem and AllocMem in exec.library, though I wonder: Will that work even if I don't load Workbench? (That is, if my game boots from a Floppy disk directly - though from my understanding, exec.library is always around, since it's part of Kickstart)

For my specific need, I really only care about detecting if I have 512k or 1MB RAM available on a regular Amiga 500 with Kickstart 1.3, but I would like to make sure that the code works on other Amigas, including an A4000 with Kickstart 3.1 and Fast RAM.

2
  • 6
    For the broad case of "any Amiga", I can't see why you would abandon Exec's fairly complete memory configuration abilities. For the narrow case of an A500 with or without belly slot expansion RAM, you could just "hack" it.
    – Brian H
    Commented Dec 3, 2020 at 15:46
  • @BrianH Fair point: I wouldn't want to abandon it, if it's the best way to do it. I just don't know if it is the best way, since I'm just starting out learning Amiga development. Commented Dec 3, 2020 at 17:14

2 Answers 2

11

If I was to write an Amiga game, what would be the best/most reliable way to detect how much RAM is actually available?

The routine you're quoting is only able to detect chip memory (not fast memory), by hardware banging in certain areas. Games sometimes tried $C00000 (popular slow memory location) in the same fashion. But there are too many fast memory configurations to try to detect them that way. The system doesn't do like that (autoconfig works better, and other non-autoconfig boards have software that declare the available memory areas to the system)

Games sometimes did that on the $200000 address without checking the mirror effect (because they didn't expect chip memory to be more than one megabyte). And that failed.

But even games that end up taking over the system use AllocMem on boot (with MEMF_CHIP or MEMF_FAST) to get a base value, mask it to try to guess the start of the memory (and then destroyed the OS). It worked rather well on boot because no other program is using up any memory at this point.

And games not taking over the system can just use AvailMem with MEMF_LARGEST flag combined to MEMF_CHIP or MEMF_FAST to try to predict if the subsequent allocations that they're going to perform are going to succeed (else they can print an error message and exit). A lot of games don't predict it and if there isn't enough memory the game will fail at a random point of the game...

    move.l 4,A6
    move.l #MEMF_CHIP|MEMF_LARGEST,d1
    jsr  _LVOAvailMem(a6)
    cmp.l #$80000,d0
    bcc.b  .one_meg
    ; 512k only
    ...
.one_meg

MEMF_LARGEST is not absolutely necessary. It just tells that you can allocate that much memory in one go and it will succeed. Useful when you want to manage the memory block yourself after that.

For fast memory, using MEMF_LARGEST will return the biggest contiguous memory block. It means that if there are different fastmem areas (Z2 & Z3, slow), you'll only get the biggest one. Use just MEMF_FAST alone to get the total available fast memory amount.

Unlike some other libraries that need some initialization, the exec library functions are available as soon as the system is running. It works from a disk custom boot sector too.

Another way (maybe cleaner) is to check exec MaxLocMem, which provides top of chipmem ($80000 for 512k, $100000 for 1 meg, ...)

move.l 4,A6
move.l MaxLocMem(a6),d1
cmp.l  #$100000,d1
bcs.b  .not_one_meg

The only drawback is when you configure WinUAE with more than 2MB chip, MaxLocMem doesn't reflect the chipmem size you configured. But that's a corner case among cornercases (the AvailMem method works even in that case)

8

I do wonder though if that's a good way to work across all Amigas, from an original A1000 with 256k Chip RAM to an A4000 with 2MB Chip and 4MB Fast RAM.

No, it's a very bad way. This code can only be safely used if you have killed the OS and taken over completely - then you have to be aware of all possible differences between machines, including additional memory and I/O cards, different CPUs etc.

I saw AvailMem and AllocMem in exec.library, though I wonder: Will that work even if I don't load Workbench?

Yes (provided you didn't kill the OS by eg. overwriting allocated memory). For greatest compatibility your game should be run from the startup-sequence (if not from an icon on Workbench) rather than from bootblock code, then users can add commands before it if necessary to enable non-autoconfig RAM etc.

You should try to use the OS as much possible in order to support various features of the machine that may have different hardware implementations. Avoid code that accesses absolute memory locations or pokes into memory that doesn't belong to it, and only access I/O ports directly after claiming them for your exclusive use.

4
  • 1
    A friend of mine who was an Amiga dev in the late 1980s said that it was difficult to use things like the Copper without completely suspending all OS functions. Had things improved since then?
    – supercat
    Commented Apr 9, 2021 at 19:28
  • 1
    @supercat There are system functions for adding commands to the copper list. Whether using them is 'difficult' depends on your ability to program via the OS vs bare metal. I find killing the OS more difficult because then I have to do everything myself, including making a complete copper list to get the display going etc. Commented Apr 9, 2021 at 21:06
  • 1
    From what I recall, the system commands to modify the copper list aren't designed to support operations that modify the copper list extensively or dynamically (e.g. reprogramming a horizontal scroll register on every many consecutive scan lines of every frame to create a "ripple" effect).
    – supercat
    Commented Apr 9, 2021 at 21:08
  • The system has to modify the copper list to support screen dragging, different resolutions and colors etc. which are likely incompatible with dynamic manipulations used to create effects used in demos. For such things you may have to prevent the OS from touching the copper list, which can be done with LoadView(NULL). This turns off the system display so it won't interfere with your bare metal code. Commented Apr 9, 2021 at 21:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .