安森美RSL10开发-DSP

软件工具资料下载

注册并下载AISP工具,获取临时授权30天,需要公司邮箱注册,要有公司网站。

相关文档:
RSL10 LPDSP32 Support Manual.pdf
user_guide_lpdsp32_v3.pdf

Jflash下载工具

授权

获取到临时授权后下载并安装相关软件及密钥:
1、ASIP_Programmer_vQ-2020.03_win.exe
2、scl_v2018.06_windows.exe
3、Synopsys_Temp_Key_Site_NEWSITE_snpslmd.lic 由txt后缀更名为lic
4、asip_installation_manual.pdf

建议软件安装目录不要更改!默认即可

LMTOOL设置如下:
在这里插入图片描述

环境变量设置如下:
在这里插入图片描述

在这里插入图片描述

计算机名称如下:
在这里插入图片描述

License修改如下:
在这里插入图片描述

LMstat的命令输出:
在这里插入图片描述

对于授权的延期,可能需要删除目录<C:\Synopsys\SCL\2018.06\admin\license>下的*.lic文件,然后重新启动lmtool中的服务

有时会出现打不开软件提示无授权,这时需要重新启动下LMTOOL工具中的服务!

调试

为了方便调试增加两个环境变量
在这里插入图片描述

  • JTalk.exe的路径:C:\Synopsys\ASIP Programmer\Q-2020.03\win64\bin\WINbin
  • JLinkARM.dll动态库的路径:C:\Program Files\SEGGER\JLink_V750
    需要下载jlink的工具点我

仿真调试

连接硬件调试

调出cmd命令行,键入:

jtalk.exe -c jlink -f 2000

启动类似于GDB Server
在这里插入图片描述
打开ChessDE ASIP Programmer Q-2020.03进行调试。
编译
点击Make
在这里插入图片描述
大致输出如下信息:

bridge -oRelease/DSP_Algorithm Release/main.o Release/CircularQueue.o Release/lpdsp32_init.o -IE:/AISP_CHESSDE_Workspace/AISP_TOOL/lpdsp32-v3_vQ-2020.03_windows/lpdsp32-v3_vQ-2020.03/lib -IE:/AISP_CHESSDE_Workspace/AISP_TOOL/lpdsp32-v3_vQ-2020.03_windows/lpdsp32-v3_vQ-2020.03/lib/isg -g -IUtils -IE:/AISP_CHESSDE_Workspace/AISP_TOOL/lpdsp32-v3_vQ-2020.03_windows/lpdsp32-v3_vQ-2020.03/lib/runtime/include -D__tct_patch__=0 -cDSP_Algorithm.bcf -LE:/AISP_CHESSDE_Workspace/AISP_TOOL/lpdsp32-v3_vQ-2020.03_windows/lpdsp32-v3_vQ-2020.03/lib -LE:/AISP_CHESSDE_Workspace/AISP_TOOL/lpdsp32-v3_vQ-2020.03_windows/lpdsp32-v3_vQ-2020.03/lib/runtime/lib -LE:/AISP_CHESSDE_Workspace/AISP_TOOL/lpdsp32-v3_vQ-2020.03_windows/lpdsp32-v3_vQ-2020.03/lib/softfloat/lib -llpdsp32 -lc -lsoftfloat -lm -a2 -m -fH +work Release/chesswork -plpdsp32
darts -IE:/AISP_CHESSDE_Workspace/AISP_TOOL/lpdsp32-v3_vQ-2020.03_windows/lpdsp32-v3_vQ-2020.03/lib +p -d -IUtils -IE:/AISP_CHESSDE_Workspace/AISP_TOOL/lpdsp32-v3_vQ-2020.03_windows/lpdsp32-v3_vQ-2020.03/lib/runtime/include -D__tct_patch__=0 +Mhex +Ihex -g +u Release/DSP_Algorithm lpdsp32

调试
在这里插入图片描述
再点击start debugging

应用开发

DSP与M3通讯两种方式:共享内存和中断,所以了解熟悉中断的配置,和链接文件是前提。

连接文件lpdsp32.bcf,位于目录C:\Synopsys\ASIP Programmer\Q-2020.03\lpdsp32-v3_vQ-2020.03_windows\lpdsp32-v3_vQ-2020.03\lib

DSP中断向量表
在这里插入图片描述
软件触发中断方式
不可设置IMSK or IE寄存器来屏蔽中断!

//Example operation: sint 0, sint 2 // even vector table address 0, 2, 4, 6, 8….30

//To trigger sint software interrupt instruction
inline assembly int software_interrupt()
clobbers() property(volatile functional loop_free)
{
	asm_begin
	sint 4; nop /*software interrupt */
	asm_end
}
// file lpdsp.bcf
// central link file with default link constraints

_symbol _ivt 0                  // interrupt vector table at PM 0
_entry_point _ivt
_symbol _main_init _after _ivt
_symbol _main _after _main_init

_stack DMA 0xe000 8184   // stack region in DMA (start_address size).
                         // SP is initialised to (start_address + size), which
                         // must be multiple of 8 (to have aligned long access).

_exclusive DMA 0x0 1 // NULL pointer
_exclusive DM 0xC00000 4 // memory location used by OCD debug client for register read/write 

// include to use main(argc,argv) arguments
_always_include _main_argv_area

DSP部分的一小段测试程序

/* ----------------------------------------------------------------------------
 * Copyright (c) 2017 Semiconductor Components Industries, LLC (d/b/a
 * ON Semiconductor), All Rights Reserved
 *
 * This code is the property of ON Semiconductor and may not be redistributed
 * in any form without prior written permission from ON Semiconductor.
 * The terms of use and warranty for this code are covered by contractual
 * agreements between ON Semiconductor and the licensee.
 *
 * This is Reusable Code.
 *
 * -----------------------------------------------------------------------------
 */

