6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Tue Nov 12, 2024 12:11 am

All times are UTC




Post new topic Reply to topic  [ 14 posts ] 
Author Message
 Post subject: BIT instruction?
PostPosted: Sat Jul 24, 2021 4:59 am 
Offline

Joined: Sat Jun 05, 2021 6:56 am
Posts: 19
So, I've never really been clear on the BIT instruction, as I so seldom encountered this opcode when poking around in assembly language back in my C64 days.

Are there any real-world code examples that would illustrate how this works?

I have at hand some code that could stand a slight rewrite, and I am wondering if a BIT instruction would be useful for that scenario.

Right now, in several places, a number is tested bit by bit, by doing an ASL or LSR followed by a BCC or BCS, based on whether a 0 or 1 is desired, then repeating the process for the next bit until all the bits have been shifted through the carry.

Seeing as the carry bit doesn't translate so well into modern high-level languages, I want to see if there are other usable approaches that don't take up so many bytes in assembly language, but readily translate into newer languages.

Now, I could just use AND to test the individual bits, but that means I have to reload the accumulator each time before testing a given bit, and that just adds to code length.

So, is BIT just a non-destructive AND?

In other words, if I do BIT #$08, and comes back 0, and I want to check for 0, I use BEQ? Then I can follow with a BIT #$04 and continue evaluating that way?


Top
 Profile  
Reply with quote  
 Post subject: Re: BIT instruction?
PostPosted: Sat Jul 24, 2021 5:33 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8482
Location: Midwestern USA
The BIT instruction performs a logical AND between the accumulator and memory, setting or clearing status register flags, but not storing the result of the logical AND.

Code:
          LDA #%01010000
          AND uart_isr
          BEQ is_zero

is logically equivalent to:

Code:
          LDA #%01010000
          BIT uart_isr
          BEQ is_zero

the difference being the second example doesn't modify the accumulator the way the first example does. The branch to is_zero will only be taken if ACCUMULATOR & MEMORY would result in $00.

BIT on the NMOS 6502 has only two addressing modes. On the 65C02 and 65C816, new addressing modes are <zp>,X and <abs>,X, plus immediate mode:

Code:
          LDA uart_isr
          BIT #%01010000
          BEQ is_zero

which may be more convenient at times.

When BIT is used on memory, as in the second example above, bits 6 and 7 of the memory location being tested are copied to the status register's V and N flags, respectively. The Z flag will always reflect the result of the logical AND operation.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
 Post subject: Re: BIT instruction?
PostPosted: Sat Jul 24, 2021 5:40 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10977
Location: England
Meterman58761 wrote:
So, is BIT just a non-destructive AND?

Very very nearly! (The difference being, as BDD notes, that two handy flags are set directly... except when used with an immediate.)


Top
 Profile  
Reply with quote  
 Post subject: Re: BIT instruction?
PostPosted: Sat Jul 24, 2021 5:54 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8539
Location: Southern California
BIT is really nice for testing port bits. If you will need to quickly test an I/O line like for the data line when you're bit-banging a synchronous-serial connection, put it on bit 6 or bit 7 of a parallel port, so you can just do:
Code:
        BIT  PORT_A
        BMI  ____        ; (or BPL or BVC or BVS, as appropriate)

without regard for what's in the accumulator, nor affecting the accumulator.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: BIT instruction?
PostPosted: Sat Jul 24, 2021 6:00 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10977
Location: England
This is, surely, the reason why the peripheral chips we use often present a useful overall status bit in bit 7.


Top
 Profile  
Reply with quote  
 Post subject: Re: BIT instruction?
PostPosted: Sat Jul 24, 2021 2:30 pm 
Offline

Joined: Sat Jun 05, 2021 6:56 am
Posts: 19
Here's a snippet showing what I mean about using the carry bit to evaluate a number and if I understand BIT based on what you guys say:

Code:
Relay status nybble: 0 = contacts closed, 1 = contacts open

Existing code:

LB_ECC0   LDA A   $C3      //   fetch status nybble
      LSR A            //   shift Relay A bit into carry
      BCS      LB_ECCA   //   contact opened like it was supposed to
      JMP      LB_EE31   //   jump to test fail: Relay A
