tschak909 Posted May 17, 2016 Share Posted May 17, 2016 Hey, I'm finally sitting down to figure out the intricacies of horizontal motion in VCS kernels. I could use a little chalk talk on the intricacies of the various reset strobes, and their interaction with HMOVE. I am currently studying the Combat and Video Olympics source to figure out where things meet, and I see the stack smashing trick, very clever way to check and set values in a constant # of cycles.... I know my way around 6502 assembly, but the whole line oriented approach is tripping my brain up. -Thom Quote Link to comment Share on other sites More sharing options...
gauauu Posted May 17, 2016 Share Posted May 17, 2016 I can't really help, but I always find Martin Korth's document to be a good reference as a starting point. It doesn't get into some of the tricks of getting extra sprites to show up by making repeated writes to RESPx though. Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted May 17, 2016 Share Posted May 17, 2016 MiniDig - best of stella has lots of useful info collected from the old email discussion group. While it's defunct, you can access everything from the archive. Also check my tutorial Collect, which covers the development of a 2K game from scratch. I put way more comments in the source than I normally would. 1 Quote Link to comment Share on other sites More sharing options...
tschak909 Posted May 17, 2016 Author Share Posted May 17, 2016 Thanks, Darrell. I'll take a look at that. I've been using the disassemblies at the dig for a long time, to understand implementation of a lot of different kernel concepts... I'm actually somewhat confused through, RESP0 and RESP1 in combat are only being set in one place, how is it delaying to the appropriate time to strobe the reset? -Thom Quote Link to comment Share on other sites More sharing options...
tschak909 Posted May 17, 2016 Author Share Posted May 17, 2016 Is there enough time in a classic 2LK, to add both a vertically delayed ball, vertically delayed players, and two missiles? -Thom Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted May 17, 2016 Share Posted May 17, 2016 I'm actually somewhat confused through, RESP0 and RESP1 in combat are only being set in one place, how is it delaying to the appropriate time to strobe the reset? I took a quick look and it appears that they're using RESP0 and RESP1 to set the players to a known position (the left and right sides of the screen) at the start of a game. After that, they only use HMP0 and HMP1 to move the players over successive frames during the game. Doing it that way means they're not keeping track of the X location of the players - smart really, you don't actually need to know it because you only care about collisions and TIA handles that for you. Since they don't know the X location, they just use the RESMP0 and RESMP1 to set the X position the missiles to the middle of the corresponding player. Not keeping track of the X locations means 4 bytes of RAM are "freed up" (2 for the players and 2 for the missiles). From Collect, this is the subroutine (and extensive comments) used to position any object. It strobes the appropriate RESxx register and stores the proper value in the HMxx register. ;=============================================================================== ; PosObject ;---------- ; subroutine for setting the X position of any TIA object ; when called, set the following registers: ; A - holds the X position of the object ; X - holds which object to position ; 0 = player0 ; 1 = player1 ; 2 = missile0 ; 3 = missile1 ; 4 = ball ; the routine will set the coarse X position of the object, as well as the ; fine-tune register that will be used when HMOVE is used. ; ; Note: The X position differs based on the object, for player0 and player1 ; 0 is the leftmost pixel while for missile0, missile1 and ball 1 is ; the leftmost pixel: ; players - X range is 0-159 ; missiles - X range is 1-160 ; ball - X range is 1-160 ; Note: Setting players to double or quad size will affect the position of ; the players. ;=============================================================================== PosObject: sec sta WSYNC DivideLoop sbc #15 ; 2 2 - each time thru this loop takes 5 cycles, which is bcs DivideLoop ; 2 4 - the same amount of time it takes to draw 15 pixels eor #7 ; 2 6 - The EOR & ASL statements convert the remainder asl ; 2 8 - of position/15 to the value needed to fine tune asl ; 2 10 - the X position asl ; 2 12 asl ; 2 14 sta.wx HMP0,X ; 5 19 - store fine tuning of X sta RESP0,X ; 4 23 - set coarse X position of object rts ; 6 29 This is the routine that calls the above for all 5 objects. It then strobes HMOVE so all the HMxx values are used to set the final positions. ;=============================================================================== ; PositionObjects ; -------------- ; Updates TIA for X position of all objects ; Updates Kernel variables for Y position of all objects ;=============================================================================== PositionObjects: ldx #4 ; position all objects POloop lda ObjectX,x ; get the object's X position jsr PosObject ; set coarse X position and fine-tune amount dex ; DEcrement X bpl POloop ; Branch PLus so we position all objects sta WSYNC ; wait for end of scanline sta HMOVE ; use fine-tune values to set final X positions Is there enough time in a classic 2LK, to add both a vertically delayed ball, vertically delayed players, and two missiles? Yep, Collect uses a 2LK and draws all 5 objects. It uses vertical delay on the players and ball when appropriate, as well as updates the playfield. Sadly there isn't a vertical delay feature for the missiles. Quote Link to comment Share on other sites More sharing options...
tschak909 Posted May 17, 2016 Author Share Posted May 17, 2016 oh yes, sorry, that's right. no delay on the missiles. derp. This is basically teaching me that I didn't read the hardware manual close enough... I thought the horizontal motion registers were only a single shot move +7 -7 from the initial reset point, after which, you needed to change where you reset the player. (Sort of similar to the 400/800 architecture, where the fine scroll registers only shifted things by 7 pixels in each direction, after which, you needed to either physically move graphic data, or change LMS pointers....anyway.) Thanks a bunch! I continue onward. (I am working on a game of Dodgeball for the VCS, which would have looked right at home with the original VCS launch titles, with two player shot balls, and one relentless bouncing ball which can be caught and reshot by the player, for a total of three potential balls that you must dodge, or lose points...catching a ball increases points...game is over when a player reaches 0) -Thom Quote Link to comment Share on other sites More sharing options...
tschak909 Posted May 17, 2016 Author Share Posted May 17, 2016 So basically, if I'm just using the basic players, missiles and ball in a 2LK, I don't really need to keep track of the X? I can just adjust the horizontal movement registers, as needed? -Thom Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted May 18, 2016 Share Posted May 18, 2016 I thought the horizontal motion registers were only a single shot move +7 -7 from the initial reset point, after which, you needed to change where you reset the player. (Sort of similar to the 400/800 architecture, where the fine scroll registers only shifted things by 7 pixels in each direction, after which, you needed to either physically move graphic data, or change LMS pointers....anyway.)I'm not familiar with 400/800 but the 2600 doesn't work that way. Every time you strobe HMOVE the values in the HMxx registers are used to change the objects' X positions. So basically, if I'm just using the basic players, missiles and ball in a 2LK, I don't really need to keep track of the X? I can just adjust the horizontal movement registers, as needed? Correct. Quote Link to comment Share on other sites More sharing options...
dmk Posted May 20, 2016 Share Posted May 20, 2016 FWIW this is what happens inside the chip: Each sprite has its own position counter that gets incremented at every visible pixel and wraps around to 0 at position 159. When it happens, a signal is generated to start drawing the sprite. Other signals are generated at positions 16, 32 and 64 and fed into the logic that generates 2nd/3rd copies of the sprite. Under normal circumstances there are 160 visible pixels and so the counter overflows and the sprite is drawn at the same position on every scanline. RESxx strobe resets the counter to 0 immediately. As there is no wrap around from 159, the sprite is not generated at the new position, but its 2nd/3rd copy will be drawn. Since 1 cpu cycle = 3pixels, it only works with 3 pixel accuracy. When HMOVE is issued, 2 things happen: 1. A flag is set, causing subsequent horizontal blanking to be extended by 8 pixels, reducing the number of visible pixels to 152. 2. A sequence of N pulses (1 pulse every 4 pixel clocks) is generated and injected into the counter clock line. N is the value 0..15 that was written to HMxx register. Now the way these pulses and regular counter clock pulses are mixed together causes some interesting side effects: * If a pulse occurs during blanking interval, the counter is incremented by 1 * If a pulse occurs during visible portion, the clock misses a beat and the counter is NOT incremented by 1 So when you issue HMOVE immediately after WSYNC, the counter is first incremented by N (0..15) during the blank and then not incremented during the first 8 pixels, resulting in -8/+7 motion range, everything works as advertised. If HMOVE is issued at other times, the pulses that occur during hblank are added, and pulses that occur during visible portion are subtracted from position counter, causing all sorts of weird effects depending on the timing. Plus, extending hblank by 8 pixels or may may not happen, causing extra 8 pixel shift. Also the sprites themselves may be weirdly stretched (sprite logic is driven by the same clock as the position counter). HTH, dmk 2 Quote Link to comment Share on other sites More sharing options...
DanOliver Posted May 20, 2016 Share Posted May 20, 2016 Am I remembering correctly that HMOVE also results in short black lines on the left side of the screen? dmk's explanation of extending hor blanking 8 pixels made me think back. Never knew the why. Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted May 20, 2016 Share Posted May 20, 2016 Am I remembering correctly that HMOVE also results in short black lines on the left side of the screen? dmk's explanation of extending hor blanking 8 pixels made me think back. Never knew the why. Yep, HMOVE causes the black line. If you hit HMOVE at cycle 73 or 74 the short line goes away, but the values for the HMxx registers that used to adjust the X position by -7 to 8 will now change them by -15 to 0. For more info on that, check out the the MiniDig tricks page. You'll find an entry called HMOVE Timing with a couple of links: hmove.txt shows the fine tuning values for every cycle you can hit HMOVE on Brad Mott takes you to the archived email message from the old Stella mailing list At the bottom of the archived email are links that let you view that particular thread, which started because Brad was trying to figure out why He-Man's titlescreen was messed up in Stella. 1 Quote Link to comment Share on other sites More sharing options...
Joe Musashi Posted May 20, 2016 Share Posted May 20, 2016 The TIA hardware notes provide a detailed description of the motion circuits. As far as I understand this, by feeding additional pulses to the position counter, sprites can only move to the left. To be able to move left and right, the (re)start of the position counter is delayed by 8 pixels, which also covers up the resulting gap on the left border with the black bar. What I don't understand is why this is done at all as the playfield could still be displayed Quote Link to comment Share on other sites More sharing options...
tschak909 Posted May 20, 2016 Author Share Posted May 20, 2016 According to something Joe Decuir had told me, your very last point was something that could have been rectified with one more rev of the chip...but that never happened. -Thom Quote Link to comment Share on other sites More sharing options...
LeChuck Posted November 29, 2016 Share Posted November 29, 2016 Somewhat related question - why do some games have lots of HMOVEs/bars (sometimes every other line) when they are seemingly only repositioning a handful of things on any given frame? Spider-Man is a good example that comes to mind. I'm only about 80% through commenting my first disassembly, perhaps the answer lies in the last 20%. Or maybe there is no general answer, and it's just game-specific. Hmm? Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted November 29, 2016 Share Posted November 29, 2016 Somewhat related question - why do some games have lots of HMOVEs/bars (sometimes every other line) when they are seemingly only repositioning a handful of things on any given frame? Spider-Man is a good example that comes to mind. Timing is very tight in the kernel. It's much quicker to regularly strobe HMOVE than to have additional logic that decides if HMOVE needs to be hit or not. Spider-Man hits it every other line so it can draw the web diagonally using a missile - without using HMOVE the web could only go directly up or down. That's the same reason it's hit every-other-line in Missile Command. Quote Link to comment Share on other sites More sharing options...
LeChuck Posted November 30, 2016 Share Posted November 30, 2016 Timing is very tight in the kernel. It's much quicker to regularly strobe HMOVE than to have additional logic that decides if HMOVE needs to be hit. Spider-Man hits it every other line so it can draw the web diagonally using a missile - without using HMOVE the web could only go directly up or down. That's the same reason it's hit every-other-line in Missile Command. Gotcha, I had a feeling the close repositions of the web had something to do with it there. Ms Pac Man was another example I had in mind - but from a quick peek in the Stella debugger, I'm guessing it's the same timing / code simplification you mention (RESP1 is strobed once per ghost, but the HMOVEs are just fired periodically down the frame). 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.