ZackAttack Posted December 16, 2017 Share Posted December 16, 2017 (edited) Here is a ROM that uses the power of the Harmony cart to display 10 colored sprites per line. It uses a prototype driver that isn't supported in emulation so you'll have to put it on a Harmony cart to run it. I'd like to get some feedback on how well this works on different systems. I've tested on a NTSC JR and 7800 and the results were good. Thanks to rbairos for providing the converted audio and graphics. Current Build: back-to-the-future4.bin Edit: 12/18/2017 - Uploaded version 4 with proper driver fix and an additional second of audio samples Edit: 12/16/2017 - Uploaded version 3 with extra nops to increase hold time Older Builds: back-to-the-future3.bin I've included a picture of it running for those who don't have a harmony and would like to see. There's more to it than what's in the picture though, so I'd recommend running it if you have the hardware handy. Here is the code for the display kernel. It's pretty messy due to the extreme optimization and complete misuse of the 6507 JSR instruction. In order to compensate for artifacts from the JSR instruction the ball is used to mask some pixels. There wasn't enough time to both resize it and enable it every scan line. So CTRLPF is used to do both by changing the size and the PF priority. The ball is always enabled, but it is shown or hidden based on the PF priority. Since JSR is used to write to GRP1 and GRP0 it's called a second time to write to AUDV1 and AUDV0. This allows for 5bit sampled audio, though this demo is only using 4 bits because of space constraints. After the GRP and AUD registers are written to a TXS is performed to reset the SP back to GRP1. The X register is preloaded with the address GRP1 in vblank and remains that value during the entire frame. Y is used for the color of the right most sprite and is loaded on the previous scan line. JSR values are computed by subtracting the number of bytes consumed by the instructions until the next JSR. Each JSR is effectively loading the values that will be stored in the next JSR when the PC gets pushed to the stack. The JSR must always target an address in the ROM. So D12 is always set. Because there are about 30 bytes between each JSR there are some values which require D11 to be set as well in order to avoid starting outside of ROM space. This is why 0x800 is added if D12 was cleared by the previous subtraction. This also increases the ball size to 2 so it covers both pixels represented by D12 and D11. Whether or not the ball was enabled was determined by D12 in the original value. There is a slight artifact if you have the second to last sprite with the pattern xxx1000 and the last sprite has a value less than 32 or so. In this case you end up with xxx1100. There simply isn't enough time to move the ball over one in order to mask just D11, so D11 remains visible. This is a very small percentage of the time and isn't very noticeable so it should be acceptable. It takes about 6 lines of vblank and overscan to fill the audio buffer, position objects, and initialize everything for the next frame. The 6507 runs a routine from ZP RAM for the other 64 lines. This routine updates the audio registers and performs the vsync. During those 64 lines the ARM CPU is currently idle. All the display kernel lookups are done between putting bytes on the 6507 data bus. Hopefully this provides enough time to load in more data from the EEPROM or the SD card. It at least provides ample time for some game logic and audio calculations though. Eventually I'll be posting the entire source to GitHub for everyone to enjoy, but I want to stabilize the design some more first. for(; i < 192;) { // Left group starts cycle 0 vcsJsr6(jsrl); // G, I Graphics <-e1 results in I=$ff vcsWrite5(GRP0, pGraphics[i*10]); // A graphic vcsWrite5(GRP1, pGraphics[i * 10 + 2]); // C graphic vcsWrite5(GRP0, pGraphics[i * 10 + 4]); // E graphic vcsWrite5(COLUP0, pColors[i * 10 + 0] << 1); // A color vcslda2(pColors[i * 10 + 2] << 1); // C color vcssta4(COLUP1); // C color vcslda2(pColors[i * 10 + 4] << 1); // E color vcstxs2(); // Should be 36 cycles prior to here vcssta3(COLUP0); // E color vcslda2(pColors[i * 10 + 6] << 1); // G Color - 41 // 0x20 - 23 = 0x09 => sample will offset range by 0-15 giving 0x20-0x2f vcsJsr6(0x1009 + ((sampleOffset & 1) ? pAudioSamples[sampleOffset >> 1] >> 4 : (pAudioSamples[sampleOffset >> 1] & 0xf))); sampleOffset++; vcssta3(COLUP1); // G Color vcssta3(GRP1); // Flush delay register vcssty3(COLUP0); // I Color - 56 i++; jsrr = (((unsigned short)pGraphics[i * 10 + 7]) << | pGraphics[i * 10 + 9]; // H and J graphics bytes vcsWrite5(HMP0, 0x80); ctrlpfr = ((jsrr & 0x1000) >> 10) ^ 0x5; vcssta3(HMP1); jsrr = (jsrr | 0x1000) - 33; //31 bytes between JSRs vcssta4(HMBL); if ((jsrr & 0x1000) == 0) { jsrr += 0x800; ctrlpfr |= 0x10; } vcsldy2(pColors[i * 10 + 9] << 1); // J Color vcsWrite5(HMOVE, 2); StaggeredFrame: if (i >= 192) { break; } // Right group starts cycle -1 vcsJsr6(jsrr); // H, J Graphics <-de results in J=$ff vcsWrite5(GRP0, pGraphics[i * 10 + 1]); // B graphic vcsWrite5(GRP1, pGraphics[i * 10 + 3]); // D graphic vcsWrite5(GRP0, pGraphics[i * 10 + 5]); // F graphic vcsWrite5(COLUP0, pColors[i * 10 + 1] << 1); // B color vcsWrite5(COLUP1, pColors[i * 10 + 3] << 1); // D color vcslda2(ctrlpfr); vcssta3(CTRLPF); vcslda2(pColors[i * 10 + 5] << 1); // F color vcstxs2(); // Should be 39 cycles prior to here vcssta3(COLUP0); // F color vcslda2(pColors[i * 10 + 7] << 1); // H Color - 44 // 0x20 - 22 = 0x0a => sample will offset range by 0-15 giving 0x20-0x2f vcsJsr6(0x100a + ((sampleOffset & 1) ? pAudioSamples[sampleOffset >> 1] >> 4 : (pAudioSamples[sampleOffset >> 1] & 0xf))); sampleOffset++; i++; jsrl = (((unsigned short)pGraphics[i * 10 + 6]) << | pGraphics[i * 10 + 8]; // G and I graphics bytes vcssta3(COLUP1); // H Color ctrlpfl = ((jsrl & 0x1000) >> 10) ^ 0x5; vcssta3(GRP1); // Flush delay register jsrl = (jsrl | 0x1000) - 30; //28 bytes between JSRs vcssty3(COLUP0); // J Color - 59 if ((jsrl & 0x1000) == 0) { jsrl += 0x800; ctrlpfl |= 0x10; } vcsWrite5(CTRLPF, ctrlpfl); vcsWrite5(HMCLR, 0x00); vcsWrite5(HMOVE, 2); vcsldy2(pColors[i * 10 + 8] << 1); // I Color } Edited December 18, 2017 by ZackAttack 6 Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted December 16, 2017 Share Posted December 16, 2017 doesn't work on my light sixer, I get a blank screen or various lines: 1 Quote Link to comment Share on other sites More sharing options...
Corby Posted December 16, 2017 Share Posted December 16, 2017 1 Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted December 16, 2017 Share Posted December 16, 2017 Update - the above was with the Encore. On my original Harmony I only get a blank screen. Quote Link to comment Share on other sites More sharing options...
ZackAttack Posted December 16, 2017 Author Share Posted December 16, 2017 Update - the above was with the Encore. On my original Harmony I only get a blank screen. That's NTSC right? Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted December 16, 2017 Share Posted December 16, 2017 Yes Quote Link to comment Share on other sites More sharing options...
ZackAttack Posted December 16, 2017 Author Share Posted December 16, 2017 doesn't work on my light sixer, I get a blank screen or various lines: Would you please try again with the next build in the first post? I changed the driver to wait for the correct ZP address to appear on the bus before tri-stating the data bus. Previously it was tri-stating the data bus as soon as the address changed away from the current ROM location. It's possible that your system is more sensitive to violating the hold time than the ones I'm testing on. Another possibility is that there is a bad bit in the RIOT RAM. Currently there are instructions executed form $80 to $B1. If the driver change doesn't help I can send you a different program that doesn't ever jump execution to RIOT RAM. Thanks for testing this. Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted December 16, 2017 Share Posted December 16, 2017 With the new build both Harmony & Encore show this, and the lines moves upward on the display. Quote Link to comment Share on other sites More sharing options...
CPUWIZ Posted December 16, 2017 Share Posted December 16, 2017 Have you tried another system, Darrell? Seems to me this is a super risky thing to do in a homebrew. Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted December 16, 2017 Share Posted December 16, 2017 That's the only Atari I have setup. The others would require me to drag an old TV out of storage, which ain't happening this month. Quote Link to comment Share on other sites More sharing options...
CPUWIZ Posted December 16, 2017 Share Posted December 16, 2017 Ahh, ok, figured you had a 7800 as well. Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted December 16, 2017 Share Posted December 16, 2017 I do have a 7800, just don't have a place to leave it permanently set up. When I use it I set it up on the kitchen table, but that's currently buried under a pile of presents I need to wrap. 1 Quote Link to comment Share on other sites More sharing options...
ZackAttack Posted December 16, 2017 Author Share Posted December 16, 2017 Have you tried another system, Darrell? Seems to me this is a super risky thing to do in a homebrew. Which part do you think is super risky? Quote Link to comment Share on other sites More sharing options...
CPUWIZ Posted December 16, 2017 Share Posted December 16, 2017 Which part do you think is super risky? Incompatibility issues, across systems. Quote Link to comment Share on other sites More sharing options...
ZackAttack Posted December 16, 2017 Author Share Posted December 16, 2017 Ah, yes. It's strange though. This really doesn't do anything questionable, especially not compared to the bus stuffing drivers we experimented with. It should just look like a normal bank switched rom to the 6507 and the 6507 is in charge of all the writes. Darrell are you flashing the harmony or loading via menu from SD card? There's a good chance this only works when loading it from the menu. Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted December 16, 2017 Share Posted December 16, 2017 From the menu Quote Link to comment Share on other sites More sharing options...
Jinroh Posted December 16, 2017 Share Posted December 16, 2017 Awesome demo! Though I get the same as Spiceware on my 4 Switch VCS with the new build. Quote Link to comment Share on other sites More sharing options...
JeremiahK Posted December 16, 2017 Share Posted December 16, 2017 Same for me on my wood-grain 4-switch. First build shows either black ar dark brown screen, sometimes with a few vertical stripes. Second build is black with dots scrolling up both edges of the screen. Note, I am still using Harmony version 1.06. I am on Arch Linux, and there is no AUR package for HarmonyCart. I am reading up on making PKGBUILD files, so I can add it to the AUR for other Arch users, although the handful of people who use Arch has very little crossover with the handful of people who have a Harmony. Quote Link to comment Share on other sites More sharing options...
ZackAttack Posted December 16, 2017 Author Share Posted December 16, 2017 With the new build both Harmony & Encore show this, and the lines moves upward on the display. IMG_9580.jpg Awesome demo! Though I get the same as Spiceware on my 4 Switch VCS with the new build. Same for me on my wood-grain 4-switch. First build shows either black ar dark brown screen, sometimes with a few vertical stripes. Second build is black with dots scrolling up both edges of the screen. Note, I am still using Harmony version 1.06. I am on Arch Linux, and there is no AUR package for HarmonyCart. I am reading up on making PKGBUILD files, so I can add it to the AUR for other Arch users, although the handful of people who use Arch has very little crossover with the handful of people who have a Harmony. Thanks for all the feedback. This was certainly a tricky one. Turns out the problem was the hold time of the last ROM byte injected before a switch to zeropage. The driver change that I made in version 2 was correct, but it resulted in a breaking change to the JSR function. Unfortunately I ran the wrong bin file and thought version 2 was working with the driver change. Turns out version 2 doesn't work anywhere I'm still trying to figure out how to fix the JSR function to work with the fixed driver, but for now I just hacked the original driver to waste some cycles before tristating the data bus. This seems to resolve it, but it's not as robust as it should be and I will fix it right once I figure out this JSR problem. What's interesting is why it worked in my testing but doesn't work for anyone else. I still had the harmony cart plugged into my test harness which allows the logic analyzer to be attached to the Atari busses. As CPUWIZ pointed out a long time ago, these "mile long" wires could cause problems. In this case it caused the hold time to increase artificially and compensated for the flawed driver. I plugged my harmony cart directly into the 7800 and then the problem appeared for me as well. I apologize for this testing failure on my part. Obviously I will test in this configuration from now on and reserve the harness for debugging purposes only. I've uploaded version 3 which uses the hack to extend the hold time and works when plugging the harmony directly into the Atari. Hopefully this will work for everyone now and serve as a reward for helping me find this problem. Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted December 16, 2017 Share Posted December 16, 2017 Success! 1 Quote Link to comment Share on other sites More sharing options...
JeremiahK Posted December 16, 2017 Share Posted December 16, 2017 Working for me now, too! That is so weird. Just yesterday I was looking up information on doing a composite mod, and I noticed that when some people do it, they use rather long wires. Of course, this causes no issues because it is only the video/audio signal, but it made me wonder what kinds of critically-timed scenarios could be negatively affected by using long wires, wires of differing lengths, etc. Deja vu, huh? 1 Quote Link to comment Share on other sites More sharing options...
Jinroh Posted December 17, 2017 Share Posted December 17, 2017 Right on my man! Worked now on my 4-Switch. 1 Quote Link to comment Share on other sites More sharing options...
ZackAttack Posted December 18, 2017 Author Share Posted December 18, 2017 Figured out the problem with the JSR function. Forget to account for mirroring. Was waiting for it to access $1a instead of $011a. Version 4 has the properly fixed driver and updated JSR function. At this point I believe this should be compatible with all systems. I'm thinking about under clocking the ARM processor during development just to add some margin for error. There's also some additional audio in version 4. Turns out I had a lot more space left in the ROM than I realized. There's still some things to work out with the linker script. Quote Link to comment Share on other sites More sharing options...
chavert Posted December 18, 2017 Share Posted December 18, 2017 (edited) . Edited September 8, 2023 by chavert 1 Quote Link to comment Share on other sites More sharing options...
TheHoboInYourRoom Posted December 20, 2017 Share Posted December 20, 2017 Version 4 on an NTSC Junior, board revision E. The sample playback works perfectly, btw. 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.