如何应用AndesCore™ EDM 安全访问机制

沈永胜,技术副哩,晶心科技股份有限公司

EDM 安全存取是 AndesCoreTM 内建的功能(option),应用在安全存取的控管。EDM 安全存取有二种的控管方式:debug access indication 和 EDM access restriction。第一种控管方式(debug access indication)提供了一个 sideband signal 用于指示从调试器(Debug host)的请求。第二种控管方式, 控制AndesCoreTM 的 input port(edm_restrict_access )达到 EDM 存取的限制。更详细的内容在后续章节会有更深入的介绍。

1. EDM功能介绍
  一个 debug system 包含一个 debug host 和一个 target system。EDM 主要的功能就是 translate debug host 发出的 TAP 指令來存取系统 memory 或是 CPU。图表 1 为基本的 debug 系统方块图:

图表 1 基本的 debug 系统方块图

图表 2 說明 TAP 指令的种類:

图表 2 TAP 指令的种類

2. 控制EDM存取的限制
  使用 EDM 的访问方式会被一个 sideband signal (edm_restrict_access) 所影响。当这个 signal 值是 high,仅仅只能对 EDM MISC registers 做讀取的动作。而想要存取CPU/System Bus/Local Memory 的动作将会被封锁住并且会得到下面的结果:

  •  讀为零写忽略
  • 不正确的 JTAG instruction(JTAG ICE debugger 会 timeout)

图表 3 說明 EDM 限制存取方块:

图表 3 EDM 限制存取方块图

在启用存取限制功能后,图表 4 說明出每个 TAP 指令的行为:

图表 4 TAP 指令的行为

如何实现 EDM 存取限制,在系统设计上有很多种实现方法,以控制 edm restrict access 的 signal。兩种基本的设计方案說明如下:

  • eFUSE 方式使用 Chip 重新编程管理控制
  • SOC 方式使用软件管理控制

图表 5 所示为 hardware 实现控制 edm_restrict_access 的示意图如下:

图表 5   Hardware 实现控制 edm_restrict_access 的示意图