LB_ECCA   LDA B   #$07   //   Write pass value to Relay A register
      STA B   $0CEA
      LSR A         //   shift Relay B bit into carry
      BCS      LB_ECD5      //   contact opened like it was supposed to
      JMP      LB_EE67   //   jump to test fail: Relay B
LB_ECD5   LDA B   #$07   //   Write pass value to Relay B register
      STA B   $0CEB
      LSR A         //   shift Relay C bit into carry
      BCS      LB_ECE0      //   contact opened like it was supposed to
      JMP      LB_EE6F   //   jump to test fail: Relay C
LB_ECE0   LDA B   #$07   //   Write pass value to Relay C register
      STA B   $0CEC
      LSR A         //   shift Relay D bit into carry
      BCS      LB_ECEB      //   contact opened like it was supposed to
      JMP      LB_EE77   //   jump to test fail: Relay D
LB_ECEB   LDA B   #$07   //   Write pass value to Relay D register
      STA B   $0CED


If I understand BIT:

LB_ECC0   LDA A   $C3      //   fetch status nybble
      BIT A   #$01      //   Test bit 0 - Relay A
      BNE      LB_ECCA   //   contact opened like it was supposed to
      JMP      LB_EE31   //   jump to test fail: Relay A
LB_ECCA   LDA B   #$07   //   Write pass value to Relay A register
      STA B   $0CEA
      BIT A   #$02   //   Test bit 1 - Relay B
      BNE      LB_ECD5      //   contact opened like it was supposed to
      JMP      LB_EE67   //   jump to test fail: Relay B
LB_ECD5   LDA B   #$07   //   Write pass value to Relay B register
      STA B   $0CEB
      BIT A   #$04   //   Test bit 2 - Relay C
      BNE      LB_ECE0      //   contact opened like it was supposed to
      JMP      LB_EE6F   //   jump to test fail: Relay C
LB_ECE0   LDA B   #$07   //   Write pass value to Relay C register
      STA B   $0CEC
      BIT A   #$08   //   Test bit 3 - Relay D
      BNE      LB_ECEB      //   contact opened like it was supposed to
      JMP      LB_EE77   //   jump to test fail: Relay D
LB_ECEB   LDA B   #$07   //   Write pass value to Relay D register
      STA B   $0CED


Top
 Profile  
Reply with quote  
 Post subject: Re: BIT instruction?
PostPosted: Sat Jul 24, 2021 2:48 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10977
Location: England
Umm, do you have two accumulators? Is this 6800, or 6809 family, perhaps, rather than 6502? I'm not very familiar but it's possible those micros have different behaviour.

On the 6502, if you needed to update some other address without disturbing A, you would typically use X or Y, which are both single-byte registers.


Top
 Profile  
Reply with quote  
 Post subject: Re: BIT instruction?
PostPosted: Sat Jul 24, 2021 3:15 pm 
Offline

Joined: Sat Jun 05, 2021 6:56 am
Posts: 19
Currently working in 6801 assembly, yes, so if / when this gets translated over to 6502, the B accumulator in this example would end up being substituted with the Y index.


Top
 Profile  
Reply with quote  
 Post subject: Re: BIT instruction?
PostPosted: Sat Jul 24, 2021 3:31 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10977
Location: England
I think you have the right idea, anyway.

There's a choice, whether to load a mask into A and BIT against a location, or load A from the location and then BIT against a constant. Sometimes it will be right to read the location just once.

If you have just 2 bits of interest and they are at the top of the byte, BIT makes more sense, I think. If your bits of interest are at the bottom of the byte, shifting and checking C makes good sense. It's not the case that BIT is always the best choice, but sometimes it is. So it's worth understanding it so you can use it as appropriate.

Sometimes a mix of tactics will be best, for example if bits 7 6 and 0 are in use.


Top
 Profile  
Reply with quote  
 Post subject: Re: BIT instruction?
PostPosted: Sat Jul 24, 2021 4:01 pm 
Offline
User avatar

