RLCA/RRCA a range of values in memory
Posted: Tue Oct 05, 2021 12:35 am
I was playing around with RRD and RLD, and came up with something that I thought was quite clever. I haven't tested this on any Z80 hardware, this was all done by writing out what should happen on paper. (Do people still do that?)
EDIT: I have tested this on WinAPE and so far it seems to work.
EDIT 2: I can get it to work for rotating right, but not left...
Imagine memory address &1000 - &1003 contain the following, in order: &23, &45, &67, &89.
Now, here's where the magic happens.
After all this is said and done, A equals what it did before any of the RRD commands took place, and the memory range has effectively been RRCA'd once. That is, the last byte is now the first, and the rest were shifted one byte over. We began with &23, &45, &67, &89, and ended with &89, &23, &45, &67.
This test worked for a 4 byte long range, but it seems like it can be generalized with the following (untested) code:
And to properly call this routine you can use this macro:
As I said before, I haven't fully tested this technique, but I believe this should work. If anyone wants to try it, feel free and please let me know if it works for you.
EDIT: I have tested this on WinAPE and so far it seems to work.
EDIT 2: I can get it to work for rotating right, but not left...
Imagine memory address &1000 - &1003 contain the following, in order: &23, &45, &67, &89.
Code: Select all
LD HL,&1000
LD A,(HL) ;A = &23
PUSH HL
Code: Select all
RRD ;A = &23, &1000 = &32 &45 &67 &89
INC HL
RRD ;A = &25, &1000 = &32 &34 &67 &89
INC HL
RRD ;A = &27, &1000 = &32 &34 &56 &89
INC HL
RRD ;A = &29, &1000 = &32 &34 &56 &78
POP HL
PUSH HL
RRD ;A = &22, &1000 = &93 &34 &56 &89
INC HL
RRD ;A = &24, &1000 = &93 &23 &56 &78
INC HL
RRD ;A = &26, &1000 = &93 &23 &45 &78
INC HL
RRD ;A = &28, &1000 = &93 &23 &45 &67
POP HL
RRD ;A = &23, &1000 = &89 &23 &45 &67
This test worked for a 4 byte long range, but it seems like it can be generalized with the following (untested) code:
Code: Select all
RRCA_Range:
;input:
;B = total size of memory range to rotate (measured in bytes)
;HL = address of zeroth element of the range.
LD A,(HL) ;ACCUMULATOR NEEDS TO EQUAL THE FIRST BYTE OF THE RANGE FOR THIS TO WORK
PUSH HL
PUSH BC
loop_RRCA_Range_firstloop:
RRD
INC HL
DJNZ loop_RRCA_Range_firstloop
POP BC
POP HL
PUSH HL
PUSH BC
loop_RRCA_Range_secondloop:
RRD
INC HL
DJNZ loop_RRCA_Range_secondloop
POP BC
POP HL
RRD
RET
Code: Select all
macro rrca_MemoryRange,addr,count
LD HL,\addr
LD b,count
call RRCA_Range ;the above subroutine
endm