#include <stdlib.h>
#include <stdint.h>

// Define the location of the CSS command register, this would normally be
// taken from a standard include file however to provide clarity in this
// example we will define it explicitly
#define CSS_CMD                         0xC00004

// Define the specific interrupt that the ARM will trigger when it wants
// us to perform a calculation
#define CSS_CMD_0                       (1<<0)

// Define the shared memory between the ARM and LPDSP processors
uint32_t chess_storage(DMB:0x00803800) sharedMemory[2];

// Define the interrupt register to notify the ARM of a completed operation
volatile static unsigned char chess_storage(DMIO:CSS_CMD) CssCmdGen;

// handling requests from the CM3 is activated
static volatile int actionRequired;

/* ----------------------------------------------------------------------------
 * Function : isr0
 * ----------------------------------------------------------------------------
 * Description : Interrupt service routine invoked on request from the CM3
 * Inputs : None
 * Outputs : sets flag indicating work needs to be done
 * Assumptions : None
 * ----------------------------------------------------------------------------
 */
extern "C" void isr0() property (isr) {
	// raise the flag indicating something needs to be processed
	actionRequired = true;
}

/* ----------------------------------------------------------------------------
 * Function : fibonacci
 * ----------------------------------------------------------------------------
 * Description : calculate the nth fibonacci number where:
 *                  0 is 0,
 *                  1 is 1,
 *                  2 is 1,
 *                  3 is 2, etc
 *
 * Inputs : nth, the number of the fibonacci sequence to return
 *
 * Outputs : the fibonacci number as defined above, or 0xFFFFFFFF if overflow
 *
 * Assumptions : None
 * ----------------------------------------------------------------------------
 */
uint32_t fibonacci(uint32_t nth) {
    
    // we know the 48th fibonacci number will be too large for a uint32_t
    if (nth >= 48)
        return 0xFFFFFFFF;

    // deal with trivial cases
    if ((nth == 0) || (nth == 1))
        return nth;

    // otherwise calculate the return value in a loop
    uint32_t value = 0, first = 0, second = 1;
    while (nth-- > 1) {
        value = first + second;
        first = second;
        second = value;
    }
    return value;
}

/* ----------------------------------------------------------------------------
 * Function : main
 * ----------------------------------------------------------------------------
 * Description : The main entry point for the program
 *
 * 	Note: this halts the core when not busy and is awoken by an interrupt
 *      from the CM3
 *
 * Inputs : None
 *
 * Outputs : returns zero but the code is not expected to ever complete
 *
 * Assumptions : None
 * ----------------------------------------------------------------------------
 */
extern "C" int main(void) {
    
    // assume nothing ready to be processed yet
    actionRequired = false;

    // enable the interrupts
    enable_interrupts();
    
    // spin forever, waiting for interrupts from the CM3
    while (true) {        
        core_halt();

        // only do something if we are responding to an interrupt from the CM3
        if (actionRequired == true) {
            actionRequired = false;

            // calculate the nth fibonacci number
            sharedMemory[1] = fibonacci(sharedMemory[0]);
            
            // notify the CM3 that we have completed processing
            CssCmdGen = CSS_CMD_0;
        }

    }
    
    return 0;
}

DSP通知 M3内核触发中断,方式:
volatile static unsigned char chess_storage(DMIO:CSS_CMD) CssCmdGen;
#define CSS_CMD_0 (1<<0)
CssCmdGen = CSS_CMD_0;

M3通知DSP触发中断,方式:
/* Tell the DSP there is data available to deal with. */
SYSCTRL_DSS_CMD->DSS_CMD_1_ALIAS = DSS_CMD_1_BITBAND;

DSP汇编中的中断向量表:
在这里插入图片描述
定义一个中断服务函数
在默认的初始化代码中,由于没有定义中断,任何硬件/软件中断都会从ISR向量返回。
定义一个中断:

  • 在中断向量表中使用jp
  • 使用这个标签来描述这个中断。
.text global 0 _main_init
      r = 1          // enable rounding
      s = 1          // enable saturation
      sp = _sp_start_value_DMA // init SP (adjusted to stack in lpdsp.bcf)	
      ie = 1  ; nop  // enable interrupts

// area to load main() arguments 
.bss global 0 _main_argv_area DMA 256

//step 1
.undef global text isr0

// the interrupt vector table with 15 interrupts
.text global 0 _ivt
	jp _main_init    // 0  - reset
	reti ; nop       // 2  - interrupt 1
	reti ; nop       // 4  - interrupt 2
	reti ; nop       // 6  - interrupt 3
	reti ; nop       // 8  - interrupt 4
	reti ; nop       // 10 - interrupt 5
	reti ; nop       // 12 - interrupt 6
	reti ; nop       // 14 - interrupt 7
	reti ; nop       // 16 - interrupt 8
	reti ; nop       // 18 - interrupt 9
	jp isr0          // 20 - interupt 10 mapped to ISR from ARM
	reti ; nop       // 22 - interrupt 11
	reti ; nop       // 24 - interrupt 12
	reti ; nop       // 26 - interrupt 13
	reti ; nop       // 28 - interrupt 14
	reti ; nop       // 30 - interrupt 15

在C文件中添加如下:

extern "C" void isr0(void) property(isr)
{

}

链接文件设置
在这里插入图片描述
在这里插入图片描述

共享内存
M3内存地址:0x20011800 ,对应DSP内存区域:0x00803800 in the DMB memory space
我们可以指定变量内存地址,共用一块内存。

