nesdev.com https://forums.nesdev.com/ 

8x16 and whatever else unreg wants to know https://forums.nesdev.com/viewtopic.php?f=10&t=7451 
Page 30 of 95 
Author:  unregistered [ Sat Dec 31, 2011 2:19 pm ] 
Post subject:  
If I have 00001111 in the accumulator... how could I check the bit value of the ones? Like how would I say check the value of bit #2? Is there a faster way to do this than Code: ror a
ror a and #$01 beq + ;code for a value of 1 + ;code for a value of 0 Does that even work? I think it does. 
Author:  Dwedit [ Sat Dec 31, 2011 2:23 pm ] 
Post subject:  
How about just "AND #$04" to check bit 00000100? 
Author:  unregistered [ Sat Dec 31, 2011 2:28 pm ] 
Post subject:  
Dwedit wrote: How about just "AND #$04" to check bit 00000100?
But the result wouldn't be a 1 or a zero... But, beq only focuses on a 0. So... is that right? edit: That's brilliant! Thanks Dwedit! Have a happy new year! 
Author:  tokumaru [ Sat Dec 31, 2011 5:10 pm ] 
Post subject:  
unregistered wrote: But the result wouldn't be a 1 or a zero... But, beq only focuses on a 0. So... is that right?
As you probably have realized, if the result is not 0 you know that the bit is set. If you wanted to copy any bit to the carry flag (sometimes we do that when rearranging bits) you could use an AND followed by a CMP: Code: ;copy bit 2 to the carry flag
and #%00000100 cmp #%00000100 Then you can shift the bit into some variable using ROR or ROL, or do whatever else you want with it. 
Author:  unregistered [ Wed Jan 04, 2012 4:21 pm ] 
Post subject:  
unregistered wrote: How do I know if the something IS water? How do I check the tile number? One of the ideas we had consisted in using 1 bit to select between water or air for the empty tiles, and 3 bits for the type of the solid tiles. In this case it would be easy to know if something is water, but since you decided to use the tile index... Well, your screenArray only has the basic collision info, it doesn't say which tiles each block uses. The only way is to make screenArray hold the index of the metatiles instead of the collision info. That way, whenever you wanted to test for collisions, you'd have to get the metatile index at the position you want and use that to fetch the collision info from a table. With the same index you can easily access the tile indexes too. It's a bit more indirect, but that's not too bad. The last part has me confused. If screenArray held "the index of the metatiles instead of the collision info" would that destroy our library and collision files? That would be terrible! My sister has done so many of them so far. That first thing you mentioned about "using 1 bit to select between water or air for the empty tiles, and 3 bits for the type of the solid tiles." Since we have two extra bits could we set one of them to select between water or air for the empty tiles by itself (without the 3 bits for the solid type tiles)? Then wouldn't it be much easier to know if something is water? 
Author:  unregistered [ Thu Jan 12, 2012 5:32 pm ] 
Post subject:  
tokumaru wrote: unregistered wrote: But the result wouldn't be a 1 or a zero... But, beq only focuses on a 0. So... is that right? As you probably have realized, if the result is not 0 you know that the bit is set. If you wanted to copy any bit to the carry flag (sometimes we do that when rearranging bits) you could use an AND followed by a CMP: Code: ;copy bit 2 to the carry flag and #%00000100 cmp #%00000100 Then you can shift the bit into some variable using ROR or ROL, or do whatever else you want with it. This is good... and it works because a)The AND puts 4 into the accumulator... b)then... the CMP puts (Accumulator  Memory) in the Accumulator? c)so now the Accumulator has a 0. Does that 0 clear the Carry flag? d) ...I dont know why this works...Could you help me please? 
Author:  tokumaru [ Thu Jan 12, 2012 6:14 pm ] 
Post subject:  
unregistered wrote: a)The AND puts 4 into the accumulator... No, it ANDs whatever is in the accumulator with 4, the result will only be 4 if bit 2 was set in the original value, otherwise it will be 0. Quote: b)then... the CMP puts (Accumulator  Memory) in the Accumulator?
No, CMP does not change the value of the accumulator. It does calculate A  4, but the result is not stored anywhere. What matters to us is the value of the carry after this subtraction: if the accumulator is 4, the subtraction will "succeed" (i.e. there will be no underflow) and the carry will be set. If the accumulator is 0, the subtraction will cause an underflow, clearing the carry. This causes the carry to become whatever bit 2 was in the first place, so we have effectively "copied" bit 2 into the carry flag. 
Author:  Kasumi [ Thu Jan 12, 2012 7:39 pm ] 
Post subject:  
Tokumaru covered CMP, but here's a little more explanation on what AND and the other bitwise operators (hey, why not?) do, and why what Dwedit suggested works: AND (like ORA and EOR) at a basic level gives an output of 1 bit from 2 input bits. Order doesn't matter in any of them, so there are three cases. 1. Both bits are 0. 2. Both bits are 1 3. 1 bit is 1, and the other is 0. AND gives an output of 1 if both input bits were 1. (if input bit 1 is 1 [true] AND input bit 2 is 1 [true], the result is true.) See how it got its name? So, AND will only return 1 in case 2, otherwise it gives 0. ORA gives an output of 1 if either input bit is one. (If input bit 1 is 1 [true] OR input bit 2 is 1[true], the result is true.) See how it got its name? So ORA will return 1 in every case except case 1. It will return 0 in case 1. EOR (Exclusive OR) gives an output of 1 if EXACTLY one of the input bits is 1. (If input 1 and ONLY input is 1 [true], the result is true. If input 2 and ONLY input 2 is 1[true], the result is true) So EOR will return 1 only in case 3, otherwise it gives 0. Now, at a basic level they work one bit at a time. The instructions work a byte at a time with corresponding bits in a byte. Code: #%00000000
^^^^^^^^  BIT#: 76543210 #%00000000 They check and return the result of bits 7 in each byte, and while that check is happening what's in bits 60 doesn't matter. Then it does bits 6, and while that check is happening what's in bits 7 and 50 doesn't matter. Etc. AND is useful for checking the status of a specific bit, because by definition of AND, a bit with a 0 in either byte will return 0. So if you AND with a number that has 7 bits as 0, the result of those seve bits will be 0. That means the bit you left 1 in the AND determines whether the accumulator is 0, or non0. Another use for AND is clearing a bit (setting it to 0). #%01111111 will clear the leftmost bit without changing the others. The 0 is guaranteed to clear the high bit because the 0 means both bits CAN'T be 1, and the 7 ones guarantee the other bits won't change. EOR is useful for toggling a bit (0>1 or 1>0). This is because a 0 in an EOR is guaranteed to not change the bit it is being EOR'd with, while a 1 in an EOR is guaranteed TO change the bit it is being EOR'd with. ORA is useful for setting a bit to 1. This is a because a 1 is guaranteed to give a result of 1, while a 0 will never change the bit you are ORA'ing with. 
Author:  unregistered [ Sun Jan 15, 2012 4:47 am ] 
Post subject:  
tokumaru, thank you so much for helping me with this! tokumaru wrote: if the accumulator is 4, the subtraction will "succeed" (i.e. there will be no underflow) and the carry will be set. No underflow? So water will not flow under the subtraction and that sets the carry? (trying to get you to teach me more about "underflow"  im interested)  tried to make this easier to read... for me at least... just added colors Kasumi wrote: Tokumaru covered CMP, but here's a little more explanation on what AND and the other bitwise operators (hey, why not?) do, and why what Dwedit suggested works:
AND (like ORA and EOR) at a basic level gives an output of 1 bit from 2 input bits. Order doesn't matter in any of them, so there are three cases. 1. Both bits are 0. 2. Both bits are 1 3. 1 bit is 1, and the other is 0. AND gives an output of 1 if both input bits were 1. (if input bit 1 is 1 [true] AND input bit 2 is 1 [true], the result is true.) See how it got its name? So, AND will only return 1 in case 2, otherwise it gives 0. ORA gives an output of 1 if either input bit is one. (If input bit 1 is 1 [true] OR input bit 2 is 1[true], the result is true.) See how it got its name? So ORA will return 1 in every case except case 1. It will return 0 in case 1. EOR (Exclusive OR) gives an output of 1 if EXACTLY one of the input bits is 1. (If input 1 and ONLY input is 1 [true], the result is true. If input 2 and ONLY input 2 is 1[true], the result is true) So EOR will return 1 only in case 3, otherwise it gives 0. Now, at a basic level they work one bit at a time. The instructions work a byte at a time with corresponding bits in a byte. Code: #%00000000 ^^^^^^^^  BIT#: 76543210 #%00000000 They check and return the result of bits 7 in each byte, and while that check is happening what's in bits 60 doesn't matter. Then it does bits 6, and while that check is happening what's in bits 7 and 50 doesn't matter. Etc. AND is useful for checking the status of a specific bit, because by definition of AND, a bit with a 0 in either byte will return 0. So if you AND with a number that has 7 bits as 0, the result of those seve bits will be 0. That means the bit you left 1 in the AND determines whether the accumulator is 0, or non0. Another use for AND is clearing a bit (setting it to 0). #%01111111 will clear the leftmost bit without changing the others. The 0 is guaranteed to clear the high bit because the 0 means both bits CAN'T be 1, and the 7 ones guarantee the other bits won't change. EOR is useful for toggling a bit (0>1 or 1>0). This is because a 0 in an EOR is guaranteed to not change the bit it is being EOR'd with, while a 1 in an EOR is guaranteed TO change the bit it is being EOR'd with. ORA is useful for setting a bit to 1. This is a because a 1 is guaranteed to give a result of 1, while a 0 will never change the bit you are ORA'ing with. Kasumi, thanks for helping us! The logic surrounding your cases is interesting. : ) There are shortcuts or cycles that can be saved, right? I have tried to think of one, but I can't think of anything... 
Author:  Kasumi [ Sun Jan 15, 2012 11:22 am ] 
Post subject:  
unregistered wrote: No underflow? You know how sbc works, right? Let's assume the carry is set before the sbc. Let's assume we're working with unsigned numbers. (#$FF = 255. Signed would mean #$FF = 1) So this Code: sbc foo will subtract foo from the accumulator. If the accumulator ends up as a larger number than what you started with (example: 0  1 = 255), the carry is cleared. That's underflow. If there was no underflow, the carry stays set. (Overflow is the term for addition when you end up with a number lower than what you started with [example: 255+1 = 0]) CMP does nearly the exact same thing as SBC, except for two things: 1. CMP doesn't care about the carry flag's status before it's run. It could be cleared and an extra one would not be subtracted. 2. CMP doesn't store the result of the subtraction in the accumulator. A never changes. CMP (or even SBC) works to compare numbers because cmping a larger number guarantees the carry will be clear, and vice versa. Think: If you subtract a larger number from a smaller number you will always pass 0. (And wrap to #$FF on the 6502.) If the number you subtract is the same, the carry stays sets and the zero flag is set because the result is 0. What tokumaru was suggesting works because anything cmp'd with 0 that is not 0 gives a result that is not 0. And anything that is not zero clears the 0 flag. Code: lda byte and #%00010000;This guarantees the accumulator is either ;#%00000000 (beq would branch) ;or ;#%00010000 (bne would branch) ;If you cmp #%00010000, it actually reverses that for reasons that should be clear given the above explanations. cmp #%00010000 ;if the accumulator has #%00000000 bne would branch. #%00000000  #%00010000 is not 0. if the accumulator has #%00010000 beq would branch. #%00010000  #%00010000 is 0 unregistered wrote: There are shortcuts or cycles that can be saved, right? I have tried to think of one, but I can't think of anything...
Optimization is my favorite business, but it's a tricky, possibly dangerous one that's always specific to what you want to do. Get your code to work first, then make it fast. Quick tips: Even though I just typed a book describing it, avoid cmping to reverse the 0 flag. If you just use the other branch, you can avoid the cmp which always makes sense to me. You shouldn't ever have to and #%10000000 to check that bit because bpl and bmi already check that highest bit when it's loaded BIT puts the highest two bits (marked X) #%XXYYYYYY into flags you can branch on, but only for variables stored in a static place. Because of that I always place the two things the need to be checked most often in those bits when I write data formats. 
Author:  tokumaru [ Sun Jan 15, 2012 12:03 pm ] 
Post subject:  
I know Kasumi already explained a lot but I still want to say a few things. unregistered wrote: No underflow? So water will not flow under the subtraction and that sets the carry? (trying to get you to teach me more about "underflow"  im interested) An overflow is when the result is too large to be represented by the accumulator, and an underflow is when it's too small. For unsigned numbers, an overflow is when an addition results in a number larger than 255, and an underflow is when the result of a subtraction is less than 0. For signed numbers, an overflow means an addition with a result larger than 127 and an underflow is a subtraction with a result of less than 128. Kasumi wrote: Because of that I always place the two things the need to be checked most often in those bits when I write data formats.
I often put my flags in the top 2 bits as well. 
Author:  unregistered [ Wed Feb 01, 2012 7:40 pm ] 
Post subject:  
Thank you Kasumi and tokumaru! Kasumi wrote: First disable rendering... by writing the relevant bits to $2000
How do I disable rendering? The 7th bit of $2000 starts or stops an NMI from running at the start of vertical blanking. Does that somehow disable rendering? 
Author:  tokumaru [ Wed Feb 01, 2012 7:49 pm ] 
Post subject:  
unregistered wrote: Kasumi wrote: First disable rendering... by writing the relevant bits to $2000 How do I disable rendering? The 7th bit of $2000 starts or stops an NMI from running at the start of vertical blanking. Does that somehow disable rendering? Kasumi probably meant $2001, where bits 3 and 4 enable or disable background and sprite rendering. To disable rendering you have to clear both bits. Bit 7 of $2000 controls whether NMIs fire or not when VBlank starts, but the rendering process isn't affected at all. 
Author:  unregistered [ Wed Feb 01, 2012 8:05 pm ] 
Post subject:  
tokumaru, thank you so much! 
Author:  unregistered [ Thu Feb 02, 2012 2:26 pm ] 
Post subject:  
tokumaru, from page 27, wrote: Do you want to use different data for each level or something like that? If that's the case, then the answer is the indirect indexed addressing mode (i.e. LDA ($XX), Y). With that addressing mode you use pointers to define the tables that will be read, and you can alter the pointers as much as you want. For example, you could have a different name for each collision table (or whatever table you want), and then make a table with all the addresses: Code: MetatileCollisionAdresses: .dw MetatileCollisionLevel1, MetatileCollisionLevel2, MetatileCollisionLevel3 Then you can read the address for the current level and put it in a pointer using the level's index When you say level's index that could be 1 for level1 and 2 for level2 right? Quote: : Code: lda LevelIndex ;get the level's index asl ;multiply by 2 because each address is 2 bytes tax ;use that as an index into the table of addresses lda MetatileCollisionAdresses+0, x ;copy the low byte sta MetatileCollision+0 lda MetatileCollisionAdresses+1, x ;copy the high byte sta MetatileCollision+1 MetatileCollision isnt set up for an address of 2 bytes... Quote: Then you can use indirect indexed addressing to read the data, instead of what we had before. The only real difference is that now you'll have to use Y as your index register, because this addressing mode doesn't work with X:
Code: ;get collision information lda (MetatileCollision), y I'm attempting to use this, for the first time, it's kind of confusing and kind of something to learn from. Hope it becomes less of the former and more of the latter; it will. 
Page 30 of 95  All times are UTC  7 hours 
Powered by phpBB® Forum Software © phpBB Group http://www.phpbb.com/ 