Topic : Inlining the 32-bit

Forum : ST7/STM8

Original Post
Post Information Post
March 27, 2012 - 12:17am
Guest

Hello,

I am trying to write the far code space on an STM8L151C8 (address 0x10000 and up). To do this, I have a flash program block routine that executes out of RAM, which programs a single 128 byte flash block at a time.

The problem is that in order to write to far addresses, I have to use far pointers and 32-bit variables, which results in

Replies
Post Information Post
+1
0
-1
March 28, 2012 - 11:02am
Raisonance Support Team

Hi,

Your post looks unfinished, but I got the idea: The far code access is very poor on the STM8. This is because there are not enough registers to hold both 24-bit source and destination addresses when performing object-to-object copies.

Here is an hidden treasure, an assembly subroutine that will help you a lot:

;-----------------------------------------------------------------------------
; Function:                 memcpyfar
;-----------------------------------------------------------------------------
; Purpose:  Performs a memcpy with far pointers (24 bits).
;           Works on STM8 only (ST7 not possible).
;-----------------------------------------------------------------------------
; C prototype:
;       unsigned long memcpyfar(unsigned long dest,     /* 32-bit address */
;                               unsigned long src,      /* 32-bit address */
;                               unsigned short num);    /* 16-bit length */
;-----------------------------------------------------------------------------
; WARNING: The data must be INSECTION (cannot cross 64kB boundaries).
;-----------------------------------------------------------------------------

$MODESTM8

    ; Pseudo-registers declaration
    EXTRN DATA0(?BH, ?BL, ?CH, ?CL)

    PUBLIC ?memcpyfar


;-----------------------------------------------------------------------------
; User-defined macro that specifies the CALL/RET model.
;-----------------------------------------------------------------------------

    LARGE   EQU   0             ; Use 1 in RCSTM8 LARGE mode

;-----------------------------------------------------------------------------
; Macros to adapt Library function calls to LARGE model
;-----------------------------------------------------------------------------

$IF(LARGE==1)
BIBRET  MACRO
    RETF
ENDM
BIBCALL MACRO address
    CALLF address
ENDM
BIBJP MACRO address
    JPF address
ENDM
$ELSE
BIBRET  MACRO
    RET
ENDM
BIBCALL MACRO address
    CALL address
ENDM
BIBJP MACRO address
    JP address
ENDM
$ENDIF

;-----------------------------------------------------------------------------
; Equate definition for the Large model, with 1 byte stack offset (CALLF)
;-----------------------------------------------------------------------------

$IF(LARGE==1)
    STKOFF  EQU 1
$ELSE
    STKOFF  EQU 0
$ENDIF

;-----------------------------------------------------------------------------
; This 24-bit storage area will hold the source pointer (high byte is ignored)
;-----------------------------------------------------------------------------

        CSTDLIB_REGISTERS       SEGMENT DATA INPAGE0
        RSEG                    CSTDLIB_REGISTERS

?SRC:   DS      3

;-----------------------------------------------------------------------------
; Actual fmemcpy function start
;-----------------------------------------------------------------------------

        MEMCPYFAR               SEGMENT CODE INSECTION0
        RSEG                    MEMCPYFAR

?memcpyfar:

    ; Copy source pointer into SRC
    LDW     X, (8+STKOFF, SP)
    LDW     ?SRC, X
    LD      A, (10+STKOFF, SP)
    LD      ?SRC+2, A

    ; Copy destination pointer into BX:CX
    LDW     X, (3+STKOFF, SP)
    LDW     ?BH, X
    LDW     X, (5+STKOFF, SP)
    LDW     ?CH, X

    ; Load the counter into X
    LDW     X, (11+STKOFF, SP)

_loop:
    DECW    X
    CPLW    X                       ; Check whether X is FFFFh
    JREQ    _end
    CPLW    X                       ; Restore X's actual value

    LDF     A, ([?SRC.e], X)        ; Loading source byte
    LDF     ([?BL.e], X), A         ; Copying the byte to destination
    JRA     _loop

_end:

    BIBRET

END

Add this in a .asm file in your application, then you can call it as follows:

char mystring[] = "The string to copy";

extern unsigned long memcpyfar(unsigned long dest,     /* 32-bit address */
                               unsigned long src,      /* 32-bit address */
                               unsigned short num);    /* 16-bit length */

void main( void )
{
    /*
       Copy the string to address 01:2345h. This will work ONLY if flash has been unlocked and
       if executing from RAM
    */
    memcpyfar(0x00012345UL, (unsigned long)mystring, sizeof(mystring) + 1);

    while ( 1 );
}

Using this you will have to copy this function to a specific address in RAM (refer to the RCSTM8 compiler documentation that describes this), then write your inram function that uses this as a helper for efficient copy of bytes to destination RAM.

Best Regards,

+1
0
-1
April 9, 2012 - 8:15pm
Guest

Hi Bruno,

Thanks for the response. The forum apparently chopped off half of my post, but I ended up figuring out how to resolve my issue through other posts on this forum.

I basically wrote a flash block program routine that assumes the hi 16-bits of the address stays constant, and the low 16-bits gets incremented to write all 128 bytes of the block. I could do this without invoking any 32-bit variable "helper" functions, and therefore not violating the "must not access flash while programming flash" rule.

Your code looks incredibly useful though. I may have another use for it.

Thank you!

+1
0
-1
April 10, 2012 - 9:54am
Raisonance Support Team

Great job bcoons!