rje 230 Posted Tuesday at 07:22 PM (edited) 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 Wednesday at 02:19 PM by rje Quote Share this post Link to post Share on other sites
Lorin Millsap 188 Posted Tuesday at 07:24 PM That’s not entirely accurate. You can totally have 1536K. Sent from my iPhone using Tapatalk Quote Share this post Link to post Share on other sites
desertfish 323 Posted Tuesday at 08:33 PM 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 1 Quote Share this post Link to post Share on other sites
Lorin Millsap 188 Posted Tuesday at 09:49 PM 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 Quote Share this post Link to post Share on other sites
desertfish 323 Posted Tuesday at 09:54 PM I don't know what you mean precisely with the question sorry Quote Share this post Link to post Share on other sites
Lorin Millsap 188 Posted Tuesday at 09:58 PM I don't know what you mean precisely with the question sorryFor 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 Quote Share this post Link to post Share on other sites
desertfish 323 Posted Tuesday at 10:11 PM 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? Quote Share this post Link to post Share on other sites
rje 230 Posted Tuesday at 10:47 PM (edited) 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 Tuesday at 10:51 PM by rje Quote Share this post Link to post Share on other sites
rje 230 Posted Tuesday at 10:52 PM (edited) 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 Tuesday at 10:58 PM by rje Quote Share this post Link to post Share on other sites
Wavicle 22 Posted Wednesday at 12:20 AM 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. Quote Share this post Link to post Share on other sites
Lorin Millsap 188 Posted Wednesday at 12:37 AM 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 1 Quote Share this post Link to post Share on other sites
Elektron72 48 Posted Wednesday at 01:29 AM 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. Quote Share this post Link to post Share on other sites
rje 230 Posted Wednesday at 02:55 AM 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. Quote Share this post Link to post Share on other sites
Lorin Millsap 188 Posted Wednesday at 03:42 AM 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 1 Quote Share this post Link to post Share on other sites
Wavicle 22 Posted Wednesday at 04:26 AM (edited) 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 Wednesday at 04:50 PM by Wavicle Testing code markdown. 1 Quote Share this post Link to post Share on other sites
rje 230 Posted Wednesday at 01:04 PM (edited) 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 Wednesday at 02:02 PM by rje 1 Quote Share this post Link to post Share on other sites
rje 230 Posted Wednesday at 02:14 PM (edited) 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 Wednesday at 02:14 PM by rje Quote Share this post Link to post Share on other sites
Lorin Millsap 188 Posted Wednesday at 02:41 PM 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 Quote Share this post Link to post Share on other sites
Elektron72 48 Posted Wednesday at 02:48 PM 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). Quote Share this post Link to post Share on other sites
desertfish 323 Posted Wednesday at 05:54 PM 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) Quote Share this post Link to post Share on other sites
Lorin Millsap 188 Posted Wednesday at 06:22 PM 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 Quote Share this post Link to post Share on other sites
Wavicle 22 Posted Wednesday at 06:27 PM 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 Quote Share this post Link to post Share on other sites
Wavicle 22 Posted Wednesday at 06:43 PM 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. Quote Share this post Link to post Share on other sites
rje 230 Posted Wednesday at 08:59 PM (edited) 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 Wednesday at 09:09 PM by rje Quote Share this post Link to post Share on other sites
rje 230 Posted Wednesday at 09:16 PM Issue logged. https://github.com/commanderx16/x16-rom/issues/199 1 Quote Share this post Link to post Share on other sites