Hello, as a learning exercise i'm trying to figure out how to do a memcpy-style implementation with only assembly.
I'm having trouble ordering my thoughts on how it should be performed. What would be a good starting point? I have difficulties trying to rationalize the process, as I am mainly C-oriented on my programming.
How should be stored and manipulated the addresses to the arrays' bytes (which would be incremented at each step)?
Remember, this is only a learning exercise. Any thoughts are aprreciated. Thanks.
Solved! Go to Solution.
Hello,
It is possible to create variables in RAM (equivalent to global variables) to store the current source and destination addresses, in addition to a byte counter. However, the solution would be more general to make use of the stack to store these values.
The next issue is to "pass" the initial parameter values to the sub-routine. The Accumulator and H:X registers are available, however these will be insufficient for the current requirement. Therefore it will be necessary to "pre-load" some of the data to the stack, prior to the sub-routine call.
If the block size does not exceed 256 bytes, you might pass the block size within Acc, the destination address within H:X, and pre-load the source address. However, for a block size that may exceed 256 bytes you will need to pass three 16-bit values. For this case, one possibility is to pre-load the source and destination addresses, and to pass the block size within H:X.
The significance of pre-loading some of the data is that the stack pointer will require adjustment after the return from the sub-routine.
The following code snippet demonstrates the process. The code should be compatible with CW assembler.
; Memory copy sub-routine
; Copy block of memory from source location to destination location.
; Source address and destination address values are pre-loaded to
; the stack prior to the sub-routine call.
; On entry, H:X contains the number of bytes to be copied.
; On exit, Acc value is preserved.
; Stack frame structure (SP index)
SRC EQU 7 ; First pre-loaded value
DEST EQU 5 ; Second pre-loaded value
COUNT EQU 1 ; Byte count yet to be copied
MEMCOPY: cphx #0 ; Test for zero bytes to be copied
beq MC3 ; Exit if so
psha ; Save current value
pshx ; Save byte quantity to stack
pshh
MC1: ldhx SRC,sp ; Current source address
lda ,x ; Fetch byte value
ldhx DEST,sp ; Current destination address
sta ,x ; Write byte value
inc SRC,sp ; Increment source address
inc DEST,sp ; Increment destination address
ldhx COUNT,sp ; Byte counter
beq MC2 ; Exit if final byte copy done
dec COUNT,sp ; Decrement byte count
bra MC1 ; Loop always for next byte
MC2: ais #2 ; Adjust stack pointer
pula ; Restore previous value
MC3: rts
; Typical usage:
; aix #-4 ; Create space on stack
; ldhx #SRC_ADDR
; sthx 3,sp ; Pre-load to stack
; ldhx #DEST_ADDR
; sthx 1,sp ; Pre-load to stack
; ldhx #BLOCK_SIZE
; jsr MEMCOPY
; ais #4 ; Adjust stack pointer
Regards,
Mac
Hello,
It is possible to create variables in RAM (equivalent to global variables) to store the current source and destination addresses, in addition to a byte counter. However, the solution would be more general to make use of the stack to store these values.
The next issue is to "pass" the initial parameter values to the sub-routine. The Accumulator and H:X registers are available, however these will be insufficient for the current requirement. Therefore it will be necessary to "pre-load" some of the data to the stack, prior to the sub-routine call.
If the block size does not exceed 256 bytes, you might pass the block size within Acc, the destination address within H:X, and pre-load the source address. However, for a block size that may exceed 256 bytes you will need to pass three 16-bit values. For this case, one possibility is to pre-load the source and destination addresses, and to pass the block size within H:X.
The significance of pre-loading some of the data is that the stack pointer will require adjustment after the return from the sub-routine.
The following code snippet demonstrates the process. The code should be compatible with CW assembler.
; Memory copy sub-routine
; Copy block of memory from source location to destination location.
; Source address and destination address values are pre-loaded to
; the stack prior to the sub-routine call.
; On entry, H:X contains the number of bytes to be copied.
; On exit, Acc value is preserved.
; Stack frame structure (SP index)
SRC EQU 7 ; First pre-loaded value
DEST EQU 5 ; Second pre-loaded value
COUNT EQU 1 ; Byte count yet to be copied
MEMCOPY: cphx #0 ; Test for zero bytes to be copied
beq MC3 ; Exit if so
psha ; Save current value
pshx ; Save byte quantity to stack
pshh
MC1: ldhx SRC,sp ; Current source address
lda ,x ; Fetch byte value
ldhx DEST,sp ; Current destination address
sta ,x ; Write byte value
inc SRC,sp ; Increment source address
inc DEST,sp ; Increment destination address
ldhx COUNT,sp ; Byte counter
beq MC2 ; Exit if final byte copy done
dec COUNT,sp ; Decrement byte count
bra MC1 ; Loop always for next byte
MC2: ais #2 ; Adjust stack pointer
pula ; Restore previous value
MC3: rts
; Typical usage:
; aix #-4 ; Create space on stack
; ldhx #SRC_ADDR
; sthx 3,sp ; Pre-load to stack
; ldhx #DEST_ADDR
; sthx 1,sp ; Pre-load to stack
; ldhx #BLOCK_SIZE
; jsr MEMCOPY
; ais #4 ; Adjust stack pointer
Regards,
Mac
I think there are a few oversights on bigmac's snippet:
* SRC and DST pointers are words, so you can't use INC (for example, use AIX #1 like in the code below)
* Similarly, use AIX #-1 (instead of DEC) for COUNT,SP
* Stack frame offsets are a bit off.
* Typical usage example should start with AIS #-4 (not AIX)
Hello,
Guest wrote:
I think there are a few oversights on bigmac's snippet:
* SRC and DST pointers are words, so you can't use INC (for example, use AIX #1 like in the code below)
* Similarly, use AIX #-1 (instead of DEC) for COUNT,SP
* Stack frame offsets are a bit off.
* Typical usage example should start with AIS #-4 (not AIX)
Thank you for correcting these oversights. The use of inc and dec instructions would have worked had I processed both low and high bytes of the address, which was not done. However, your alternative suggestion does result in more efficient code. Two of the stack frame offsets are actually a "byte" off - the accumulator value was pushed to the stack as an afterthought, without correspondingly adjusting the stack offset values. The corrected code follows -
; Memory copy sub-routine
; Copy block of memory from source location to destination location.
; Source address and destination address values are pre-loaded to
; the stack prior to the sub-routine call.
; On entry, H:X contains the number of bytes to be copied.
; On exit, Acc value is preserved.
; Stack frame structure (SP index)
SRC EQU 8 ; First pre-loaded value
DEST EQU 6 ; Second pre-loaded value
COUNT EQU 1 ; Byte count yet to be copied
MEMCOPY: cphx #0 ; Test for zero bytes to be copied
beq MC3 ; Exit if so
psha ; Save current value
pshx ; Save byte quantity to stack
pshh
MC1: ldhx SRC,sp ; Current source address
lda ,x ; Fetch byte value
aix #1
sthx SRC,sp ; Store incremented address
ldhx DEST,sp ; Current destination address
sta ,x ; Write byte value
aix #1
sthx DEST,sp ; Store incremented address
ldhx COUNT,sp ; Byte counter
beq MC2 ; Exit if final byte copy done
aix #-1
sthx COUNT,sp ; Store decremented byte count
bra MC1 ; Loop always for next byte
MC2: ais #2 ; Adjust stack pointer
pula ; Restore previous value
MC3: rts
; Typical usage:
; ais #-4 ; Create space on stack
; ldhx #SRC_ADDR
; sthx 3,sp ; Pre-load to stack
; ldhx #DEST_ADDR
; sthx 1,sp ; Pre-load to stack
; ldhx #BLOCK_SIZE
; jsr MEMCOPY
; ais #4 ; Adjust stack pointer
Regards,
Mac
Very clear answer, clean implementation made me understand the concept very easily. Thank you
Hello. Link is not working. Thanks.
There is a problem with our server. They're doing some maintenance. Try refreshing the page a few times, or a bit later.
I wasn't able to fully understand your code syntax. When I have some more time I'll try to get t working.
Hi Bruno,
I you have CW10 installed, please look at:
C:\Freescale\CW MCU v10.3\MCU\Help\PDF\HCS08-RS08_Assembler_MCU_Eclipse.pdf
Regards,
David