-
Content Count
5,587 -
Joined
-
Last visited
-
Days Won
2
Content Type
Profiles
Member Map
Forums
Blogs
Gallery
Calendar
Store
Everything posted by SeaGtGruff
-
Yes, there is a short delay of 2 color clocks (2/3 of a machine cycle), although some versions or clones of the VCS have a delay of 3 color clocks (1 machine cycle). Attached is a little table I made that shows when you need to write to a given playfield register. The first two columns list the playfield registers in the order they're drawn in. The first column lists them in the order they're drawn if you're using a repeated playfield (PF0-PF1-PF2-PF0-PF1-PF2), and the second column lists them in the order they're drawn if you're using a reflected playfield (PF0-PF1-PF2-PF2-PF1-PF0). Note that the table lists each pixel, not just the entire register, with the number after the dash being the pixel number within that register (*not* the bit number, which is different). The letter in front of the register name indicates whether the register is being drawn on the left side or the right side of the screen. The third column shows the screen position (numbered from 0 to 159) where the pixel starts. The fourth column shows the color clock (numbered from 0 to 227) where the pixel starts-- basically, the value in the third column plus 68. The fifth column shows (for a standard TIA) the *latest* machine cycle when you can write to the given playfield register to have the new value be used for the given pixel. The sixth column shows the same thing, but for the non-standard TIAs or TIA clones where the delay is a tad longer. The seventh column contains an asterisk wherever columns five and six are different. playfield_timings_2.txt
-
By the way, there's another type of page-crossing situation, which is where you're doing a branch instruction and the target of the branch instruction is on a different page-- not from the address where the branch instruction starts, but from the address *after* it. It sounds like maybe you were confusing these two types of page crossings.
-
The page-crossing penalty occurs if the address plus the index offset crosses a page boundary. Your Screen_PF0 table starts at the beginning of a page (the least significant byte of the address is 0) and index Y will always be between 0 and 255 inclusive, so there will never be a page-crossing situation for LDA $F900,Y. The other two addresses are not too far from the end of a page, so sometimes there will be page crossings and sometimes not, depending on the value of Y: $F9E5 is below page boundary $FA00. $FA00 - $F9E5 = $1B (or 27). So LDA $F9E5,Y will cross the page boundary at $FA00 when Y is 27 or greater, but not when Y is 26 or less. $FAC9 is below page boundary $FB00. $FB00 - $FAC9 = $37 (or 55). So LDA $FAC9,Y will cross the page boundary at $FB00 when Y is 55 or greater, but not when Y is 54 or less.
-
Nope, I don't like that explanation. As I was moving the sprite up and down that vertical line wondering "What the heck is this?!?" it suddenly hit me. You've created the 2600's first exotic pole dancer!
-
Assembly Gurus: Flicker-Free Multi Sprite Possible?
SeaGtGruff replied to Gemintronic's topic in Atari 2600 Programming
Being able to do hi-res stuff sounds potentially great-- but (1) the six-digit score "sprite" isn't wide enough to cover very much of the screen's horizontal real estate; and (2) you'd basically have to settle for using just one sprite color per scan line. -
When I tried to call a user function last night, I was getting a black screen when trying to do it with bankswitching. I don't know if the reason's the same in your case, but in my case it was because I was trying to let batari Basic call the user routine but it was located in another bank and I hadn't yet figured out that I needed to call the function manually with inline assembly so I could switch banks. Thus, it was gosubbing to the correct ROM address for the user function, but not in the correct bank, causing the program to crash. You might be running into a similar type of issue-- trying to goto or gosub to a routine and you're ending up at the correct address but in the wrong bank.
-
It looks okay to me, I guess-- although you might want to point out that not all programs will have all of those sections. Also, I'm not sure about "The Foundation"-- maybe something like "Program Setup" or "Declarations" would be better, since it's where you declare the ROM cartridge type, constants, variable definitions, etc. To me, "Foundation" sounds too much like "Skeleton" or "Framework," which is something else (more on that in a moment). In any case, inline commands can occur within any section of code, not just in the "Foundation" as you're calling it. As for what I started to say a moment ago, you might want to mention something about the skeleton, framework, outline, or structure of the program-- basically, a high-level outline of the overall program flow, made up of pseudocode written as broadly as possible (i.e., with as little detail as possible). It looks like you've tried to list the parts of a program in a more or less sequential order, but the code doesn't necessarily have to appear in that order within the source code, especially when you're using subroutines. Anyway, the program's outline is more than just a list of its parts in sequential order; it should also include some brief pseudocode for any input or decision-making that determines the program flow, or how control is passed from one part of the program to the others.
-
But what about calling a function in another bank? Is it just "a=myfunction(b) bank2"?
-
Note, if you want to try what I suggested, it turns out you'll need to modify both the function definition and the function call. I did it successfully last night-- modified the "sgn" function example from Random Terrain's web page to set the return value using inline assembly and return from the function call using "return otherbank," but then I had to modify the call to use inline assembly as well so it could call the function in another bank. So it's doable, but not elegant. An alternative is to put all statements that call the functions in the same bank as the functions, then use gosubs to go to the specific call statement you want to use. That would use more cycles because you'd have nested subroutines.
-
Adventure was 2613, so it was... a racing game! Actually that sort of fits-- racing to get away from the dragons, racing to catch the bat. Haunted House was 2654, so it was a gambling game-- where you gamble with... your life! Anyway, Adventure was released in 1979, so maybe as early as 1979 the classifications weren't very strict?
-
Based on compiling the sgn function example and looking at the assembly listing, it appears that when you return a value from a function, the value is placed in the Y register and then moved to the A register. I'm not sure why it's put in both places, because the calling code gets the return value from A. Anyway, if you need to return a value but need to return to a different bank, you could probably use inline assembly to load the return value into A and then use "return otherbank."
-
I haven't read all the posts in this thread and checked all the code, but I'd like to suggest an alternate approach-- if not for use with this project, then for future consideration. Rather than rearranging everything so the reclaimed bytes of RAM are contiguous, how about using the already-contiguous "user varables" memory, a through z, for the sprite data, and use the reclaimed bytes with dims for your other program variables?
-
The value mismatches are not errors as such, they should just be warnings from where addresses change between the assembler's initial pass through the code and subsequent passes. So I think pfcenter and pfwidth are the real errors-- they aren't defined anywhere but something in the code is referring to them. Are you generating a list file? You might search through the list file for references to pfcenter and pfwidth.
-
Crud, I posted that without being able to compile it first. When I tried to compile it at home the batari Basic compiler crashed. I had to split up the following two lines as follows to get it to compile: b = 0 : a = a + 1 : if a > 127 then a = 0 c = song_notes[a] : if c < 32 then AUDV0 = 4 Change those lines to b = 0 : a = a + 1 if a > 127 then a = 0 c = song_notes[a] if c < 32 then AUDV0 = 4
-
I know that several years ago I read a post or two on web sites or in the Stella mailing list in which someone either asked, or wondered out loud, whether it might be necessary to set AUDCx to 0 in addition to setting AUDVx to 0, but that was back when the TIA sound was still a bit unexplained (e.g., back when it was commonly believed that some AUDCx settings use the CPU clock instead of the pixel clock to generate the audio clocks), so I think it was just idle speculation. I can't speak of all the different variations and clones of the TIA, but the schematics for the TIA-1A indicate that setting AUDVx to 0 should kill the sound. I'd be surprised if there are any variations or clones that don't work the same way, but it would be good to test them all and see for sure. In any case, setting AUDCx (and AUDFx and AUDVx) each time through the loop doesn't take up much ROM or cycles, so the only real reason to do it as in my last version would be if you were down to the wire on cycles and needed to shave off as many unnecessary clocks as possible. Edit: And if that were the case, then writing to AUDCx, AUDFx, and AUDVx only when their values need to be changed might not really save any clocks anyway, since if the cycles were so tight that you needed to avoid writing to those registers in order to stay within the available cycles, then you'd probably go over the available cycles on those frames where you do have to write to those registers.
-
Except you don't need to set AUDC0 to 0, too. I moved the AUDC0 = 4 statement up out of atari2600land's loop because I didn't see the need to execute it each time. There's no need to execute the AUDF0 and AUDV0 statements each time, either. So my final version of atari2600land's program is as follows. This version updates AUDF0 only when a is updated, and updates AUDV0 only when b = 7 (for the staccato effect) or when a gets updated and the new note value is less than 32. It also updates AUDV0 before AUDF0, to make sure there's no microseconds of note 99 before the volume gets set to 0. Lastly, a and b are initialized to 254 so the program will need to update them the first time through the loop (so the first note gets played), and c is repurposed to hold the new note value since now the AUDV0 register gets set directly: set romsize 2k a = 254 : b = 254 AUDC0 = 4 title b = b + 1 if b = 7 then AUDV0 = 0 if b < 13 then skip_AUDF0 b = 0 : a = a + 1 : if a > 127 then a = 0 c = song_notes[a] : if c < 32 then AUDV0 = 4 AUDF0 = c skip_AUDF0 drawscreen goto title data song_notes 15, 16, 15, 20, 24, 20, 31, 99 15, 16, 15, 20, 24, 20, 31, 99 15, 13, 12, 15, 12, 15, 13, 16 13, 16, 15, 16, 15, 16, 15, 99 15, 16, 15, 20, 24, 20, 31, 99 15, 16, 15, 20, 24, 20, 31, 99 15, 13, 12, 15, 12, 15, 13, 16 13, 16, 15, 16, 15, 13, 12, 99 11, 12, 11, 15, 18, 15, 23, 99 11, 12, 11, 15, 18, 15, 23, 99 11, 10, 9, 11, 9, 11, 10, 12 10, 12, 11, 12, 11, 14, 11, 99 11, 12, 11, 15, 18, 15, 23, 99 11, 12, 11, 15, 18, 15, 23, 99 11, 10, 9, 11, 9, 11, 10, 12 10, 12, 11, 12, 14, 12, 11, 99 end
-
By the way, the "multiple of 8" solution did work, but-- as you discovered-- it didn't work out the way you had wanted, since there were some "multiple of 8" notes that you did *not* want to skip. And for a general solution you can't rely on skipping every 8th note or whatever. What you're looking for is a way to add "rests" to the music, and a rest could happen anywhere in a measure, so you need a solution that can work with any note, not just every 8th note or 12th note or whatever. I think the best way to do it is by using a note value that's "illegal"-- anything over 31. Of course, you can actually set the audio frequency counter to any value from 0 to 255 and it will work, because it will just drop the 3 highest bits from the high nibble. So as long as you check for whatever value you're using to mean "rest," you can turn off the volume before you play the note. A more generic test for the "illegal" value would have been "if song_notes[a] > 31." But there's one possible wrinkle, which is that you could theoretically use the extra bits of the high nibble for something else that has a possible value of 0 to 7. For example, you could use those bits to indicate the length of the note, or the volume of the note. You can just move the whole byte to AUDF0, but to get the extra bits you'd have to divide the note value by 32 and store it in some other variable or temp variable. For example, if you want to use the extra 3 bits for a note volume control, you'd probably want to divide by 32 to get the 3-bit value, then (as a separate step) multiply it by 2 to get a 4-bit value, which would let you indicate any even-numbered volume (0, 2, 4, 6, 8, 10, 12, or 14) for each individual note. Or you could use the extra 3 bits to indicate the length of the note, either in terms of how many "beats" or "ticks" to play the note, or how long to play the note before turning off the volume. In either of those two examples, you could still turn the note off entirely-- or play a rest-- but rather than setting the note value to some number like 99 you'd set the upper 3 bits to 0-- i.e., play the note at volume 0, or play the note for a duration of 0.
-
Here's a minor revision-- I thought it best to check the note value for 99 before setting the note. I also shortened the data lines to put the 99s at the end (where they occur). popcorn1.bas popcorn1.bas.bin
-
I think this is what you want? I got rid of the first byte of data and started with a = 0, since you were skipping the first byte anyway. To get the moment of silence you were looking for I set some data bytes to 99, then if the note value is 99 I turn off the volume. popcorn1.bas popcorn1.bas.bin
-
Back a few years ago when I was helping someone write a game with the multisprite kernel, I ran into the same sort of problems. As I recall, my solution was to use different limits at the top and bottom of the screen for player0 and the various player1 sprites. As for the flickering, I wonder if it has anything to do with player1 being used in the score? The virtual copies of player1 have to separated by a couple of lines if you want to avoid flickering, so I presume they also can't get too close to the score without flickering.
-
I found the following at ftp://ftp.pigwa.net/stuff/collections/holmes%20cd/Holmes%202/PC%20Atari%20Emulators%20Old/v7800%200.12%207800/V7800.TXT Maybe you could look at the headers of some actual A78 files in a hex editor to see how they compare with this? And I just found this: https://sites.google.com/site/atari7800wiki/a78-header
-
I agree. My heavy sixer has a beautiful picture as far as the vtbrancy of the colors, but my 7800 has washed-out colors. I figured it was because my heavy sixer is a newer purchase, whereas my 7800 is ancient-- but from what I'm reading in this thread, it's a common experience.
-
Well, I already have a cheap TV tuner device-- I don't have it handy right now to get the exact model, but it's a Hauppauge WinTV something-or-other. When I bought it and tried using it with my 7800 and/or 2600, it gave less than satisfactory results-- the color either kept flickering out or was always out-- so I stopped using it. That didn't happen with regular TV signals, just the Atari. I see someone mentioned a similar problem with the Dazzle or other device, and was able to resolve the issue by turning the Atari on first, then the device, so I might try that sometime. I also have a Snappy I can connect between my computer and a VCR or DVD recorder, which worked fine on an older computer, but that computer died and I don't have the CD with the software handy. What I currently use to record my 2600 or 7800 is a DVD recorder-- that's what I used to record my 2600 playing all of the TIA's sounds, or recording palette displays, etc. It works great, and I don't mind using up a recordable DVD for this, since I hardly ever record anything with my DVD recorder as it is. So I'm not actually in the market to buy the Dazzle or similar device right now; I was just wondering about the huge difference in price between the two versions of the Dazzle.
-
According to Pinnacle's web site, the $49.95 Dazzle DVD Recorder HD includes Pinnacle Studio HD v.14, whereas the $99.95 Dazzle Video Creator Platinum HD includes Pinnacle Studio HD v.15. Unless the differences between v.14 and v.15 are worth the $50 price difference, I'd hope there are other differences, too. I'm just wondering if it's really worth paying twice the price for the Platinum version?
-
What's the difference in features and functionality between Dazzle DVD Recorder HD and Dazzle Video Creator Platinum HD? Are the differences enough to justify the cost being doubled? Does anyone know?
