8
\$\begingroup\$

I have came across a question while working on assembly language. Here is the question:

Assume that bit P2.2 is used to control an outdoor light and bit P2.5 a light inside a building. Show how to turn on the outside light and turn off the inside one.

Solution given:

SETB C            ; CY = 1
ORL C, P2.2       ; CY = P2.2 ORed w/ CY
MOV P2.2, C       ; turn it on if not on
CLR C             ; CY = 0
ANL C, P2.5       ; CY = P2.5 ANDed w/P2.5
MOV P2.5,C        ; turn it off if not off

I just felt like it would do just the same job to code:

SETB P2.2
CLR P2.5

What's wrong with that?

\$\endgroup\$
3
  • 2
    \$\begingroup\$ Maybe just didactics- showing how to use the carry bit as an accumulator. There's no advantage that I can see in this particular case. This looks like 8051 assembly code. \$\endgroup\$ Commented Sep 1, 2017 at 20:01
  • \$\begingroup\$ @SpehroPefhany But as far as I know, the Acc register is used in some cases since it is the only register that supports some instructions like DA, RR, RL etc. I don't think this is the case here. Am I wrong? \$\endgroup\$ Commented Sep 1, 2017 at 20:11
  • \$\begingroup\$ The carry is one bit wide. You might want to use it as an accumulator in some cases such as ladder logic evaluation. \$\endgroup\$ Commented Sep 1, 2017 at 20:18

6 Answers 6

11
\$\begingroup\$

You are right in that it appears the code you show is silly. Perhaps whatever machine this runs on can't do immediate operations to set bits on I/O ports, and that that's why something like SETB P2.2 isn't possible.

Still setting the CY bit to 1, then ORing anything into it is just plain silly. The same goes for setting the CY bit to 0, then ANDing something into it. Clearly the CY bit can be directly copied into a I/O pin bit, since the code does that. At most this should be 4 instructions, certainly not 6.

\$\endgroup\$
3
  • \$\begingroup\$ So I can say that if a bit is bit-addressable, I am allowed to use bit instructions on whatever bit is it, right? \$\endgroup\$ Commented Sep 1, 2017 at 20:03
  • 1
    \$\begingroup\$ @İlk: Not necessarily. There might be restriction like the bit instructions only work on certain registers, certain "near" memory, and the like. Without knowing the processor, we can't say for sure whether SETB P2.2 would have been possible. However, SETB C followed by MOV P2.2, C, is clearly possible. \$\endgroup\$ Commented Sep 1, 2017 at 20:12
  • 1
    \$\begingroup\$ @OlinLathrop: The processor is almost certainly some 8051 variant, and the instruction set for those would allow the same locations to be used for SETB bit and CLR bit instructions as for MOV bit,C. Further, while using discrete instructions to read an I/O port, update the value, and write it back will yield different semantics from using read-modify-write instructions, the bitwise instructions all use the same read-modify-write semantics on I/O ports. \$\endgroup\$
    – supercat
    Commented Sep 1, 2017 at 20:48
9
\$\begingroup\$

The code is almost certainly for a processor using the 8051 instruction set. On that processor, the code variation you give would have the same effect as the original except that it would run faster. Executing "ORL C,P2.2" when carry is set will have no observable effect except to waste some number of cycles (two CPU cycles totaling 24 clock cycles on an 8051 if I recall correctly; likely a different number on some other variants). Likewise with executing "ANL C,P2.5" when carry is clear. Although there may be some kinds of processor where a request to read some I/O locations would have some observable effect, I don't think any 8051-style processor has ever had such behavior for any bit-addressable I/O locations, much less for bits of P2.

Perhaps the purpose of the code was to demonstrate the ORL C,bit and ANL C,bit instructions, but this seems like a weird example to demonstrate them.

\$\endgroup\$
7
\$\begingroup\$

The assembly code given is likely compiler-generated. It is the unoptimized version of the following C statements, where P2_2 and P2_5 are the bit-addressable objects:

P2_2 |= 1;
P2_5 &= 0;

This may seem equivalent to P2_2 = 1; and P2_5 = 0;, but it isn't if the bit-addressable registers are volatile objects. A read-modify-write operation on a volatile object must perform the read and the write, in that order. This ensures that any side-effects from reading or writing the register actually occur.

Although I know of no 8051 bit-addressable register with side-effects, a compiler cannot assume there isn't or won't ever be one.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Good point about possibly being compiler-generated. However, it then moves the question to why someone would write P2_2 |= 1 instead of just P2_2 = 1. \$\endgroup\$ Commented Sep 2, 2017 at 15:20
3
\$\begingroup\$

The real difference between these may be subtle.

In your simplified answer the logic is read the port, set or clear the bit value and then write it back out to the port. Note the whole port could be re-written here.

The solution on the other hand uses the MOV bit instruction which may operate in a rather different manner.

Without going into the details of the particular part used here it is difficult to determine if there is a difference, or if it matters.

Or it could just be the instructor decided to make you think.... which is after all.. his real job.

\$\endgroup\$
1
\$\begingroup\$

Technically, a compiler would have to treat P2.2 and P2.5 as volatile bit-valued variables (that are aliased into and with the volatile byte-valued variable P2), since the read and write operations on them may be entirely different operations, unconnected to one another; and P2 is associated with external pins on the CPU. So, it depends on how it's set up in the circuit containing the CPU.

Port 2 function is time-multiplexed as address bits 8-15 of the 16-bit address bus along with bi-directional I/O (address bits 0-7 go out through port 0, i.e. P0). This is seen here Internal architecture of the 8051 Ports 0, 1, 2 and 3 in further detail. I don't exactly remember what it is, but I'm pretty sure that there is also an external pin made available for the circuit to use to determine when P0 and P2 are in address-bus mode versus bi-directional I/O mode. For bi-directional I/O operations, the inputs and outputs are separately latched. That is the sense in which reads and writes on P2 are independent.

Apart from timing (which may actually be relevant), the operations you specified are equivalent to the sequence:

    write 1 to CY
    read P2.2, then write 1 to P2.2
    write 0 to CY
    read P2.5, then write 0 to P2.5

What the read operations actually do depends entirely on how the circuit is set up. Reads might do things in the circuit, even if the values read aren't being used by the CPU. These are the same kinds of issues that you encounter when dealing with volatile variables in C or C++.

\$\endgroup\$
0
\$\begingroup\$

The only answer is that the processor does not support 1 bit instructions directly. However, when the carry bit is used, it knows it is only one bit being manipulated.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.