software 实现控制 edm_restrict_access的例子如下:

  • sethi $r2,#0x80000
  • ori $r2,$r2,#0x8c
  • sethi $r3,#0x04030
  • ori $r3,$r3,#0x201
  • swi $r3,[$r2+#0]

3. EDM 存取指示
  AndesCoreTM 增加一个额外的 sideband signal,xdebug_access(active-high),根据此 sideband signal 來决定 request 的 host 是否为 EDM。而 device 就能根据此 sideband signal 决定是否要把 request 的 data 内容传回到host。

sideband signal 的名称根据 bus interface 的類型而有所不同。对于AndesCoreTM 处理器,基本的信号名称如下所示:
• AHB/AHB-Lite => hdebug_access
• APB => pdebug_access
• EILM => eilm_debug_access
• EDLM => edlm_debug_access

3.1. debug 存取識别信号控制
  当 debug exception 发生后,CPU 将进入debug mode。然后 CPU 将会留在 debug access mode 直到CPU 执行到 IRET instruction 并且 trusted_debug_exit 是处于high 后CPU 将離开 debug access mode,反之 trusted_debug_exit 如果是low, CPU 将会保留在debug access mode。
实现控制 trusted_debug_exit 信号,有二种可供选择的方式如下:
• trusted_debug_exit 信号总是给 high
增加一个权限管理邏辑去控制trusted_debug_exit 信号是high 或是 low 权限管理邏辑方块图如图表 6 所示:

图表 6 权限管理邏辑方块图

如何控制 trusted_debug_exit 信号时序图如图表 7 所示:

图表 7   如何控制 trusted_debug_exit 信号时序图

如下例子說明了如何产生 trusted_debug_exit 控制信号的verilog code:

  • The code example (Verilog) of trusted_debug_exit generation is described below:
  • //
  • //— Utilize passcode to generate trusted_debug_exit in AHB Bus Controller
  • //* assume zero-wait-state AHB access
  • parameter AUTH_CODE = 32’h0a0b0c0d;
  • always @(posedge hclk or negedge hreset_n) begin
  • if (!hreset_n) begin
  • passcode_reg <= 32’d0;
  • end
  • else if (passcode_wen) begin //debugger enters passcode through debug access
  • passcode_reg <= hwdata[31:0];
  • end
  • end
  • //validate passcode to generate trusted_debug_exit
  • assign trusted_debug_exit = (passcode_reg == AUTH_CODE);

3.2. debug 存取指示应用
图表 8 說明 AHB bus 如何使用 hdebug_access 和验证邏辑來防止惡意的 debug存取

图表 8   AHB bus 如何使用hdebug_access 和验证邏辑來防止惡意的 debug 存取

如下 verilog code 說明了如何使用 hdebug_access 信号:

  • //— Use hdebug_access to prevent malicious debug access in AHB Bus Controller
  • //* assume zero-wait-state AHB access
  • parameter IRRELEVANT_DATA = 32’hcafe0001;
  • parameter AUTH_CODE = 32’h01020304;
  • always @(posedge hclk or negedge hreset_n) begin
  • if (!hreset_n) begin
  • dbg_acc_d1 <= 1’b0;
  • end
  • else begin // data phase indication of debug access
  • dbg_acc_d1 <= hdebug_access;
  • end
  • end
  • always @(posedge hclk or negedge hreset_n) begin
  • if (!hreset_n) begin
  • passcode_reg <= 32’d0;
  • end
  • else if (passcode_wen) begin //debugger enters passcode through debug access
  • passcode_reg <= hwdata[31:0];
  • end
  • end
  • //validate passcode to check authentication
  • assign auth_check_fail = (passcode_reg != AUTH_CODE);
  • //return irrelevant data if the authentication check of debug access fails
  • assign hrdata_out = {32{data_read_en}} &
  • ((dbg_acc_d1 & auth_check_fail) ? IRRELEVANT_DATA : normal_data_out);

4. 实际的应用
  使用者经由上面的介绍完成了权限管理邏辑后,并且挂在 AndesCoreTMAHB bus 上,再经由仿真器(Cadence)仿真此权限管理邏辑的行为,如下面几张图所示:

• edm_restrict_access 信号控制
图表 9 說明由 sw code 把 edm_restrict_access signal disable

图表 9   由 sw code 把 edm_restrict_access signal disable

• trusted_debug_exit 信号控制

图表 10   经由 debug access 把 trusted_debug_exit signal 设定成high

• debug_access 信号
图表 11 說明经由 debug host 來做存取时,debug_access signal 会从 low 变成 high:

图表 11   经由 debug host 來做存取时,debug_access signal 会从 low 变成 high

图表 12 說明经由执行 IRTE instruction 时,debug_access signal 会从 high 变成 low:

图表 12   经由执行 IRTE instruction 时,debug_access signal 会从high 变成 low

5. 结语
EDM 安全存取是 AndesCoreTM 保护周边装置内容不被窃取的功能,也因为越來越多客户使用到此功能,所以撰写此技术文章让客户更能进一步了解到此功能的用途,让客户能够很快速的上手,并且使用晶心开发的 EDM 安全存取是一件愉快与简单的工作。

Continue Reading如何应用AndesCore™ EDM 安全访问机制

当高速AndesCore™遇上低速 Embedded Flash的晶片效能提升方法

陈群旻,技术副理,晶心科技股份有限公司

  AndesCore™除提供 AHP,APB ,HSMP 接口外,亦可透过 EILM 接口与内存整合,使 AndesCore™可以不透过 AMBA BUS 直接透过 EILM 接口撷取指令。然而嵌入式 Flash 的执行速度目前,并不能赶及 AndesCore™的工作频率, AndesCore™的执行效能将受限于嵌入式 Flash 的执行速度。此时可透过在 AndesCore™与 Flash 间的 EILM 接口之间加入一个预取模块,减少 AndesCore™因为 Flash throughput 跟不上 AndesCore™ 效能,使执行效能下降的影响。文章中所提供的参考预取模块,以 data width 32 bits 的 Flash 为操作对象,预取 buffer size 为两道 Instructions(32bits*2)提供一预取机制的设计参考。
  本文之目的在提供与介绍一个预取模块的参考设计作为用户设计预取模块的参考。期望能对使用者有所帮助,也希望读者不吝指教提供您宝贵的意见。

1. Prefetch design 界面介绍
  AndesCore™透过 EILM 接口可与外部 external local memory 整合,为了透过 Prefetch 模块根据前一道指令撷取时的地址,以 AndesCore™将循序撷取指令为预测逻辑来预取下道指令,并储存该指令内容于 Prefetch 模块,供 AndesCore™循序撷取指令时使用,我们将原本 AndesCore™与 EILM 的整合方式(如图一所示),改为在 AndesCore™与 EILM 之间加入 Prefetch 模块的整合方式(如图一所示)。
  AndesCore™透过 EILM 接口跟 Prefetch 模块提交 request,Prefetch 模块透过 eilm_wait 告知 AndesCore™该 request 执行是否需要 wait,并在对应的时序提供 AndesCore™欲撷取的指令内容。
  Prefetch 模块另有接口与 memory (Flash or ROM)整合,透过该接口进行对 memory 的读取。由于坊间 Flash or ROM 有各种 protocol,Andes 提供的 Prefetch reference design 主要专注于提供 prefetch 机制的参考设计,memory 接口以一 pseudo Flash 接口为设计对象,用户后续可根据所使用的 memory 的 protocol 进行调整设计。

1.1 Block Diagram  

1.2 Signal Descriptions
Prefetch 模块的 clock 与 reset,与 AndesCore™使用相同的 clock,reset 讯号源作设计,此外有一 input 讯号”ratio”用以设定 AndesCore™与 memory 工作频率倍率关系。其余讯号,我们分作两个群组”EILM”与”MEM”分别说明。

  1.2.1. Global signals

  1.2.2. EILM
  Prefetch 模块透过 EILM 接口与 AndesCore™整合,依循 AndeStar 所定义的 protocol 与 AndesCore™沟通。

以下时序图说明 EILM 接口 Read/Write 时的讯号

1.2.3. 本次仿真使用的 Flash 接口的讯号
  Prefetch 模块的 memory 接口以一 pseudo Flash 接口为设计对象。并以此 memory 的 behavior module 与 Prefetch 模块整合后仿真。以下图表介绍此 pseudo Flash 之讯号与工作之时序。

图表 8 Pseudo Flash Timing Diagram
图表 9 Pseudo Flash AC Characteristics

2. Prefetch 模块的主要功能介绍
  透过 Prefetch 模块来提升 AndesCore EILM 撷取指令时的效率,减少 AndesCore 提出指令 request 后,等待 read data 自 Flash 回复有效值的等待时间,来增加 AndesCore 的执行效能。
  实现方式是以前次 AndesCore 提出指令 request 时,所发出的 address 来预测后续 AndesCore 提出指令 request 的 address 为递增方式,在 AndesCore 提出指令 request 前,Prefetch 模块先将该递增 address 的指令内容由 Flash 取回并储存于 Prefetch 模块中,当 AndesCore 提出指令 request 的 address 确为递增方式,且指令内容已在 Prefetch 模块中,AndesCore 将不需 wait,可在下一时序即可自 Prefetch 模块撷取指令内容。
  若 AndesCore 提出指令 request 的 address 为非递增方式,或是 AndesCore 提出指令 request 的频率高过 Prefetch 模块预取数据的频率,Prefetch 模块中已无事先预取的指令内容时,则依然透过 wait 讯号来延迟 AndesCore 撷取指令内容。

2.1 预取功能说明
  图表 10 所示为 Prefetch 模块自 Flash 撷取指令内容的 function 示意图

图表 10 Prefetch 模块自 Flash 撷取指令内容的 function 示意图

Reset 后, Prefetch 模块内并无预取的指令内容,于是执行 general prefetch function,后续当 AndesCore 提出指令 request 为递增方式,若指令已预取完成,则将指令内容传给 AndesCore,若指令预取未完成则拉 wait 讯号来延迟 AndesCore 撷取指令内容。再以目前 request 的 address 递增来预取指令。当 AndesCore 提出指令 request 不为递增方式(本文后续称为 branch),则拉 wait 讯号来延迟 AndesCore 撷取指令内容,同时 Prefetch 模块自 Flash 撷取该指令,当 Prefetch 模块得到有效数据时,撤回 wait 讯号,并将有效数据传给 AndesCore。再以目前 request 的 address 递增来预取指令。

2.2 主要程序说明
以下我们剪辑 Prefetch 模块 RTL 程序中几个重要部分来做说明

  2.2.1 branch 判断:
  当一个 AndesCore™ request (instruction fetch)被 Prefetch 模块接受时,若此 时的 address 不等于预设的递增 address,表示一个 branch 发生,Prefetch 模块将跟据 branch 时应有的动作来对 Flash 读取指令,使用 wait 讯号来延迟 AndesCore,选择 read data 等。


相关程序片断:
assign    branch= eilm_read_req_valid&((lastest_eilm_ifetch_addr_inc1!=eilm_addr)|eilm_ifetch_n);

  2.2.2 prefetch 判断:
  当 Prefetch 模块处于 idle 状态时,若需要被预取的指令内容,未储存于 Prefetch 模块,则进行 prefetch 的动作,对 Flash 读取指令,并存放至 Prefetch 模块。 Prefetch 模块预取深度我们设计为 2,故我们会预取下一道 (lastest_eilm_ifetch_addr_inc1)及下下一道(lastest_eilm_ifetch_addr_inc2)指令。

相关程序片断:
assign     prefetch_next1= (state_cnt==4’h0)& (~wait_for_write)&
                                                              (~((lastest_eilm_ifetch_addr_inc1==addr0)&addr0_valid )&
                                                                 ~((lastest_eilm_ifetch_addr_inc1==addr1)&addr1_valid ));
  assign      prefetch_next2= (state_cnt==4’h0)& (~wait_for_write)&
                                                                  (~((lastest_eilm_ifetch_addr_inc2==addr0)&addr0_valid )&
                                                                      ~((lastest_eilm_ifetch_addr_inc2==addr1)&addr1_valid ));

  2.2.3选择执行branch, prefetch 或 idle
  当 Branch 发生时,不论需要被预取的指令内容是否已储存于 Prefetch 模块,执行 branch 时应有的动作,若有 prefetch 的动作执行中则放弃。
当Branch 未发生时,需要被预取的指令内容未储存于 Prefetch 模块,执行 prefetch时应有的动作,若需要被预取的指令内容已储存于 Prefetch 模块,Prefetch 模块处于 idle。

相关程序片断:

 

 

 

 

 

 

 

 

 

2.2.4 选择 read data:
  若 Prefetch 模块处在执行 branch 时应有 function 的动作,自 Flash 于数据有效时撤回wait 讯号,选择 DO (Flash read data)作为响应给AndesCore 的read data。若 AndesCore 提出指令 request 为递增方式,则以预取的指令内容,作为响应给 AndesCore 的 read data。

相关程序片断:

 

 

 

 

2.2.5 储存预取的指令内容:
  当进行 prefetch 的动作完成时,更新预取的指令内容。
A_latch 为进行 prefetch 的动作发 request 给 Flash 时所发出的 address,我们以 A_latch 最后一个位选择要储存于两个 buffer 中的哪一个。

相关程序片断:

 

 

 

 

 

 

 

 

 

 

 

 

2.3 波形圖說明
 
以下小节,为 After Reset, Branch, Sequential 三种状况下的波形图以及说明。

 

 2.3.1. After Reset

图表 11 After reset 波形图

波形图说明:


 

 

 

 

2.3.2. Branch fetch
 

图表 12 branch fetch 波形图

波形图说明:

 

 

 

 

 

 

2.3.3. Sequential fetch

图表 13 sequential fetch 波形图

波形图说明:

 

 

 

 

 

 

 

 

 

3. Instruction fetch效能改善
   
由于参考模块,以 32 bits Flash 为设计对象,默认 AndesCore™ frequency 与 Flash frequency 为 n:1 (n≧2),Instruction fetch performance 受限 Flash 输出频率,故未能有明显提升。
 
当Flash 扩充带宽为64 bits,使Flash 输出及上AndesCore™指令消耗速度后, Instruction fetch performance 将会有明显提升。
 
Andes 已有客戶參考此設計,並加以修改,使之支援頻寬為 64 bits之Flash。以 AndesCore™ frequency 與 Flash frequency 為 2:1 下,由原本 fetch 一道指令平均需要兩 cycle 增進為 fetch 一道指令平均需要 1.1cycle。Instruction fetch 效能改善 80%左右。

  Instruction fetch 效能改善可透过下列公式计算。
Instruction fetch performance improvement = ( 2/(1+ branch instruction ratio)
-1)*100%
(当branch 发生时,由于欲 fetch 的指令不在prefetch 内,此时仍需花费 2cycle fetch 该指令。)

4. 结语
   
AndesCore™所提供的 EILM 接口相当方便客户与 Flash 或 ROM 整合,然而 Flash 或 ROM 目前最高速 access time 目前不能与AndesCore™所能实现的最高工作频率相同。AndesCore™的执行效能将受限于 Flash 或 ROM 目前最高速 access time。Prefetch 模块提供一预取的机制来增加 AndesCore™与 Flash 或 ROM 整合时的执行效能。文章中所提供的参考预取模块,以 data width 32 bits 的 Flash 为操作对象,提供一预取机制的设计参考。使用者可参考此设计概念,将 data width 32 bits 的 Flash 为操作对象改为 data width 64 bits 的 Flash,在增加此设计后, Instruction fetch performance 将可得到符合使用者期待的效果。

Continue Reading当高速AndesCore™遇上低速 Embedded Flash的晶片效能提升方法

如何在晶心平台实作ROM patch

赖歆雅,技术经理,晶心科技股份有限公司

笔者曾协助多家公司工程师,在 AndesCore™上发展 firmware。我们发现,当客户开发 Non-OS 的程序代码,最常遇到的问题在于开发者不知如何撰写 linker script。网络上有 GNU ld 的使用文件,但是 linker script 的范例太少,尤其开发者需要撰写进阶的 linker script,常常不知如何下手。

本篇文章我们分享如何实作 ROM patch。使用晶心 CPU 建构的 embedded system,一般具有 CPU、外围 IP 及 RAM、ROM。部份客户使用 ROM code开机,程序代码放在 ROM 内,data section 放在 SRAM 里。ROM code 的特性是成本低,跟着 IC 光罩一起生产,当 IC 制作完成即不可修改,若有制作上的错误或是程序代码逻辑上的错误,只能用 ROM patch 的方式修补。也就是将需要修补的程序代码放到小容量的 flash 里。这就是我们今天要分享的技术。

1. 主程序架构
  首先介绍主程序的架构。IC主的程M序emory layout 如下图。

图表1  主程序的 memory layout 图

红色框线的部份,为主程序编译的范围。主程序 main 会呼叫到 func1、func2
和 func3 这 3 个 function。

在上图中,黄色区域是 IC 的 ROM,这部份的程序是 IC 制作出来即不可以改变。绿色部份是 flash。在图中,flash 分成 2 区,一个是 jump_table,存放 func1~func3的地址。剩余的空间 FUNC_PATCH,预留给 patch 使用。

为了要修补 ROM 内的 function,所以规划出 jump_table 区域,原本都是指向 ROM 的 function。如果 ROM 里的部份 function 损坏或是需要改写,就把 jump_table 改为指向 FUNC_PATCH 里新建的 function。

   1.1 源代码
  主程序的程序代码如下:(main.c)

 1.2 主程序 linker script (仅列需要修改的部份)

Flash 的地址由 0x510000 起,将 FUNC_TABLE 固定在 flash 的最开头,语法如上。

   1.3 主程序执行结果

2. 经过Patch之后的架构图
假设ROM里的func2 损坏,要改用flash里的func2。需要更改指向func2的指标,及func2的内容。如下图:

图表2 ROM patch 的 memory layout 图

用红色框线标起来的地方,表示为 patch 编译的范围。其中 jump table 在这里重新编译,指向新的地址。

   2.1 实作方法
  (1) 导出主程序的 symbol table。
在主程序的 Linker flags 加上-Wl,–mgen-symbol-ld-script=export.txt ,ld 会产生 export.txt 这个档案, 这个档案包含了一个 SECTION block 以及许多变数的地址。如下图所示。

图表 3 主程序的 symbol

Linker script 在 import Main program 的 symbols 时,除了需要修改的 func2不要 import 之外,其他的 symbols 全部要 import 进来。(将 export.txt 删去这一行: func2 = 0x005001c4; /* ./main.o */)


   (2) patch 在编译之前,先汇入主程序的 symbol table。(将 export.txt 档案放在一起编译)。Patch 的 linker script 要汇入主程序的 symbol,写法如下面红色字体。

   (3) patch 的程序代码里如下,没有 main function,也不要加入 startup files。改写 func2。func2 放在 flash 的 FUNC_PATCH section。并且将 jump_table里的 func2,改成指向新的 func2。

   (4) patch 的 linker script,加入 FUNC_PATH 在 jump_table 之后。

3. 如何除错
首先,将程序代码存放在 IC 的 ROM 及 flash 里。(本文为了示范,我们的做法是在 AndeShape™ ADP-XC5 的 FPGA 板上,用 RAM 模拟 ROM 及 flash,分别将主程序和 patch 的 bin 文件 restore 到板子上。)

当 gdb debug 时,载入 patch 的 symbol。以下节录 gdb 指令。

上面过程中,先加载 main 的 symbol,再加载 patch 的 symbol 及 debug information。”add-symbol-file patch.adx 0x500000 -s FUNC_TABLE 0x510000 -s FUNC_PATCH 0x510020″是将 patch section 的symbol 及 debug information 也载入 gdb 以 debug。读者可以在 gdb 里,打”help add-symbol-file”查阅 add-symbol-file 的用法。

   3.1 主程序 patch 后的执行结果

4. 结语
目前晶心科技使用GNU的toolchain,其功能非常强大。读者可多动手试试不同的linker script写法,使得开发firmware更有弹性及效率。

5. 参考数据
gnu linker ld manual
http://sourceware.org/binutils/docs-2.22/ld/index.html

6. 作者简历
赖歆雅,女,台湾省新竹县人。1977 年出生,2002 年毕业于台灣成功大学电机研究所 VLSI/CAD 组硕士班。
2002~2005 年就读台灣成功大学电机研究所 VLSI/CAD 组博士班(肄业)。
2005~2010 年任职于工业技术研究院,担任副工程师,负责 Linux 上的软件开发。
2010~2012 年任职于晶心科技,担任技术经理,负责客户的技术支持。

Continue Reading如何在晶心平台实作ROM patch

如何移植 Linux 到晶心平台

沈智明,资深技术经理,晶心科技股份有限公司

有鉴于越來越多使用者将 Linux 移植在晶心平台(Andes Embedded™)的上(AndesCore™ N12 或 N10),本文之目的在协助使用者快速、有效率的将 Linux 移植到自建的 FPGA 板子上(CPU 是 AndesCore™ 的 N12 或 N10)。笔者曾协助多家公司工程师进行 Linux 移植到晶心平台的工作,将 Linux 移植过程容易遭遇的问题与盲点进行实务說明,期望能对使用者有所助益,也希望讀者不吝指教提供您宝贵的意見。

在进行实务的 Linux 移植时会发现,使用者的晶心平台可能会有各式各样的组合,除了 CPU 是使用 N12 或 N10 外,使用者对于其他的周边(如 RAM,ROM, Timer…..)之搭配各有所好,为了有系统性說明 Linux 移植的要領,将选定一明确的硬件,软件,与开发工具(toolchain)环境做演練說明,除了让讀者可以实作明了文中之叙述,当使用者的周边非原设计之硬件(使用者自己的 IP)时,可以运用移植的基本原则,更改希望移植 IP 的 Linux 驱动程序,其他原始码不动,逐一的将使用者的周边驱动程序移植到晶心的平台。

在 Linux 移植过程中,使用者须建立一基本观念,那就是整个 Linux OS 可分为兩部分,第一部分是与硬件相关的 HW dependence code,这部分的程序代码会因对应不同的硬件而造成软件部分需做不同程度的改写;第二部份是与硬件无关的 generic code,这部分的程序代码与硬件无关,纯软件运作,不会因平台(Andes, X86, Arm..)的改变而有差别。移植 Linux 的工程师第一步需要能区分出哪一部分程序代码是 HW dependence code,另外部分的程序代码就是 generic code,如果在这阶段对程序代码判断错误(HW dependence code/generic code)会拖延 Linux 移植的时程与增加除错时的困难。

Linux 移植到晶心平台过程中,首先须先做到 Linux 基础架构移植成功。在除错时,Linux 的基础架构组件是 CPU,timer,interrupt 与 UART,当 CPU 与这 3 项周边移植成功后,scheduler 可以运行了,printk 也可以运行了 Linux 系统已经可以正常的运作了。接下來的工作只需将需移植的驱动程序一个一个移植即可,基础骨架移植完成后,除错也有 printk 可用,接下來只需将肉 (需要加的device drivers) 填上即可。Linux 移植比较困难的地方是 Linux 基础架构尚未完成之前(Linux 移植的初期阶段)的除错,所幸晶心提供的标准除错工具与AndeShape™的除错器 AICE,可以一步一步找出问题之所在,让初期移植 Linux 的除错也变得很简单,具体得作法,后文会详细說明。本文叙述着重在如何建立Linux 基础架构在晶心平台,至于个别 Linux 驱动程序的移植,坊间有许多的书在介绍,本文就不多加赘述。

1. 开发环境与程序
使用者开始进行 Linux 移植到晶心平台,首先须先选定一版晶心的 Linux 原始码作为基准再进行软件移植,修改原始码以符合使用者的开发平台,经由工具列的compile 与 link 所产生的 Linux 的映像档,再放上 FPGA 板子以验证程序编写的正确与否,依此开发程序:软件编写->FPGA 板子验证,再回到软件编写程序直到所有周边IP 在FPGA 板子验证完全,Linux 移植才完成,如图表 1 所示,Linux 移植过程中,AICE 除错可以有效加快 Linux 移植的速度。

图表 1 Linux 移植的开发流程

选定一组 Linux 原始码,工具列,FPGA 板子与 netlist 作为晶心的平台(于1.1,1.2,1.3 中所述),作为使用者的平台的对照组,经由使用者的平台与晶心的平台比对可以有效缩短产品开发时程。

   1.1 晶心版 Linux 原始码
目前晶心最新版本的 Linux 原始码在 AndeSoft™的 BSP310 中,Linux 原始码放在 BSP310 套件位置: BSPv310/source/Linux/linux-2.6.tgz。使用BSP310 中的 ramdisk ”xc5_glibc_ramdisk.img”作为 filesystem。

   1.2 工具列
  此晶心平台选用的工具列是 AndeSoft™的 nds32le-linux-glibc-v2。

   1.3 FPGA 板子与 netlist
  FPGA 板子是晶心 AndeShape™的 XC5 开发板。Netlist 是选定晶心AndesCore™的 N10 production version.

移植平台是指使用者要移植 Linux 的平台,也就是移植 Linux 的目标平台。将移植平台与晶心平台的比较列表如下: (其中所列之软件皆属于 BSP310 中之套件)。

图表 2平台与晶心平台的比较表

2. Boot loader
  如果使用者有自己惯用的 boot loader,可以使用惯用的 boot loader 以加快开发时程,如果没有 boot loader 的开发经验,可以选用 u-boot 作为系统的 boot loader.。u-boot 的 source ocde 位置在BSPv310/source/Standalone/u-boot/u-boot.tgz。

   2.1 U-boot
AndeSoft™的 BSP310 中 u-boot source code 是需要 EBIOS boot up 后再执行的 u-boot 版本。直接 boot up 不需要其他软件协助的 U-boot 版本(ROM 版) 是比较符合使用者的需要,晶心版的 u-boot 使用方法请參考 BSP310 User
Manua。l 如果要 ROM 版的 u-boot 需要在 BSP310 中的 u-boot 软件做 patch,
其指令如下:
# patch -p1 <burn-mode.patch
   patching file arch/nds32/cpu/n1213/ag101/cpu.c
   patching file arch/nds32/cpu/n1213/start.S
   patching file arch/nds32/include/asm/u-boot-nds32.h
   patching file arch/nds32/lib/board.c
   patching file board/AndesTech/adp-ag101p/config.mk
   patching file include/configs/adp-ag101p.h

patch 完成的 u-boot source code 可以产生 ROM 版的 u-boot image,直接开机后的执行结果如图表 3 所示。

图表 3 u-boot 执行结果图

3. 除错环境
  在移植 Linux 到晶心平台之前,先架设好除错的环境,尤其对底层 Linux 原始码的移植,有莫大的助益,在 printk 尚未正常运作前,需依靠 AndeShape™的 AICE
与 AndeSoft™的 GDB 來进行除错。

  3.1 设定 Linux kernel 除错选项
  Linux Kernel 需要设定一些除错选项,才能顺利的运用 AndeSoft™的 GDB 进行除错。晶心平台中 Linux kernel 除错选项设定如图表 4 所示,增加这些选项会增加 kernel 映像档的空间,如果空间占用过大以至于不符合设计需求时,可在除错工作完毕后将除错选项关闭以节约不必要的空间浪费。

图表 4设定 Kernel hacking 中除错选项勾选

   3.2 Linux kernel 除错的程序
   Build 成 kernel bootpImage (含 kernel debug message 如图表四选项) 后, Linux 的映像档放到 FPGA 板子上,PC host 端的 AndeSoft™的 GDB 透过网路(socket)与 AICE 連接至 FPGA 板子,进行除错的工作。

   3.2.1 编译链结成映像档
  设定好 AndeSoft™的 cross-compiler 路径后,利用下列指令经由 compiler and linker 后可以得到 bootpImage,指令如下:

#CROSS_COMPILE=”nds32le-linux-” ARCH=”nds32″ make xc5_defconfig
#CROSS_COMPILE=”nds32le-linux-” ARCH=”nds32″ make menuconfig
# CROSS_COMPILE=”nds32le-linux-” ARCH=”nds32″ make bootpImage
INITRD=xc5_glibc_ramdisk.img

将生成的 bootpIamge 放到 FPGA 板子上,将 AICE 連接到 FPGA 板子启动
ICEman,指令如下:

#C:\Andestech\AndeSight200MCU\ice>ICEman.exe –p 1234

PC host 端的 AndeSoft™的 GDB 透过网路(socket)与 AICE 連接至FPGA 板子,进行除错的工作,示范指令如下:

#ddd –debugger nds32le-linux-gdb vmlinux
gdb>target remote 10.0.2.164:1234

其中IP 值 10.0.2.164 是一个应用范例,使用者可依环境实际 IP 值进行设定。环境设定完成后,可以开始进行除错工程。

4. 移植Linux至晶心平台关键点经验传承
     4.1 Kernel 加载程序除错实作
    kernel 加载程序目的将 kernel 主程序进行解压缩并加载正确位置,此程序与kernel 主程序是兩个不同程序,但会一起包在 zImage 中只是 kernel 加载程序会 attached 在 zImage 的前面。除错时需 file 不同的 ELF file 才能进行正确的除错工作,kernel 加载程序的位置在
arch/nds32/boot/compressed/vmlinux,指令如下所示。
#ddd –debugger nds32le-linux-gdb arch/nds32/boot/compressed/vmlinux

kernel 主程式的 ELF file “vmlinux”在 kernel source code 的根目錄下指令如下所示。
#ddd –debugger nds32le-linux-gdb vmlinux

   4.2 Linux kernel 除错实作
kernel 加载程序执行完毕后会跳到 kernel 主程序执行。进入点是arch/nds32/kernel/head.S 的 assembly code 执行完后会进入 kernel 的主要函數 “start_kernel”。

   4.2.1. RAM offset patch
  晶心版 Linux 原始码搭配 XC5 平台,RAM 的起始位置(指的是 PA)是 0x0, 使用者 FPGA 开发板的 RAM 起始位置如果不是 0x0,必须要修改 FPGA 板子中 RAM 的起始位置,做法是在晶心版的 Linux 原始码中进行 RAM address patch,将原始码中 RAM 位置调整到 FPGA 开发板中 RAM 的真实位置。

   4.2.2. PA/VA remap table
  当 FPGA 板子 IO 的 PA 设定正确后,使用者需要设定 PA/VA remap table, 作法可參考 arch/nds32/include/asm/spec-ag101.h,依照 apec-ag101.h 中PA/VA 对应的关系去增减使用者自己 IO device 的 PA/VA remap table。

   4.2.3. Kernel 解压缩与 software breakpoint
  在进行 kernel 除错时,如果在低地址处,例如:head.S 中进行除错,当设定software breakpoint 时,会有 breakpoint 无法停下來与 AICE 断线的情况发生。原因是当使用者设定 software breakpoint 时,breakpoint 处的 instruction 会修改并加入 break instruction。但 kernel 解压缩时会将除错的程序代码覆盖造成与 GDB 除错不一致性而产生错误。解决的方法就是原设定 software breakpoint 改为 hardware breakpoint,这样就可以避免因 kernel 解压缩所造成除错的错误,降低除错时的困难度。

   4.2.4. PA/VA 观念說明与除错要領
  在原始码 arch/nds32/kernel/head.S 中
la      $lp,        mmap_switched
mtsr $lp, $IPC
iret

执行完 iret 后,系统就会从 PA 转成 VA,MMU translation status 从translation off 转为 translation on 在此分界处除错规则如下所述,如果观念不清楚及容易产生除错时的错误,请务必牢记。

     4.2.4.1. MMU translation off 时期除错
  在这个时期除错,VA 是不存在的。所有的 IO address 与 memory 都是 PA
没有 VA,如果除错地址设成 VA,容易 hit illegal address 而造成 exception。

     4.2.4.2. MMU translation on 时期除错
  在这个时期除错,PA 是不存在的。所有的 IO address 与 memory 都是 VA
没有 PA,如果除错地址设成 PA,容易 hit illegal address 而造成 exception.

  4.2.5. 移植 Linux 的基础组件
  MMU translation on 后,很快就会进入 start_kernel 函數,接下來移植的重点就是移植 Linux 基础组件,那就是 interrupt,timer and UART。当这 3 个device 移植成功后,Linux 的架构就建立起來了,printk 也可以用了,Linux 已经可以正常的运作。如果没有意外,可以执行完 kernel 甚至将 filesystem 带起來。接下來用户可以将自己的周边组件一个一个的 device driver 移植入系统。当周边组件移植完成后,Linux 系统移植到晶心平台就完成了。

5. 结语
Linux操作系统运作在晶心平台已有多年的时间。各式各样的Linux软件运作在晶心平台不计其數。皆可证明Linux操作系统运作结合晶心平台是一个稳定与成熟的产品,只要能明了熟悉Linux 移植的技巧与重点,使用晶心平台开发Linux的产品将是一件愉快与简单的工作。

Continue Reading如何移植 Linux 到晶心平台

μC/OS-II在AndesCore™ N1033A-S上的移植

周杰,应用工程师,晶心宏科技(杭州)有限公司

µC/OS-II 是一种代码公开、可裁剪的嵌入式实时多任务操作系统。该内核通过实现抢占式任务调度算法和多任务间通信等功能,使之具有执行效率高、实时性能优良等特点。另外,其占用空间非常小(最小可裁剪至 2KB)并且具有高度可移植性,因此被广泛的应用于微处理器和微控制器上。

晶心科技 (Andes)作为亚洲首家原创性32 位微处理器IP 与系统芯片平台设计公司,推出的 AndesCore™ N10 系列产品 N1033A-S, 搭配应用广泛的嵌入式实时操作系统 µC/OS-II 以及相关的软硬件开发资源,有效的帮助客户降低现有成本、提升系统效能、减少系统功耗,并缩短产品开发上市时程。本文将介绍如何将 µC/OS-II 移植到 AndesCore™ N1033A-S 处理器上。

1. 开发环境及处理器介绍
  1.1 软/硬件开发环境
  本移植过程使用的软件环境是 AndeSight™ v1.4 集成开发套件,它是晶心科技最新推出的针对各种 AndesCore™的软件集成开发环境,包括编译器、调试器、分析器以及强大的 ESL 工具。硬件平台采用晶心科技的 FPGA 评估板 ADP-XC5,该评估板采用 AndesCore™ N1033A-S 作为处理器内核,并具有丰富的片上资源。

AndesCore™ N1033A-S 介绍
AndesCore™ N10 系列产品 N1033A-S 是一款哈弗结构的 32 位RISC 处理器内核,具有 5 级流水线(pipeline)及动态分支预测(Dynamic branch prediction)架构。N1033A-S 新加入了最新 AndeStar™ V2 指令集,把 CPU 效能推至 1.66DMIPS/Mhz 之上。同时还实现完整的 Audio 指令集,达到完全整合 CPU与 DSP 功能的目标。N1033A-S 还支持向量中断模式以及 2D 直接内存访问 (DMA)功能,更为实时信号处理添增效能。

2.µC/OS-II 在 N1033A-S 上的可移植性分析
  µC/OS-II 具有高度可移植性,目前已经移植到近 40 多种处理器体系上,涵盖从 8 位到 64 位的各种 CPU(包括 DSP)。
  µC/OS-II 的正常运行需要处理器平台满足以下要求: 1)处理器的 C 编译器能产生可重入代码;2)用 C 语言就可以打开和关闭中断;3)处理器支持中断,并且能产生定时中断;4)处理器支持能够容纳一定量数据的硬件堆栈;5)处理器有将堆栈指针和其它 CPU 寄存器读出和存储到堆栈或内存中的指令。
  AndesCore™ N1033A-S 内部提供了 32 个通用寄存器,其中 R31 被用来做专门的堆栈指针。32 根地址线最多可访问 4GB 存储单元,因此只要系统 RAM空间允许,堆栈空间理论不会产生限制。N1033A-S 处理器提供的 AndeStar™ V2指令集包含了丰富且十分高效的对堆栈进行操作的指令。例如指令 SMW(store multiple word)可实现仅使用一条指令将多个寄存器的值存储到堆栈中并同时更新堆栈指针位置,而且还能很好的处理地址非对齐字的存取。N1033A-S 支持中断并能产生定时器中断,处理器中的 PSW(Processor Status Word)寄存器中包含一个全局中断禁止位 GIE,控制它便可实现打开和关闭中断。此外, AndeSight™集成开发环境中内置的编译器可以产生可重入代码,并且支持内联汇编,C 环境中可以任意进行开关中断的操作。综上所述,µC/OS-II 完全可以移植到 N1033A-S 上运行。

