Wickeycolumbus Posted March 29, 2008 Share Posted March 29, 2008 This is my first homebrew for the 2600 written in assembly, and I am very proud of it, since I am only 14 years old. The name of it is "Vong" for Vertical pong. It plays like pong, but instead of the ball going side to side, it goes up and down, hence the name Vong. There is some AI, but it is not too good. I plan to change all of the colors to black and white, like the original pong. There is no scoring currently, but there will be in a future update. I would also like to add paddle support, and a 2 player option. Enjoy! vong20080328.zip Quote Link to comment Share on other sites More sharing options...
Devin Posted March 29, 2008 Share Posted March 29, 2008 This is my first homebrew for the 2600 written in assembly, and I am very proud of it, since I am only 14 years old. The name of it is "Vong" for Vertical pong. It plays like pong, but instead of the ball going side to side, it goes up and down, hence the name Vong. There is some AI, but it is not too good. I plan to change all of the colors to black and white, like the original pong. There is no scoring currently, but there will be in a future update. I would also like to add paddle support, and a 2 player option. Enjoy! It's looking great so far! I look forward to see how this project progresses. Cheers. Quote Link to comment Share on other sites More sharing options...
retrogeek Posted March 29, 2008 Share Posted March 29, 2008 This is my first homebrew for the 2600 written in assembly, and I am very proud of it, since I am only 14 years old. The name of it is "Vong" for Vertical pong. It plays like pong, but instead of the ball going side to side, it goes up and down, hence the name Vong. There is some AI, but it is not too good. I plan to change all of the colors to black and white, like the original pong. There is no scoring currently, but there will be in a future update. I would also like to add paddle support, and a 2 player option. Enjoy! Nice! Very impressive for your age! Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted March 29, 2008 Author Share Posted March 29, 2008 Thanks Guys! Quote Link to comment Share on other sites More sharing options...
accousticguitar Posted March 29, 2008 Share Posted March 29, 2008 I am impressed with ANYONE who can program ANYTHING using assembly language on the 2600. Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted March 29, 2008 Share Posted March 29, 2008 Kudos for going the hard way and use assembler! Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted March 29, 2008 Author Share Posted March 29, 2008 Kudos for going the hard way and use assembler! Thank you, I like a challenge. Quote Link to comment Share on other sites More sharing options...
gambler172 Posted March 29, 2008 Share Posted March 29, 2008 Hi Wickey Great,for a young guy.Now you need to add scores.This can become a nice game. greetings Walter Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted March 29, 2008 Author Share Posted March 29, 2008 Ok, I made it black and white like real pong, put a white line it the middle of the play field, and made the opponent's paddle a bit bigger in hopes of better AI. There is still some screen rolling though, and I plan to fix that and add scoring in the next version. vong20080329.zip Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted March 29, 2008 Share Posted March 29, 2008 I posted sample paddle reading code here. Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted March 29, 2008 Author Share Posted March 29, 2008 I posted sample paddle reading code here. thank you for the link. Are those macros a part of macro.h? and I also have some questions about the code. MAC READ_PADDLE_1 lda INPT0 ; 3 - always 9 bpl .save ; 2 3 .byte $2d ; 4 0 What does this do? .save sty Paddle1 ; 0 3 To read the paddle you read Paddle1? (lda Paddle1) ENDM You say before you posted this code that Y holds the current scanline. Do you have to put the current scanline into Y, or does that just happen after you use the macro? Thanks. Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted March 29, 2008 Share Posted March 29, 2008 (edited) .byte $2d ; 4 0 What does this do? This is the byte code for the "BIT absolute" instruction ($2c, NOT $2d!). The trick is, that it uses the two next bytes (sty Paddle1) as argument to read from, effectively doing nothing and just skipping the next two bytes with constant(!) cycle count. It takes 4 cycles to execute. .save sty Paddle1; 0 3 To read the paddle you read Paddle1? No, that's just the name of a RAM variable you write to as long as the paddle's capacitor hasn't loaded. INPT0 is reading the first paddle (BTW: actually that's paddle 0, not 1). Do you have to put the current scanline into Y, or does that just happen after you use the macro? Yes. Though a lot of kernels use Y as a global scanline count variable, so then you have the value required there already and save some cycles. The code was originally discussed here. Edited March 29, 2008 by Thomas Jentzsch Quote Link to comment Share on other sites More sharing options...
Impaler_26 Posted March 29, 2008 Share Posted March 29, 2008 Nice work so far, keep it up! Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted March 30, 2008 Author Share Posted March 30, 2008 (edited) .byte $2d; 4 0 What does this do? This is the byte code for the "BIT absolute" instruction ($2c, NOT $2d!). The trick is, that it uses the two next bytes (sty Paddle1) as argument to read from, effectively doing nothing and just skipping the next two bytes with constant(!) cycle count. It takes 4 cycles to execute. .save sty Paddle1; 0 3 To read the paddle you read Paddle1? No, that's just the name of a RAM variable you write to as long as the paddle's capacitor hasn't loaded. INPT0 is reading the first paddle (BTW: actually that's paddle 0, not 1). Do you have to put the current scanline into Y, or does that just happen after you use the macro? Yes. Though a lot of kernels use Y as a global scanline count variable, so then you have the value required there already and save some cycles. The code was originally discussed here. Ok, so I run the macro, with the current scanline count in Y. I still dont really get how you read it tho... EDIT: I clicked the link, and it was dead. EDIT: I clicked it again and it worked. EDIT: So would something like this work? sta HMCLR lda INPT0 cmp shadowINPT0 bmi paddleminus bpl paddleplus paddleminus lda #%00010000 sta HMP1 sta shadowHMP1 jmp regular paddleplus lda #%11110000 sta HMP1 sta shadowHMP1 regular ;on with the rest of the program Edited March 30, 2008 by Wickeycolumbus Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted March 30, 2008 Author Share Posted March 30, 2008 slightly better AI, still needs to be improved more tho... vong200803292.zip Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted March 30, 2008 Share Posted March 30, 2008 .byte $2d; 4 0 What does this do? This is the byte code for the "BIT absolute" instruction ($2c, NOT $2d!). Oops- my mistake, it's correctly using $2c in the "2 paddle" macros which is what I used in MM and the sample. Quote Link to comment Share on other sites More sharing options...
+Omegamatrix Posted March 30, 2008 Share Posted March 30, 2008 Impressive for someone so young to be able to play around with programming a 6502. I look forward to updates of this game. Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted March 30, 2008 Share Posted March 30, 2008 Can you just attach the .bin file in the future so the game can be played directly instead of needing to download and unzip? Thanks. Quote Link to comment Share on other sites More sharing options...
ovalbugmann Posted March 30, 2008 Share Posted March 30, 2008 Thanks for the Pong style game , I'm going to try to load it onto a 2600 with a supercharger. What are you using to load it into a 2600? Or are you using Stella for the PC? Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted March 30, 2008 Share Posted March 30, 2008 (edited) EDIT: So would something like this work? I suppose you want to execute the code once each frame right? Won't work. The problem is, that INPT0 does NOT contain a variable value. It either contains 0 or 1 (at bit 7, the other bits are unused here), so your code has to measure how long it takes to switch that bit. And this is usually done during the display kernel. BTW: After posting my answer here yesterday, I found an even faster (though a bit more complicated) solution: bit INPT0 ; 3 bmi .save+1 ; 2/3 .save: sty paddle ; 3/2 paddle has to be at the address of an 1 byte, 2 cycles opcode, e.g. $ea (NOP) Total: 8 cycles, 1 cycle saved Edited March 30, 2008 by Thomas Jentzsch Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted March 30, 2008 Author Share Posted March 30, 2008 Can you just attach the .bin file in the future so the game can be played directly instead of needing to download and unzip? Thanks. Sure. I did not think of that. Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted March 30, 2008 Author Share Posted March 30, 2008 Thanks for the Pong style game , I'm going to try to load it onto a 2600 with a supercharger. What are you using to load it into a 2600? Or are you using Stella for the PC? I have been using Stella os X, but I do have an Eprom programmer that I use to do testing with too. Quote Link to comment Share on other sites More sharing options...
Wickeycolumbus Posted March 30, 2008 Author Share Posted March 30, 2008 EDIT: So would something like this work? I suppose you want to execute the code once each frame right? Won't work. The problem is, that INPT0 does NOT contain a variable value. It either contains 0 or 1 (at bit 7, the other bits are unused here), so your code has to measure how long it takes to switch that bit. And this is usually done during the display kernel. BTW: After posting my answer here yesterday, I found an even faster (though a bit more complicated) solution: bit INPT0 ; 3 bmi .save+1; 2/3 .save: sty paddle ; 3/2 paddle has to be at the address of an 1 byte, 2 cycles opcode, e.g. $ea (NOP) Total: 8 cycles, 1 cycle saved So paddle is just any RAM address and it contains the number of scanlines that it took to get a 1 from INPT0? Dont you have to do something before you execute that code to instruct the paddle to start charging the capicitor? Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted March 30, 2008 Share Posted March 30, 2008 Yep - done via VBLANK. At the MiniDig you can find the Stella Programmer's Guide which has this on page 11: 12.1 Dumped Input Ports (INPT0 thru INPT3)These four ports are used to read up to four paddle controllers. Each paddle controller contains an adjustable pot controlled by the knob on the controller. The output of the pot is used to charge a capacitor in the console, and when the capacitor is charged the input port goes HI. The microprocessor discharges this capacitor by writing a "1" to D7 of VBLANK then measures the time it takes to detect a logic one at that port. This information can be used to position objects on the screen based on the position of the knob on the paddle controller. The D7 refers to a specific bit, whenever ordered as 76543210. $80 has bit 7 turned on. $82 has bits 7 and 1 turned on. The detail for VBLANK can be found on page 38: VBLANK This address controls vertical blank and the latches and dumping transistors on the input ports by writing into bits D7, D6 and D1 of the VBLANK register. D1 [ 1 = start vert. blank, 0 = stop vert. blank] D6 [ 1 = Enable I4 I5 latches, 0 = disable I4 I5 latches] D7 [ 1 = dump I6I1I2I3 ports to ground, 0 = remove dump path to ground] Note : Disable latches (D6 = 0) also resets latches to logic true The code from my demo: VerticalBlank: lda #$82 sta WSYNC sta VSYNC ; 3 start vertical sync, D1=1 sta VBLANK ; 3 6 start vertical blank and dump paddles to ground ... ldx Paddles2Read lda #153 ; prep paddle results with highest possible value sta Paddle1,x ; our initial paddle results will be 1-153 sta Paddle3,x ; and will be adjusted to 0-152 in overscan lda #0 VblankWait lda INTIM bpl VblankWait sta WSYNC sta HMCLR ; clear hmoves for next time around stx VBLANK ; turn on video output & remove paddle dump to ground The lda #0 just before VblankWait was supposed to be ldx #0 so that the stx VLBANK would be zeroing out all bits. However X can only have a value of 0 or 1, which is stored in bit 0 - lucky for me, as seen in the bit from page 38, VBLANK only cares about what's in bits 7, 6 and 1. Quote Link to comment Share on other sites More sharing options...
supercat Posted March 30, 2008 Share Posted March 30, 2008 The problem is, that INPT0 does NOT contain a variable value. It either contains 0 or 1 (at bit 7, the other bits are unused here), so your code has to measure how long it takes to switch that bit. And this is usually done during the display kernel. Atari implemented their paddles the cheapest way possible. Discharge a capacitor, release it, charge it through a variable resistance, and time how long it takes to reach a certain threshold. That time will be directly proportional to the variable resistance; on the 2600, it's designed to vary from almost nothing to something over a full frame (though I don't think any games use the latter part of the range). One approach which can be handy in certain types of kernels is to vary the time that you release the cap, so that it will reach the threshold within a fairly narrow range of scan lines. It's only possible to read one paddle per frame with this approach, but it's possible to read paddles with single-line resolution even if much of the screen has large groups of lines with no spare cycles. For example, if your screen is divided into 10-line blocks, and you only have a few cycles at the end of each such block, all you need to squeeze in once every ten lines is something like (preferably do this just before a loop branch so you won't have to copy much code) ldx paddlectr dex bne nohit stx.w VBLANK .. one copy of succeeding code nohit: stx lctr .. another copy of succeeding code Ten cycles, every ten scan lines. Some time later on the screen, you'll need a loop which checks the paddle every line, and you'll have to adjust the starting value of paddlectr so that the paddle is expected to time out around the middle of that loop. A somewhat tricky approach, but it can yield very nice results. 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.