The proper way to shift a byte using a Z80

In a nutshell, why can I not shift a byte using this way?

``````LD A, 11110000b  ; I want this to be 00001111b
LD C, 4
SRA C
OUT (0), A  ; doesn't give correct number
``````

What is the proper way of shifting a byte by a fixed amount?

I could do it using this pretty sketchy way:

``````LD A, 11110000b
RRA
RRA
RRA
RRA
OUT (0), A  ; Gives 00001111b
``````

Some context: so it has been some tough days, and day-by-day I was assembling my breadboard Z80 computer, that uses a CMOS Z80, so I can debug (single step) the CPU easily. It has 256 bytes RAM and 256 bytes ROM, and using a simple 74573 D-type latch, I added a single output port to the CPU.

I have done testing that my memory configuration, 573 and everything is okay, and it was. Now I was writing subroutines to interface a simple 1602 LCD and in the arithmetic involved I had to right shift the accumulator by 4, a thing that I didn't think was hard. But the LCD never worked correctly using the way I mentioned first using the `SRA` instruction and only worked when I ran the instruction `RRA` four times.

I literally am pretty new to assembly, and I apologize if what I am asking about is pretty basic. So what I am missing up here?

• Going by <jgmalcolm.com/z80/advanced/shif#sra>, `sra x` is `x >>= 1`, not `a >>= x`. It stands for ‘shift right, arithmetic’, not ‘shift right the accumulator’. Commented Jun 19, 2021 at 21:02
• What is so ‘sketchy’ about `rra` (other than it being a bit rotation instruction instead of a bit shift)? Commented Jun 19, 2021 at 21:05
• @user3840170 I really don't know but I don't feel good of executing an instruction multiple times to shift.... and I don't really like making a 'for loop' (some how i don't know in assembly) to execute the instruction efficiently... Commented Jun 19, 2021 at 21:30
• @ShamsM.Monem But you want to do multiple bits, don't you? Then doing the shift multiple times is the natural way. Anything else is decadent :)) Commented Jun 19, 2021 at 22:08

TL;DR:

Simply because `SRA C` doesn't shift A by the content of C, but shifts C right by one with keeping bit 7 (sign) static.

Z80 and shifting:

While the Z80 did add some nice new shifts and rotates, like the mentioned Shift Left Arithmetic for all 7 registers and memory, it still only shifts by one bit position per execution. So any shift by more than one position will, like with many other 8-bit CPUs, require repetition - as loop or unrolled, as in:

``````    LD  A,11110000b  ;(*1)
SRA A
SRA A
SRA A
SRA A
OUT (0),A
``````

Why not?

Well, doing multi position shift would either

• require a barrel shifter - not really cool as that needs quite a lot of real estate, whereas a single bit shifter comes almost free with regular ALU design.

• Or need a micro program loop to handle that case - again rather costly.

Keep in mind, (classic) 8 bit CPUs are not about making life comfortable, but getting work done at all - they are only one step above no CPU.

So is there a better way?

Yes, use `RRA`. It takes only 4 T-states while `SRA` takes 8.

``````    LD  A,11110000b
RRA
RRA
RRA
RRA
OUT (0),A
``````

This is due the fact that `SRA` is an Z80 enhancement which needs, while doing essentially the same operation, a prefix byte (0CBh), which in itself eats up 4 T-states.

`RRA` is a basic 8080 instruction (*2), encoded in a single byte (01Fh) and thus able to be executed in 4 T-states. In 8080 assembly it's called `RAR`.

Using `RRA` thus brings 3 advantages at once:

• More compact code
• Faster execution
• Compatibility with other 8080 compatible CPUs

Yes but ...

As Supercat reminds us, there's an odd pair of instructions rotating nibble wise:

• RLD - Rotate Left Digit and
• RRD - Rotate Right Digit

They rotate a byte pointed to by HL thru the lower 4 bits of A.

• RLD moves the top 4 bit of a memory location into the lower 4 bit of A, moves the lower 4 bit of that location into the higher 4 and stores the lower 4 of the original content of A into the lower 4. Confusing? Lake a look here:

• RRD does the same just the other way around:

Sounds great, especially when considering that output is more often than not multiple bytes from memory, which are pointed to by HL anyway. To output both nibbles of a byte pointed to by HL code might look like this:

``````    LD   A,(HL)
AND  0Fh
OUT  (0),A
RLD
AND  0Fh
OUT  (0),A
``````

(Outputting the lower 4 first)

The whole works has just two tiny disadvantages:

• it destroys the input byte and
• it isn't much faster at all

While the 4 SRA take 16 T-states, RLD takes 18 - but saves an additional LD - which in turn may or may not be needed depending on the over all program structure.

This two, plus the fact that the vast majority of Z80 programmers will need to look at the manual when encountering an RLD/RRD, make a good reason to stay with the classic 8080 compatible RRA sequence.

*1 - It's bad practice to add spaces in assembler parameters, as that's not portable -especially not if one wants to use tools contemporary to that CPUs.

*2 - Not to be confused with `RR A`, which is the same but in Z80 encoding, like `SRA`, with a 0CBh prefix and 8 T-states.

• For other examples that have the lower 4 bits set, you might have to `and` `a` with `11110000b` beforehand and clear the carry bit Commented Jun 19, 2021 at 22:13
• @S.S.Anne `AND` already clears the carry bit, not that it makes any difference if you're not using `RRCA` (or `RLCA`).
– Neil
Commented Jun 20, 2021 at 8:39
• The Z80 also includes instructions to move rotate ranges of memory four bits at a time. Unfortunately, there are no register-based equivalents. Commented Jun 20, 2021 at 21:40
• @S.S.Anne Not really - see the added section - depending on the surrounding program it may not save anything but create additional problems. These two instructions do really only make sense when operation on longer BCD strings. (Also, for your remark about ANDing, cleaning output should always done when needed, not premature - that only makes reading harder.) Commented Jun 20, 2021 at 23:36
• @Raffzahn: RRD/RLD aren't necessarily only four BCD--they could be used in any situation where one would need to shift a sequence of bytes left or right by four, such as shifting a black and white bitmap left or right by four pixels, or a four-bits-per-pixel bitmap left or right one pixel. Still, probably not as broadly useful as they could have been with register operands. Commented Jun 21, 2021 at 4:22