3. 移植步骤
  为了方便移植,大部分的 µC/OS-II 代码是用 C 语言写的,用户只需要用 C语言和汇编语言写一些与处理器相关的代码就可以实现移植。这部分工作的内容包括:一个完成基本设置的头文件 os_cpu.h、一个与处理器相关的汇编文件 os_cpu_a.S 和一个与操作系统相关的 C 代码文件 os_cpu_c.c。

3.1 在 os_cpu.h 中完成基本的配置和定义
   3.1.1. 定义与处理器相关的数据类型
为保证可移植性,µC/OS-II 没有直接使用 C 语言中的 short、int 和 long 等数据类型的定义,因为不同的处理器有不同的字长。对于 N1033A-S 这样的 32位处理器,其数据类型定义实现如下:

   3.1.2.定义中断禁止/允许宏
  做为实时内核,µC/OS-II 需要先禁止中断再访问代码临界区,并且在访问完毕后重新允许中断。µC/OS-II 定义了两个宏来禁止和允许中断: OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。在N1033A-S 处理器上的实现代码如下:

GIE_SAVE 和 GIE_RESTORE 的实现如下:

中断禁止时间是判断系统实时性的重要指标之一。中断禁止时间能否达到最短,不仅与操作系统的设计有关,还依赖于处理器结构和编译器产生的代码质量。

