shazz Posted August 21, 2013 Share Posted August 21, 2013 Hi again, Can somebody explain me the BIT instruction... In some pieces of code I read : - NOP, BIT $ea - BIT GRP0 I read that you can do : .BYTE $2C LDX #$20 => $2C $A2 $20 so it is equals to a BIT $20A2... yes I agree... an so ???? As A is not defined, what is the goal to do ??? AND ($20A2) ? It looks like BIT can be used to do something else than A AND (MEM) => Z/V/N but I don't get it.... I feel stupid... Quote Link to comment Share on other sites More sharing options...
danwinslow Posted August 21, 2013 Share Posted August 21, 2013 I read the same thing you did, and my impression was that it had to do with JUST setting the flags without actually doing anything else. Could be wrong there, I'm no 6502 expert. Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted August 21, 2013 Share Posted August 21, 2013 I don't know why somebody would use BIT GRP0 - it's probably related to mirrored memory as reading GRP0 is the same as reading INPT3 (the 4th paddle). What you'll normally see BIT used for in Atari programs is for testing the collision registers, firebuttons and paddle ports (see page 46). When you BIT something, the value in bit 7 is moved into the N flag (they call it S in that documentation - it's the Negative flag, or Sign) and the value in bit 6 is moved into the V flag. So this code would check for collisions between the players and the missiles: bit CXM0P ; bit 7 = Missile 0 & Player 1, bit 6 = Missile 0 & Player 0 bpl .skip1 jsr ProcessMissile0Player1Collision .skip1 bvc .skip2 jsr ProcessMissile0Player0Collision .skip2 bit CXM1P ; bit 7 = Missile 1 & Player 0, bit 6 = Missile 1 and Player 1 bpl .skip3 jsr ProcessMissile1Player0Collision .skip3 bvc .skip4 jsr ProcessMissile1Player1Collision .skip4 ... ProcessMissile0Player1Collision and ProcessMissile1Player0Collision need to preserve the state of V. They can do so by using PHP at the start, then PLP at the end, or by not doing anything that changes V. Another solution would be to just do another BIT test after .skip1 and .skip3. This code would check if the players hit FIRE bit INPT4 ; bit 7 on = fire not pressed, bit 7 off = fire pressed bmi .skip5 jsr ProcessLeftFireButton .skip5 bit INPT5 ; bit 7 on = fire not pressed, bit 7 off = fire pressed bmi .skip6 jsr ProcessRightFireButton .skip6 ... Quote Link to comment Share on other sites More sharing options...
Mr SQL Posted August 21, 2013 Share Posted August 21, 2013 Regarding the AND function the difference is that it drops the result in the bit bucket behind the CPU rather than updating the accumulator with the ANDed value. It might make it easier to follow that the V and N flags happen to be bits 6 and 7 of the condition code register; consider these bits aren't being used to represent overflow or negative conditions in this instance though, they are just copied over from whatever you BIT into Quote Link to comment Share on other sites More sharing options...
RevEng Posted August 21, 2013 Share Posted August 21, 2013 The $2c trick is used to skip the next 2 bytes by turning them into a harmless bit instruction. Its usually used with a proceeding branch to the LDX. The magic is, following the branch and not following the branch will take the same number of cycles. Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted August 22, 2013 Share Posted August 22, 2013 I don't know why somebody would use BIT GRP0 - it's probably related to mirrored memory as reading GRP0 is the same as reading INPT3 (the 4th paddle). Since BIT is a type of read instruction (loads from memory rather than stores to memory), and GRP0 is a write-only address, I'd say any code that contains "BIT GRP0" was either "poorly" written using the "wrong" label for the intended address, or it was disassembled "wrong" using a write-only address where it should have used a read-only address. I remember another thread-- I think it was actually in the stella mailing list-- in which someone asked about a section of code where a game was reading (loading) the TIM1T register (IIRC), which would actually have the same effect as reading INTIM, since TIM1T is $294 and INTIM is $284, but because of the way mirroring works within the RIOT addresses, $294 is a mirror of $284 (IIRC) when performing a read instruction. So in that case either the "LDA TIM1T" code was a lucky programming mistake that happened to work, or the programmer had defined INTIM as $294 and the disassembler was interpreting it as TIM1T. Note, it may have been TIM8T ($295) and TIMINT ($285), but the explanation is still the same-- mirroring within the RIOT, coupled with the state of the R/W line. Sorry for the digression from the BIT instruction, but unless someone's looking at the original source code, my guess is that it's most likely a disassembly boo-boo. Mirroring, coupled with read-only and write-only addresses, can complicate disassembly a bit. Quote Link to comment Share on other sites More sharing options...
Omegamatrix Posted August 22, 2013 Share Posted August 22, 2013 BIT is often used to save a byte in a case where there is an always branch to an address 1 or 2 bytes ahead. Inside of a kernel BIT is often used in time critical areas to help even out cycles so not matter what path the program follows, the cycles are the same. Illegal NOP's are used by a lot of 2600 programmers instead of BIT, since all flags are preserved. skip 1 byte with: BIT zeropage = $24 NOP zeropage = $04 ; <--- this is used by the SLEEP marco in macros.h skip 2 bytes with: BIT absolute = $2C NOP absolute = $0C Illegal nops and BIT's are also good for bankswitching purposes. Quote Link to comment Share on other sites More sharing options...
Omegamatrix Posted August 22, 2013 Share Posted August 22, 2013 I remember another thread-- I think it was actually in the stella mailing list-- in which someone asked about a section of code where a game was reading (loading) the TIM1T register (IIRC), which would actually have the same effect as reading INTIM, since TIM1T is $294 and INTIM is $284, but because of the way mirroring works within the RIOT addresses, $294 is a mirror of $284 (IIRC) when performing a read instruction. So in that case either the "LDA TIM1T" code was a lucky programming mistake that happened to work, or the programmer had defined INTIM as $294 and the disassembler was interpreting it as TIM1T. Note, it may have been TIM8T ($295) and TIMINT ($285), but the explanation is still the same-- mirroring within the RIOT, coupled with the state of the R/W line. If you are going to go a BIT off-topic, then I will too. The $2xx registers (TIM64T, INTIM, etc...) can be jumped between operator and operand in some cases for new instructions: Operands: SWCHA ===> nop #$02 ; waste 2 cycles SWCHB ===> nop #$02 ; waste 2 cycles SWBCNT ===> sax (WSYNC,X) INTIM ===> sty WSYNC TIMINT ===> sta WSYNC TIM1T ===> sty WSYNC,X TIM8T ===> sta WSYNC,X TIM64T ===> stx WSYNC,Y T1024T ===> sax WSYNC,Y Very limited use, but interesting. One more interesting thing is using INTIM as an address. How it works is you INTIM will always have a value $00-$FF, while the register read for the high address (TIMINT) will always point to zeropage or one of its mirrors. So conceivably you can set the timer to decrement with one of the timers, and jump into a zero page location. It would be fun to run some self modifying code in zero page that kept using INTIM to loop itself both as an address and counter. This is something I wanted to try at one point, just for this: jmp.ind (INTIM) There is just something damn cool about jumping in time. Kinda like Quantum Leap. 1 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.