Why does the 6502 have the BIT instruction?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{
margin-bottom:0;
}
The 6502 has a bit
instruction which
- copies two of the bits into the
N
andV
flags, - pretends to
and
the byte with the accumulator, but discards the result and only affectsZ
.
I'm having a hard time picturing a use for this. And curiously, it's missing any indexed or indirect addressing modes, and so can only be used absolutely or in the zero page.
(Incidentally, it's convenient also for skipping two bytes in the instruction stream in cases where you don't care what happens to the flags, but I don't imagine that's the use MOS had in mind). What kinds of things was it meant for?
6502 instruction-set
|
show 2 more comments
The 6502 has a bit
instruction which
- copies two of the bits into the
N
andV
flags, - pretends to
and
the byte with the accumulator, but discards the result and only affectsZ
.
I'm having a hard time picturing a use for this. And curiously, it's missing any indexed or indirect addressing modes, and so can only be used absolutely or in the zero page.
(Incidentally, it's convenient also for skipping two bytes in the instruction stream in cases where you don't care what happens to the flags, but I don't imagine that's the use MOS had in mind). What kinds of things was it meant for?
6502 instruction-set
The nature of this question is similar to that of Why does the Z80 include the RLD and RRD instructions?
– Wilson
May 25 at 16:00
1
Looking at the ProDOS 8 source code,BIT
is used to check for a flag in bits 6 or 7, check if a number in memory is negative (again, bit 7), to read i/o memory (without destroying registers). It's also used twice as a clever hack to set theV
flag (since there's aCLV
instruction but noSEV
instruction), and once used to hide other instructions.
– Kelvin Sherlock
May 25 at 17:16
4
You are mistaken, the AND affects the Z flag, not the C flag.
– Janka
May 25 at 18:28
1
@fadden Is it an undocumented instruction? What is the opcode?
– berendi
May 27 at 15:26
2
@berendiBIT imm
is not a 6502 but a 65C02 instruction.Opcode is $89.
– Raffzahn
May 27 at 17:17
|
show 2 more comments
The 6502 has a bit
instruction which
- copies two of the bits into the
N
andV
flags, - pretends to
and
the byte with the accumulator, but discards the result and only affectsZ
.
I'm having a hard time picturing a use for this. And curiously, it's missing any indexed or indirect addressing modes, and so can only be used absolutely or in the zero page.
(Incidentally, it's convenient also for skipping two bytes in the instruction stream in cases where you don't care what happens to the flags, but I don't imagine that's the use MOS had in mind). What kinds of things was it meant for?
6502 instruction-set
The 6502 has a bit
instruction which
- copies two of the bits into the
N
andV
flags, - pretends to
and
the byte with the accumulator, but discards the result and only affectsZ
.
I'm having a hard time picturing a use for this. And curiously, it's missing any indexed or indirect addressing modes, and so can only be used absolutely or in the zero page.
(Incidentally, it's convenient also for skipping two bytes in the instruction stream in cases where you don't care what happens to the flags, but I don't imagine that's the use MOS had in mind). What kinds of things was it meant for?
6502 instruction-set
6502 instruction-set
edited May 26 at 20:40
fadden
3,6291 gold badge15 silver badges52 bronze badges
3,6291 gold badge15 silver badges52 bronze badges
asked May 25 at 15:59
WilsonWilson
14.7k7 gold badges68 silver badges161 bronze badges
14.7k7 gold badges68 silver badges161 bronze badges
The nature of this question is similar to that of Why does the Z80 include the RLD and RRD instructions?
– Wilson
May 25 at 16:00
1
Looking at the ProDOS 8 source code,BIT
is used to check for a flag in bits 6 or 7, check if a number in memory is negative (again, bit 7), to read i/o memory (without destroying registers). It's also used twice as a clever hack to set theV
flag (since there's aCLV
instruction but noSEV
instruction), and once used to hide other instructions.
– Kelvin Sherlock
May 25 at 17:16
4
You are mistaken, the AND affects the Z flag, not the C flag.
– Janka
May 25 at 18:28
1
@fadden Is it an undocumented instruction? What is the opcode?
– berendi
May 27 at 15:26
2
@berendiBIT imm
is not a 6502 but a 65C02 instruction.Opcode is $89.
– Raffzahn
May 27 at 17:17
|
show 2 more comments
The nature of this question is similar to that of Why does the Z80 include the RLD and RRD instructions?
– Wilson
May 25 at 16:00
1
Looking at the ProDOS 8 source code,BIT
is used to check for a flag in bits 6 or 7, check if a number in memory is negative (again, bit 7), to read i/o memory (without destroying registers). It's also used twice as a clever hack to set theV
flag (since there's aCLV
instruction but noSEV
instruction), and once used to hide other instructions.
– Kelvin Sherlock
May 25 at 17:16
4
You are mistaken, the AND affects the Z flag, not the C flag.
– Janka
May 25 at 18:28
1
@fadden Is it an undocumented instruction? What is the opcode?
– berendi
May 27 at 15:26
2
@berendiBIT imm
is not a 6502 but a 65C02 instruction.Opcode is $89.
– Raffzahn
May 27 at 17:17
The nature of this question is similar to that of Why does the Z80 include the RLD and RRD instructions?
– Wilson
May 25 at 16:00
The nature of this question is similar to that of Why does the Z80 include the RLD and RRD instructions?
– Wilson
May 25 at 16:00
1
1
Looking at the ProDOS 8 source code,
BIT
is used to check for a flag in bits 6 or 7, check if a number in memory is negative (again, bit 7), to read i/o memory (without destroying registers). It's also used twice as a clever hack to set the V
flag (since there's a CLV
instruction but no SEV
instruction), and once used to hide other instructions.– Kelvin Sherlock
May 25 at 17:16
Looking at the ProDOS 8 source code,
BIT
is used to check for a flag in bits 6 or 7, check if a number in memory is negative (again, bit 7), to read i/o memory (without destroying registers). It's also used twice as a clever hack to set the V
flag (since there's a CLV
instruction but no SEV
instruction), and once used to hide other instructions.– Kelvin Sherlock
May 25 at 17:16
4
4
You are mistaken, the AND affects the Z flag, not the C flag.
– Janka
May 25 at 18:28
You are mistaken, the AND affects the Z flag, not the C flag.
– Janka
May 25 at 18:28
1
1
@fadden Is it an undocumented instruction? What is the opcode?
– berendi
May 27 at 15:26
@fadden Is it an undocumented instruction? What is the opcode?
– berendi
May 27 at 15:26
2
2
@berendi
BIT imm
is not a 6502 but a 65C02 instruction.Opcode is $89.– Raffzahn
May 27 at 17:17
@berendi
BIT imm
is not a 6502 but a 65C02 instruction.Opcode is $89.– Raffzahn
May 27 at 17:17
|
show 2 more comments
5 Answers
5
active
oldest
votes
Early MOS documentation (KIM-1 Programming Manual, Synertek SY6500/MCS6500 Microcomputer Programming manual, etc) states:
The
BIT
instruction actually combines two instructions from
thePDP-11
andMC6800
, that ofTST
(Test Memory) and (BIT Test).
...
In addition to the nondestructive feature of the
BIT
which
allows us to isolate an individual bit by use of the branch equal or
branch no equal test, two modifications to thePDP-11
version of that
instruction have been made in theMCS650X
microprocessor. These are
to allow a test of bit 7 and bit 6 of the field examined with theBIT
test. This feature is particularly useful in serving polled interrupts
and particularly in dealing with theMCS6520
(Peripheral Interface
Device). This device has an interrupt sense bit in bit 6 and bit 7
of the status words. It is a standard of theM6800
bus that whenever
possible, bit 7 reflects the interrupt status of an I/O device. This
means that under normal circumstances, an analysis of theN
flag
after a load orBIT
instruction should indicate the status of the
bit 7 on the I/O device being sampled. To facilitate this test using
theBIT
instruction, bit 7 from the memory being tested is set
into theN
flag irrespective of the value in the accumulator.
This is different from the bit instruction in theM6800
which
requires that bit 7 also be set on the accumulator to setN
. The
advantage to the user is that if he decides to test bit 7 in the
memory, it is done directly by sampling theN
bit with aBIT
followed by branch minus or branch plus instruction. This means that
I/O sampling can be accomplished at any time during the operation
of instructions irrespective of the value preloaded in the accumulator.
Another feature of the
BIT
test is the setting of bit 6 into
theV
flag. As indicated previously, theV
flag is normally reserved
for overflow into the sign position during an add and subtract instruction.
In other words, theV
flag is not disturbed by normal
instructions. When theBIT
instruction is used, it is assumed that
the user is trying to examine the memory that he is testing with the
BIT
instruction. In order to receive maximum value from aBIT
instruction, bit 6 from the memory being tested is set into theV
flag.
In the case of a normal memory operation, this just means that the
user should organize his memory such that both of his flags to be
tested are in either bit 6 or bit 7, in which case an appropriate
mask does not have to be loaded into the accumulator prior to
implementing theBIT
instruction. In the case of theMCS6520
, theBIT
instruction can be used for sampling interrupt, irrespective of the
mask. This allows the programmer to totally interrogate both bit 6 and
bit 7 of theMCS6520
without disturbing the accumulator. In the case
of the concurrent interrupts, i.e., bit 6 and bit 7 both on, the fact
that theV
flag is automatically set by theBIT
instruction allows
the user to postpone testing for the "6th bit on" until after he has
totally handled the interrupt "for bit 7 on" unless he performs an
arithmetic operation subsequent to theBIT
operation.
add a comment
|
I'm having a hard time picturing a use for this [BIT]
It's mainly an I/O issue.
The 6502 is in many ways designed especially for control/embedded applications and BIT
is a part of this. 6500 specific IO-devices are designed to report any service conditions on bit 7 (and 6). For example the 6522 will set bit 7 of the Interrupt Flag Register when an interrupt condition has been reported. So a 6522 can be polled in a system without interrupts without eating up many instructions. Even an active wait in polling would be just two instructions. As long as it's about bit 6 and 7 BIT
operates non destructive - unlike a sequence of LDA
/AND
- so no registers need to be saved, only flags changed, enabling the insertion of frequent checks.
Same reason why the Apple II's keyboard port puts the key-pressed flag into bit 7. so a quick BIT
can be used to check if a key has been pressed. And only the flags are affected.
As a side-effect BIT
is versatile for fast test of flags/semaphores. Bit 6/7 of a flag byte can be tested right away. Likewise (counting) semaphores/locks. In addition bit can be used to test for a numbers sign, again without touching anything but the flags.
And curiously, it's missing any indexed or indirect addressing modes, and so can only be used absolutely or in the zero page.
Not a concern for I/O, as these addresses are usually in fixed locations, especially when thinking embedded systems.
Bottom Line: BIT
is an instruction meant to speed up I/O handling.
The design side reasoning is to have an instruction to enable branching on as many bits as possible with minimal impact. Of the four testable bits (N
/V
/Z
/C
) one, carry, is as well usable as user flag (SEC
/CLC
), so keeping that function leaves 3. Using the AND function already implemented sets N
and Z
, so BIT
just needs to suppress copying the result of AND
back to A and copying Bit 6 into V
.
Sounds like minimal effort to add a quite handy instruction.
add a comment
|
A good example would be reading from the floppy drive on the C64. The incoming clock and data signals of the serial bus are (perhaps not accidentally) wired to bits 6 and 7 of port A on CIA#2, appearing at $DD00
.
BIT $DD00
samples both inputs and stores them in the N
and V
flags. Jumping back conditionally with
BVC $-3
waits while the clock is low, as data must be sampled on the rising clock edge. When it falls through the BVC
, the N
flag contains the data bit. It can be transferred to the C
flag this way
BMI $+4
CLC
BIT $38
just to showcase the secondary use of the BIT
instruction, skipping the SEC
(opcode $38
), where BMI
is jumping to.
Now the data bit is in the carry flag, without altering any of the three data registers. It can be shifted into the accumulator, which would hold the data byte being assembled. Meanwhile X
can count the number of bits received, and Y
can serve as offset when storing the received data with STA (zp),Y
That BMI, CLC, BIT$38 snippet is indeed a part of many I/O routines.
– Janka
May 26 at 0:02
Sampling both inputs at a time can be handy. An even cuter exploitation of BIT can be found on the Atari 2600's video chip. It has 15 sprite-collision input flags and 6 controller input flags, but rather than e.g. using two 8-bit registers for the sprite flags and one for the inputs, it puts the collision flags on bits 6-7 of eight addresses, and the controller inputs on bit 7 of six more. What makes this especially cute is that the chip only includes drive circuitry for the top two bits of the data bus; since code won't care what's on the bottom six bits, there's no need to drive them.
– supercat
May 28 at 15:06
add a comment
|
Simply it gives the developer the ability to set status flags without actually moving any memory or destroying any registers. With a register starved system like the 6502, and the fact that (pretty much) all data movement is through the registers, there can certainly be use cases where this capability can come in handy.
add a comment
|
I spent a lot of time in the 80s going through 6502 ROMs for home computers. I can honestly tell you what the BIT instruction is used for most of the time in practice.
Mostly it's not used for any calculation of interest. It's used as a filler instruction to allow multiple entry points to a routine, each with different common parameter values. I don't think I ever saw it used for the intended purpose. (Maybe once or twice.)
So for example if you had a routine which prints an ASCII character, you might commonly want to print space, or carriage return or things like '?' on the Commodore machines etc. and to save space in the ROM they just used the BIT instruction to isolate LDA instructions, or other loads. For example:
label_print_CR:
LDA #$0D - carriage return
.byte $2C (BIT instruction op code)
label_print_space:
LDA #$20 - space
.byte $2C
label_print_question_mark:
LDA #$3F - '?'
label_print_character:
main code to print character in A
That would assemble to be:
A9 0D 2C A9 20 2C A9 3F etc..
If you disassemble it you get:
LDA #$0D
BIT $20A9
BIT $3FA9
etc
so the BIT is doing nothing, but it's giving you these cunning specific extra entry points to the routine for printing.
Here's the entry points for the Commodore PET V4.0 BASIC (I don't have the code unfortunately.)
bb1d strout Output String
bb3a outspc Output Format Character
bb41 -Print '<cursor right>'
bb44 -Print '?'
bb46 - Output Character in A
You can clearly see the entry points are just 2-3 bytes apart for 41, 44, 46 so there's no way they're using branches or jumps to load and jump into the general routine.
This application of the BIT instruction is just totally ubiquitous across 6502 machines of that era. I used it in my own code all the time. As you can tell from the disassembly it can be rather confusing as to what they're doing.
This is from the 1976 Microsoft 6502 BASIC listing which you can check out here https://www.pagetable.com/docs/M6502.MAC.txt
DEFINE SKIP1, <XWD ^O1000,^O044> ;BIT ZERO PAGE TRICK.
DEFINE SKIP2, <XWD ^O1000,^O054> ;BIT ABS TRICK.
Note these values are in octal so that's $24 and $2c for the two byte and three byte BIT instructions.
Here's an example:
PARCHK: JSR CHKOPN ;ONLY POSSIBILITY LEFT IS
JSR FRMEVL ;A FORMULA IN PARENTHESIS.
;RECURSIVELY EVALUATE THE FORMULA.
CHKCLS: LDAI 41 ;CHECK FOR A RIGHT PARENTHESE
SKIP2
CHKOPN: LDAI 40
SKIP2
CHKCOM: LDAI 44
;
; "SYNCHK" LOOKS AT THE CURRENT CHARACTER TO MAKE SURE IT
; IS THE SPECIFIC THING LOADED INTO ACCA JUST BEFORE THE CALL TO
; "SYNCHK". IF NOT, IT CALLS THE "SYNTAX ERROR" ROUTINE.
; OTHERWISE IT GOBBLES THE NEXT CHAR AND RETURNS,
;
; [A]=NEW CHAR AND TXTPTR IS ADVANCED BY "CHRGET".
;
SYNCHR: LDYI 0
CMPDY TXTPTR ;CHARACTERS EQUAL?
BNE SNERR
CHRGO5: JMP CHRGET
1
From the OP: "(Incidentally, it's convenient also for skipping two bytes in the instruction stream in cases where you don't care what happens to the flags, but I don't imagine that's the use MOS had in mind). What kinds of things was it meant for?)"
– Wilson
May 28 at 10:50
add a comment
|
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "648"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
noCode: true, onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fretrocomputing.stackexchange.com%2fquestions%2f11108%2fwhy-does-the-6502-have-the-bit-instruction%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
Early MOS documentation (KIM-1 Programming Manual, Synertek SY6500/MCS6500 Microcomputer Programming manual, etc) states:
The
BIT
instruction actually combines two instructions from
thePDP-11
andMC6800
, that ofTST
(Test Memory) and (BIT Test).
...
In addition to the nondestructive feature of the
BIT
which
allows us to isolate an individual bit by use of the branch equal or
branch no equal test, two modifications to thePDP-11
version of that
instruction have been made in theMCS650X
microprocessor. These are
to allow a test of bit 7 and bit 6 of the field examined with theBIT
test. This feature is particularly useful in serving polled interrupts
and particularly in dealing with theMCS6520
(Peripheral Interface
Device). This device has an interrupt sense bit in bit 6 and bit 7
of the status words. It is a standard of theM6800
bus that whenever
possible, bit 7 reflects the interrupt status of an I/O device. This
means that under normal circumstances, an analysis of theN
flag
after a load orBIT
instruction should indicate the status of the
bit 7 on the I/O device being sampled. To facilitate this test using
theBIT
instruction, bit 7 from the memory being tested is set
into theN
flag irrespective of the value in the accumulator.
This is different from the bit instruction in theM6800
which
requires that bit 7 also be set on the accumulator to setN
. The
advantage to the user is that if he decides to test bit 7 in the
memory, it is done directly by sampling theN
bit with aBIT
followed by branch minus or branch plus instruction. This means that
I/O sampling can be accomplished at any time during the operation
of instructions irrespective of the value preloaded in the accumulator.
Another feature of the
BIT
test is the setting of bit 6 into
theV
flag. As indicated previously, theV
flag is normally reserved
for overflow into the sign position during an add and subtract instruction.
In other words, theV
flag is not disturbed by normal
instructions. When theBIT
instruction is used, it is assumed that
the user is trying to examine the memory that he is testing with the
BIT
instruction. In order to receive maximum value from aBIT
instruction, bit 6 from the memory being tested is set into theV
flag.
In the case of a normal memory operation, this just means that the
user should organize his memory such that both of his flags to be
tested are in either bit 6 or bit 7, in which case an appropriate
mask does not have to be loaded into the accumulator prior to
implementing theBIT
instruction. In the case of theMCS6520
, theBIT
instruction can be used for sampling interrupt, irrespective of the
mask. This allows the programmer to totally interrogate both bit 6 and
bit 7 of theMCS6520
without disturbing the accumulator. In the case
of the concurrent interrupts, i.e., bit 6 and bit 7 both on, the fact
that theV
flag is automatically set by theBIT
instruction allows
the user to postpone testing for the "6th bit on" until after he has
totally handled the interrupt "for bit 7 on" unless he performs an
arithmetic operation subsequent to theBIT
operation.
add a comment
|
Early MOS documentation (KIM-1 Programming Manual, Synertek SY6500/MCS6500 Microcomputer Programming manual, etc) states:
The
BIT
instruction actually combines two instructions from
thePDP-11
andMC6800
, that ofTST
(Test Memory) and (BIT Test).
...
In addition to the nondestructive feature of the
BIT
which
allows us to isolate an individual bit by use of the branch equal or
branch no equal test, two modifications to thePDP-11
version of that
instruction have been made in theMCS650X
microprocessor. These are
to allow a test of bit 7 and bit 6 of the field examined with theBIT
test. This feature is particularly useful in serving polled interrupts
and particularly in dealing with theMCS6520
(Peripheral Interface
Device). This device has an interrupt sense bit in bit 6 and bit 7
of the status words. It is a standard of theM6800
bus that whenever
possible, bit 7 reflects the interrupt status of an I/O device. This
means that under normal circumstances, an analysis of theN
flag
after a load orBIT
instruction should indicate the status of the
bit 7 on the I/O device being sampled. To facilitate this test using
theBIT
instruction, bit 7 from the memory being tested is set
into theN
flag irrespective of the value in the accumulator.
This is different from the bit instruction in theM6800
which
requires that bit 7 also be set on the accumulator to setN
. The
advantage to the user is that if he decides to test bit 7 in the
memory, it is done directly by sampling theN
bit with aBIT
followed by branch minus or branch plus instruction. This means that
I/O sampling can be accomplished at any time during the operation
of instructions irrespective of the value preloaded in the accumulator.
Another feature of the
BIT
test is the setting of bit 6 into
theV
flag. As indicated previously, theV
flag is normally reserved
for overflow into the sign position during an add and subtract instruction.
In other words, theV
flag is not disturbed by normal
instructions. When theBIT
instruction is used, it is assumed that
the user is trying to examine the memory that he is testing with the
BIT
instruction. In order to receive maximum value from aBIT
instruction, bit 6 from the memory being tested is set into theV
flag.
In the case of a normal memory operation, this just means that the
user should organize his memory such that both of his flags to be
tested are in either bit 6 or bit 7, in which case an appropriate
mask does not have to be loaded into the accumulator prior to
implementing theBIT
instruction. In the case of theMCS6520
, theBIT
instruction can be used for sampling interrupt, irrespective of the
mask. This allows the programmer to totally interrogate both bit 6 and
bit 7 of theMCS6520
without disturbing the accumulator. In the case
of the concurrent interrupts, i.e., bit 6 and bit 7 both on, the fact
that theV
flag is automatically set by theBIT
instruction allows
the user to postpone testing for the "6th bit on" until after he has
totally handled the interrupt "for bit 7 on" unless he performs an
arithmetic operation subsequent to theBIT
operation.
add a comment
|
Early MOS documentation (KIM-1 Programming Manual, Synertek SY6500/MCS6500 Microcomputer Programming manual, etc) states:
The
BIT
instruction actually combines two instructions from
thePDP-11
andMC6800
, that ofTST
(Test Memory) and (BIT Test).
...
In addition to the nondestructive feature of the
BIT
which
allows us to isolate an individual bit by use of the branch equal or
branch no equal test, two modifications to thePDP-11
version of that
instruction have been made in theMCS650X
microprocessor. These are
to allow a test of bit 7 and bit 6 of the field examined with theBIT
test. This feature is particularly useful in serving polled interrupts
and particularly in dealing with theMCS6520
(Peripheral Interface
Device). This device has an interrupt sense bit in bit 6 and bit 7
of the status words. It is a standard of theM6800
bus that whenever
possible, bit 7 reflects the interrupt status of an I/O device. This
means that under normal circumstances, an analysis of theN
flag
after a load orBIT
instruction should indicate the status of the
bit 7 on the I/O device being sampled. To facilitate this test using
theBIT
instruction, bit 7 from the memory being tested is set
into theN
flag irrespective of the value in the accumulator.
This is different from the bit instruction in theM6800
which
requires that bit 7 also be set on the accumulator to setN
. The
advantage to the user is that if he decides to test bit 7 in the
memory, it is done directly by sampling theN
bit with aBIT
followed by branch minus or branch plus instruction. This means that
I/O sampling can be accomplished at any time during the operation
of instructions irrespective of the value preloaded in the accumulator.
Another feature of the
BIT
test is the setting of bit 6 into
theV
flag. As indicated previously, theV
flag is normally reserved
for overflow into the sign position during an add and subtract instruction.
In other words, theV
flag is not disturbed by normal
instructions. When theBIT
instruction is used, it is assumed that
the user is trying to examine the memory that he is testing with the
BIT
instruction. In order to receive maximum value from aBIT
instruction, bit 6 from the memory being tested is set into theV
flag.
In the case of a normal memory operation, this just means that the
user should organize his memory such that both of his flags to be
tested are in either bit 6 or bit 7, in which case an appropriate
mask does not have to be loaded into the accumulator prior to
implementing theBIT
instruction. In the case of theMCS6520
, theBIT
instruction can be used for sampling interrupt, irrespective of the
mask. This allows the programmer to totally interrogate both bit 6 and
bit 7 of theMCS6520
without disturbing the accumulator. In the case
of the concurrent interrupts, i.e., bit 6 and bit 7 both on, the fact
that theV
flag is automatically set by theBIT
instruction allows
the user to postpone testing for the "6th bit on" until after he has
totally handled the interrupt "for bit 7 on" unless he performs an
arithmetic operation subsequent to theBIT
operation.
Early MOS documentation (KIM-1 Programming Manual, Synertek SY6500/MCS6500 Microcomputer Programming manual, etc) states:
The
BIT
instruction actually combines two instructions from
thePDP-11
andMC6800
, that ofTST
(Test Memory) and (BIT Test).
...
In addition to the nondestructive feature of the
BIT
which
allows us to isolate an individual bit by use of the branch equal or
branch no equal test, two modifications to thePDP-11
version of that
instruction have been made in theMCS650X
microprocessor. These are
to allow a test of bit 7 and bit 6 of the field examined with theBIT
test. This feature is particularly useful in serving polled interrupts
and particularly in dealing with theMCS6520
(Peripheral Interface
Device). This device has an interrupt sense bit in bit 6 and bit 7
of the status words. It is a standard of theM6800
bus that whenever
possible, bit 7 reflects the interrupt status of an I/O device. This
means that under normal circumstances, an analysis of theN
flag
after a load orBIT
instruction should indicate the status of the
bit 7 on the I/O device being sampled. To facilitate this test using
theBIT
instruction, bit 7 from the memory being tested is set
into theN
flag irrespective of the value in the accumulator.
This is different from the bit instruction in theM6800
which
requires that bit 7 also be set on the accumulator to setN
. The
advantage to the user is that if he decides to test bit 7 in the
memory, it is done directly by sampling theN
bit with aBIT
followed by branch minus or branch plus instruction. This means that
I/O sampling can be accomplished at any time during the operation
of instructions irrespective of the value preloaded in the accumulator.
Another feature of the
BIT
test is the setting of bit 6 into
theV
flag. As indicated previously, theV
flag is normally reserved
for overflow into the sign position during an add and subtract instruction.
In other words, theV
flag is not disturbed by normal
instructions. When theBIT
instruction is used, it is assumed that
the user is trying to examine the memory that he is testing with the
BIT
instruction. In order to receive maximum value from aBIT
instruction, bit 6 from the memory being tested is set into theV
flag.
In the case of a normal memory operation, this just means that the
user should organize his memory such that both of his flags to be
tested are in either bit 6 or bit 7, in which case an appropriate
mask does not have to be loaded into the accumulator prior to
implementing theBIT
instruction. In the case of theMCS6520
, theBIT
instruction can be used for sampling interrupt, irrespective of the
mask. This allows the programmer to totally interrogate both bit 6 and
bit 7 of theMCS6520
without disturbing the accumulator. In the case
of the concurrent interrupts, i.e., bit 6 and bit 7 both on, the fact
that theV
flag is automatically set by theBIT
instruction allows
the user to postpone testing for the "6th bit on" until after he has
totally handled the interrupt "for bit 7 on" unless he performs an
arithmetic operation subsequent to theBIT
operation.
answered May 25 at 17:42
Kelvin SherlockKelvin Sherlock
9585 silver badges10 bronze badges
9585 silver badges10 bronze badges
add a comment
|
add a comment
|
I'm having a hard time picturing a use for this [BIT]
It's mainly an I/O issue.
The 6502 is in many ways designed especially for control/embedded applications and BIT
is a part of this. 6500 specific IO-devices are designed to report any service conditions on bit 7 (and 6). For example the 6522 will set bit 7 of the Interrupt Flag Register when an interrupt condition has been reported. So a 6522 can be polled in a system without interrupts without eating up many instructions. Even an active wait in polling would be just two instructions. As long as it's about bit 6 and 7 BIT
operates non destructive - unlike a sequence of LDA
/AND
- so no registers need to be saved, only flags changed, enabling the insertion of frequent checks.
Same reason why the Apple II's keyboard port puts the key-pressed flag into bit 7. so a quick BIT
can be used to check if a key has been pressed. And only the flags are affected.
As a side-effect BIT
is versatile for fast test of flags/semaphores. Bit 6/7 of a flag byte can be tested right away. Likewise (counting) semaphores/locks. In addition bit can be used to test for a numbers sign, again without touching anything but the flags.
And curiously, it's missing any indexed or indirect addressing modes, and so can only be used absolutely or in the zero page.
Not a concern for I/O, as these addresses are usually in fixed locations, especially when thinking embedded systems.
Bottom Line: BIT
is an instruction meant to speed up I/O handling.
The design side reasoning is to have an instruction to enable branching on as many bits as possible with minimal impact. Of the four testable bits (N
/V
/Z
/C
) one, carry, is as well usable as user flag (SEC
/CLC
), so keeping that function leaves 3. Using the AND function already implemented sets N
and Z
, so BIT
just needs to suppress copying the result of AND
back to A and copying Bit 6 into V
.
Sounds like minimal effort to add a quite handy instruction.
add a comment
|
I'm having a hard time picturing a use for this [BIT]
It's mainly an I/O issue.
The 6502 is in many ways designed especially for control/embedded applications and BIT
is a part of this. 6500 specific IO-devices are designed to report any service conditions on bit 7 (and 6). For example the 6522 will set bit 7 of the Interrupt Flag Register when an interrupt condition has been reported. So a 6522 can be polled in a system without interrupts without eating up many instructions. Even an active wait in polling would be just two instructions. As long as it's about bit 6 and 7 BIT
operates non destructive - unlike a sequence of LDA
/AND
- so no registers need to be saved, only flags changed, enabling the insertion of frequent checks.
Same reason why the Apple II's keyboard port puts the key-pressed flag into bit 7. so a quick BIT
can be used to check if a key has been pressed. And only the flags are affected.
As a side-effect BIT
is versatile for fast test of flags/semaphores. Bit 6/7 of a flag byte can be tested right away. Likewise (counting) semaphores/locks. In addition bit can be used to test for a numbers sign, again without touching anything but the flags.
And curiously, it's missing any indexed or indirect addressing modes, and so can only be used absolutely or in the zero page.
Not a concern for I/O, as these addresses are usually in fixed locations, especially when thinking embedded systems.
Bottom Line: BIT
is an instruction meant to speed up I/O handling.
The design side reasoning is to have an instruction to enable branching on as many bits as possible with minimal impact. Of the four testable bits (N
/V
/Z
/C
) one, carry, is as well usable as user flag (SEC
/CLC
), so keeping that function leaves 3. Using the AND function already implemented sets N
and Z
, so BIT
just needs to suppress copying the result of AND
back to A and copying Bit 6 into V
.
Sounds like minimal effort to add a quite handy instruction.
add a comment
|
I'm having a hard time picturing a use for this [BIT]
It's mainly an I/O issue.
The 6502 is in many ways designed especially for control/embedded applications and BIT
is a part of this. 6500 specific IO-devices are designed to report any service conditions on bit 7 (and 6). For example the 6522 will set bit 7 of the Interrupt Flag Register when an interrupt condition has been reported. So a 6522 can be polled in a system without interrupts without eating up many instructions. Even an active wait in polling would be just two instructions. As long as it's about bit 6 and 7 BIT
operates non destructive - unlike a sequence of LDA
/AND
- so no registers need to be saved, only flags changed, enabling the insertion of frequent checks.
Same reason why the Apple II's keyboard port puts the key-pressed flag into bit 7. so a quick BIT
can be used to check if a key has been pressed. And only the flags are affected.
As a side-effect BIT
is versatile for fast test of flags/semaphores. Bit 6/7 of a flag byte can be tested right away. Likewise (counting) semaphores/locks. In addition bit can be used to test for a numbers sign, again without touching anything but the flags.
And curiously, it's missing any indexed or indirect addressing modes, and so can only be used absolutely or in the zero page.
Not a concern for I/O, as these addresses are usually in fixed locations, especially when thinking embedded systems.
Bottom Line: BIT
is an instruction meant to speed up I/O handling.
The design side reasoning is to have an instruction to enable branching on as many bits as possible with minimal impact. Of the four testable bits (N
/V
/Z
/C
) one, carry, is as well usable as user flag (SEC
/CLC
), so keeping that function leaves 3. Using the AND function already implemented sets N
and Z
, so BIT
just needs to suppress copying the result of AND
back to A and copying Bit 6 into V
.
Sounds like minimal effort to add a quite handy instruction.
I'm having a hard time picturing a use for this [BIT]
It's mainly an I/O issue.
The 6502 is in many ways designed especially for control/embedded applications and BIT
is a part of this. 6500 specific IO-devices are designed to report any service conditions on bit 7 (and 6). For example the 6522 will set bit 7 of the Interrupt Flag Register when an interrupt condition has been reported. So a 6522 can be polled in a system without interrupts without eating up many instructions. Even an active wait in polling would be just two instructions. As long as it's about bit 6 and 7 BIT
operates non destructive - unlike a sequence of LDA
/AND
- so no registers need to be saved, only flags changed, enabling the insertion of frequent checks.
Same reason why the Apple II's keyboard port puts the key-pressed flag into bit 7. so a quick BIT
can be used to check if a key has been pressed. And only the flags are affected.
As a side-effect BIT
is versatile for fast test of flags/semaphores. Bit 6/7 of a flag byte can be tested right away. Likewise (counting) semaphores/locks. In addition bit can be used to test for a numbers sign, again without touching anything but the flags.
And curiously, it's missing any indexed or indirect addressing modes, and so can only be used absolutely or in the zero page.
Not a concern for I/O, as these addresses are usually in fixed locations, especially when thinking embedded systems.
Bottom Line: BIT
is an instruction meant to speed up I/O handling.
The design side reasoning is to have an instruction to enable branching on as many bits as possible with minimal impact. Of the four testable bits (N
/V
/Z
/C
) one, carry, is as well usable as user flag (SEC
/CLC
), so keeping that function leaves 3. Using the AND function already implemented sets N
and Z
, so BIT
just needs to suppress copying the result of AND
back to A and copying Bit 6 into V
.
Sounds like minimal effort to add a quite handy instruction.
edited May 26 at 18:42
answered May 25 at 23:42
RaffzahnRaffzahn
71.1k7 gold badges177 silver badges297 bronze badges
71.1k7 gold badges177 silver badges297 bronze badges
add a comment
|
add a comment
|
A good example would be reading from the floppy drive on the C64. The incoming clock and data signals of the serial bus are (perhaps not accidentally) wired to bits 6 and 7 of port A on CIA#2, appearing at $DD00
.
BIT $DD00
samples both inputs and stores them in the N
and V
flags. Jumping back conditionally with
BVC $-3
waits while the clock is low, as data must be sampled on the rising clock edge. When it falls through the BVC
, the N
flag contains the data bit. It can be transferred to the C
flag this way
BMI $+4
CLC
BIT $38
just to showcase the secondary use of the BIT
instruction, skipping the SEC
(opcode $38
), where BMI
is jumping to.
Now the data bit is in the carry flag, without altering any of the three data registers. It can be shifted into the accumulator, which would hold the data byte being assembled. Meanwhile X
can count the number of bits received, and Y
can serve as offset when storing the received data with STA (zp),Y
That BMI, CLC, BIT$38 snippet is indeed a part of many I/O routines.
– Janka
May 26 at 0:02
Sampling both inputs at a time can be handy. An even cuter exploitation of BIT can be found on the Atari 2600's video chip. It has 15 sprite-collision input flags and 6 controller input flags, but rather than e.g. using two 8-bit registers for the sprite flags and one for the inputs, it puts the collision flags on bits 6-7 of eight addresses, and the controller inputs on bit 7 of six more. What makes this especially cute is that the chip only includes drive circuitry for the top two bits of the data bus; since code won't care what's on the bottom six bits, there's no need to drive them.
– supercat
May 28 at 15:06
add a comment
|
A good example would be reading from the floppy drive on the C64. The incoming clock and data signals of the serial bus are (perhaps not accidentally) wired to bits 6 and 7 of port A on CIA#2, appearing at $DD00
.
BIT $DD00
samples both inputs and stores them in the N
and V
flags. Jumping back conditionally with
BVC $-3
waits while the clock is low, as data must be sampled on the rising clock edge. When it falls through the BVC
, the N
flag contains the data bit. It can be transferred to the C
flag this way
BMI $+4
CLC
BIT $38
just to showcase the secondary use of the BIT
instruction, skipping the SEC
(opcode $38
), where BMI
is jumping to.
Now the data bit is in the carry flag, without altering any of the three data registers. It can be shifted into the accumulator, which would hold the data byte being assembled. Meanwhile X
can count the number of bits received, and Y
can serve as offset when storing the received data with STA (zp),Y
That BMI, CLC, BIT$38 snippet is indeed a part of many I/O routines.
– Janka
May 26 at 0:02
Sampling both inputs at a time can be handy. An even cuter exploitation of BIT can be found on the Atari 2600's video chip. It has 15 sprite-collision input flags and 6 controller input flags, but rather than e.g. using two 8-bit registers for the sprite flags and one for the inputs, it puts the collision flags on bits 6-7 of eight addresses, and the controller inputs on bit 7 of six more. What makes this especially cute is that the chip only includes drive circuitry for the top two bits of the data bus; since code won't care what's on the bottom six bits, there's no need to drive them.
– supercat
May 28 at 15:06
add a comment
|
A good example would be reading from the floppy drive on the C64. The incoming clock and data signals of the serial bus are (perhaps not accidentally) wired to bits 6 and 7 of port A on CIA#2, appearing at $DD00
.
BIT $DD00
samples both inputs and stores them in the N
and V
flags. Jumping back conditionally with
BVC $-3
waits while the clock is low, as data must be sampled on the rising clock edge. When it falls through the BVC
, the N
flag contains the data bit. It can be transferred to the C
flag this way
BMI $+4
CLC
BIT $38
just to showcase the secondary use of the BIT
instruction, skipping the SEC
(opcode $38
), where BMI
is jumping to.
Now the data bit is in the carry flag, without altering any of the three data registers. It can be shifted into the accumulator, which would hold the data byte being assembled. Meanwhile X
can count the number of bits received, and Y
can serve as offset when storing the received data with STA (zp),Y
A good example would be reading from the floppy drive on the C64. The incoming clock and data signals of the serial bus are (perhaps not accidentally) wired to bits 6 and 7 of port A on CIA#2, appearing at $DD00
.
BIT $DD00
samples both inputs and stores them in the N
and V
flags. Jumping back conditionally with
BVC $-3
waits while the clock is low, as data must be sampled on the rising clock edge. When it falls through the BVC
, the N
flag contains the data bit. It can be transferred to the C
flag this way
BMI $+4
CLC
BIT $38
just to showcase the secondary use of the BIT
instruction, skipping the SEC
(opcode $38
), where BMI
is jumping to.
Now the data bit is in the carry flag, without altering any of the three data registers. It can be shifted into the accumulator, which would hold the data byte being assembled. Meanwhile X
can count the number of bits received, and Y
can serve as offset when storing the received data with STA (zp),Y
edited May 26 at 4:23
answered May 25 at 20:55
berendiberendi
2,1591 gold badge7 silver badges18 bronze badges
2,1591 gold badge7 silver badges18 bronze badges
That BMI, CLC, BIT$38 snippet is indeed a part of many I/O routines.
– Janka
May 26 at 0:02
Sampling both inputs at a time can be handy. An even cuter exploitation of BIT can be found on the Atari 2600's video chip. It has 15 sprite-collision input flags and 6 controller input flags, but rather than e.g. using two 8-bit registers for the sprite flags and one for the inputs, it puts the collision flags on bits 6-7 of eight addresses, and the controller inputs on bit 7 of six more. What makes this especially cute is that the chip only includes drive circuitry for the top two bits of the data bus; since code won't care what's on the bottom six bits, there's no need to drive them.
– supercat
May 28 at 15:06
add a comment
|
That BMI, CLC, BIT$38 snippet is indeed a part of many I/O routines.
– Janka
May 26 at 0:02
Sampling both inputs at a time can be handy. An even cuter exploitation of BIT can be found on the Atari 2600's video chip. It has 15 sprite-collision input flags and 6 controller input flags, but rather than e.g. using two 8-bit registers for the sprite flags and one for the inputs, it puts the collision flags on bits 6-7 of eight addresses, and the controller inputs on bit 7 of six more. What makes this especially cute is that the chip only includes drive circuitry for the top two bits of the data bus; since code won't care what's on the bottom six bits, there's no need to drive them.
– supercat
May 28 at 15:06
That BMI, CLC, BIT$38 snippet is indeed a part of many I/O routines.
– Janka
May 26 at 0:02
That BMI, CLC, BIT$38 snippet is indeed a part of many I/O routines.
– Janka
May 26 at 0:02
Sampling both inputs at a time can be handy. An even cuter exploitation of BIT can be found on the Atari 2600's video chip. It has 15 sprite-collision input flags and 6 controller input flags, but rather than e.g. using two 8-bit registers for the sprite flags and one for the inputs, it puts the collision flags on bits 6-7 of eight addresses, and the controller inputs on bit 7 of six more. What makes this especially cute is that the chip only includes drive circuitry for the top two bits of the data bus; since code won't care what's on the bottom six bits, there's no need to drive them.
– supercat
May 28 at 15:06
Sampling both inputs at a time can be handy. An even cuter exploitation of BIT can be found on the Atari 2600's video chip. It has 15 sprite-collision input flags and 6 controller input flags, but rather than e.g. using two 8-bit registers for the sprite flags and one for the inputs, it puts the collision flags on bits 6-7 of eight addresses, and the controller inputs on bit 7 of six more. What makes this especially cute is that the chip only includes drive circuitry for the top two bits of the data bus; since code won't care what's on the bottom six bits, there's no need to drive them.
– supercat
May 28 at 15:06
add a comment
|
Simply it gives the developer the ability to set status flags without actually moving any memory or destroying any registers. With a register starved system like the 6502, and the fact that (pretty much) all data movement is through the registers, there can certainly be use cases where this capability can come in handy.
add a comment
|
Simply it gives the developer the ability to set status flags without actually moving any memory or destroying any registers. With a register starved system like the 6502, and the fact that (pretty much) all data movement is through the registers, there can certainly be use cases where this capability can come in handy.
add a comment
|
Simply it gives the developer the ability to set status flags without actually moving any memory or destroying any registers. With a register starved system like the 6502, and the fact that (pretty much) all data movement is through the registers, there can certainly be use cases where this capability can come in handy.
Simply it gives the developer the ability to set status flags without actually moving any memory or destroying any registers. With a register starved system like the 6502, and the fact that (pretty much) all data movement is through the registers, there can certainly be use cases where this capability can come in handy.
answered May 25 at 17:22
Will HartungWill Hartung
5,06612 silver badges26 bronze badges
5,06612 silver badges26 bronze badges
add a comment
|
add a comment
|
I spent a lot of time in the 80s going through 6502 ROMs for home computers. I can honestly tell you what the BIT instruction is used for most of the time in practice.
Mostly it's not used for any calculation of interest. It's used as a filler instruction to allow multiple entry points to a routine, each with different common parameter values. I don't think I ever saw it used for the intended purpose. (Maybe once or twice.)
So for example if you had a routine which prints an ASCII character, you might commonly want to print space, or carriage return or things like '?' on the Commodore machines etc. and to save space in the ROM they just used the BIT instruction to isolate LDA instructions, or other loads. For example:
label_print_CR:
LDA #$0D - carriage return
.byte $2C (BIT instruction op code)
label_print_space:
LDA #$20 - space
.byte $2C
label_print_question_mark:
LDA #$3F - '?'
label_print_character:
main code to print character in A
That would assemble to be:
A9 0D 2C A9 20 2C A9 3F etc..
If you disassemble it you get:
LDA #$0D
BIT $20A9
BIT $3FA9
etc
so the BIT is doing nothing, but it's giving you these cunning specific extra entry points to the routine for printing.
Here's the entry points for the Commodore PET V4.0 BASIC (I don't have the code unfortunately.)
bb1d strout Output String
bb3a outspc Output Format Character
bb41 -Print '<cursor right>'
bb44 -Print '?'
bb46 - Output Character in A
You can clearly see the entry points are just 2-3 bytes apart for 41, 44, 46 so there's no way they're using branches or jumps to load and jump into the general routine.
This application of the BIT instruction is just totally ubiquitous across 6502 machines of that era. I used it in my own code all the time. As you can tell from the disassembly it can be rather confusing as to what they're doing.
This is from the 1976 Microsoft 6502 BASIC listing which you can check out here https://www.pagetable.com/docs/M6502.MAC.txt
DEFINE SKIP1, <XWD ^O1000,^O044> ;BIT ZERO PAGE TRICK.
DEFINE SKIP2, <XWD ^O1000,^O054> ;BIT ABS TRICK.
Note these values are in octal so that's $24 and $2c for the two byte and three byte BIT instructions.
Here's an example:
PARCHK: JSR CHKOPN ;ONLY POSSIBILITY LEFT IS
JSR FRMEVL ;A FORMULA IN PARENTHESIS.
;RECURSIVELY EVALUATE THE FORMULA.
CHKCLS: LDAI 41 ;CHECK FOR A RIGHT PARENTHESE
SKIP2
CHKOPN: LDAI 40
SKIP2
CHKCOM: LDAI 44
;
; "SYNCHK" LOOKS AT THE CURRENT CHARACTER TO MAKE SURE IT
; IS THE SPECIFIC THING LOADED INTO ACCA JUST BEFORE THE CALL TO
; "SYNCHK". IF NOT, IT CALLS THE "SYNTAX ERROR" ROUTINE.
; OTHERWISE IT GOBBLES THE NEXT CHAR AND RETURNS,
;
; [A]=NEW CHAR AND TXTPTR IS ADVANCED BY "CHRGET".
;
SYNCHR: LDYI 0
CMPDY TXTPTR ;CHARACTERS EQUAL?
BNE SNERR
CHRGO5: JMP CHRGET
1
From the OP: "(Incidentally, it's convenient also for skipping two bytes in the instruction stream in cases where you don't care what happens to the flags, but I don't imagine that's the use MOS had in mind). What kinds of things was it meant for?)"
– Wilson
May 28 at 10:50
add a comment
|
I spent a lot of time in the 80s going through 6502 ROMs for home computers. I can honestly tell you what the BIT instruction is used for most of the time in practice.
Mostly it's not used for any calculation of interest. It's used as a filler instruction to allow multiple entry points to a routine, each with different common parameter values. I don't think I ever saw it used for the intended purpose. (Maybe once or twice.)
So for example if you had a routine which prints an ASCII character, you might commonly want to print space, or carriage return or things like '?' on the Commodore machines etc. and to save space in the ROM they just used the BIT instruction to isolate LDA instructions, or other loads. For example:
label_print_CR:
LDA #$0D - carriage return
.byte $2C (BIT instruction op code)
label_print_space:
LDA #$20 - space
.byte $2C
label_print_question_mark:
LDA #$3F - '?'
label_print_character:
main code to print character in A
That would assemble to be:
A9 0D 2C A9 20 2C A9 3F etc..
If you disassemble it you get:
LDA #$0D
BIT $20A9
BIT $3FA9
etc
so the BIT is doing nothing, but it's giving you these cunning specific extra entry points to the routine for printing.
Here's the entry points for the Commodore PET V4.0 BASIC (I don't have the code unfortunately.)
bb1d strout Output String
bb3a outspc Output Format Character
bb41 -Print '<cursor right>'
bb44 -Print '?'
bb46 - Output Character in A
You can clearly see the entry points are just 2-3 bytes apart for 41, 44, 46 so there's no way they're using branches or jumps to load and jump into the general routine.
This application of the BIT instruction is just totally ubiquitous across 6502 machines of that era. I used it in my own code all the time. As you can tell from the disassembly it can be rather confusing as to what they're doing.
This is from the 1976 Microsoft 6502 BASIC listing which you can check out here https://www.pagetable.com/docs/M6502.MAC.txt
DEFINE SKIP1, <XWD ^O1000,^O044> ;BIT ZERO PAGE TRICK.
DEFINE SKIP2, <XWD ^O1000,^O054> ;BIT ABS TRICK.
Note these values are in octal so that's $24 and $2c for the two byte and three byte BIT instructions.
Here's an example:
PARCHK: JSR CHKOPN ;ONLY POSSIBILITY LEFT IS
JSR FRMEVL ;A FORMULA IN PARENTHESIS.
;RECURSIVELY EVALUATE THE FORMULA.
CHKCLS: LDAI 41 ;CHECK FOR A RIGHT PARENTHESE
SKIP2
CHKOPN: LDAI 40
SKIP2
CHKCOM: LDAI 44
;
; "SYNCHK" LOOKS AT THE CURRENT CHARACTER TO MAKE SURE IT
; IS THE SPECIFIC THING LOADED INTO ACCA JUST BEFORE THE CALL TO
; "SYNCHK". IF NOT, IT CALLS THE "SYNTAX ERROR" ROUTINE.
; OTHERWISE IT GOBBLES THE NEXT CHAR AND RETURNS,
;
; [A]=NEW CHAR AND TXTPTR IS ADVANCED BY "CHRGET".
;
SYNCHR: LDYI 0
CMPDY TXTPTR ;CHARACTERS EQUAL?
BNE SNERR
CHRGO5: JMP CHRGET
1
From the OP: "(Incidentally, it's convenient also for skipping two bytes in the instruction stream in cases where you don't care what happens to the flags, but I don't imagine that's the use MOS had in mind). What kinds of things was it meant for?)"
– Wilson
May 28 at 10:50
add a comment
|
I spent a lot of time in the 80s going through 6502 ROMs for home computers. I can honestly tell you what the BIT instruction is used for most of the time in practice.
Mostly it's not used for any calculation of interest. It's used as a filler instruction to allow multiple entry points to a routine, each with different common parameter values. I don't think I ever saw it used for the intended purpose. (Maybe once or twice.)
So for example if you had a routine which prints an ASCII character, you might commonly want to print space, or carriage return or things like '?' on the Commodore machines etc. and to save space in the ROM they just used the BIT instruction to isolate LDA instructions, or other loads. For example:
label_print_CR:
LDA #$0D - carriage return
.byte $2C (BIT instruction op code)
label_print_space:
LDA #$20 - space
.byte $2C
label_print_question_mark:
LDA #$3F - '?'
label_print_character:
main code to print character in A
That would assemble to be:
A9 0D 2C A9 20 2C A9 3F etc..
If you disassemble it you get:
LDA #$0D
BIT $20A9
BIT $3FA9
etc
so the BIT is doing nothing, but it's giving you these cunning specific extra entry points to the routine for printing.
Here's the entry points for the Commodore PET V4.0 BASIC (I don't have the code unfortunately.)
bb1d strout Output String
bb3a outspc Output Format Character
bb41 -Print '<cursor right>'
bb44 -Print '?'
bb46 - Output Character in A
You can clearly see the entry points are just 2-3 bytes apart for 41, 44, 46 so there's no way they're using branches or jumps to load and jump into the general routine.
This application of the BIT instruction is just totally ubiquitous across 6502 machines of that era. I used it in my own code all the time. As you can tell from the disassembly it can be rather confusing as to what they're doing.
This is from the 1976 Microsoft 6502 BASIC listing which you can check out here https://www.pagetable.com/docs/M6502.MAC.txt
DEFINE SKIP1, <XWD ^O1000,^O044> ;BIT ZERO PAGE TRICK.
DEFINE SKIP2, <XWD ^O1000,^O054> ;BIT ABS TRICK.
Note these values are in octal so that's $24 and $2c for the two byte and three byte BIT instructions.
Here's an example:
PARCHK: JSR CHKOPN ;ONLY POSSIBILITY LEFT IS
JSR FRMEVL ;A FORMULA IN PARENTHESIS.
;RECURSIVELY EVALUATE THE FORMULA.
CHKCLS: LDAI 41 ;CHECK FOR A RIGHT PARENTHESE
SKIP2
CHKOPN: LDAI 40
SKIP2
CHKCOM: LDAI 44
;
; "SYNCHK" LOOKS AT THE CURRENT CHARACTER TO MAKE SURE IT
; IS THE SPECIFIC THING LOADED INTO ACCA JUST BEFORE THE CALL TO
; "SYNCHK". IF NOT, IT CALLS THE "SYNTAX ERROR" ROUTINE.
; OTHERWISE IT GOBBLES THE NEXT CHAR AND RETURNS,
;
; [A]=NEW CHAR AND TXTPTR IS ADVANCED BY "CHRGET".
;
SYNCHR: LDYI 0
CMPDY TXTPTR ;CHARACTERS EQUAL?
BNE SNERR
CHRGO5: JMP CHRGET
I spent a lot of time in the 80s going through 6502 ROMs for home computers. I can honestly tell you what the BIT instruction is used for most of the time in practice.
Mostly it's not used for any calculation of interest. It's used as a filler instruction to allow multiple entry points to a routine, each with different common parameter values. I don't think I ever saw it used for the intended purpose. (Maybe once or twice.)
So for example if you had a routine which prints an ASCII character, you might commonly want to print space, or carriage return or things like '?' on the Commodore machines etc. and to save space in the ROM they just used the BIT instruction to isolate LDA instructions, or other loads. For example:
label_print_CR:
LDA #$0D - carriage return
.byte $2C (BIT instruction op code)
label_print_space:
LDA #$20 - space
.byte $2C
label_print_question_mark:
LDA #$3F - '?'
label_print_character:
main code to print character in A
That would assemble to be:
A9 0D 2C A9 20 2C A9 3F etc..
If you disassemble it you get:
LDA #$0D
BIT $20A9
BIT $3FA9
etc
so the BIT is doing nothing, but it's giving you these cunning specific extra entry points to the routine for printing.
Here's the entry points for the Commodore PET V4.0 BASIC (I don't have the code unfortunately.)
bb1d strout Output String
bb3a outspc Output Format Character
bb41 -Print '<cursor right>'
bb44 -Print '?'
bb46 - Output Character in A
You can clearly see the entry points are just 2-3 bytes apart for 41, 44, 46 so there's no way they're using branches or jumps to load and jump into the general routine.
This application of the BIT instruction is just totally ubiquitous across 6502 machines of that era. I used it in my own code all the time. As you can tell from the disassembly it can be rather confusing as to what they're doing.
This is from the 1976 Microsoft 6502 BASIC listing which you can check out here https://www.pagetable.com/docs/M6502.MAC.txt
DEFINE SKIP1, <XWD ^O1000,^O044> ;BIT ZERO PAGE TRICK.
DEFINE SKIP2, <XWD ^O1000,^O054> ;BIT ABS TRICK.
Note these values are in octal so that's $24 and $2c for the two byte and three byte BIT instructions.
Here's an example:
PARCHK: JSR CHKOPN ;ONLY POSSIBILITY LEFT IS
JSR FRMEVL ;A FORMULA IN PARENTHESIS.
;RECURSIVELY EVALUATE THE FORMULA.
CHKCLS: LDAI 41 ;CHECK FOR A RIGHT PARENTHESE
SKIP2
CHKOPN: LDAI 40
SKIP2
CHKCOM: LDAI 44
;
; "SYNCHK" LOOKS AT THE CURRENT CHARACTER TO MAKE SURE IT
; IS THE SPECIFIC THING LOADED INTO ACCA JUST BEFORE THE CALL TO
; "SYNCHK". IF NOT, IT CALLS THE "SYNTAX ERROR" ROUTINE.
; OTHERWISE IT GOBBLES THE NEXT CHAR AND RETURNS,
;
; [A]=NEW CHAR AND TXTPTR IS ADVANCED BY "CHRGET".
;
SYNCHR: LDYI 0
CMPDY TXTPTR ;CHARACTERS EQUAL?
BNE SNERR
CHRGO5: JMP CHRGET
edited May 28 at 8:19
answered May 28 at 7:44
RobotbugsRobotbugs
1594 bronze badges
1594 bronze badges
1
From the OP: "(Incidentally, it's convenient also for skipping two bytes in the instruction stream in cases where you don't care what happens to the flags, but I don't imagine that's the use MOS had in mind). What kinds of things was it meant for?)"
– Wilson
May 28 at 10:50
add a comment
|
1
From the OP: "(Incidentally, it's convenient also for skipping two bytes in the instruction stream in cases where you don't care what happens to the flags, but I don't imagine that's the use MOS had in mind). What kinds of things was it meant for?)"
– Wilson
May 28 at 10:50
1
1
From the OP: "(Incidentally, it's convenient also for skipping two bytes in the instruction stream in cases where you don't care what happens to the flags, but I don't imagine that's the use MOS had in mind). What kinds of things was it meant for?)"
– Wilson
May 28 at 10:50
From the OP: "(Incidentally, it's convenient also for skipping two bytes in the instruction stream in cases where you don't care what happens to the flags, but I don't imagine that's the use MOS had in mind). What kinds of things was it meant for?)"
– Wilson
May 28 at 10:50
add a comment
|
Thanks for contributing an answer to Retrocomputing Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fretrocomputing.stackexchange.com%2fquestions%2f11108%2fwhy-does-the-6502-have-the-bit-instruction%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
The nature of this question is similar to that of Why does the Z80 include the RLD and RRD instructions?
– Wilson
May 25 at 16:00
1
Looking at the ProDOS 8 source code,
BIT
is used to check for a flag in bits 6 or 7, check if a number in memory is negative (again, bit 7), to read i/o memory (without destroying registers). It's also used twice as a clever hack to set theV
flag (since there's aCLV
instruction but noSEV
instruction), and once used to hide other instructions.– Kelvin Sherlock
May 25 at 17:16
4
You are mistaken, the AND affects the Z flag, not the C flag.
– Janka
May 25 at 18:28
1
@fadden Is it an undocumented instruction? What is the opcode?
– berendi
May 27 at 15:26
2
@berendi
BIT imm
is not a 6502 but a 65C02 instruction.Opcode is $89.– Raffzahn
May 27 at 17:17