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

1. 前言

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

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

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

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

2.1 stage0:BootROM

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

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

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

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

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 
#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;
}

输出结果:
在这里插入图片描述

你可能感兴趣的:(ARM)