Jump to content
rje

Count your RAM banks

Recommended Posts

Here's how I DID it.  See what's wrong?

void determineBankCount()
{
   setRAMbank(1);
   POKE(0xa000,17); // 17 is "a very random number"
   bankCount = 256;  // starting assumption; prove me wrong.
   setRAMbank(129);
   if (PEEK(0xa000) == 17) bankCount = 128; // 1024K
   setRAMbank(65);
   if (PEEK(0xa000) == 17) bankCount = 64; // 512K
}
	

 

Here's a mo' betta' way:

void determineBankCount()
{
   bankCount = 256;

   // I could do this with a loop, but meh.

   setRAMbank(192);  
   POKE(0xb000,17);
   setRAMbank(0);
   if (PEEK(0xb000) == 17) bankCount = 192;

   setRAMbank(128);
   POKE(0xb000,17);
   setRAMbank(0);
   if (PEEK(0xb000) == 17) bankCount = 128;

   setRAMbank(64);
   POKE(0xb000,17);
   setRAMbank(0);
   if (PEEK(0xb000) == 17) bankCount = 64;
}
	

 

Edited by rje

Share this post


Link to post
Share on other sites
If you use MEMTOP kernal routine with carry set, it will return the number of ram banks in A:
secjsr  MEMTOP     ; $FF99sta  num_banks

 


Question. I’m not as much of a programmer, but is MEMTOP not mirrored in RAM?


Sent from my iPhone using Tapatalk

Share this post


Link to post
Share on other sites
I don't know what you mean precisely with the question sorry

For at least most KERNAL routines they are located in RAM in a vector table. The problem with using the ROM vector table is new routines that supersede the KERNAL functions can be pointed to using the RAM vectors whereas if you use the ROM vectors you don’t get the benefit of the new routines. The commodore systems would copy the KERNAL vectors to RAM locations which meant you could inject patches.

 

I don’t know if this routine in particular has a RAM vector or not.

 

 

Sent from my iPhone using Tapatalk

Share this post


Link to post
Share on other sites

For what I can see, it is not mirrored via a vector in ram. The entry at $ff99 in the kernal's jump table directly jmps to another location in rom, instead of doing a vectored (indirect) jmp. Indeed a handful of kernal routines do the vectoring (not many, tbh), but  MEMTOP isn't among those.   Does this matter?

 

Share this post


Link to post
Share on other sites
3 hours ago, Lorin Millsap said:

That’s not entirely accurate. You can totally have 1536K.


Sent from my iPhone using Tapatalk

Ha, yeah I suspected so.  Actually I do have that line in my code... but the (r38) emulator won't allow that setting for testing.
 

   setRAMbank(193);
   if (PEEK(0xa000) == 17) bankCount = 192;

The r38 Usage says

Quote

-ram <ramsize>

Specify banked RAM size in KB (8, 16, 32, ..., 2048).

The default is 512.

And it poops out when I run it with -ram 1536 😞

Edited by rje

Share this post


Link to post
Share on other sites
2 hours ago, desertfish said:

If you use MEMTOP kernal routine with carry set, it will return the number of ram banks in A:


sec
jsr  MEMTOP     ; $FF99
sta  num_banks

 

You're right - I could (should) just use MEMTOP and check the accumulator.  I did it brute force instead, which might actually not work in real life if the X16 doesn't do RAM mirroring.

 

And as far as MEMTOP goes: the KERNAL routine itself has been rejiggered to return the bank count, so I don't think it matters that the vector is in ROM.

 

And... correct me if I'm wrong; I've never really had to think about this, but:  isn't it just the I/O KERNAL routines that COME FROM (for those of you fluent in INTERCAL) an indirect vector that's initialized into RAM at boot time?   I.E. the only things you'd need to "re-vector" are I/O, isn't that correct?     Oh heck, I need to go back to pagetable.com and study harder.

 

Edited by rje

Share this post


Link to post
Share on other sites
40 minutes ago, rje said:

You're right - I could just use MEMTOP and check the accumulator.  I did it brute force instead, which might actually not work in real life if the X16 doesn't do RAM mirroring.

Your thinking isn't far off though. You can see how KERNAL does it here. The biggest difference between your implementation and KERNAL is that you use the random number 17 and KERNAL uses the random number "1 + whatever is in $a000 of bank 0". If I'm reading the code correctly, KERNAL is making the optimization assumption that the number of banks will always be a power of 2 since the loop uses the accumulator to select the bank and modifies the accumulator with asl. If loop #7 passes (testing bank #128) it calls memtop with 0 in A, which I guess means 256 banks (2 MB).

2 hours ago, desertfish said:

For what I can see, it is not mirrored via a vector in ram. The entry at $ff99 in the kernal's jump table directly jmps to another location in rom, instead of doing a vectored (indirect) jmp. Indeed a handful of kernal routines do the vectoring (not many, tbh), but  MEMTOP isn't among those.   Does this matter?

 

