+SpiceWare Posted April 9, 2016 Share Posted April 9, 2016 Did you change COLUPF to a non-zero value? CLEAN_START sets everything to 0, so all TIA objects will be black, and black on black doesn't show up very well. Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3487530 Share on other sites More sharing options...
Just Jeff Posted April 9, 2016 Share Posted April 9, 2016 Cancel that.. Guess I'm a little rusty. I was compiling it wrong: forgot the o in the output file name. I'm surprised DASM didn't show me an error though. Its displaying the stripes now. Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3487562 Share on other sites More sharing options...
Just Jeff Posted April 9, 2016 Share Posted April 9, 2016 Thanks Darrell- I put that seed value right after clean start assuming it would be a good place to know that wouldn't happen. I also didn't change any of your PF colors hoping they would already be correct. Anyway, its working now- just a dumb mistake. On the bright side, it forced me to go through some of your old replies so I could try to remember how to use the debugger better. I don't have any of the symbols(labels?) showing up and I know its some option I need to use. Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3487568 Share on other sites More sharing options...
+SpiceWare Posted April 10, 2016 Share Posted April 10, 2016 Sounds good! If you didn't get an error for excluding the o then the first letter of your filename was a valid option for dasm.Symbol dump is specified with the -s option. There's a readme.txt file included with all version of collect that goes into detail on it. Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3488307 Share on other sites More sharing options...
Just Jeff Posted April 12, 2016 Share Posted April 12, 2016 Ah.. The first letter was a D.. OK I understand the options better now- I assumed you could only use one and I just used -o since its the one I learned first and it at least worked. I tried reading the dasm documentation at one point but it was way above my head at that point and I didn't understand it. I've been meaning to ask you- after compiling, I see messages- bytes until the end of the cartridge and bytes until HumanGFX. What's the relevance of bytes until the graphics? Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3489674 Share on other sites More sharing options...
+SpiceWare Posted April 12, 2016 Share Posted April 12, 2016 I've been meaning to ask you- after compiling, I see messages- bytes until the end of the cartridge and bytes until HumanGFX. What's the relevance of bytes until the graphics? Would you ask this again in the blog? I'm sure others will wonder about that at some point and would prefer the answer to be there. Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3489711 Share on other sites More sharing options...
Just Jeff Posted April 16, 2016 Share Posted April 16, 2016 Sure! Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3492244 Share on other sites More sharing options...
Just Jeff Posted June 5, 2016 Share Posted June 5, 2016 Hi- I'm still having trouble writing a two line kernal. Does anone know of an easy to undertand code example and/or guide? Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3525311 Share on other sites More sharing options...
+SpiceWare Posted June 5, 2016 Share Posted June 5, 2016 Hi- I'm still having trouble writing a two line kernal. Does anone know of an easy to undertand code example and/or guide? Don't know if this will help, but I converted CollectMini to be a 2LK. Basically line 1 updates TIA for player0, line 2 updates for player1. ArenaLoop: ; 23 - worse case time to get here sta WSYNC ; 3 26 ;---------------------------- start of line 1 of the 2LK lda #HUMAN_HEIGHT-1 ; 2 2 - height of the human graphics, dcp Player0Draw ; 5 7 - Decrement Player0Draw and compare with height bcs DoDrawGrp0 ; 2 9 - (3 10) if Carry is Set then player0 is on current scanline lda #0 ; 2 11 - otherwise use 0 to turn off player0 .byte $2C ; 4 15 - $2C = BIT with absolute addressing, trick that ; causes the lda (Player0Ptr),y to be skipped DoDrawGrp0: ; 10 - from bcs DoDrawGRP0 lda (Player0Ptr),y ; 5 15 - load the shape for player0 sta GRP0 ; 3 18 sta WSYNC ; 3 21 ;---------------------------- start of line 2 of the 2LK lda #BOX_HEIGHT-1 ; 2 2 - height of the box graphics, subtract 1 due to starting with 0 dcp Player1Draw ; 5 7 - Decrement Player1Draw and compare with height bcs DoDrawGrp1 ; 2 9 - (3 10) if Carry is Set, then player1 is on current scanline lda #0 ; 2 11 - otherwise use 0 to turn off player1 .byte $2C ; 4 15 - $2C = BIT with absolute addressing, trick that ; causes the lda (Player1Ptr),y to be skipped DoDrawGrp1: ; 10 - from bcs DoDrawGrp1 lda (Player1Ptr),y ; 5 15 - load the shape for player1 sta GRP1 ; 3 18 dey ; 2 20 - update loop counter bne ArenaLoop ; 2 22 - 3 23 if taken CollectMini_2LK.bin CollectMini_2LK.asm Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3525344 Share on other sites More sharing options...
tschak909 Posted June 6, 2016 Share Posted June 6, 2016 (edited) Hi- I'm still having trouble writing a two line kernal. Does anone know of an easy to undertand code example and/or guide? The example that Darrell posts below should help. My advice is to just keep trying, you will get it. The biggest concept that you must understand, is that with the VCS, it is ALL ABOUT THE LINE. Your job in a kernel is to figure out where to find the time to write to the bits that you want the TIA to display on a line. This can be helped with some charts that show VCS timing as to when the latest you can enable the various bits, to put them in the right place... ..but really, there is enough known here that a utility could be made to parse little fragments of 6502 assembler, to count cycles, and to place a dot (for missile/ball enables), or a dash (for GRP0/1 writes or resets) on a chart to tell you where you are. This would help a TON. No HMOVE calculation would really be needed...but I digress. -Thom Edited June 6, 2016 by tschak909 Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3525740 Share on other sites More sharing options...
Just Jeff Posted June 7, 2016 Share Posted June 7, 2016 I think I'm going to have to take the Collect Mini kernal code and embellish every comment so I can better keep track of what's going on at any one time. The concept of 2LK makes perfect sense to me, but when I don't seem to be able to remember which variable? is doing what and why. Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3526573 Share on other sites More sharing options...
Just Jeff Posted June 9, 2016 Share Posted June 9, 2016 (edited) Hi! I was making my way fine through line 1 of the kernal (making lots of notes) until I got to where PlayerPtr is loaded. When I looked into the routine that generated PlayerPtr, I found: ; Set Player0Ptr to proper value for drawing player0 lda #<(HumanGfx + HUMAN_HEIGHT - 1) sec sbc ObjectY sta Player0Ptr lda #>(HumanGfx + HUMAN_HEIGHT - 1) sbc #0 sta Player0Ptr+1 I must not understand the first lda because it looks like its taking graphics data and adding to it and subtracting from it. I definitely don't understand what "<" does. PlayerPtr is eventually stored in GRP0 so it must be the graphics data. Definitely stumped on this one... Also, what does Ptr stand for? Pointer? Painter? Peter? Thanks for all the help! Edited June 9, 2016 by BNE Jeff Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3528043 Share on other sites More sharing options...
+SpiceWare Posted June 9, 2016 Share Posted June 9, 2016 Ptr = pointer. They are used to point at data. From the source where the RAM locations are defined: ; DoDraw Graphic Pointers in $87-8a Player0Ptr: ds 2 ; used for drawing player0 Player1Ptr: ds 2 ; used for drawing player1 From dasm.txt: 20 <exp take LSB byte of a 16 bit expression 20 >exp take MSB byte of an expression LSB is the Least Significant Byte of a value. If the expression value is $1234 the LSB is $34MSB is the Most Significant Byte of a value. If the expression value is $1234 the MSB is $12.From CollectMini_2LK.sym (symbols): HUMAN_HEIGHT 0014 HumanGfx fa00 (R ) HumanGfx + HUMAN_HEIGHT - 1 = $fa00 + $14 - 1 = $fa13So the < value is $13 while the > value is $fa. You can see that in CollectMini_2LK.lst (the listing): 385 f8db ; Set Player0Ptr to proper value for drawing player0 386 f8db a9 13 lda #<(HumanGfx + HUMAN_HEIGHT - 1) 387 f8dd 38 sec 388 f8de e5 83 sbc ObjectY 389 f8e0 85 87 sta Player0Ptr 390 f8e2 a9 fa lda #>(HumanGfx + HUMAN_HEIGHT - 1) 391 f8e4 e9 00 sbc #0 392 f8e6 85 88 sta Player0Ptr+1 The values going across the second line of that snippet are: 386 - line number in source f8db - location in ROM a9 - machine code instruction 13 - operand as required by the instruction (0, 1, or 2 bytes in length) lda #<(HumanGfx + HUMAN_HEIGHT - 1) - original source Look at the 6502 opcodes for LDA and you'll find: LDA (LoaD Accumulator) Affects Flags: S Z MODE SYNTAX HEX LEN TIM Immediate LDA #$44 $A9 2 2 Zero Page LDA $44 $A5 2 3 Zero Page,X LDA $44,X $B5 2 4 Absolute LDA $4400 $AD 3 4 Absolute,X LDA $4400,X $BD 3 4+ Absolute,Y LDA $4400,Y $B9 3 4+ Indirect,X LDA ($44,X) $A1 2 6 Indirect,Y LDA ($44),Y $B1 2 5+ + add 1 cycle if page boundary crossed lda # is the mnemonic code for machine code instruction $A9. 1 Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3528110 Share on other sites More sharing options...
Just Jeff Posted June 11, 2016 Share Posted June 11, 2016 (edited) OK, I think I might be following a little bit... So when you: lda (Player0Ptr),y is this pointing to random garbage data on every scan line except when we are on the lines where Player 0 is drawn, it runs through the graphics lines? Edited June 11, 2016 by BNE Jeff Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3529276 Share on other sites More sharing options...
tschak909 Posted June 11, 2016 Share Posted June 11, 2016 If the Y register is 0, and Player0Ptr has been set to an address where there is graphic data (e.g. somewhere off in $F000 in the ROM via a source code label), then the Y accumulator will now hold the first byte of that data. If you change that Y register to 1, then Player0Ptr will advance to the next byte in that address. Technically, this is called an (Indirect),Y addressing mode. The Indirect means, that you can change the address that you're indirecting into, to something else (e.g. another table with graphics for another player), and the code will still function as expected, rendering the new data, assuming it is in the format needed. The extra layer of indirection gives you more flexibility, than if you were simply just using e.g. the Indexed,X or Indexed,Y modes. (There IS a very specific form of X that is called the Indirect X mode, but it has very limited use on the 2600 due to the limited amount of actual RAM) Some good refs: https://github.com/jefftranter/6502/blob/master/docs/6502refcard.pdf 2 Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3529340 Share on other sites More sharing options...
alex_79 Posted June 11, 2016 Share Posted June 11, 2016 So when you: lda (Player0Ptr),y is this pointing to random garbage data on every scan line except when we are on the lines where Player 0 is drawn, it runs through the graphics lines? The instruction "lda (Player0Ptr),y" is not executed at all if the player is not being drawn on the current scanline, because it's skipped using the ".byte $2C" trick. it works because "lda (Player0Ptr),y" is a two bytes instruction: the first byte is the opcode for the "lda (),y or lda Indirect, Y" instruction ($B1, as per the table posted above by Spiceware), the second is the single byte indicating the zero-page address of the operand (Player0Ptr, which is $87 in this case). So, when you assemble the source with dasm, the "lda (Player0Ptr),y" is translated into the byte sequence $B1 $87 in the binary file. (The actual values are not relevant in this case, just the fact that they are exactly 2 bytes). If the player is not being drawn, the carry won't be set after "dcp Player0Draw", so the branch "bcs DoDrawGrp0" won't be taken. Therefore the following instruction will be executed (lda #0), then the 6502 cpu will read the next byte in the binary ($2C). This is the opcode for the instruction BIT Absolute, which is a 3 bytes instruction. (the opcode itself, plus 2 bytes indicating the absolute 16 bit address). The next 2 bytes in the binary are those of the "lda (Player0Ptr),y" instruction, which in this case are interpreted as the operand (the address) of the BIT instruction. So the three bytes $2C $B1 $87 are interpreted as BIT $87B1. Since the BIT instruction affects some of the flags but not the Accumulator, the latter will still be set to 0 and the following "sta GRP0" instruction will therefore clear the player graphics. 2 Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3529349 Share on other sites More sharing options...
tschak909 Posted June 11, 2016 Share Posted June 11, 2016 (for the record, I don't like using tricks, unless I am at the end of a project, and I need to squeeze things in...It's far too often that I write a piece of clever code, only to come back to it some time later, and try to remember WHY THE HELL I DID THAT?!) -Thom Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3529353 Share on other sites More sharing options...
+SpiceWare Posted June 11, 2016 Share Posted June 11, 2016 OK, I think I might be following a little bit... So when you: lda (Player0Ptr),y is this pointing to random garbage data on every scan line except when we are on the lines where Player 0 is drawn, it runs through the graphics lines? If that line was executed then yes, it would be pointing at "garbage" (the data in ROM before/after HumanGfx). You may like to review the comments of Step 4, I go over that routine in a bit more detail. (for the record, I don't like using tricks, unless I am at the end of a project, and I need to squeeze things in...It's far too often that I write a piece of clever code, only to come back to it some time later, and try to remember WHY THE HELL I DID THAT?!) -Thom The byte $2c trick's been around a long time, I learned it in the early 80s on my Vic 20. I didn't use the DCP trick until the 2600, the 3 cycle savings during the time critical kernel is too much to ignore. Both tricks are covered in detail in the comments of Step 4. 2 Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3529378 Share on other sites More sharing options...
Mr SQL Posted June 11, 2016 Share Posted June 11, 2016 Hi- I'm still having trouble writing a two line kernal. Does anone know of an easy to undertand code example and/or guide? Jeff, you might find the two line kernel in Virtual World BASIC a little simpler to follow, it's commented and I've recently revised it to remove an extra layer of indirection so it may be less confusing. The advanced Assembly programmers discussing nuances, tricks and esoteria may be difficult to understand on a beginner thread: Programmer 1: You put the glop-de-glop in the gloop-gloop. Programmer 2: And you adjust it 5 glicks. Programmer 3: Yes, it's always 5 glicks! Johnny Mnemonic has a simple overview of addressing modes that is easy to understand. If the Y register is 0, and Player0Ptr has been set to an address where there is graphic data (e.g. somewhere off in $F000 in the ROM via a source code label), then the Y accumulator will now hold the first byte of that data. If you change that Y register to 1, then Player0Ptr will advance to the next byte in that address. Technically, this is called an (Indirect),Y addressing mode. The Indirect means, that you can change the address that you're indirecting into, to something else (e.g. another table with graphics for another player), and the code will still function as expected, rendering the new data, assuming it is in the format needed. The extra layer of indirection gives you more flexibility, than if you were simply just using e.g. the Indexed,X or Indexed,Y modes. (There IS a very specific form of X that is called the Indirect X mode, but it has very limited use on the 2600 due to the limited amount of actual RAM) Some good refs: https://github.com/jefftranter/6502/blob/master/docs/6502refcard.pdf That takes more cycles though tschak; it is possible to remove that extra layer or indirection by normalizing the data in the graphics table into multiple tables with a common index. I recently did this transformation to the Virtual World BASIC kernel in order to free time for multicolor sprites and playfield attributes: 1 Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3529622 Share on other sites More sharing options...
gauauu Posted June 12, 2016 Share Posted June 12, 2016 (for the record, I don't like using tricks, unless I am at the end of a project, and I need to squeeze things in...It's far too often that I write a piece of clever code, only to come back to it some time later, and try to remember WHY THE HELL I DID THAT?!) -Thom I tend to try to keep my code clean and non-tricky as well, but it's easy enough to make a macro to make this one obvious and not feel hacky. I have a "Skip2Bytes" macro that I use, which just does the $byte 2c, but makes it obvious so my code still reads cleanly. Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3529763 Share on other sites More sharing options...
Omegamatrix Posted June 12, 2016 Share Posted June 12, 2016 After spending a little time with assembly you'll find it's very easy to read "tricky" stuff like .byte $2C. You'll just recognize it. Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3529799 Share on other sites More sharing options...
Just Jeff Posted June 12, 2016 Share Posted June 12, 2016 Thanks Everybody.. I did have some understanding of the .byte trick. I knew it worked, but as I've been trying to add comments to the CollectMini code, I finally got around to reading up on why.. I learned that it requires a two byte operand and so it swallows up the next line of code as its operand. I didn't know that the $2C had relevance till now though. By saying the lda points to random garbage, I was imagining the program counter going to it and passing over it, but I see, yes, it doesn't actually get there, it would, but it ends up as operand for the .byte. Whew! I'm at my limits of understanding.. I mean that in a good way. Pretty exciting. I did note that during this, we are using two bytes, while we only need one stored into the player register.(The LSB, I think) Are we doing this only because $2C is looking for two bytes? The MSB is treated strangely if so: lda #>(HumanGfx + HUMAN_HEIGHT - 1) sbc #0 sta Player0Ptr+1 Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3529839 Share on other sites More sharing options...
alex_79 Posted June 12, 2016 Share Posted June 12, 2016 (edited) [...] it doesn't actually get there, it would, but it ends up as operand for the .byte. .byte is not a 6502 instruction, but a dasm one, used to insert bytes values directly in the source. The .byte instruction itself doesn't translate into any value in the resulting binary. It is mostly used to insert data tables (like graphics, for example), but in this case is used because there's no way to tell dasm to just insert the BIT opcode without an operand (it would report an error). So the two bytes corresponding to the "lda (),y" become the operand of the BIT instruction (that is, the $2C value), not of .byte. I did note that during this, we are using two bytes, while we only need one stored into the player register.(The LSB, I think) Are we doing this only because $2C is looking for two bytes? All the data registers (A, X, Y) and every addressable memory location are 8 bit (1 byte) wide. So all load/store instructions read or write a single byte. When you specify a two byte operand, that's the address where that single byte value is to be loaded from or stored to. The lda (Player0Ptr),y has 1 byte as operand because it's a zero-page instruction and only the LSB of the address needs to be specified (the MSB is always $00 in page 0). Moreover is an indirect addressing instruction, so the operand is not the address of the value to be stored/loaded but the address of the pointer to the value (that is, the address where the address of the value is stored). It means: take the address whose LSB is in memory location Player0Ptr and whose MSB is in memory location Player0Ptr+1, add the value of Y to it and then load the value stored in the resulting address into the Accumulator. (and "memeory location Player0Ptr" means the address whose LSB is Player0Ptr and whose MSB is $00) Edited June 12, 2016 by alex_79 Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3530068 Share on other sites More sharing options...
+SpiceWare Posted June 12, 2016 Share Posted June 12, 2016 The instruction ldy (Player0Ptr),y uses a 16 bit value that's stored in zero_page memory locations Player0Ptr and Player0Ptr+1. That's why the pointer is defined as 2 bytes, not 1: ; DoDraw Graphic Pointers in $87-8a Player0Ptr: ds 2 ; used for drawing player0 Player1Ptr: ds 2 ; used for drawing player1 The MSB is treated strangely if so: lda #>(HumanGfx + HUMAN_HEIGHT - 1) sbc #0 sta Player0Ptr+1 That's part of a routine which is doing 16 bit math. From before the (HumanGfx + HUMAN_HEIGHT - 1) value is $FA13, so this bit of code: ; Set Player0Ptr to proper value for drawing player0 lda #<(HumanGfx + HUMAN_HEIGHT - 1) sec sbc ObjectY sta Player0Ptr lda #>(HumanGfx + HUMAN_HEIGHT - 1) sbc #0 sta Player0Ptr+1would be calculating $FA13 - ObjectY and storing the results in Player0Ptr. ObjectY is only an 8 bit value so we hard code 0 (the SBC #0) as the MSB for the value of ObjectY. Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3530123 Share on other sites More sharing options...
Just Jeff Posted June 16, 2016 Share Posted June 16, 2016 (edited) OK.. I see that .byte is not the command... Now it seems like it is a way to trick DASM, not the 6502. I'd think that DASM could just allow the command but I'm sure there is a reason it doesn't. So indirect addressing means the operand is the location where the location of the data is stored? I hope that's right because I've been having a hard time with that stuff. I have immediate addressing down pretty good though! So if I understand correctly, we are using 16 bits, just because we are required to by a command that expects a 16 bit operand- One of the bytes does nothing in our case. I am still thrown off by the sbc #0. This looks like "subtract zero" to me, and not "make it zero". It seems like deleting the command would have the same result stored into PlayerPtr+1, though the carry flag could potentially cause it to store 255? maybe?, in which case MSB is not "hard coded to zero" though? Come to think of it, since we subtract zero, the carry flag would never matter, I think. Hmm. Thanks for the 16 bit math link. I think I grasped it. Edited June 16, 2016 by BNE Jeff Quote Link to comment https://forums.atariage.com/topic/27010-introduction-2600-programming-for-newbies/page/6/#findComment-3533081 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.