How to shift the contents of a memory location left 1 bit to another memory using z80 assembly language

651 views Asked by At

Example , left shifting 1 bit from location 1900H and store in location 1901H , and empty bit positions are filled with zero

2

There are 2 answers

3
tum_ On

Home work?

Not 100% sure if this is what you're asking for, but anyway:

...
    XOR A          ; clear Carry
    LD A,(1900H)
    RLA            ; left shift, bit 7 goes to Carry, bit 0 filled with 0
    LD (1900H),A   ; save shifted value
    LD A,(1901H)
    RLA            ; left shift, bit 0 filled with bit 7 of the original (1900h)
    LD (1901H),A   ; save shifted value
    ...

There are, of course, other ways to achieve the same.

Added another one from the comment:

LD HL,(1900H)   ; load 16-bit value: L<-(1900H), H<-(1901H)
ADD HL,HL       ; HL <- HL+HL = HL*2 - equivalent of left shift by 1 bit
LD (1900H),HL   ; save to the same location

The above snippet is 7 bytes in size and, probably, the shortest possible code for the task.

0
Zeda On

Let's start with the simpler case of shifting one byte left, and shifting in a 0-bit. On the Z80, this perfectly describe the sla set of instructions:

    sla [reg8]

Where reg8 is one of the registers A/B/C/D/E/H/L, or (HL), or (IX+d) or (IY+d). The top bit gets shifted out of the register (or memory location in the case of (HL)/(IX+d)/(IY+d)) and into the carry flag.

There is a well known trick for 4 special cases on the Z80. Since shifting left (while shifting in a 0) is the same as multiplying by 2, you can actually simulate an sla with:

    add a,a     ; replaces `sla a`, save 1 byte, 4cc
    add hl,hl   ; replaces `sla l \ rl h`, save 3 bytes, 5cc
    add ix,ix   ; (to my knowedge, this is the only "legal" way to shift the IX register pair like this)
    add iy,iy   ; (same with IY)

These are faster and smaller and almost always the best replacement.

In any event, the bit that was shifted out is now in the carry flag, so you can shift that into the next byte using the rl class of instructions:

    rl [reg8] ;2 bytes,  8 clock cycles
    rla       ;1b, 4cc. Basically a fast `rl a` but affects fewer flags.

Notice that the Z80 has an optimized ersion of this specifically for the A register.


Now on to your question: There are many ways to do this on the Z80. If you know precisely where in memory the bytes are, @tum_ provided the fastests and smallest option:

    ld hl,(1900H) ; Read the two bytes into HL
    add hl,hl     ; Shift left
    ld (1900H),hl ; Store HL back to the bytes.

This takes advantage of the sla trick from earlier, where you can just add HL to itself (HL*2) to shift it left. However, if the bytes are not at a pre-determined location, but HL points to the bytes, then:

    sla (hl)  ; `sla` the byte at HL
    inc hl    ; Advance to the next byte
    rl (hl)   ; `rl` the byte at HL

You can also do it a little slower (not recommened, just showing this for educational purposes):

    ld a,(hl) ; read the byte at HL into A
    add a,a   ; `sla a`, but faster and smaller
    ld (hl),a ; Store it back to the byte at HL
    inc hl    ; advance to the next byte
    ld a,(hl) ; read the byte at HL into A
    rla       ; `rl a`, but faster and smaller
    ld (hl),a ; Store it back to the byte at HL

This is a lot of info, but hopefully this helps!