It is stored in the KERNAL variable area (KVAR segment, which is $0200-$02BA I think) but you'd probably need to look at the assembler map file to know where. Most importantly though: doing so would be a bad idea. There is nothing that says the location is guaranteed to be the same across all releases of KERNAL. MEMTOP is guaranteed to always return the correct value.

Share this post


Link to post
Share on other sites

I guess in this case a custom version of the routine is unlikely so using the ROM vector would be safe.

The real hardware does not mirror the ram. So if you attempted to read or write banks that don’t exist what you will get is garbage.


Sent from my iPhone using Tapatalk

  • Thanks 1

Share this post


Link to post
Share on other sites
43 minutes ago, Lorin Millsap said:

I guess in this case a custom version of the routine is unlikely so using the ROM vector would be safe.

The ROM vectors for routines that have RAM vectors are simply indirect jumps through the RAM vectors, so I don't think it would make a difference if the ROM vectors were used even if this routine had a RAM vector. For example, the ROM vector for OPEN (a routine that has a RAM vector) contains this:

Quote

jmp ($031a)

As $031A is the RAM vector for OPEN, the way the routine is called makes no difference.

Additionally, considering that there is no way to perform an indirect JSR, using the vector table in ROM is usually more convenient than trying to directly access the RAM vectors.

Share this post


Link to post
Share on other sites
2 hours ago, Wavicle said:

Your thinking isn't far off though. You can see how KERNAL does it here.

Ah.  If you can write to it and then read it back, the bank exists.  I think I'll modify my algo...  better yet, I'll use MEMTOP.

 

Share this post


Link to post
Share on other sites
Ah.  If you can write to it and then read it back, the bank exists.  I think I'll modify my algo...  better yet, I'll use MEMTOP.
 

A lot of this is a good approach to a full RAM test.


Sent from my iPhone using Tapatalk
  • Like 1

Share this post


Link to post
Share on other sites
13 hours ago, rje said:

Ah.  If you can write to it and then read it back, the bank exists.  I think I'll modify my algo...  better yet, I'll use MEMTOP.

 

Not exactly. That algorithm actually writes to the banked memory and then checks to see if that value appears in bank zero. If so, then the bank does not exist and loop exits. I've annotated what I think the code is doing here:

    stz ram_bank    ; Switch to bank 0
    ldx $a000       ; Create 'magic X' value by adding
    inx             ; 1 to whatever is @ bank 0 offset 0
    lda #1          ; Set A to begin at bank 1

:    sta ram_bank    ; Switch to bank specified by A
    ldy $a000       ; Save value at bank A offset 0
    stx $a000       ; Write 'magic X' value to offset 0
    stz ram_bank    ; Switch to bank 0
    cpx $a000       ; Check if 'magic X' is mysteriously here
    sta ram_bank    ; Switch back to bank A
    sty $a000       ; Restore original value
    beq :+          ; If 'magic X' was found, we're done.
    asl             ; Double # of banks considered

I'm not quite sure how to get the forum software to format that with a monospace font, but I think you can get the general idea.

Edited by Wavicle
Testing code markdown.
  • Thanks 1

Share this post


Link to post
Share on other sites

Lorin Said:

Quote

A lot of this is a good approach to a full RAM test.

That sounds fun.  I'll extend my dumper.

 

9 hours ago, Wavicle said:

Not exactly. That algorithm actually writes to the banked memory and then checks to see if that value appears in bank zero. If so, then the bank does not exist and loop exits. I've annotated what I think the code is doing here:

  ...

I'm not quite sure how to get the forum software to format that with a monospace font, but I think you can get the general idea.

Use [ code ] and [ / code ] (sans spaces).

Thank you for that, by the way.

Edited by rje
  • Thanks 1

Share this post


Link to post
Share on other sites

It seems that the bank routine in MEMTOP is slightly incorrect, then?

Due to the ASL, if there is 1536K of banked RAM, e.g. 3 chips, then MEMTOP will only report 1024K, won't it?

 

Edited by rje

Share this post


Link to post
Share on other sites
Not exactly. That algorithm actually writes to the banked memory and then checks to see if that value appears in bank zero. If so, then the bank does not exist and loop exits. I've annotated what I think the code is doing here:

    stz ram_bank    ; Switch to bank 0

    ldx $a000       ; Create 'magic X' value by adding

    inx             ; 1 to whatever is @ bank 0 offset 0

    lda #1          ; Set A to begin at bank 1

 