PRAM区域:40KB大小
DSP_DRAM区域:48KB大小 0x0080 0000 - 0x0080 C000(DSP中的地址)
共享内存区域:2KB大小 0x0080 3800 + 0x0080 4000(DSP中的地址)
中断
lpdsp32_init.s中断向量表修改如下:

// initialisation before entering the main function.
.text global 0 _main_init
      r = 1          // enable rounding
      s = 1          // enable saturation
      sp = _sp_start_value_DMA // init SP (adjusted to stack in lpdsp.bcf)	
      ie = 1  ; nop  // enable interrupts

// area to load main() arguments 
.bss global 0 _main_argv_area DMA 256

.undef global text isr_DSS_CMD_0_BITBAND
.undef global text isr_DSS_CMD_1_BITBAND
.undef global text isr_DSS_CMD_2_BITBAND
.undef global text isr_DSS_CMD_3_BITBAND
.undef global text isr_DSS_CMD_4_BITBAND
.undef global text isr_DSS_CMD_5_BITBAND
.undef global text isr_DSS_CMD_6_BITBAND

// the interrupt vector table with 15 interrupts
.text global 0 _ivt
	jp _main_init    // 0  - reset
	reti ; nop       // 2  - interrupt 1
	reti ; nop       // 4  - interrupt 2
	reti ; nop       // 6  - interrupt 3
	reti ; nop       // 8  - interrupt 4
	reti ; nop       // 10 - interrupt 5
	reti ; nop       // 12 - interrupt 6
	reti ; nop       // 14 - interrupt 7
	reti ; nop       // 16 - interrupt 8
	jp isr_DSS_CMD_0_BITBAND          // 18 - interupt 9 mapped to ISR from ARM
	jp isr_DSS_CMD_1_BITBAND          // 20 - interupt 10 mapped to ISR from ARM
	jp isr_DSS_CMD_2_BITBAND          // 22 - interupt 11 mapped to ISR from ARM
	jp isr_DSS_CMD_3_BITBAND          // 24 - interupt 12 mapped to ISR from ARM
	jp isr_DSS_CMD_4_BITBAND          // 26 - interupt 13 mapped to ISR from ARM
	jp isr_DSS_CMD_5_BITBAND          // 28 - interupt 14 mapped to ISR from ARM
	jp isr_DSS_CMD_6_BITBAND          // 30 - interupt 15 mapped to ISR from ARM

中断服务修改如下:
main.c

/* ----------------------------------------------------------------------------
 * Function : isr_DSS_CMD_0_BITBAND
 * ----------------------------------------------------------------------------
 * Description : Interrupt service routine invoked on request from the CM3
 * Inputs : None
 * Outputs : sets flag indicating work needs to be done
 * Assumptions : None
 * ----------------------------------------------------------------------------
 */
extern "C" void isr_DSS_CMD_0_BITBAND() property (isr) 
{
	// raise the flag indicating something needs to be processed
}

/* ----------------------------------------------------------------------------
 * Function : isr_DSS_CMD_1_BITBAND
 * ----------------------------------------------------------------------------
 * Description : Interrupt service routine invoked on request from the CM3
 * Inputs : None
 * Outputs : sets flag indicating work needs to be done
 * Assumptions : None
 * ----------------------------------------------------------------------------
 */
extern "C" void isr_DSS_CMD_1_BITBAND() property (isr) 
{
	// raise the flag indicating something needs to be processed
}

/* ----------------------------------------------------------------------------
 * Function : isr_DSS_CMD_2_BITBAND
 * ----------------------------------------------------------------------------
 * Description : Interrupt service routine invoked on request from the CM3
 * Inputs : None
 * Outputs : sets flag indicating work needs to be done
 * Assumptions : None
 * ----------------------------------------------------------------------------
 */
extern "C" void isr_DSS_CMD_2_BITBAND() property (isr) 
{
	// raise the flag indicating something needs to be processed
}

/* ----------------------------------------------------------------------------
 * Function : isr_DSS_CMD_3_BITBAND
 * ----------------------------------------------------------------------------
 * Description : Interrupt service routine invoked on request from the CM3
 * Inputs : None
 * Outputs : sets flag indicating work needs to be done
 * Assumptions : None
 * ----------------------------------------------------------------------------
 */
extern "C" void isr_DSS_CMD_3_BITBAND() property (isr) 
{
	// raise the flag indicating something needs to be processed
}

/* ----------------------------------------------------------------------------
 * Function : isr_DSS_CMD_4_BITBAND
 * ----------------------------------------------------------------------------
 * Description : Interrupt service routine invoked on request from the CM3
 * Inputs : None
 * Outputs : sets flag indicating work needs to be done
 * Assumptions : None
 * ----------------------------------------------------------------------------
 */
extern "C" void isr_DSS_CMD_4_BITBAND() property (isr) 
{
	// raise the flag indicating something needs to be processed
}

/* ----------------------------------------------------------------------------
 * Function : isr_DSS_CMD_5_BITBAND
 * ----------------------------------------------------------------------------
 * Description : Interrupt service routine invoked on request from the CM3
 * Inputs : None
 * Outputs : sets flag indicating work needs to be done
 * Assumptions : None
 * ----------------------------------------------------------------------------
 */
extern "C" void isr_DSS_CMD_5_BITBAND() property (isr) 
{
	// raise the flag indicating something needs to be processed
}

/* ----------------------------------------------------------------------------
 * Function : isr_DSS_CMD_6_BITBAND
 * ----------------------------------------------------------------------------
 * Description : Interrupt service routine invoked on request from the CM3
 * Inputs : None
 * Outputs : sets flag indicating work needs to be done
 * Assumptions : None
 * ----------------------------------------------------------------------------
 */