Joined: Sun Nov 01, 2020 10:36 am
Posts: 37
Location: Tatooine
If you want to check all the bits of a location, one by one, you could do something like:
Code:
LDA #$01
BIT mem
BNE bit0set
ASL
BIT mem
BNE bit1set
ASL
BIT mem
BNE bit2set
...

I think that maybe you're describing a byte of flags (where each bit is a flag). You may prefer to use a whole byte as a flag and just focus on the bit 7 of the byte and check it with the BIT instruction and the BPL/BMI branches.
Code:
true = $FF
false = $00

LDA #false
;LDA #true
STA memflag
[...]
BIT memflag
BPL flagisfalse

Similarly another useful opportunity is to check if a signed number in memory is positive or negative, without compromising the accumulator:
Code:
BIT num
BMI isneg


Top
 Profile  
Reply with quote  
 Post subject: Re: BIT instruction?
PostPosted: Sat Jul 24, 2021 5:44 pm 
Offline

Joined: Sat Jun 05, 2021 6:56 am
Posts: 19
This successive bit-shifting is done in several places in the code.

The most common use is to interpret the relay status nybble to determine whether the four relays opened or closed as directed, and to set the pass / fail conditions as appropriate.

It is also used within the main loop; at various points in the code, a 'configuration byte' is set and program flow is then directed back to the main loop as a 'do this step now but not that' (this section uses ASL and BCC to run through bits 7-3, 1, and 0; when the carry bit is 0, the program drops down to the next bit to be evaluated).

My goal is to end up with something that works in assembly, whether 6801 or 6502, yet intuitively translates to higher level languages (i.e. C++).

This code was riddled with shortcuts and odd programming quirks and I've pried out as many as I could find.
Perhaps I should post the initial configuration check code just to show you what I'm working with...


Top
 Profile  
Reply with quote  
 Post subject: Re: BIT instruction?
PostPosted: Sat Jul 24, 2021 8:41 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8539
Location: Southern California
I probably wouldn't use BIT here. Instead, I might do something like:
Code:
        LDY  #7

        LDA  $C3              ; fetch status nybble
        LSR                   ; shift Relay A bit into carry
        BCC  REL_A_TEST_FAIL  ; branch to test fail: Relay A

        STY  $0CEA            ; Write pass value to Relay A register
        LSR                   ; shift Relay B bit into carry
        BCC  REL_B_TEST_FAIL  ; Branch to test fail: Relay B

        STY  $0CEB            ; Write pass value to Relay B register
        LSR                   ; shift Relay C bit into carry
        BCC  REL_C_TEST_FAIL  ; Branch to test fail: Relay C

        STY  $0CEC            ; Write pass value to Relay C register
        LSR                   ; shift Relay D bit into carry
        BCC  REL_D_TEST_FAIL  ; jump to test fail: Relay D

        STY  $0CED            ; Write pass value to Relay D register

using the BCC instead of BCS around a JMP, and put them all within branch range. It looks like the various places to jump to are all short enough to put them together within branch range.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: BIT instruction?
PostPosted: Sun Jul 25, 2021 4:44 am 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 410
Location: Minnesota
BIT is quite handy for waiting until a status line goes to a desired state:

Code:

      lda #$10    ; status bit is bit #4 in this example
@1    bit ioport
      beq @1       ; wait until set (or bne if waiting until clear)



You might see something like this in bit-banged serial i/o, for instance.


Top
 Profile  
Reply with quote  
 Post subject: Re: BIT instruction?
PostPosted: Thu Jul 29, 2021 6:16 am 
Offline

Joined: Sat Jun 05, 2021 6:56 am
Posts: 19
As for using BIT to wait for one line to change state, that's actually not a bad idea. Will have to see if that would work better than the existing approach.

Anyway, coming back to the original part of my post, for the post-test relay check routine I did end up using BIT rather than LSR paired with BCC / BCS, as the routine which it replaced was several layers deep and a mass of shifts, carries, branches, and even jumps that was scattered out into several sections. 500+ bytes (in 5-6 places) replaced by a ~100-byte subroutine and two JSRs.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 14 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 12 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron