欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

在ZYNQ7020上学习ARM架构(1)——练习指令集

程序员文章站 2022-06-09 08:43:33
...

1. 前言

最近在看ARM的架构,看到指令集 这一章,讲的比较简单,也没有具体的例子,所以就想着实践一下。ARM官网也给出了几个练习,就想着先尝试一下。但是官方的开发软件是收费的同时使用的还是模拟器,而我手边正好有搭载ARM Cortex-A9的ZYNQ7020,就直接在ZYNQ上练习好了。

Note: 这篇文章记录了我的思路历程,不是纯粹的教程,可能会繁琐。

2. ZYNQ的ARM核是怎么样启动的

到最后才发现,这里其实不需要知道就可以继续了,但是既然去了解了我就把他写下来。

2.1 stage0:BootROM

可以理解为固件,是写死在芯片上的(具体写在哪里我也没找到),在APU上电后或者系统复位后(PS_POR_B 接口复位)就开始执行。
在ZYNQ7020上学习ARM架构(1)——练习指令集
首先判断是JTAG启动还是Flash Device启动

  • 如果是JTAG启动,后面还会细分Cascade还是Independent模式,没看太懂,这里暂时不细致研究
  • 如果是Flash Device启动,图上给出了很多细节,重点就是会把FSBL或者用户配置的代码搬运到OCM(On-chip Memory).
    在ZYNQ7020上学习ARM架构(1)——练习指令集

2.2 stage1:执行启动/用户代码

BootROM会从SD卡或者QSPI读取FSBL,具体步骤可以参见基础教程6.4节。这里有一个关键的理解就是,boot文件的构成
在ZYNQ7020上学习ARM架构(1)——练习指令集
使用SDK生成Boot Image的时候,第一项会自动生成,第二项需要新建fsbl工程然后编译出fsbl.elf,第三项就是自己的工程代码然后编译xxx.elf。创建Boot Image的方法:
在ZYNQ7020上学习ARM架构(1)——练习指令集
在ZYNQ7020上学习ARM架构(1)——练习指令集

2.3 小结

了解了这一部分内容之后,如果想直接编写汇编程序简单操作ARM Cortex-A9而的话甚至不需要建立工程,将自己的.s文件编译好得到可执行文件.elf后即可制作boot image然后使用SD卡或者其他方式进行加载,当然也可以使用SDK的system debuger使用JTAG加载/调试。

3. 汇编程序求最大公约数GCD

这是ARM文档里的第一次Exercise

3.1 算法描述-更相减损法

可以参考博文
更相减损术
不妨设A>B,设A和B的最大公约数为X,所以 A=aX,B=bx,其中a和b都为正整数,且a>b。
C = A-B,则有:
C=aX−bX=(a−b)X

因为a和b均为正整数,所以C也能被X整除,即A、B、C最大公约数均为X
所以gcd(A,B) = gcd(B,A-B)

不断迭代后(a-b)一定可以归一,然后a b也会先后归一, X即为A=B的值。

3.2 官方答案

gcd:
    CMP    w0, w1         // Compare a and b
    B.EQ   end            // If they are equal, skip to the end
    B.LS   less_than      // If unsigned less than, branch to b = b -a
    SUB    w0, w0, w1     // a = a - b
    B      gcd            // Branch back to start
less_than:
    SUB    w1, w1, w0     // b = b - a
    B      gcd            // Branch back to start
end:
    RET

官方给出的是基于ARMv8 A64的代码,而Cortex-A9是v7 A32的代码,同时架构不同。总体差别还是挺大的。

3.3 最终代码

我也不大会写汇编,东拼西凑把这个简单的函数凑出来了

    .section  GCD,"ax"
    .align 2

    .global gcd
    // uint32_t gcd(uint32_t a, uint32_t b)
    .type gcd, %function
 .fnstart
 gcd:
 	cmp r0,r1
 	beq end
 	blt less_than
 	sub r0,r0,r1
 	b gcd
 less_than:
 	sub r1,r1,r0
    b gcd
 end:
 	bx lr

 .fnend

3.4 主函数

主函数还是使用了c来写,同时使用了helloworld模板,简单做了UART输出

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"

extern uint32_t gcd(uint32_t, uint32_t);

int main()
{
    init_platform();
    uint32_t result, a, b;

    a = 24;
    b = 86;

    result = gcd(a, b);

    printf("GCD Workbook: The GCD of %d and %d is %d\n", a, b, result);

    cleanup_platform();
    return 0;
}

输出结果:
在ZYNQ7020上学习ARM架构(1)——练习指令集

相关标签: ARM