Svetlana Posted March 10, 2016 Share Posted March 10, 2016 Hi everybody! I started playing around with 2600 assembly today, trying to make a breakout clone first for practice. I've been following the guide so far but I haven't had much luck with the horizontal movement of sprites. I understand the concept of it (waiting until the electron gun is at a certain X, resetting sprite position there, HMOVE for finer tuning), but I couldn't get any of the examples I've found to work, so I'm trying to figure it out on my own for now. My code is here: https://github.com/Lana-chan/break2600 I haven't implemented HMOVE yet but the current code is used as a test to see what delays I can use with RESP0 to get the paddle to move. I'd love to hear any comments and suggestions on my code! I've worked with Z80 assembly for Sega Master System before, though I never got too far with it, but it gave me a basic understanding of assembly programming in general. Quote Link to comment Share on other sites More sharing options...
ZackAttack Posted March 10, 2016 Share Posted March 10, 2016 There's a pretty nice routine that you can use to position objects in this post. Quote Link to comment Share on other sites More sharing options...
Svetlana Posted March 10, 2016 Author Share Posted March 10, 2016 There's a pretty nice routine that you can use to position objects in this post. That one looks much clearer than the ones I've found so far, thanks! I'll give that one a shot. Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted March 11, 2016 Share Posted March 11, 2016 Check out my blog series Collect - the series starts at the bottom of page 2. I hope you'll be using paddles instead of joystick. If so also check out my blog entries covering the development of Medieval Mayhem. For paddles you have to check the state of the paddle mutiple times during the kernel. I used these macros: MAC READ_PADDLE_1 lda INPT0 ; 3 - always 9 bpl .save ; 2 3 .byte $2d ; 4 0 .save sty Paddle1 ; 0 3 ENDM MAC READ_PADDLE_2 lda INPT1 ; 3 - always 9 bpl .save ; 2 3 .byte $2d ; 4 0 .save sty Paddle2 ; 0 3 ENDM MAC READ_PADDLE_3 lda INPT2 ; 3 - always 9 bpl .save ; 2 3 .byte $2d ; 4 0 .save sty Paddle3 ; 0 3 ENDM MAC READ_PADDLE_4 lda INPT3 ; 3 - always 9 bpl .save ; 2 3 .byte $2d ; 4 0 .save sty Paddle4 ; 0 3 ENDM MAC READ_PADDLE_1_OR_2 ldx Paddles2Read ; 13-14 3 lda INPT0,x ; | 4 bpl .save ; | 2 3 .byte $2c ; | 4 0 .save sty Paddle1,x ; | 0 4 ; +-14 worse case scenerio ENDM MAC READ_PADDLE_3_OR_4 ldx Paddles2Read ; 13-14 3 lda INPT2,x ; | 4 bpl .save ; | 2 3 .byte $2c ; | 4 0 .save sty Paddle3,x ; | 0 4 ; +-14 worse case scenerio ENDM MAC READ_TWO_PADDLES ldx Paddles2Read ; 21-23 3 lda INPT0,x ; | 4 bpl .save1 ; | 2 3 .byte $2c ; | 4 0 .save1 sty Paddle1,x ; | 0 4 lda INPT2,x ; | 4 bpl .save2 ; | 2 3 .byte $2c ; | 4 0 .save2 sty Paddle3,x ; | 0 4 ; +-23 worse case scenerio ENDM Quote Link to comment Share on other sites More sharing options...
Svetlana Posted March 11, 2016 Author Share Posted March 11, 2016 (edited) I hope you'll be using paddles instead of joystick. If so also check out my blog entries covering the development of Medieval Mayhem. For paddles you have to check the state of the paddle mutiple times during the kernel. I wanted to use the paddles but the paddle controller was never bundled with the Brazilian clones of the 2600, so it would make it impossible for me to try it on hardware if I ever managed to build an Atari cartridge. (I already built a homebrew SMS cartridge using an EEPROM once) So I'm still thinking on what input to use. If I'm using only paddle 1 to move a single object in the screen, why do you need to check it more than once per frame? EDIT: So I'm having the same trouble with the routine linked by ZackAttack as I was having with the other routines, wherever in the frame I put the routine in, it just glitches out the screen with some intermittent beeps. I guess I'm not too clear on how to put this function into my code? I replaced the area in my code labeled "WaitPos" with that snippet. EDIT 2: Nevermind, I fixed -that-, but the routine doesn't seem to be updating the horizontal movement properly. The code in the GitHub is updated with that routine, I'll include a binary here for convenience. brick.bin Edited March 11, 2016 by Svetlana Quote Link to comment Share on other sites More sharing options...
ZackAttack Posted March 11, 2016 Share Posted March 11, 2016 After you position all the objects with that routine you need to do Sta hmove right after a Sta wsync. Also, make sure you initialize SP to $ff and look into using the timer for over scan and vblank timing. Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted March 11, 2016 Share Posted March 11, 2016 If I'm using only paddle 1 to move a single object in the screen, why do you need to check it more than once per frame? On other systems you can read a single register and get an 8 bit value that tells you how far the paddle (or analog stick) is turned. The Atari is much more primitive. Instead, the paddle controls how long it takes to recharge a capacitor (the capacitors are the Atari, not in the paddles - there's one capacitor per paddle). The INPTx registers are just 1 bit, not 8. The process is: discharge the capacitors during Vertical Sync (this grounds the capacitors):LDA #$82 STA VBLANK Remove the ground at the start of the kernel so the capacitors can start recharging. Rate of charge is controlled by the paddle:LDA #$00 STA VBLANK During the kernel repeatedly check if the capacitor has fully recharged. The scanline you're on is the value for how far the paddle is turned. Paddle games tend to have simpler graphics because you have to spend so much time during the kernel to read the state of the paddles. In Medieval Mayhem I was able to get better graphics by using a 32K ROM and totally unrolling the kernel. EDIT: So I'm having the same trouble with the routine linked by ZackAttack as I was having with the other routines, wherever in the frame I put the routine in, it just glitches out the screen with some intermittent beeps. I guess I'm not too clear on how to put this function into my code? I replaced the area in my code labeled "WaitPos" with that snippet. EDIT 2: Nevermind, I fixed -that-, but the routine doesn't seem to be updating the horizontal movement properly. The code in the GitHub is updated with that routine, I'll include a binary here for convenience. PosObject is normally called in a loop, and after the loop is done HMOVE is triggered to use the fine-tuning to set the final position of the objects. From Collect: 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 I put a lot of comments in the source for Collect, way more than I normally would. The PosObject function with comments is this: ;=============================================================================== ; 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 All those comments are why I recommend the series to people who are beginning to learn programming for the 2600. Quote Link to comment Share on other sites More sharing options...
Svetlana Posted March 12, 2016 Author Share Posted March 12, 2016 After you position all the objects with that routine you need to do Sta hmove right after a Sta wsync. sta HMOVE is exactly what I was missing, thanks. On other systems you can read a single register and get an 8 bit value that tells you how far the paddle (or analog stick) is turned. The Atari is much more primitive. Instead, the paddle controls how long it takes to recharge a capacitor (the capacitors are the Atari, not in the paddles - there's one capacitor per paddle). That sounds pretty difficult.. I think I might leave paddle for a later project, since I wouldn't even have a way to play it with an actual paddle anyway. PosObject is normally called in a loop, and after the loop is done HMOVE is triggered to use the fine-tuning to set the final position of the objects. From Collect: I was calling it correctly but I was missing the HMOVE call, I got it to work now. All those comments are why I recommend the series to people who are beginning to learn programming for the 2600. Sorry I didn't look much into it at first, I was already getting kinda overwhelmed by the guide I was trying to follow but yours is much clearer. I started rewriting my code using your timer source as a template and I got everything to work more or less right, but I'm still getting some oddities I'll work out later. That code is on my GitHub now, I hope it's okay to use your code as a starting point. I've credited you in the comments. Thanks for the help so far, everybody! Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted March 12, 2016 Share Posted March 12, 2016 That sounds pretty difficult.. I think I might leave paddle for a later project, since I wouldn't even have a way to play it with an actual paddle anyway. Yeah, the way you read paddles on the 2600 is just as odd as the way you position the sprites - their both time based I hope it's okay to use your code as a starting point. I've credited you in the comments. That's fine, that's why I wrote the tutorial. What are you using as an editor? If you're not already using a programmers editor then I suggest you check out jEdit. I posted this topic about it, and have this blog series about it. If you do decide to use jEdit you'll want to make a revision to your source. Change this line: ; put into a "reduced package". This package limits the 6507 to an 8K To this: ; put into a "reduced package". This packaging limits the 6507 to an 8K jEdit picks up on the word package and uses what follows it when compiling the source and launching of Stella. For Collect it makes dasm's output: limits.collect.bin limits.collect.lst limits.collect.sym Instead of: collect.bin collect.lst collect.sym Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted March 12, 2016 Share Posted March 12, 2016 That code is on my GitHub now I do see one thing you'll want to change now so it doesn't potentially give you problems later. You have PosObject at the end of your project, move it to the start so it's directly after the ORG $F000. The reason for this is if a branch command (the BCS in PosObject) crosses a page it takes an extra cycle of processor time which will throw off the routine. Items are on the same page when the high-byte of their addresses have the same value, so addresses $F100 and $F1FF are both on the same page (page F1) while $F1FF and $F200 are on different pages. As an example, if DivideLoop ends up at address F5FE the BCS command will be at address F600. Since F5 is a different page than F6 the branch command will take 6 cycles, instead of 5, to branch back to Divideloop. If that happens your objects won't end up at the proper X locations. Quote Link to comment Share on other sites More sharing options...
Svetlana Posted March 12, 2016 Author Share Posted March 12, 2016 What are you using as an editor? If you're not already using a programmers editor then I suggest you check out jEdit.I already use Notepad++ under Windows and gedit under Linux, which are the ones I'm most comfortable with at the moment. I do see one thing you'll want to change now so it doesn't potentially give you problems later. You have PosObject at the end of your project, move it to the start so it's directly after the ORG $F000.I made the change on my copy (not pushed to GitHub yet) but I didn't notice anything different visually. The weirdness I'm still getting is the colors are different than what I had before even though the values should be the same, and when the paddle reaches around the last quarter of the screen horizontally, the screen goes monochrome and shifts down one scanline. I'm sure it's something I'm doing wrong in the code, but I haven't looked much into it yet. This is just a hobby project anyway Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted March 12, 2016 Share Posted March 12, 2016 I already use Notepad++ under Windows and gedit under Linux, which are the ones I'm most comfortable with at the moment. I don't know if anybody's set up syntax highlighting rules for those, but they'll work I made the change on my copy (not pushed to GitHub yet) but I didn't notice anything different visually. I suggested the change to prevent the issue from cropping up in the future. As you add more code to your program, the location of PosObject will change - depending upon where, you could end up with the branch crossing a page. It's hard to track things like that down, so it's a good practice to put routines with critical timing at the start of the ROM. The weirdness I'm still getting is the colors are different than what I had before even though the values should be the same, and when the paddle reaches around the last quarter of the screen horizontally, the screen goes monochrome and shifts down one scanline. I'm sure it's something I'm doing wrong in the code, but I haven't looked much into it yet. This is just a hobby project anyway Your scanline count used to be 270, which Stella detected as NTSC. In the new version it's 290, which Stella detected as PAL. The Atari outputs different colors for each video system: NTSC, PAL, and SECAM. In Stella you can use the Developer Key COMMAND-L (on Mac) or ALT-L (Linux or Windows) to display the scanline count, video format, and cartridge type: prior version detected as NTSC current version detected as PAL When the paddle gets to the far right the scanline count increases to 291. Color information is lost on PAL displays if the scanline count is odd. In checking the code I see you're calling PosObject in the middle of your kernel. The scanline count increased by 1 because PosObject takes longer (more CPU time) to position objects on the right side of the screen. You should move the call to PosObject to the end of Vertical Blank where an extra scanline won't cause problems (that's why we use timers to check for the end of Vertical Blank and Overscan). I've changed it here: brick.asm It's possible to reposition objects during the kernel; though, that is a more advanced technique, in part because you need to make sure the scanline count stays consistent. You'll need to decide if you're targeting NTSC or PAL and use the appropriate number of scanlines. For NTSC you want to output 262, for PAL 312. While Stella will work with counts different than those, real TVs often have problems. Quote Link to comment Share on other sites More sharing options...
Svetlana Posted March 12, 2016 Author Share Posted March 12, 2016 I suggested the change to prevent the issue from cropping up in the future. As you add more code to your program, the location of PosObject will change - depending upon where, you could end up with the branch crossing a page. It's hard to track things like that down, so it's a good practice to put routines with critical timing at the start of the ROM.Got it! Your scanline count used to be 270, which Stella detected as NTSC. In the new version it's 290, which Stella detected as PAL. The Atari outputs different colors for each video system: NTSC, PAL, and SECAM. You'll need to decide if you're targeting NTSC or PAL and use the appropriate number of scanlines. For NTSC you want to output 262, for PAL 312. While Stella will work with counts different than those, real TVs often have problems.That makes sense! The reason why I was getting a wonky scanline count though is I forgot the RTS instruction at the end of my kernel -- it was calling overscan twice I fixed and tweaked the code (now pushed) to go back to the NTSC linecount I had before, but I need to check if my Brazilian 2600 clone (Dactar) uses NTSC or PAL TIA. (Brazil uses PAL-M or PAL60, which is 60hz NTSC timing with PAL color freqs.) In checking the code I see you're calling PosObject in the middle of your kernel. The scanline count increased by 1 because PosObject takes longer (more CPU time) to position objects on the right side of the screen. You should move the call to PosObject to the end of Vertical Blank where an extra scanline won't cause problems (that's why we use timers to check for the end of Vertical Blank and Overscan). I've changed it here:For some reason in my mind I had to call it somewhere in there because of how the scanlines worked, since I was thinking about visible space, but now I realize I can do it outside that. Thanks for the patience and big help! Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted March 13, 2016 Share Posted March 13, 2016 I need to check if my Brazilian 2600 clone (Dactar) uses NTSC or PAL TIA. (Brazil uses PAL-M or PAL60, which is 60hz NTSC timing with PAL color freqs.) That I don't know, though I do know that Stella supports PAL60, which is NTSC timing with PAL colors. While running Stella you can hit CONTROl-F to cycle through the systems: NTSC, PAL, SECAM, NTSC50, PAL60, SECAM60. If you happen to be launching Stella via command line (or via Notepad++ or gedit) you can set it like this: stella -format PAL60 brick.bin Thanks for the patience and big help! No problem! Quote Link to comment Share on other sites More sharing options...
LS_Dracon Posted March 13, 2016 Share Posted March 13, 2016 Brazilian consoles are NTSC compatible, both screen format and colors displayed, at 60 fps. 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.