:    sta ram_bank    ; Switch to bank specified by A

    ldy $a000       ; Save value at bank A offset 0

    stx $a000       ; Write 'magic X' value to offset 0

    stz ram_bank    ; Switch to bank 0

    cpx $a000       ; Check if 'magic X' is mysteriously here

    sta ram_bank    ; Switch back to bank A

    sty $a000       ; Restore original value

    beq :+          ; If 'magic X' was found, we're done.

    asl             ; Double # of banks considered

I'm not quite sure how to get the forum software to format that with a monospace font, but I think you can get the general idea.

That’s interesting. I might need to bring that up with Micheal. Because what should happen if you try to access banks that don’t actually exist is the CS lines will not connect to anything. If the CPU writes a nonexistent address then no CS line is ever asserted so the data will just float on the buss till it gets changed by something driving the buss. On a read again since no CS line goes active the buss will just kinda float. Unused banks do not mirror.

 

 

Sent from my iPhone using Tapatalk

Share this post


Link to post
Share on other sites
29 minutes ago, rje said:

It seems that the bank routine in MEMTOP is slightly incorrect, then?

Yes; it appears that the current version of MEMTOP assumes that the number of banks must be a power of two.

29 minutes ago, rje said:

Due to the ASL, if there is 1536K of banked RAM, e.g. 3 chips, then MEMTOP will only report 1024K, won't it?

The behavior I've predicted is actually worse: I think it will report 2048K. After testing for the existence of bank 128 (which will succeed), it will left-shift the value in A, which will cause it to contain zero upon return (side note: a zero in A from MEMTOP indicates 256 banks).

4 minutes ago, Lorin Millsap said:

That’s interesting. I might need to bring that up with Micheal. Because what should happen if you try to access banks that don’t actually exist is the CS lines will float. If the CPU writes a nonexistent address then no CS line is ever driven so the data will just float on the buss till it gets changed by something driving the buss. On a read again since no CS line goes active the buss will just kinda float. Unused banks do not mirror.

At this point, I think it's clear that the entire MEMTOP routine needs to be rewritten. Someone should open a GitHub issue about this (I might do that later today).

Share this post


Link to post
Share on other sites

is it even physically possible to have a non-power-of-two number of banks?  🤔   Having an odd number of mem chips on the board somehow seems "off" to me (but i'm a noob regarding that so yeah)

Share this post


Link to post
Share on other sites
is it even physically possible to have a non-power-of-two number of banks?     Having an odd number of mem chips on the board somehow seems "off" to me (but i'm a noob regarding that so yeah)

Absolutely. There is nothing about the design that limits that. In fact the base 512k is just one.


Sent from my iPhone using Tapatalk

Share this post


Link to post
Share on other sites
3 hours ago, Elektron72 said:

Yes; it appears that the current version of MEMTOP assumes that the number of banks must be a power of two.

The behavior I've predicted is actually worse: I think it will report 2048K. After testing for the existence of bank 128 (which will succeed), it will left-shift the value in A, which will cause it to contain zero upon return (side note: a zero in A from MEMTOP indicates 256 banks).

At this point, I think it's clear that the entire MEMTOP routine needs to be rewritten. Someone should open a GitHub issue about this (I might do that later today).

If I put on my computer science hat, I would point out that a binary search has the same time complexity, O(log N), as the current implementation.

If I put on my software engineer hat, I would point out that a binary search is rather a lot of easy-to-get-wrong code just for counting available memory banks.

If I put on my computer engineer hat, I would point out that there is probably a minimum increment that could be checked, probably around 64K, which would significantly reduce the size of a linear search while still getting the right number.

Having close to zero 6502 experience, I'm not the right person to fix it in any case 🤔

Share this post


Link to post
Share on other sites
33 minutes ago, desertfish said:

is it even physically possible to have a non-power-of-two number of banks?  🤔   Having an odd number of mem chips on the board somehow seems "off" to me (but i'm a noob regarding that so yeah)

In general parallel bus RAM chips usually have a power of 2 memory size. I'm not 100% certain of this, but I suspect that it is probably so that there are no invalid combinations of their address wires. Off the top of my head, I cannot recall seeing such a RAM chip that was not sized as a power of 2.

Seeing a non-power (or even multiple) of 2 RAM chips on a design is reasonably common. Usually all of the memory components are the same size, but this is mostly done to save on production costs.

Share this post


Link to post
Share on other sites

Banked RAM consists of up to four RAM chips, each with 512K of static RAM, if I understand correctly.

Chip 1: Banks 0-63.  Always present (required, since Bank 0 is used by the OS).
Chip 2: Banks 64-127.
Chip 3: Banks 128-191.
Chip 4: Banks 192-255.

Thus, a test would check one bank as a proxy for each 512K segment (say, banks 65, 129, and 193), and see if it can write/read that bank.

 

I wonder if a 256K static RAM would fit in those spots... horrors...

 

Edited by rje

Share this post


Link to post
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.

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.


×
×
  • Create New...

Important Information

Please review our Terms of Use