lucienEn Posted December 22, 2022 Share Posted December 22, 2022 Hi, Question: in Stella debugger I don't see the player position correspond to the pixel position when strobing RESP0. See below: pixel position is 136 but the P0 position is 141. I thought maybe that's the HMP0 value but that shows as 0 below. Could that be related to VDel which is set here? Also I noticed that "Pos#" is changing very often even if it doesn't go over a RESP0 strobe. For example after: STA CXCLR, STA COLUP0 Thanks, Lucien Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted December 23, 2022 Share Posted December 23, 2022 Did you have a look at Andrew Towers' notes? There you will find the answer to your RESPx question. Can you give an example, where Pos is changing due to e.g. CXCLR? Note: If you put a breakpoint after it, Pos might be in red, because it has changed since the last debugger interrupt, no because of CXCLR changing it. 1 Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 23, 2022 Author Share Posted December 23, 2022 (edited) 8 hours ago, Thomas Jentzsch said: Did you have a look at Andrew Towers' notes? There you will find the answer to your RESPx question. Can you give an example, where Pos is changing due to e.g. CXCLR? Note: If you put a breakpoint after it, Pos might be in red, because it has changed since the last debugger interrupt, no because of CXCLR changing it. Thanks that explains it! Seems most docs ignore these details. The other mystery is how blanking first 8 pixels works. Someone mentioned WSYNC+HMOVE blanks first 8 pixels but not sure why and I don't always see that working as expected (seems it must be on every line to take effect). But I believe that doc might explain it, reading that now:-). Regarding changing Pos# in debugger: I'm debugging Pitfall and the position for P0 is changing a lot. For example see below. The other weird thing is that in Pitfall I never see HMOVE set for P0 so I wonder how that's accomplished without? P0 pos. before instruction: f235: 132 (WSYNC) f237: 132 (HMOVE) f239: 132 (STA COLUP0) f23b: 131 (dex) f23c: 130 (bpl LF221) Edited December 23, 2022 by lucienEn Quote Link to comment Share on other sites More sharing options...
+splendidnut Posted December 23, 2022 Share Posted December 23, 2022 13 minutes ago, lucienEn said: Someone mentioned WSYNC+HMOVE blanks first 8 pixels but not sure why and I don't always see that working as expected (seems it must be on every line to take effect). HMOVE hides/blanks the first eight pixels only on the lines that it is used. So, IF you want to use the WSYNC+HMOVE to hide the first eight pixel column, THEN it must be done on every line. Your other option to blank the first eight pixels is to set the color of one of the Player/Missiles to black and position it there. Why do you want to hide the first eight pixels? Are you just trying to avoid the HMOVE "comb" OR are you trying to use that as a clipping area (hide sprite graphics that wrap-around)? Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 23, 2022 Author Share Posted December 23, 2022 53 minutes ago, splendidnut said: HMOVE hides/blanks the first eight pixels only on the lines that it is used. So, IF you want to use the WSYNC+HMOVE to hide the first eight pixel column, THEN it must be done on every line. Your other option to blank the first eight pixels is to set the color of one of the Player/Missiles to black and position it there. Why do you want to hide the first eight pixels? Are you just trying to avoid the HMOVE "comb" OR are you trying to use that as a clipping area (hide sprite graphics that wrap-around)? David Crane referred to the left black lines in Air Sea Battle as a chipset bug and they avoided that issue so I'm curious proper way to do that and what's exactly causing this. You see it also in Space Invaders but different spacing. In Pitfall I can see they always have WSYNC + HMOVE and that clearly works but not clear how that works since HMOVE is just described as applying all offsets. And why is it exactly 8 pixels? Does HMOVE just happen to delay drawing by 8 pixels always? Regarding the jumping of Pos# in debugger, I noticed it's always outside the visible space. And 2nd why HM is always 0 might be that the debugger does not repeat HM once it is applied and instead adjust the Pos# on the next line and resets HM. At least that's the only explanation I can think off. I did find the subroutine in Pitall! that computes both coarse (15 cycle loop) and fine calculations. So that seems all straightforward at least: F388: Input: A = xPos Output:A = fine Offset. Y = Coarse pos. (x 15 cycles) Quote Link to comment Share on other sites More sharing options...
alex_79 Posted December 23, 2022 Share Posted December 23, 2022 (edited) 1 hour ago, lucienEn said: Regarding changing Pos# in debugger: I'm debugging Pitfall and the position for P0 is changing a lot. For example see below. The other weird thing is that in Pitfall I never see HMOVE set for P0 so I wonder how that's accomplished without? That's because, while the coarse positioning (RESP0) is immediate, the fine positioning (HMOVE) isn't. The "Tia Hardware notes" document linked above explains this in detail, but in short, each moveable object has a position counter that's only incremented during the visible part of the scanline, while it stays "dormant" during the Horizontal Blank part. The counter wraps around in exactly 160 TIA clocks, and when it does, the object is displayed. So normally each object will show up exactly on the same horizontal position on each line. If you write to RESP0, the counter for P0 is reset immediately, and it will show up on the new position starting from the next scanline (starting drawing isn't immediate, actually, so there's an offset of 4 pixels for Missile and Balls, 5 pixels for single size Player and 6 pixels for double and quad size players, which accounts for the differences you noted in the first post). HMOVE works differently. When you strobe that register, the position counter receives some extra clocks during the horizontal blank (the amount of which corresponds to the value stored into the high nybble of HMP0 after inverting bit 7, and so ranges from 0 to 15 extra clocks). Each one of these extra clocks will cause the counter to wrap around 1 pixel earlier, so it will move the object 1 pixel to the left. In fact this mechanism alone would only allow for movement to the left. That's why when you strobe HMOVE, in addition to providing the extra clocks, the Horizontal blank is extended by 8 pixels, which cause all the objects to move to the right by the same amount. The combination of the 0 to 15 pixels to the left caused by the extra clocks, and 8 pixels to the right for the extended HBLANK results in the -7 to +8 pixels fine positioning. During HBLANK, the estimated position in the debugger TIA tab is updated as the counter receives the extra clocks. (for each clock, the position is decreased by one, and each clock happens every 4 TIA clks, or 1.33 CPU cycles) and at the end of HBLANK, the position is increased by 8 again because of the extended Blank period. that's why you see it change, even when HMP0 is set to 0 (which corresponds to 8 extra clocks). Edited December 23, 2022 by alex_79 1 Quote Link to comment Share on other sites More sharing options...
alex_79 Posted December 23, 2022 Share Posted December 23, 2022 1 minute ago, lucienEn said: David Crane referred to the left black lines in Air Sea Battle as a chipset bug I wouldn't call it a bug. It's just one of the many compromises done while designing the TIA to obtain the functionality required as efficiently and cost effectively as possible. 1 Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 23, 2022 Author Share Posted December 23, 2022 (edited) 1 hour ago, alex_79 said: That's because, while the coarse positioning (RESP0) is immediate, the fine positioning (HMOVE) isn't. The "Tia Hardware notes" document linked above explains this in detail, but in short, each moveable object has a position counter that's only incremented during the visible part of the scanline, while it stays "dormant" during the Horizontal Blank part. The counter wraps around in exactly 160 TIA clocks, and when it does, the object is displayed. So normally each object will show up exactly on the same horizontal position on each line. If you write to RESP0, the counter for P0 is reset immediately, and it will show up on the new position starting from the next scanline (starting drawing isn't immediate, actually, so there's an offset of 4 pixels for Missile and Balls, 5 pixels for single size Player and 6 pixels for double and quad size players, which accounts for the differences you noted in the first post). HMOVE works differently. When you strobe that register, the position counter receives some extra clocks during the horizontal blank (the amount of which corresponds to the value stored into the high nybble of HMP0 after inverting bit 7, and so ranges from 0 to 15 extra clocks). Each one of these extra clocks will cause the counter to wrap around 1 pixel earlier, so it will move the object 1 pixel to the left. In fact this mechanism alone would only allow for movement to the left. That's why when you strobe HMOVE, in addition to providing the extra clocks, the Horizontal blank is extended by 8 pixels, which cause all the objects to move to the right by the same amount. The combination of the 0 to 15 pixels to the left caused by the extra clocks, and 8 pixels to the right for the extended HBLANK results in the -7 to +8 pixels fine positioning. During HBLANK, the estimated position in the debugger TIA tab is updated as the counter receives the extra clocks. (for each clock, the position is decreased by one, and each clock happens every 4 TIA clks, or 1.33 CPU cycles) and at the end of HBLANK, the position is increased by 8 again because of the extended Blank period. that's why you see it change, even when HMP0 is set to 0 (which corresponds to 8 extra clocks). Thanks very much, those details I just missed in few books and docs I've seen. I found Pitfall! code where the positioning is done and looking at Stella debugger it applies the HMOVE offset at the next scanline to the P0 pos (and HM stays but is reset later in this code): Lf1cc sta WSYNC ;3 = 3 * Kernel loop set sprite x, calc. in f388 and stored in 95/98 for Harry sta HMOVE ;3 * Example: x=38 (ram_E1); fine=E0 (+2 in ram_95), coarse=2 (ram_98) ldy #$00 ;2 * Pos#=34;PixelPos=-59 sty ram_F6,x ;4 * temp memory ldy ram_98,x ;4 * Pos#=31;PixelPos Load coarse position (x=0: harry) bne Lf1e2 ;2/3 * Pos#=28; if pos = 0 then reset ;---------------- RESET POSITION IF pos. = 0 ldy #$60 ;2 * Reset position sty ram_F6,x ;4 * sta RESP0,x ;4 * Start pos. new screen sta HMBL ;3 * bne Lf1ea ;2/3 = 30 * ;---------------- SET COARSE POSITION Lf1e2 ; 15 cycle loop to set coarse position (here: 2 loops). PixelPos start: -20 dey ;2 * Pos#=26 (2x +6) bne Lf1e2 ;2/3 * Pos#=34 (+9 +6 for last) sta.w HMBL ;4 * PixelPos=7 (-20+6+6+9+6) Filler +12? sta RESP0,x ;4 = 12 * PixelPos=19 ;---------------- SET FINE POSITION (next scanline) Lf1ea sta WSYNC ;3 = 3 * Pos#=36 (PixelPos=31 + 5 for P0) sta HMOVE ;3 dex ;2 bpl Lf1b0 ;2/3 jsr Lf3a6 ;6 lda ram_95 ;3 * Pos#=36; Harry fine position sta HMP0 ;3 lda ram_96 ;3 sta HMP1 ;3 * Pos#=36;HM=E0 sta WSYNC ;3 = 28 ;--------------------------------------- sta HMOVE ;3 * jsr Lf3a6 ;6 * After: Pos#=33;HM=E0 (outside of visible scanline, settles at 38 at PixelPos=16) lda ram_F6 ;3 * Pos#=38 sta HMP0 ;3 lda ram_F7 ;3 sta HMP1 ;3 lda ram_E9 ;3 clc ;2 adc ram_F2 ;3 adc #$15 ;2 tay ;2 lda ram_E5 ;3 sta REFP0 ;3 sta WSYNC ;3 = 42 sta HMOVE ;3 Edited December 23, 2022 by lucienEn Added comments values Quote Link to comment Share on other sites More sharing options...
Ecernosoft Posted December 23, 2022 Share Posted December 23, 2022 There's a much simpler way to do this: SetHorizPos sta WSYNC ; start a new line sec ; set carry flag DivideLoop sbc #15 ; subtract 15 bcs DivideLoop ; branch until negative eor #7 ; calculate fine offset asl asl asl asl sta RESP0,x ; fix coarse position sta HMP0,x ; set fine offset rts ; return to caller Set X to the sprite you want to set the position for, and A to the actual XPOS, and it will do it for you with a simple JSR after doing those. 1 Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 23, 2022 Author Share Posted December 23, 2022 (edited) 25 minutes ago, Ecernosoft said: There's a much simpler way to do this: SetHorizPos sta WSYNC ; start a new line sec ; set carry flag DivideLoop sbc #15 ; subtract 15 bcs DivideLoop ; branch until negative eor #7 ; calculate fine offset asl asl asl asl sta RESP0,x ; fix coarse position sta HMP0,x ; set fine offset rts ; return to caller Set X to the sprite you want to set the position for, and A to the actual XPOS, and it will do it for you with a simple JSR after doing those. That's nice and compact code. Only thing missing might be HMOVE after WSYNC but I assume not needed for that scanline since it's not drawing anything? I'll give that a try, thanks. In Pitfall! the logic for calculating and setting is split. The calculation is every 2-3 frames only for P0 & P1. See below code in Pitfall! for that calc. Haven't analyzed that but it's doing some extra stuff it seems (although end result should be same so not sure why it's doing the modulus 15): ; subroutine to compute fine and coarse offsets for x in Pitfall! Lf388 ; A = X position player tay ;2 iny ;2 tya ;2 and #$0f ;2 sta ram_F6 ;3 tya ;2 lsr ;2 lsr ;2 lsr ;2 lsr ;2 tay ;2 clc ;2 adc ram_F6 ;3 cmp #$0f ;2 bcc Lf39f ;2/3 sbc #$0f ;2 iny ;2 = 36 Lf39f eor #$07 ;2 asl ;2 asl ;2 asl ;2 asl ;2 rts ;6 = 16 Edited December 23, 2022 by lucienEn Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted December 23, 2022 Share Posted December 23, 2022 3 minutes ago, lucienEn said: Only thing missing might be HMOVE after WSYNC That routine's often used to set all the object positions, after which a single HMOVE is done. From my tutorial: ;=============================================================================== ; 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 You might find the tutorial useful as I put in way more comments that I normally would, such as: ;=============================================================================== ; 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 1 Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 23, 2022 Author Share Posted December 23, 2022 I understand HMOVE is needed after that but wasn't sure if every line needs to have it to get the blanking of first 8 pixels. I'm seeing some odd behavior when I don't have it on every scanline. Quote Link to comment Share on other sites More sharing options...
glurk Posted December 23, 2022 Share Posted December 23, 2022 A commented Pitfall! disassembly (by Thomas Jentzsch) is available here: http://www.bjars.com/source/Pitfall.asm It might be worth studying, as the game has many (9) kernel sections, and the positioning is done in various ways to suit the needs of the specific sections. Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted December 23, 2022 Share Posted December 23, 2022 40 minutes ago, lucienEn said: I understand HMOVE is needed after that but wasn't sure if every line needs to have it to get the blanking of first 8 pixels. I'm seeing some odd behavior when I don't have it on every scanline. If you want those pixels blanked then do an HMOVE on every scanline. You can see that in Pitfall by switching to Debug Colors - the 8 pixels hidden by HMOVE are drawn in white: In Boxing they also used the BALL object to hide the 8 pixels on some scanlines: If you disable the BALL you can see what it's hiding: Quote Link to comment Share on other sites More sharing options...
Ecernosoft Posted December 23, 2022 Share Posted December 23, 2022 4 hours ago, lucienEn said: That's nice and compact code. Only thing missing might be HMOVE after WSYNC but I assume not needed for that scanline since it's not drawing anything? I'll give that a try, thanks. that can be fixed with STA WSYNC. By the way, anyone have a good PF + Multisprite kernal? In case I make any more 2600 games. Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 23, 2022 Author Share Posted December 23, 2022 10 minutes ago, glurk said: A commented Pitfall! disassembly (by Thomas Jentzsch) is available here: http://www.bjars.com/source/Pitfall.asm It might be worth studying, as the game has many (9) kernel sections, and the positioning is done in various ways to suit the needs of the specific sections. Yes I looked at that earlier. For some reason that one is not running correctly for me (no jumping and no collision detection). But good to understand what the variables mean. Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 23, 2022 Author Share Posted December 23, 2022 (edited) 4 minutes ago, Ecernosoft said: that can be fixed with STA WSYNC. By the way, anyone have a good PF + Multisprite kernal? In case I make any more 2600 games. I don't but I'm thinking there must be a way to create a nice UI tool that can automate the kernels generation. Where you can designate display bands and set properties like static (playfield+background editor)/dynamic sprites etc. If I look at Circus Convoy I'm thinking there must have been some tools as well to help with the numerous multi-colored overlapping sprites. Edited December 23, 2022 by lucienEn Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 23, 2022 Author Share Posted December 23, 2022 10 minutes ago, SpiceWare said: If you want those pixels blanked then do an HMOVE on every scanline. You can see that in Pitfall by switching to Debug Colors - the 8 pixels hidden by HMOVE are drawn in white: In Boxing they also used the BALL object to hide the 8 pixels on some scanlines: I've seen that but finally understanding now why some lines don't show HM and some do (in Pitfall it's for all). It's simply those lines where HMOVE was applied for the scanline. Quote Link to comment Share on other sites More sharing options...
alex_79 Posted December 23, 2022 Share Posted December 23, 2022 24 minutes ago, lucienEn said: For some reason that one is not running correctly for me (no jumping and no collision detection) Add the line TIA_BASE_READ_ADDRESS = $30 at the beginning of the disassembly, so it will assemble correctly with the "vcs.h" file from a current version of dasm. Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 23, 2022 Author Share Posted December 23, 2022 52 minutes ago, alex_79 said: Add the line TIA_BASE_READ_ADDRESS = $30 at the beginning of the disassembly, so it will assemble correctly with the "vcs.h" file from a current version of dasm. I just figured reason why it didn't work for me correctly. I can't just add HMOVE on every line, I also need to make sure I do HMCLR unless there is really a fine positioning needed. 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.