从上面的实现代码看到,由于 Andes 处理器提供了 setgie.d 和 setgie.e 两条直接控制中断的开关的指令,整个禁止/允许中断的过程经过编译器产生的机器码只有 3/2 条,最大限度地减小了中断禁止时间。

   3.1.3. 定义栈增长方向
   µC/OS-II 使用结构常量 OS_STK_GROWTH 来指定堆栈的增长方式,设置为 0 表示堆栈从下往上增长,设置为 1 表示从上往下增长。这里我们定义成后者,即堆栈的增长方向是从内存高地址向低地址方向递减并且堆栈指针总是指向栈 顶数据:

   3.1.4. 定义 OS_TASK_SW()宏
  OS_TASK_SW()是一个宏,它在 µC/OS-Ⅱ 从低优先级任务切换到最高优先级任务时被调用的。任务切换只是简单的将处理器寄存器保存到将被挂起的任务
的堆栈中,并且将更高优先级的任务从堆栈中恢复出来。可采用两种方式定义这个宏,使用软中断将中断向量指向 OSCtxSW()函数;或者直接调用 OSCtxSW()函数,这里我们采用后者(OSCtxSW()函数的实现将在后面介绍):

3.2 处理器相关部分汇编实现
  µC/OS-Ⅱ 的移植需要用户编写三个最基本的汇编语言函数:
OSStartHighRdy(),OSCtxSw(),OSIntCtxSw()。它们会共用一些代码,为了方便阅读将它们写在同一个汇编文件 os_cpu_a.S 中。

   3.2.1 OSStartHighRdy():运行优先级最高的就绪任务。
   OSStartHighRdy()函数是在 OSStart()多任务启动之后,负责从最高优先级任务的 TCB 控制块中获得该任务的堆栈指针 SP,并通过SP 恢复 CPU 现场以启动最高优先级的任务执行。另外 OSStartHighRdy()还必须在最高优先级任务恢复之前和调用 OSTaskSwHook()之后设置OSRunning 为 TRUE。其实现代码如下:

   3.2.2 OSCtxSw()和OSIntCtxSw()
  OSCtxSw()是任务优先级切换函数,它的作用是先将当前任务的CPU 现场保存到该任务的堆栈中,然后获得最高优先级任务的堆栈指针,并从该堆栈中恢复此任务的 CPU 现场,使之继续执行,该函数就完成了一次任务切换。
  OSIntCtxSw()是中断级的任务切换函数。由于中断可能会使更高优先级的任务进入就绪态,因此为了让更高优先级的任务能立即运行,在中断服务子程序最后会调用 OSIntCtxSw()做任务切换。这样做能够尽快的让高优先级的任务得到相应的处理,保证系统的实时性能。
  OSCtxSw()和OSIntCtxSw()都是用于任务切换的函数,其区别在于,在 OSIntCtxSw()中无需再保存处理器寄存器,因为在OSIntCtxSw()之前已发生中断,所以可以保证所有的处理器寄存器都被正确地保存到了被中断的任务的堆栈之中。OSCtxSw()和OSIntCtxSw()实现代码如下:

  N1033A-S 处理器定义了四级(0-3)中断,在各级中断的转换时需要保存当前中断层级的寄存器。调用 OSCtxSw()时,中断将由 0 级(即没有中断)转到 1 级,所以需要将第 0 级的寄存器 PSW 和 PC 保存到第 1 级的寄存器 IPSW和 IPC 中。CtxSave 和 CtxRestore 两个宏用来保存和恢复任务上下文。需要保存或恢复的寄存器包括 32 个通用寄存器(R0-R31)的值、程序计数器(PC) 的值以及处理器状态字寄存器(PSW) 的值。宏IntlSwitch n 通过修改 PSW.INIT 的值来切换中断层级。CtxSave 和 IntlSwitch 的汇编实现如下(由于 CtxRestore 与 CtxSave 过程类似,这里不做赘述):

3.3 移植 C 语言编写的几个与操作系统相关的函数
    µC/OS-Ⅱ 有六个与 CPU 相关的函数:OSTaskStkInit()、OSTaskCreateHook()、OSTaskDelHook()、OSTaskSwHook()、 OSTaskStatHook()、OSTimeTickHook(),它们被定义在 ucos_ii.h 中。其中唯一必须移植的函数是任务堆栈初始化函数 OSTaskStkInit(),其它五个函数必须得声明但没必要包含代码。因此这里我们只介绍 OSTaskStkInit(),其代码的实现如下:

OSTaskStkInit()在任务创建时被调用,负责初始化任务的堆栈结构并返回新堆栈的指针,使得堆栈看起来就像刚发生过中断并将所有的寄存器保存到堆栈中
的情形一样。除了要保存任务的地址、变量的指针以及处理器状态字的值外, Andes N1033A-S 处理器还要求用户保存所有 32 个通用寄存器(R0-R31)、四个用户寄存器(d0.hi, d0.lo, d1.hi, d1.lo)。还有一点需要注意,在 N1033A-S 处理器中,堆栈指针的地址必须满足 8Byte 对齐,程序最后一段逻辑即将堆栈指针调整到正确的位置,这一点在编写其他代码例如在宏 CtxSave 中同样需要注意。

4. 結語
  基于 AndesStar™架构的优势,可以很容易的实现 µC/OS-Ⅱ 在 N1033A-S处理器上的移植。不仅 µC/OS-Ⅱ ,其它嵌入式操作系统也可以很方便地移植到 AndesCore™相应的处理器上,例如 Nuclues、FreeRTOS 以及 Contiki。
  晶心科技利用 AndesCore™ N1033A-S 高效能的 Audio ISA 和 FPGA 开发平台弹性的设计架构,基于各种 RTOS,为客户提供了的丰富的软件资源(中间件、优化的函数库、应用实例等)以及完整的多媒体语音解决方案,从而帮助客户更快地在 Andes 平台上进行产品开发。

Continue ReadingμC/OS-II在AndesCore™ N1033A-S上的移植

基于晶心科技 Andes 平台的 MP3 移植

晶心科技 (Andes)作为亚洲首家原创性 32 位微处理器 IP 与系统芯片开发平台的设计公司,面向 32 位市场推出了 Andes Core N9,N10,N12 三个系列低功耗高性价比的 32 位处 理器软硬核 IP。基于各系列处理器,晶心科技针对不同音频应用提供了多种解决方案。其中包括将多种音频格式的编、解码器(开源),例如 MP3、AAC、WMA、G729 等移植到 Andes 平台上。并且利用 nds32(基于 Andes Core)架构的优势和针对音频效能的扩展指令集,以及算法上的改进,对这些编解码器做了进一步的优化,使其不仅占用的空间较小而且具备了较高的运行性能。本文以 MP3 解码器为例,介绍如何将 madplay 移植到 Andes 平台,以及晶心科技基于 N903A 处理器提供的 MP3 解决方案。

1. MP3 简介
MPEG-1 Audio Layer3(简称 MP3)是一种有损音频编码方式,它利用掩蔽效应(一 种心理声学模型),将脉冲编码调制(Pulse Code Modulation)音频数据中人耳听觉系统无法察觉的那部分数据去掉,使得 MP3 能够在音质丢失很小的情况下把音乐文件压缩到很小的程度(1:10 甚至 1:12 的压缩率)。因为其体积小、音质高的特点,MP3 已经成为当今最为流行的音频格式。madplay 是目前使用较为广泛的一种 MP3 的解码器,下面将详细介绍如何使用 Andes 提供的 AndeSight 集成开发工具将 madplay 移植到 Andes 平台。

2. 环境及软件介绍
2.1 系统环境:
Linux:Fedora8

2.2 开发环境:
AndeSight1.4
AndeSight 是晶心科技提供的一种基于 nds32 架构开发嵌入式工程的图形化的集成开发环境。主要由 AndeSight IDE, AndESLive 和 nds32 工具集 3 个部分组成。
AndeSight IDE 为工程师提供了各种友好的界面,包括对嵌入式工程做编辑,编译,运行,调试或者评测等等操作。
AndESLive 提供了基于 nds32 架构的仿真器和一种图形化的虚拟 SoC 构建模型,它与 AndeSight IDE 相结合为用户提供了一个虚拟的硬件平台。这个虚拟评估平台提供 Andes 自行定义 ISA 的多组系列 32 位 CPU IP 以及各种外围设备 IP,并且支持用户自定义 IP 模型。
AndESLive 配合 AndeSight IDE 不仅使得 SoC 设计者能在计划初期就开始软件设计、侦错、最优化等工作,并对系统架构及功能进行检验,而且使硬件工程师和软件工程师具有一样的能力去制作和修改他们各自的系统模型,可以有效的控制 NRE(NonRecurring Engineering)成本,让软件工程师在拿到硬件原型之前,即可以进行软件的开发和优化。
nds32 工具集提供了一套在 Andes 平台上开发嵌入式应用程序所需要的标准工具,例如编译器、调试器、链接器等等。

2.3 交叉编译器:
nds32le‐linux‐gcc。
nds32 工具集中对应不同的 Andes Core 型号,不同的系统函数库以及大小端形式等条件,提供了各种对应的交叉编译器。这里我们选用 nds32le-linux-gcc。

2.4 软件包:
除了源码外,madplay 还需要 MP3 的解码库 libmad,以及 zlib 和libid3tag 来正确的读取 MP3 头段信息。这四个软件包都可以在开源网站上获得。其中,madplay‐0.15‐1b.tar.gz、libmad‐0.15.1b.tar.gz、libid3tag‐0.15.1b.tar.gz 可以在http://sourceforge.net/project/showfiles.php?group_id=12349 獲取,zlib‐1.2.4.tar.gz 可以在http://zlib.net/獲取。

3. Madplay 的移植
3.1 编译函数库
3.1.1 编译 libmad庫
进入 libmad 目录,首先将如下 nds32 架构和目标平台运行环境的信息加入到配置文件config.sub 中(可加到第 675 行):
nds32*)
                basic_machine=nds32‐linux os=‐
                linux
                ;;
然后依次执行:
#CC=nds32le‐linux‐gcc ./configure ‐‐prefix=$PREFIX/MP3_Decoder ‐‐host=nds32‐linux
‐‐disable‐debugging ‐‐disable‐shared
#make
#make check
#make install
编译成功后,可以在$PREFIX/MP3_Decoder($PREFIX 是用户设定的路径)目录下的included 和lib 目录里找到相应的.h 文件和.a 文件。

3.1.2 编译 zlib 和 libid3tag
需要先编译 zlib。进入 zlib 目录后,依次执行:
#CC=nds32le‐linux‐gcc ./configure ‐‐prefix=$PREFIX/MP3_Decoder
#make
#make install
然后编译 libid3tag。先将 nds32 架构信息加入到文件 config.sub 中(方法同 libmad),然后执行如下命令,编译 libid3tag 时需要用到编译 zlib 生成的头文件和库文件:
#CC=nds32le‐linux‐gcc ./configure ‐‐prefix=$PREFIX/MP3_Decoder ‐‐disable‐debugging
‐‐disable‐shared CPPFLAGS=”‐I/tmp/MP3_Decoder/include” LDFLAGS=”‐L/tmp/MP3_Decoder/lib”
‐‐host=nds32‐linux
#make
#make install
同样,在编译成功后 libid3tag 的相关文件也保存在$PREFIX/MP3_Decoder 目录下面。

3.2 在 AndeSight 中生成 madplay
在进入 AndeSight 图形化集成开发环境之前,需要先对 madplay 源码中的 makefile 进行配置。首先同样需要将 nds32 架构信息加入到 config.sub 文件中,然后执行如下配置:
#CC=nds32le‐linux‐gcc ./configure ‐‐disable‐debugging ‐‐disable‐shared ‐‐host=nds32‐linux CPPFLAGS=”‐I$PREFIX/MP3_Decoder/include ‐lmad ‐lid3tag ‐lz” LDFLAGS=”‐L$PREFIX/MP3_Decoder/lib”
‐‐prefix=/Andestech/AndeSight14/ide/workspace/MP3decoder_madplay
接着打开 AndeSight v1.4,建立一个 STD C(标准 C)工程 mp3decoder,并将madplay目录下的所有文件导入工程中。选择 Project 菜单栏选择 Build Project 一项,成功进行编译和链接后,在指定的目录下就会生成 madplay 的可执行文件,如图 1 所示。这样 madlpay 就成功移植到 Andes 平台上了。

3.3 测试与验证
为了验证移植的正确性,这里我们采用在虚拟的 Andes 硬件平台上运行的方式,也就是在 AndeSight 中通过 AndESLive 提供的虚拟 SoC 平台进行仿真。这里选用 Andes_demo.vep这个虚拟开发平台,它与真实的 Andes demo 开发板是一样的。
选取一首 MP3 格式的歌曲“test.mp3"拷贝到工程 mp3decoder 的目录下,然后在运行视窗的 Arguments 选项中加入指定输入文件和输出的文件的格式:
‐‐output=wave:PATH1/test.wav PATH2/test.mp3(输出格式还可以为.pcm)。

图 2 在虚拟 SoC 平台上运行madplay

这里 madplay 运行在虚拟开发平台的 linux 环境下在虚拟开发平台上运行 madplay。运行结束后,在工程目录下会看到“test.wav"文件,如图 2 所示。这个文件可以在 Windows Media Player 进行播放,这样就验证了 madplay 移植到 Andes 平台上的正确性。如果希望 madplay 运行在无操作系统的环境中,只需对 madplay 的源代码做一些修改(处理与系统调用相关的函数),然后使用 nds32le-elf-gcc 这款交叉编译器进行编译即可。

4. 晶心科技在 MCU 层级的 mp3 解决方案
随着人们对于音频电子产品功能的需求越来越高,8 位及 16 位 MCU 逐渐向 32 位 MCU转型已经成为市场趋势。晶心科技基于 Andes Core N903A 处理器对 MCU 层级的音频应用提供了全方位的解决方案,包括硬件平台和软件包支持。图 3 展示了晶心科技提供的完整的音频开发平台。

图 3 晶心科技提供的音频开发平台

考虑到从 8 位 MCU 升级到 32 位带来的硬件成本的增加,晶心科技推出了 N903A 低功耗高性价比的 32 位处理器。N903A 提供了完全可配置的处理器 IP 核,包括可配置的 I/D cache 大小,I/D local memory 大小,GPR 数量,硬件乘法器等等。这样,客户可以根据自己产品的需求,以最小的硬件成本获得较 8 位系统更为优化的系统性能。在指令方面,N903A不仅包含了晶心科技自主知识产权的一套高效指令集,而且加入了为提高音频数据处理能力而特别设计的四十余条音频扩展指令。另外,针对现有及可预期未来的大多数软硬件应用特性,晶心科技还提供一种 16bit/32bit 混合指令集形式,在提供功能之余,缩小了程序所需的内存空间,从而进一步实现降低成本的效益。

软件方面,晶心科技同样提供了全方面的支持。包括操作系统、设备驱动、开发工具、中间件、函数库以及上层的各种应用程序。对于 MP3 的编解码器,晶心科技对其代码大小做了进一步的优化,并利用 nds32 架构的优势以及音频扩展指令集,使其在 Andes 平台上运行的性能达到很高的水平。以 48KHz/128Kbps 的 MP3 歌曲为例,晶心科技优化的 madplay解码器正朝着 10MHz 的工作频率迈进。表 1 为晶心科技优化的 MP3 编解码器在 N903A 处理器上运行的结果。

Continue Reading基于晶心科技 Andes 平台的 MP3 移植

Andes 的分散聚合(SAG)机制