extern "C" void isr_DSS_CMD_6_BITBAND() property (isr) 
{
	// raise the flag indicating something needs to be processed
}

M3发送通知,DSP触发中断

SYSCTRL_DSS_CMD->DSS_CMD_0_ALIAS = DSS_CMD_0_BITBAND;/**< 触发isr_DSS_CMD_0_BITBAND中断*/

集成固化

DSP执行地址为:0x00220000 size:40K

If we bind the LPDSP32 code to the Arm Cortex-M3 core executable in some way, we can utilize the Arm
Cortex-M3 core to perform the loading operation. The Arm Cortex-M3 core application would normally reside in flash,
so we can store the LPDSP32 program with the Arm Cortex-M3 core and then have the Arm Cortex-M3 core copy the
data over as part of the initialization stage. RSL10 also provides an efficient Flash Copier block which can be employed
by the Arm Cortex-M3 core to enable this.
通常我们将代码二进制保存到flash中,M3启动后进行加载dsp代码到dsp的执行地址。

从DSP编译生成的二进制文件中提取code与数据
首先确保已经安装python,我的版本Python 3.9.6

工具用python写的,键入以下命令安装 elf文件解析工具:

python -m pip install pyelftools

生成如下数据:

typedef struct
{
	void *buffer;
	uint32_t fileSize;
	uint32_t memSize;
	uint32_t vAddress;
} memoryDescription;

uint8_t __attribute__ ((section (".dsp"))) echo_dsp_DM_Lo_0[] = { };
uint8_t __attribute__ ((section (".dsp"))) echo_dsp_DM_Lo_8[] = { };
uint8_t __attribute__ ((section (".dsp"))) echo_dsp_DM_Lo_264[] = { 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0xff, };
uint8_t __attribute__ ((section (".dsp"))) echo_dsp_DM_Lo_32760[] =
{ };
memoryDescription __attribute__ ((section (".dsp"))) echo_dsp_DM_Lo_SegmentList[] =
{
	/*buffer,          fileSize,   memSize,  vAddress*/
	{ echo_dsp_DM_Lo_0, 0x00000000, 0x00000008, 0x00000000 },
	{ echo_dsp_DM_Lo_8, 0x00000000, 0x00000100, 0x00000008 },
	{ echo_dsp_DM_Lo_264, 0x00000010, 0x00000010, 0x00000108 },
	{ echo_dsp_DM_Lo_32760, 0x00000000, 0x00008000, 0x00007ff8 },
};

typedef struct
{
	memoryDescription *entries;
	uint32_t count;
} memoryOverviewEntry;

typedef struct
{
	memoryOverviewEntry PM;
	memoryOverviewEntry DMH;
	memoryOverviewEntry DML;
} memoryOverview;

/*总览*/
memoryOverview echo_dsp_Overview =
{
	/*memoryDescription ,count */
	{ echo_dsp_PM_SegmentList, 3 },
	{ echo_dsp_DM_Hi_SegmentList, 1 },
	{ echo_dsp_DM_Lo_SegmentList, 4 }
};

使用方法
拷贝elfConvert文件夹到DSP工程根目录,即与*.prx文件同级目录

# 新建auto目录后,执行如下命令
python elfConvert\elfConverter.py --elf Release\echo --output auto --tag echo_dsp

# 1、命令行中echo为编译生成的二进制文件名
# 2、echo_dsp是你对生成的文件,需要加的文件名前缀
# 3、auto指定生成的文件到auto目录下

对于脚本文件需要作下修改的,否则运行错误,其实写了修改过程的,但是操蛋的win11给我死机了,直接贴出来,自己用对比软件查看
DSPMemoryIntegrator.py文件

# ----------------------------------------------------------------------------
# Copyright (c) 2017 Semiconductor Components Industries, LLC (d/b/a
# ON Semiconductor), All Rights Reserved
#
# This code is the property of ON Semiconductor and may not be redistributed
# in any form without prior written permission from ON Semiconductor.
# The terms of use and warranty for this code are covered by contractual
# agreements between ON Semiconductor and the licensee.
#
# This is Reusable Code.
#
# -----------------------------------------------------------------------------
#

from struct import unpack
from DSPSegmentKey import DSPSegmentKey

# Define base and extent of the PM, DM_High and DM_Low memory areas
#
_PM_BASE        = 0x00000000
_PM_TOP         = 0x00200000

_DM_LOW_BASE    = 0x00000000
_DM_LOW_TOP     = 0x00010000

_DM_HIGH_BASE   = 0x00800000
_DM_HIGH_TOP    = 0x00804000

# Define the segment type tags used by the LPDSP32 ELF file to identify the
# Memory Map and Memory Name segments
# 
_LPDSP32_SEGMENT_MEMORY_MAP  = 0x70123456
_LPDSP32_MEMORY_NAMES        = 0x70123457

class DSPMemoryIntegrator(object):
    '''
    This class provides the hooks to convert the memory segments stored
    in an LPDSP32 ELF file into C header and source files which can be
    incorporated into a CM3 program.
    '''
    
    def __init__(self, elf, output, tag, v1):
        '''
        Constructor
        
        elf
            An ELFFile object that has already parsed the original file into
            parsable structures
        output
            The folder to which the generated files will be written
        tag
            A tag that is used when creating file and structure names so that
            they are identifiable by the CM3
        v1
            Flag indicating of old style formatting should be handled.
        '''
        self.elf = elf
        self.output = output
        self.tag = tag
        self._unpackUint32 = ">LL" if v1 else "<LL"
        self._divisor = 3 if v1 else 1 
        self._createSegmentTypeMapping()
        
    def _uint32Generator(self, segmentData):
        ''' generate a uint32_t item from packed data ''' 
        for chunk in [segmentData[i:i+8] for i in range(0, len(segmentData), 8)]:
            yield unpack(self._unpackUint32, chunk)
        
    def _createSegmentMap(self, segmentData):
        ''' create a single segment mapping table '''
        self._segmentMap = dict(pair for pair in self._uint32Generator(segmentData))
    
    def _createSegmentTypeMapping(self):
        '''
        Construct a mapping table so we can recover the types of segments later
        '''
        self._segmentIndexMap = {}
        for index in range(self.elf.num_segments()):
            segment = self.elf.get_segment(index)
            self._segmentIndexMap[DSPSegmentKey(segment.header, segment.data())] = index
            if segment.header.p_type == _LPDSP32_MEMORY_NAMES:
                self._segmentTypes = segment.data()
            elif segment.header.p_type == _LPDSP32_SEGMENT_MEMORY_MAP:
                self._createSegmentMap(segment.data())
        
    def _segmentTypeString(self, index):
        ''' retrieve the segment type string '''
        interesting = self._segmentTypes[index:].decode().split('\0')
        return interesting[0]
    
    def _segmentType(self, segment):
        ''' retrieve the type of LOADable segments '''
        if segment.header.p_type == 'PT_LOAD':
            segIndex = self._segmentIndexMap[DSPSegmentKey(segment.header, segment.data())]
            segTypeIndex = self._segmentMap[segIndex]
            return self._segmentTypeString(segTypeIndex)
        return None
    
    def _area(self, areaName):
        ''' helper routine defining an area name format '''
        return "%s_%s" % (self.tag, areaName)
    
    # When creating the memory overview header, we define the memoryOverview and
    # memoryOverviewEntry using conditional compilation, this may be defined in
    # multiple header files as each module is standalone. The conditional
    # compilation ensures we don't get compilation errors if more than one
    # header file is included.
    def _createMemoryOverviewHeader(self, pmTag, dmhTag, dmlTag):
        ''' Create a memory overview file '''
        define = "_%s_H_" % (self.tag)
        header = "%s/%s.h" % (self.output, self.tag)
        with open(header, "w") as output:
            output.write("#ifndef %s\n" % define.upper())
            output.write("#define %s 1\n" % define.upper())
            output.write("\n")
            output.write("/* Auto generated file\n")
            output.write(" */\n")
            output.write("\n")
            output.write("#include <stdint.h>\n")
            output.write("#include <utilities.h>\n")
            output.write("\n")
            output.write("#include \"%s.h\"\n" % self._area(pmTag))
            output.write("#include \"%s.h\"\n" % self._area(dmhTag))
            output.write("#include \"%s.h\"\n" % self._area(dmlTag))
            output.write("\n")
            output.write("#ifndef _MEMORY_OVERVIEW_DESCRIPTION_\n")
            output.write("#define _MEMORY_OVERVIEW_DESCRIPTION_ 1\n")
            output.write("\n")
            output.write("typedef struct {\n")
            output.write("    const memoryDescription *entries;\n")
            output.write("    uint32_t                count;\n")
            output.write("} memoryOverviewEntry;\n")                
            output.write("\n")
            output.write("typedef struct {\n")
            output.write("    memoryOverviewEntry    PM;\n")
            output.write("    memoryOverviewEntry    DMH;\n")
            output.write("    memoryOverviewEntry    DML;\n")
            output.write("} memoryOverview;\n")                
            output.write("\n")
            output.write("#endif\n")
            output.write("\n")
            output.write("extern USED memoryOverview %s_Overview SECTION(\".dsp\");\n" % self.tag)
            output.write("\n")
            output.write("#endif\n")

    def _findSegments(self, tag, base, top):
        '''
        find all segments of the defined type, which are contained within the
        bounds of the "base" and "top" indicators
        '''
        segments = []
        for segment in self.elf.iter_segments():
            if self._segmentType(segment) == tag:
                if (segment.header.p_vaddr >= base) and (segment.header.p_vaddr < top):
                    segments.append(DSPSegmentKey(segment.header, segment.data()))
        return segments
        
    def _overviewSegments(self, area, suffix, base, top):
        ''' helper method to provide a single segment in a standard form '''
        compositeName = area if suffix == '' else "%s_%s" % (area, suffix)
        listName = "%s_%s_SegmentList" % (self.tag, compositeName)
        segments = self._findSegments(area, base, top)
        return "    {%s, %d}" % (listName, len(segments)) if len(segments) > 0 else None
    
    def writeOverviewSegments(self, output, text):
        if text is None:
            return
        output.write("%s,\n" % text)
        
    def _createMemoryOverview(self, pm, pmSuffix, dmh, dmhSuffix, dml, dmlSuffix):
        ''' Create the memory overview structure '''
        source = "%s/%s.c" % (self.output, self.tag)
        with open(source, "w") as output:
            output.write("/* Auto generated file\n")
            output.write(" */\n")
            output.write("\n")
            output.write("#include \"%s.h\"\n" % self.tag)
            output.write("\n")
            output.write("memoryOverview %s_Overview = {\n" % self.tag)
            self.writeOverviewSegments(output, self._overviewSegments(pm, pmSuffix, _PM_BASE, _PM_TOP))
            self.writeOverviewSegments(output, self._overviewSegments(dmh, dmhSuffix, _DM_HIGH_BASE, _DM_HIGH_TOP))
            self.writeOverviewSegments(output, self._overviewSegments(dml, dmlSuffix, _DM_LOW_BASE, _DM_LOW_TOP))
            output.write("};\n")
            output.write("\n")

    def _createMemorySource(self, areaName, suffix, generator):
        '''
        Create a C source file containing descriptions of each memory section
        in the specified memory area.
        '''
        compositeName = areaName if suffix == '' else "%s_%s" % (areaName, suffix)
        taggedName = self._area(compositeName)
        source = "%s/%s.c" % (self.output, taggedName)
        header = "%s.h" % taggedName
        with open(source, "w") as output:
            output.write("/* Auto generated file\n")
            output.write(" */\n")
            output.write("\n")
            output.write("#include \"%s\"\n" % header)
            output.write("\n")
            for line in generator(areaName, taggedName):
                output.write("%s\n" % line)
            output.write("\n")
    
    # When creating the memory header, we define the memoryDescription structure
    # using conditional compilation, this may be defined in multiple header
    # files as each module is standalone. The conditional compilation ensures
    # we don't get compilation errors if more than one header file is included.
    def _createMemoryHeader(self, areaName, suffix, generator):
        '''
        Create a header file describing the contents of the C file associated
        with the given memory space.
        '''
        compositeName = areaName if suffix == '' else "%s_%s" % (areaName, suffix)
        taggedName = self._area(compositeName)
        header = "%s/%s.h" % (self.output, taggedName)
        define = "_%s_H_" % (taggedName)
        with open(header, "w") as output:
            output.write("#ifndef %s\n" % define.upper())
            output.write("#define %s 1\n" % define.upper())
            output.write("\n")
            output.write("/* Auto generated file\n")
            output.write(" */\n")
            output.write("\n")
            output.write("#include <stdint.h>\n")
            output.write("#include <utilities.h>\n")
            output.write("\n")
            output.write("#ifndef _MEMORY_DESCRIPTION_\n")
            output.write("#define _MEMORY_DESCRIPTION_ 1\n")
            output.write("\n")
            output.write("typedef struct {\n")
            output.write("    const void  *buffer;\n")
            output.write("    uint32_t    fileSize;\n")
            output.write("    uint32_t    memSize;\n")
            output.write("    uint32_t    vAddress;\n")
            output.write("} memoryDescription;\n")                
            output.write("\n")
            output.write("#endif\n")
            output.write("\n")
            output.write("extern USED const memoryDescription %s_SegmentList[] SECTION(\".dsp\");\n" % taggedName)
            output.write("\n")
            output.write("#endif\n")
    
    def _highByte40(self, b):
        ''' fetch high byte of 40 bit encoded program word '''
        return format(b, '#04x')
    
    def _midByte40(self, b1, b2):
        ''' fetch middle byte of 40 bit encoded program word '''
        return format((b1 & 0x0f) | ((b2 << 4) & 0xf0), '#04x')
    
    def _lowByte40(self, b1, b2):
        ''' fetch low byte of 40 bit encoded program word '''
        return format(((b1 >> 4) & 0x0f) | ((b2 << 4) & 0xf0), '#04x')
    
    def _fortyBit(self, chunk):
        ''' fetches the next program word as a encoded 40 bit value '''
        if len(chunk) != 6:
            raise ValueError("Unexpected PM Size")
        
        return "    %s, %s, %s, %s, %s," % \
            (self._highByte40(chunk[5]), self._highByte40(chunk[4]),
             self._midByte40(chunk[3], chunk[2]),
             self._lowByte40(chunk[2], chunk[1]), self._lowByte40(chunk[1], chunk[0]))
    
    def _thirtyTwoBit(self, chunk):
        '''
        Fetches the next 32 bits of data, padding it if the remaining data
        is not big enough
        '''
        while len(chunk) < 4:
            chunk.append(0)
        return ", ".join(format(b, '#04x') for b in chunk)
    
    def _listSegments(self, tag, segments, divisor=1):
        '''
        Method to provide the data for each segment in a defined format for
        the overview sections.
        '''
        if len(segments) > 0:    
            yield "USED const memoryDescription %s_SegmentList[] SECTION(\".dsp\") = {" % tag
            for segment in segments:
                yield "    {%s_%s, 0x%08x, 0x%08x, 0x%08x}," % (tag, segment.vaddr, int(segment.filesz), int(segment.memsz), int(segment.vaddr / divisor) )
            yield "};\n"
        
    def _PMGenerator(self, areaName, tag):
        '''
        Generator for a given program memory segment
        
        This will create the initial data array for each provided segment and
        then an overview table which provides details of each memory area
        in the file and how to access it.
        '''        
        segments = self._findSegments(areaName, _PM_BASE, _PM_TOP)
        for segment in segments:
            yield "USED const uint8_t %s_%s[] SECTION(\".dsp\") = {" % (tag, segment.vaddr)
            data = bytearray(segment.data)
            for chunk in [data[i:i+6] for i in range(0, len(data), 6)]:
                yield self._fortyBit(chunk)
            yield "};\n"
            
        for line in self._listSegments(tag, segments, self._divisor):
            yield line 
        
    def _paddedAndAligned(self, data, address):
        '''
        This ensures that each data area is correctly aligned and padded to full
        word boundaries. This is necessary to ensure the Flash Copier can be
        effectively used by the CM3 when loading the data area.
        '''
        result = bytearray(data)
        
        # If we don't start on a word boundary, insert bytes at the start
        bytesToAdd = address & 3
        while (bytesToAdd > 0):
            result.insert(0, 0)
            bytesToAdd -= 1

        # if we don't end on a word boundary, append bytes at the end
        while (len(result) & 3) > 0:
            result.append(0)        
                
        return result
        
    def _DMGenerator(self, tag, segments):
        '''
        Generator for a given data memory segment
        
        This will create the initial data array for each provided segment and
        then an overview table which provides details of each memory area
        in the file and how to access it.
        '''
        # Process each segment in turn
        for segment in segments:
            yield "USED const uint8_t %s_%s[] SECTION(\".dsp\") = {" % (tag, segment.vaddr)
            data = self._paddedAndAligned(segment.data, segment.vaddr)
            for chunk in [data[i:i+4] for i in range(0, len(data), 4)]:
                yield "    %s," % self._thirtyTwoBit(chunk)
            yield "};\n"
                    
        # Create the memory area overview for this type of memory 
        for line in self._listSegments(tag, segments):
            yield line 
        
    def _DMLowGenerator(self, areaName, tag):
        '''
        Generator which provides the segment details for the high data memory 
        '''
        segments = self._findSegments(areaName, _DM_LOW_BASE, _DM_LOW_TOP)
        for line in self._DMGenerator(tag, segments):
            yield line 
        
    def _DMHighGenerator(self, areaName, tag):
        '''
        Generator which provides the segment details for the high data memory 
        '''
        segments = self._findSegments(areaName, _DM_HIGH_BASE, _DM_HIGH_TOP)
        for line in self._DMGenerator(tag, segments):
            yield line 
    
    def _createMemoryFiles(self, areaName, suffix, generator):
        '''
        Create the source and header files associated with a single memory area
        '''
        self._createMemorySource(areaName, suffix, generator)
        self._createMemoryHeader(areaName, suffix, generator)
    
    def parseMemoryAreas(self):
        '''
        This is the only public method in this class and it manages the
        extraction process for each of the memory areas and then creates the
        overview files
        '''
        self._createMemoryFiles('PM', '', self._PMGenerator)
        self._createMemoryFiles('DM', 'Hi', self._DMHighGenerator)
        self._createMemoryFiles('DM', 'Lo', self._DMLowGenerator)
        
        self._createMemoryOverviewHeader('PM', 'DM_Hi', 'DM_Lo')
        self._createMemoryOverview('PM', '', 'DM', 'Hi', 'DM', 'Lo')

新建utilities.h文件,内容如下:

#ifndef UTILITIES_H
#define UTILITIES_H

#ifndef SECTION
  #ifdef __CC_ARM                        /* ARM Compiler */
      #define SECTION(x)                 __attribute__((section(x)))
      #define USED                       __attribute__((used))
      #define UNUSED_CODE                __attribute__((unused))
  #elif defined (__IAR_SYSTEMS_ICC__)    /* for IAR Compiler */
      #define SECTION(x)                 @ x
      #define USED                       __root
      #define UNUSED_CODE                     
  #elif defined (__GNUC__)               /* GNU GCC Compiler */
      #define SECTION(x)                 __attribute__((section(x)))
      #define USED                       __attribute__((used))
      #define UNUSED_CODE                __attribute__((unused))
  #else
      #error not supported tool chain
  #endif /* __CC_ARM */
#endif

#endif
/******************************** End of file *********************************/

加入到M3的编译环境中,同时也加入以下生成的文件

命令执行完毕后生成如下文件:

# 位于auto目录下
echo_dsp.c
echo_dsp.h
echo_dsp_DM_Hi.c
echo_dsp_DM_Hi.h
echo_dsp_DM_Lo.c
echo_dsp_DM_Lo.h
echo_dsp_PM.c
echo_dsp_PM.h

M3中加载
官方提供了示例代码,flashCopier.cloader.c

static void g722PLCDSPInitialise(CODEC codec)
{
    pBaseDSPCodec object  UNUSED_CODE = getDSPCodec(codec);
    SYSCTRL->DSS_CTRL = DSS_LPDSP32_PAUSE;
    loadDSPMemory(&g722_plc_dsp_Overview);
    SYSCTRL->DSS_CTRL = DSS_LPDSP32_RESUME;
}

编译注意事项

添加源文件

在这里插入图片描述

设置头文件路径

在这里插入图片描述

消除“__”符号内部保留不给使用问题

使用如下设置,当然这是官方不推荐的设置。
在这里插入图片描述
更多的设置使用参考chess_user-manual.pdf文档

编程注意事项

指针的使用

因为双核通讯涉及到共享内存,所以操作指针尤其注意指针赋值和引用问题,《RSL10 LPDSP32 Support Manual》第16页,4.2.3 Shared Memory一章中提及。

For the purposes of this example, we need two words that are visible to both the Arm Cortex-M3 core and the
LPDSP32. We can choose any suitable locations, provided we take care to avoid other items that may be trying to share
the space. For now we will allocate the words at fixed locations that we know are not conflicting. From the Arm
Cortex-M3 core, we use two words based at address 0x20011800.
These appear in the memory map of the LPDSP32 at location 0x00803800 in the DMB memory space.

对于相同的内存地址,在地址映射关系是不同的,分别有各自的地址,所以对使用同一个指针,去操作里面的数据是有问题的!

变量地址

DMA address range 0,8388607
DMB address range 8388608,12582911

链接文件bcf的修改

可查看官方文档
在这里插入图片描述

Entry point

# 方式一
_entry_point symbol

# 方式二
_entry_point addr

_entry_point 1000 // start execution at address 1000
_entry_point _ivt // take _ivt as start symbol (to be put on 1000).

Memory Regions

# 栈区域
_stack memory address-range

# 跳过堆栈对齐检查,不建议
_stack memory address-range _no_check

# 保留内存区域-指明不可自动分配占用
_reserved memory address-range

# 指明只读属性内存,代码,常量,和constmem段,对应于函数中需要的常量值池会分配到这里
# 可以使用 +w 链接器选项从只读内存区域排除constmem部分(以便将它们映射到可写内存)。
_rodata memory address-range

# 不是所有符号都适用于只读属性内存,链接会出现错误,除非配置文件中添加如下指令
_prefer_read_only

# 只有符号不可以映射到独占属性之外的内存,他才可以声明为独占属性内存,实现几种方式:它可以在区域内有一个固定的地址,或者它可以有一个地址范围,这个地址范围是排他范围的子范围,或者它可以分配给一个内存子范围别名,它完全被排他范围覆盖
_exclusive memory address-range

# .bss段的初始化,一般以零初始化,以其他值初始化,使用以下语句
_fill memory address-range fill-value

对常量存储地址的指定

.bss .data等段的含义

_mapping _in_range _type .bss DMA 0x5000 .. 0x9800 
_mapping _in_range _type .data DMA 0x5000 .. 0x9800 
_mapping _in_range _type .rodata DMA 0x5000 .. 0x9800 

Sort Symbols Before Mapping

# 默认情况下,符号会按照它们在object文件中出现的顺序映射到内存中(但请考虑§3.3中讨论的single_symbol_sections的影响)
# 从左到右处理命令行上指定的不同对象文件
# 命令行上指定的归档的对象文件部分在命令行上指定的对象文件之后被处理
# 归档的Object文件部分按照它们在归档中出现的顺序进行处理
# 归档按照命令行上从左到右指定的方式进行处理
# 在第一个过程中,所有文本符号的数据都被映射
# 在第二次传递中,所有空间(.bss)符号都被映射
# 每个符号都根据其大小和对齐约束进行映射
# 当然,由符号(映射)语句处理的符号是首先映射的

# To sort the symbols during mapping, the following configuration statements can be used:
_symbol_sort what how memory
# The what field must be one of:
alignment
alignment_only
mem_size
size
size_only
type

Symbol Addresses

使用_afteror_next必须是同一块内存。

# 指定符号存放地址
_symbol symbol addr

# 如果一个已定义的函数符号或具有名称符号的对象符号存在于一个要链接的对象文件中,
# 该符号将被放置在该符号所属的内存地址addr处。
# 要把一个符号放在另一个符号之后,可以使用下面的语句:
_symbol symbol2 _after symbol1

# 如果名称为symbol2的全局函数符号或全局对象符号存在于要链接的对象文件中,
# 则该符号将直接放在名称为symbol1的符号之后。
# 要将一个符号放在前面_symbol行中指定的符号之后,而不重复前面_symbol行中符号的名称,请使用_next语句:
_symbol symbol _next

# 将符号放入一个内存区域范围
_symbol symbol address-range

# 将符号放入指定段中
_symbol symbol _in_segment segment

Symbol Alignment

带有名称符号的已定义函数符号或对象符号将被放置,以使指定的对齐约束得到遵守。对齐值的指定应该考虑到符号映射到的内存。例如,当4字节整数对象的对齐约束为4(在一个字节可寻址内存中)时,您可以将对齐约束增加为的倍数
链接器配置文件中的4,但不能以非4的倍数减少或增加。在后一种情况下,链接会因错误而停止。

_align symbol alignment

Symbol Wrapping

意义不大

# 封装符号两种
_wrap symbol
_real symbol

# 原始bcf
_symbol value_table 0x1000 (also when using range)
_symbol __real_value_table 0x1000 (also when using range)
_symbol value_table _after _ivt (also when using _next shorthand)
_symbol __real_value_table _after _ivt (also when using _next shorthand)
_symbol _ivt _after value_table (also when using _next shorthand)
_symbol _ivt _after __real_value_table (also when using _next shorthand)
# will be executed as:
_symbol __wrap_value_table 0x1000
_symbol value_table 0x1000
_symbol __wrap_value_table _after _ivt
_symbol value_table _after _ivt
_symbol _ivt _after __wrap_value_

符号引用

所有对这个__StackLimit 符号的引用将得到值0x9800 ,不会有任何对齐或自由空间检查。

# C文件引用符号:
extern int __StackLimit ;

# bcf文件定义符号
_symbol __StackTop 0xAFFF //0x9800 + 0x1800 
_extern __StackTop

_symbol __StackLimit 0x9800 //Stack Base Addr 0x9800
_extern __StackLimit

将在.map文件中找到如下:


External symbols:

    DRAM_DSP_SHARE_ADDR = 0x803800
    __StackLimit = 0x9800
    __StackTop = 0xafff
    __Vectors = 0x0
    _ctors_end = 0x0
    _ctors_start = 0x0
    _dtors_end = 0x0
    _dtors_start = 0x0
    _sp_end_DMA = 0x9800
    _sp_start_DMA = 0xb000

符号的重定义

所有引用symbol1 将被替换为symbol2,注意,在_wrap语句中使用的符号不能同时解析为其他符号使用

_resolve symbol1 symbol2

不初始化区域定义

# 符号
_symbol symbol addr _no_init
_symbol symbol2 _after symbol1 _no_init
_symbol symbol _next _no_init
_symbol symbol address-range _no_init

# 内存地址
_no_init_range memory address-range

# 段
_segment segment memory address-range _no_init
_overlay_segment segment1 segment2 ... _no_init

指定内存大小

_mem_size memory size

段的分配

Either the memory region is specified explicitly in the BRIDGE configuration file:
_segment segment memory address-range
or when omitting the end address, the end address is determined during linking:
_segment segment memory start-addr
To place segments after previously mapped segments or overlay segments, use the _next keyword:
_segment segment memory _next
To place segment at the end of all mapped symbols, use the _last keyword:
_segment segment memory _last

设定共享内存区域

Shared Memory Regions

_shared memory1 address-range1 memory2 address-range2 ...

M3内核开发

点击前往

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aron566

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值