+Al_Nafuur Posted January 17, 2022 Share Posted January 17, 2022 The last few days I have been dealing with a strange behavior of the VCS 6502 hardware (Maybe this behavior is commonly known, but it took me a few days). I want to add @cd-w's 24 char textkernel to display the online HSC table in 1942 bB. One part of the HSC table screen data is in ROM (the title rows) and the other part is in SC-RAM (the table). The base address for the indexed read is in SC-RAM and if I want to display a row from ROM the index is greater 127 and the page boundary from SC-RAM to the first ROM page is crossed. This takes only an additional cpu cycle and works fine on the emulators (except for a wrong scanline count). But on the real hardware it looks like the low byte of the new address is set in the regular cycle and the high byte in the additional. Unfortunately the first of these two cycles looks like an access to the low byte of the same page for the cartridge, which is in our case (even more unfortunately) the write port of the SC-RAM, so the cartridge takes whatever is on the data-bus at then end of this cycle and writes it to the SC-RAM! textkernel_HSC.asm textkernel_HSC.asm.bin Quote Link to comment Share on other sites More sharing options...
+splendidnut Posted January 17, 2022 Share Posted January 17, 2022 Due to the way the 6502 is designed, page-crossing will cause a bad address to appear on the address bus for a single CPU cycle before the proper address appears. (the 8-bit ALU is in the middle of calculating the 16-bit address that the code wants to access). This usually doesn't matter. BUT, for the Atari 2600, the cartridge doesn't have access to the R/W line. So you'll end up with these sorts of corruption issues. It's best to try and avoid page crossing when reading/writing data to SC-RAM. 5 Quote Link to comment Share on other sites More sharing options...
SvOlli Posted January 19, 2022 Share Posted January 19, 2022 What you are experiencing is a so-called "ghost read". The CPU does a dummy-read on an address where the "summed up" hi-byte of the address was not taken into account.I ran into a similar problem when writing a UDP stack for a C64 network card. I noticed it in short here rather at the end: Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted January 20, 2022 Share Posted January 20, 2022 (edited) I will create an issue for Stella for this. Edited January 20, 2022 by Thomas Jentzsch Quote Link to comment Share on other sites More sharing options...
+Al_Nafuur Posted January 20, 2022 Author Share Posted January 20, 2022 6 minutes ago, Thomas Jentzsch said: For development you should enable "Trap on 'ghost' reads" (Options/Developer/Debugger). Then you would notice this. it was/is enabled, but I still don't see the same effect than on hardware: @JetSetIlly added the "feature" to gopher2600 and this is what it looks like (and on the PlusCart too) : we wern't able to test on the Harmony cart, because the test ROM is 4kSC but the Harmony seems to detect it as 4k. And we are also not sure if the Harmony cart supports 4kSC at all. Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted January 20, 2022 Share Posted January 20, 2022 (edited) Yea, I had already edited my post. There is a bug in Stella (new issue here). Fixed! Edited January 20, 2022 by Thomas Jentzsch 1 Quote Link to comment Share on other sites More sharing options...
+Al_Nafuur Posted January 20, 2022 Author Share Posted January 20, 2022 3 hours ago, Thomas Jentzsch said: Yea, I had already edited my post. There is a bug in Stella (new issue here). Fixed! As far as I can see from your code you are storing random values in the SC-RAM when a read (or ghost-read) occurs to the SC-RAM write port. I think it would be a better emulation to store the last byte on the data-bus to the SC-RAM. Technically the data-bus is not driven in that cycle. It has been driven by the cartridge with the last value from the ROM ($f0 in our example here) until the beginning of that cycle (indicated to the cartridge by the address-bus change). b9 80 f0 lda RAM_Messages+0,Y so the situation is (nearly) the same than reading a value from an ZP write address. Only that in this case the cart and not the 6502 is reading the (fading) value from the data-bus. If there are some pull-ups or downs involved in the data-bus circuitry the value might fade faster on different setups and the read will be not be the last value on the data-bus. So using random values or the last value on the bus is both not an exact emulation. But I consider using the last value the better solution. I am not sure, but even if some disturbance is involved on the data-bus the resulting value will not be last byte, but it should be always the same value for the same "start" byte. 1 Quote Link to comment Share on other sites More sharing options...
alex_79 Posted January 20, 2022 Share Posted January 20, 2022 11 minutes ago, Al_Nafuur said: As far as I can see from your code you are storing random values in the SC-RAM when a read (or ghost-read) occurs to the SC-RAM write port. That comes from testing original superchip games: https://atariage.com/forums/topic/285759-stella-getting-into-details-help-wanted/ 1 Quote Link to comment Share on other sites More sharing options...
alex_79 Posted January 20, 2022 Share Posted January 20, 2022 (edited) Real superchip games use standard mask roms, (eg. there's an 8k rom for an f8SC game, even if two pages of it aren't actually visible by the 2600, as the ram is mapped there), with the Sara chip handling the chip select signal to the rom. My pet theory is that when addressing the first page on a bank, the rom can be briefly selected while the address bus is stabilizing, thus driving the data bus with whatever is on the mask rom on that address (which is not what you find on the dump unless the chip has been removed from the cart to obtain the binary). This doesn't happen on an harmony/melody/unocart/pluscart, where the arm is emulating the cartridge hardware and only reacts after the address is stable, thus resulting in the last value on the bus to be written to ram (edit: after rereading the old thread, the harmony seems to drive one of the bits high). Edited January 20, 2022 by alex_79 3 Quote Link to comment Share on other sites More sharing options...
+Karl G Posted January 20, 2022 Share Posted January 20, 2022 Huh. I guess I had better compile a version of Stella with this fix applied to make sure I'm not doing this in Penult anywhere. The idea that it may have been missed both on Stella and even playing on real hardware through a multicart is concerning. Quote Link to comment Share on other sites More sharing options...
+Al_Nafuur Posted January 20, 2022 Author Share Posted January 20, 2022 3 minutes ago, Karl G said: Huh. I guess I had better compile a version of Stella with this fix applied to make sure I'm not doing this in Penult anywhere. The idea that it may have been missed both on Stella and even playing on real hardware through a multicart is concerning. It just fails differently on a multicart and real SC-RAM/masked ROM hardware, but I don't see any chance that your code will work as expected on a multicart when it uses this "feature". 1 Quote Link to comment Share on other sites More sharing options...
+splendidnut Posted January 20, 2022 Share Posted January 20, 2022 Food for thought: Don't forget that the 7800 is a different beast altogether. It's probably best not to rely on any specific bus behavior. Quote Link to comment Share on other sites More sharing options...
SvOlli Posted January 20, 2022 Share Posted January 20, 2022 6 hours ago, Al_Nafuur said: we wern't able to test on the Harmony cart, because the test ROM is 4kSC but the Harmony seems to detect it as 4k. And we are also not sure if the Harmony cart supports 4kSC at all. Simple trick: just copy the 4kSC ROM two times to get an F8SC. When both banks contain the same, it does not matter when a bank-switch is triggered. Also when accessing original SARA, you have to take into account that the RAM is too slow for handling the "full" clockspeed of the 2600. This is why you can't have code running from $F0xx. Quote Link to comment Share on other sites More sharing options...
JetSetIlly Posted January 20, 2022 Share Posted January 20, 2022 (edited) Semi-related question: why don't Tigervision cartridges (method 3F) bank switch on phantom reads? Take Miner2049er for example. In bank 2 at address $3611, the instruction STA VSYNC,X will cause a phantom read of address 0. Absent some other condition, this phantom read will cause a switch to bank 0. What's the condition in the cartridge that prevents this from happening? If we say that 3F only bank switches on access of address $003F then it solves the problem. However, it is my understanding that any primary TIA address will work, thereby causing the issue of phantom access. Edited January 20, 2022 by JetSetIlly Quote Link to comment Share on other sites More sharing options...
+Al_Nafuur Posted January 20, 2022 Author Share Posted January 20, 2022 11 minutes ago, JetSetIlly said: Semi-related question: why don't Tigervision cartridges (method 3F) bank switch on phantom reads? Take Miner2049er for example. In bank 2 at address $3611, the instruction STA VSYNC,X will cause a phantom read of address 0. Absent some other condition, this phantom read will cause a switch to bank 0. What's the condition in the cartridge that prevents this from happening? If we say that 3F only bank switches on access of address $003F then it solves the problem. However, it is my understanding that any primary TIA address will work, thereby causing the issue of phantom access. IMHO because VSYNC is $00 a bank switching will only occur if X is $3F. Also a ghost write (with sta VSYNC,X) or a ghost read with (lda VSYNC,x) should never appear, because no matter what value X has there will never be a page crossed if the base address is the first byte of a page. Quote Link to comment Share on other sites More sharing options...
+Pat Brady Posted January 20, 2022 Share Posted January 20, 2022 8 hours ago, Al_Nafuur said: we wern't able to test on the Harmony cart, because the test ROM is 4kSC but the Harmony seems to detect it as 4k. And we are also not sure if the Harmony cart supports 4kSC at all. How hard would it be to expand the test ROM to F8SC? Quote Link to comment Share on other sites More sharing options...
SvOlli Posted January 20, 2022 Share Posted January 20, 2022 4 minutes ago, Pat Brady said: How hard would it be to expand the test ROM to F8SC? Simple: just concatinate the 4k-file two times into one 8k-file and you've got an F8SC. 1 1 Quote Link to comment Share on other sites More sharing options...
+Al_Nafuur Posted January 20, 2022 Author Share Posted January 20, 2022 5 minutes ago, Pat Brady said: How hard would it be to expand the test ROM to F8SC? according to @SvOlli its not hard: 2 hours ago, SvOlli said: Simple trick: just copy the 4kSC ROM two times to get an F8SC. When both banks contain the same, it does not matter when a bank-switch is triggered. so here you go: textkernel_HSC_8kSC.asm.bin 1 Quote Link to comment Share on other sites More sharing options...
JetSetIlly Posted January 20, 2022 Share Posted January 20, 2022 1 hour ago, Al_Nafuur said: IMHO because VSYNC is $00 a bank switching will only occur if X is $3F. Yes. If we say that the switching only ever occurs on access of $003f then that works. But I'm not sure it is limited to that single address. According to this old document by Kevin Horton (v6.0 of Cartridge Information) then scheme 3F will switch on an access of an address between 00 and 3f. http://kevtris.org/files/sizes.txt Maybe the document is wrong and it strictly works with address 3f 1 hour ago, Al_Nafuur said: Also a ghost write (with sta VSYNC,X) or a ghost read with (lda VSYNC,x) should never appear, because no matter what value X has there will never be a page crossed if the base address is the first byte of a page. It will. There's always a ghost read with indexed addressing. The base address is put on the bus while the index addition is taking place. Quote Link to comment Share on other sites More sharing options...
alex_79 Posted January 20, 2022 Share Posted January 20, 2022 The bankswitch happens if any address with both A6 and A7 low is accessed, and if A12 goes from low to high right after that access. That second part is the reason why that write (sta VSYNC,X, with X=$40) does not cause a bankswitch. This very old thread explains how the 3f banking was implemented. I quote it here with fixed formatting of the ASCII schematic. I also changed the labeling to avoid confusion about what A11 and A12 represent in the schematic: "RA11" and "RA12" are the ROM address pins, while "A11" and "A12" refers to the ones from the CPU. Quote Here's some text I got from Kevin Horton and Chad Schell plus an ascii diagram I did up. Not 100% sure of the inductor values or the caps to ground. -3F: Tigervision was the only user of this intresting method. This works in a similar fashion to the above method; however, there are only 4 2K segments instead of 4 1K ones, and the ROM image is broken up into 4 2K slices. As before, the last 2K always points to the last 2K of the image. You select the desired bank by performing an STA $3F instruction. The accumulator holds the desired bank number (0-3; only the lower two bits are used). Any STA in the $00-$3F range will change banks. This appears to interfere with the TIA addresses, which it does; however you just use $40 to $7F instead! :-) $3F does not have a corresponding TIA register, so writing here has no effect other than switching banks. Very clever; especially since you can implement this with only one chip! (a 74LS173) They are the simplest things inside. normal 8K ROM and a 74xx chip. It's a quad transparent latch. (can't remember the part # now exactly). D0, D1 run to the inputs on the D inputs on the latch, and the 2 outputs run to the upper address lines on the ROM. /OE runs to A11, and there are pullups on the outputs so that when A11 is high, the outputs tristate but are pulled up. This selects the last bank of ROM into the second bank in the 6502 address space. when A11 is low, the outputs of the latches are in effect so it selects the desired bank. The clock line is connected to A12, and the two enables are tied to A6 and A7. To get a valid latch, A12 has to go from LOW to HI, while A6 and A7 are low. ---------------------------------------------------------------------------- 74173 4-bit 3-state D flip-flop with reset, dual clock enables and dual output enables. 5v 5v | | | | / / 5.1k 5.1k +---+--+---+ / / gnd______/OE1 |1 +--+ 16| VCC________5v | | A11______/OE2 |2 15| RST________gnd | RA11__|______________Q0 |3 14| D0_________d0 RA12___|______________________Q1 |4 74 13| D1_________d1 Q2 |5 173 12| D2_________gnd Q3 |6 11| D3_________gnd A12_______CLK |7 10| /CLKEN1________, gnd_______GND |8 9| /CLKEN2___, | +----------+ | | _______ | | A7___///_____| |____| | 750 |_______| | | 10uh ___ | ___ | | | | | gnd | _______ | A6___///_____| |_________| 750 |_______| | 10uh ___ ___ | | gnd when executing the code "sta VSYNC,x" , there's a ghost read from the base address $00, followed by the write to the final address $40. So, while $00 is an hotspot, the bankswitch is not triggered, because there's not the clock pulse (A12 going from low to high) until after A6 goes high, which disables the latch. 2 Quote Link to comment Share on other sites More sharing options...
JetSetIlly Posted January 20, 2022 Share Posted January 20, 2022 3 minutes ago, alex_79 said: The bankswitch happens if any address with both A6 and A7 low is accessed, and if A12 goes from low to high right after that access. That second part is the reason why that write (sta VSYNC,X, with X=$40) does not cause a bankswitch. This very old thread explains how the 3f banking was implemented. I quote it here with fixed formatting of the ASCII schematic. I also changed the labeling to avoid confusion about what A11 and A12 represent in the schematic: "RA11" and "RA12" are the ROM address pins, while "A11" and "A12" refers to the ones from the CPU. when executing the code "sta VSYNC,x" , there's a ghost read from the base address $00, followed by the write to the final address $40. So, while $00 is an hotspot, the bankswitch is not triggered, because there's not the clock pulse (A12 going from low to high) until after A6 goes high, which disables the latch. Fantastic information. Quote Link to comment Share on other sites More sharing options...
+batari Posted January 20, 2022 Share Posted January 20, 2022 5 hours ago, Al_Nafuur said: So using random values or the last value on the bus is both not an exact emulation. But I consider using the last value the better solution. I wouldn't call it a solution, really, as there is no way to emulate this behavior because it can vary between consoles and between different carts in the same console, or even by waving your hand near the console or cart, or by temperature or other environmental effects. While I think Stella's behavior of using the last value by default is fine, the optional setting that randomly drives unused bits is very important in testing so that certain bugs may be found. Quote Link to comment Share on other sites More sharing options...
+batari Posted January 20, 2022 Share Posted January 20, 2022 19 minutes ago, alex_79 said: The bankswitch happens if any address with both A6 and A7 low is accessed, and if A12 goes from low to high right after that access. That second part is the reason why that write (sta VSYNC,X, with X=$40) does not cause a bankswitch. This very old thread explains how the 3f banking was implemented. I quote it here with fixed formatting of the ASCII schematic. I also changed the labeling to avoid confusion about what A11 and A12 represent in the schematic: "RA11" and "RA12" are the ROM address pins, while "A11" and "A12" refers to the ones from the CPU. when executing the code "sta VSYNC,x" , there's a ghost read from the base address $00, followed by the write to the final address $40. So, while $00 is an hotspot, the bankswitch is not triggered, because there's not the clock pulse (A12 going from low to high) until after A6 goes high, which disables the latch. That's one of my favorite circuits for bankswitching. Particularly I like the pair of RLC circuits to delay the write pulse until the right time. 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.