在嵌入式系统设计中,通常使用不同的存储器,如 Flash、SRAM、SDRAM,并位于不同的物理地址空间,怎样更好地利用这些不同的存储器并让系统高效地运行呢?通常这需要复杂的 link script 来管理实现,而 Andes 提供了分散聚合 (SAG, Scattering-And-Gathering)机制,SAG 机制能够将加载和运行时存储器中的代码和数据描述在一个 SAG 格式的文本描述文件中,并通过 link generator tool 将SAG 文件转化为标准GNU 的link script 文件,以供链接时使用。采用Andes的分散聚合机制,不仅可以帮助工程师清晰的描述存储器的使用情况,更可以避免使用复杂的标准 linker 脚本语言 。本文详细介绍了 SAG 语法格式,并以实际工程为例,阐述 SAG 的使用方法和益处。

1. Andes ELF 的目标文件的构成
Andes 使用标准的 GNU link script 格式,Andes 的目标文件也遵行标准的
ELF(Executable and Linking Format)格式。
ELF 目标文件主要由 .text 段 .data 段 .bss 段,还有一些其它的段如:.debug .comment 段。

下面以一个简单的 link script 的例子作为说明:
  SECTIONS 是 link script 语法中的关键 command,它用来描述输出文件的内存布局。例如上例中就含.text, .data, .bss 三个部分。
  .=0x10000; 其中的.是 location counter(LC)。表示.text 段虚拟地址从
0x10000 开始的。
  AT 用来说明加载地址,AT(0)表示.text 段的加载地址是 0。{ *(.text) },这个表示输出文件的.text 段内容由所有输入文件()的.text 段组成。后面的一个. = 0x40000。如果没有这个赋值,那么 LC 应该等于 0x10000+sizeof(text 段),这里强制指定 LC=0x40000.表明后面的.data 段的虚拟地址从 0x40000 开始。
  LOADADDR 用来得到加载地址,此处.data 段的加载地址是 AT(LOADADDR (.text) + SIZEOF (.text)),它紧接着.text 段,.data 为所有输入目标文件的.data段构成。同理,.bss 段的虚拟地址是紧接着.data 段虚拟地址之后,而加载地址是紧接着.data 段加载地址之后的。.bss 段由所有输入目标文件的.bss 段组成。通常在实际使用中的link script 会更加的复杂,SAG 机制能够很好的简化link
script 的设计,那接下来将对 SAG 机制作介绍。

2. Andes SAG 语法
SAG 使用巴科斯范式(BNF notation)中的以下几种符号表示:

SAG 格式总览
SAG 语法格式由:load regions,execution regions,input sections 等几部分组成,如下图所示:

2.1 关于 LMA 和 VMA
一般在嵌入式系统中,程序存储和运行在不同的地址空间,LMA 表示的是程序装载地址,VMA 表示的是程序运行地址,LMA 不等于 VMA 时程序在加载后不可直接运行,程序运行前,要把程序的内容,拷贝到对应的内存地址处,才能正确地运行。

2.2 header 格式
当要使用用户自定义的 section 时,须要使用 USER_SECTIONS 这个关键字。

2.3 Load Region(加载区)
Load Region 格式为:
load_region_name 用来表示某个程序加载区的名称。
address 表示的是 LMA。
offset 表示的是偏移量,当此时是第一个 load region 时表示的是与 0 地址的偏移量,当表示的不是第一个 load region 时,表示的是与前一个 load region结尾处的偏移量。
load_attr 表示属性,现在可以设置为 ALIGN alignment, 如 ALIGN 0x4 max_size 表示该加载区域的最大值。
例子:
LOAD_ROM_1 0x0000 ALIGN 0x4 0x10000
在这个例子中 load_region_name 是:LOAD_ROM_1,LMA 是 0x0000,以 4-byte 对齐,
max_size 是 64k

2.4 Execution Region(执行区)
Execution Region 格式为:
exe_region_name 用于表示某个程序执行区的名称
address 表示的是 VMA。
offset 当表示的是第一个 execution region,表示的是与该加载区的偏移量,当表示的不是第一 execution region 时,offset 表示的是前一个 execution region结尾处的偏移量。
exe_attr 表示属性,如可以设置为 ALIGN alignment,如 ALIGN 0x4 max_size 表示该 execution region 的最大值。
例子:
EXEC_ROM_1 0x0000 ALIGN 0x4 0x8000
在这个例子中exe_region_name 是 EXEC_ROM_1,它的 VMA 是 0x0000, 以
4-byte 对齐,max_size 是 32k

2.5 Input Section(输入段)
Input Section 的描述格式为:
此处:
module_select_pattern 可以是目标文件名
input_attr 可以是KEEP,该属性可以保证该 section 在链接时不会被remove
掉,或者是 SORT,用于排序。例子如:
program1.o KEEP(+RO)
此时该 input section 将包含目标文件 program1.o 中所有的 read-only section,由于加了 KEEP,所以所添加的 section 在链接的时候不会被 gc-section删除掉。
input_section_selector 中最常用的是 input section_attr。 input section_attr 有以下几种:

input_section_selector 中另外一种用的是 input_section_pattern,它的表示方法是 input_section_pattern ::= (.text | .data|…)。

ADDR variable 用于得到该处的 VMA 赋给 variable。 LOADADDR variable 用于得到该处的 LMA 赋给 variable。 STACK “=” num 为 sp 准备一个初始值 num。
VAR 用于设定并初始化一个变量。如 VAR _ILM_BASE = 0x00600000。

2.6 Execution Overlay Region(overlay 的执行区)
当使用 overlay 功能时,需要设定 Execution Overlay Region,设定格式为:
它在后面加了个:OVERLAY 的关键字。
pagesize 后面表示 Overlay 的大小,当是 0 时,表示 software Overlay,其它的设置和前面的 execution region 相同。

2.7 Overlay Input Section(overlay 的输入段)
当使用 overlay 功能时,要设置 Overlay Input Section,它和前面的 Input Section 类似。

3. 例子
如下例子所示的效果是:
在一个系统中,从 0x0000 开始,大小为 0x2000 的是 ROM1, 从 0x4000
开始,大小为 0x8000 的是 ROM2,此时我们需要将目标文件 program1.o 的 RO和 RW,ZI data。 存放在 ROM1 中,将其它目标文件的 .text,RO,RW, ZI 存放在 ROM2 中。此时的 LMA 效果对应于下图的左侧。
同时需要将目标文件program1.o 中的RW, ZI 的运行地址设置在从0x10000开始的大小为 0x8000 的 DRAM 上,将其它目标文件的 RW,ZI 的运行地址设置在从 0x18000 开始,大小为 0x8000 的SRAM 上。此时的 VMA 效果对应于下图的右侧。

该例子中 program1.o 中的 RO 和其它目标文件中的.text, RO 的 LMA 和 VMA 是相等的,此时所有的 RW,ZI 的加载区域是分别在 ROM1 和 ROM2 上,但是运行地址是分别在 DRAM 和 SRAM 上,所以 RW,ZI 的 LMA 不等于 VMA,所以在程序使用到 RW, ZI 所代表的.data,.bss 段之前需要将它们从加载区复制到运行区,以达到所图中右侧所示的效果。

对应的 SAG 可以这样设计:
利用 SAG 机制,除了快速设计上列所示的系统中存储的分配机制,还可以快速的进行 overlay 程序的设计,overlay 程序主要是用于分时重复利用快速但存储空间有限的存储器。

4.将 SAG 文件转化成 linker script
在 AndeSight 或者 BSP package 中提供了叫做 nds_ldsag 的工具,该工具可以将 SAG 文件转化成标准的 GUN link script 文件。在 cygwin 下,执行方法如下,filename.ld 就是我们希望获得的link script 文件。
./nds_ldsag.exe filename.sag -o filename.ld

5.结语
Andes 提供的通俗、易用的 SAG 描述语言,可以帮助工程师根据系统中的存储设备的特点,对程序的加载与运行区域进行很方便的设计和描述,甚至可以快速的进行更为复杂的 overlay 程序的设计,然后通过自动化工具 nds_ldsag 将 SAG 描述文件转成标准 link 脚本供连接器使用,从而大大提高在 Andes core 平台上的软件开发效率。

参考文档:
1: BSP321 programming guide link generator
2: The GNU Linker Manual

Continue ReadingAndes 的分散聚合(SAG)机制