编写ARM汇编程序,完成两个64位数相加,结果存放在NUM单元

编写ARM汇编程序,完成两个64位数相加,结果存放在NUM单元,第1张

MOV R0 #X;第一个立即数的低32位

MOV R1 #Y;第二个立即数的低32位

ADD R2 R1 R0;低位相加

MOV R0 #X>>32;第一个立即数的高32位

MOV R1 #Y>>32;第二个立即数的高32位

ADC R1 R0;带进位的高位相加

MOV R0 #NUM;内存单元NUM地址送入R0

STR R2 [R0];存储低32位结果

STR R1 [R0,#32];存储高32位结果

keil 里面的stdioh

和PC上的一样只是个头文件而已

库里面的printf函数不是用来显示的

而是你 如果51单片机的串口初始化了

printf函数会把你的数据从串口输出而已

你软件仿真查看串口那边的输出就知道了

存在问题:“普通电脑显示器”可能比较难,需要了解CRT或LCD显示器的接口。一般是驱动TFT等类型的LCD显示器。

前期基础:了解ARM核基本使用、了解C/C++语言基础及一点ARM汇编、了解开发工具链基本使用;还需要了解一些简单的硬件基础。

基本条件:有原理图,有相应芯片的datasheet。

开始:(各种ARM芯片流程大致类似)

1 ARM启动代码:异常向量、中断初始化;(代码搬移,可选);堆、栈初始化;CPU、MMU、时钟等的初始化,C运行环境的其他准备。

2 进入C后,基本驱动编写:需要了解ARM芯片是否有LCD控制器,然后根据情况编写这部分驱动代码(第一回配置可能不太容易,可参考样例程序),如果没有LCD控制器就有点麻烦了(其他芯片做?自己写?);其他驱动程序(存储器,如SDRAM、FLASH等),根据需要编写。

3 基本库程序:可以自写,也可以找现成的,主要涉及字符串处理、IO处理(printf)等,其他基本库(内存分配等)。

4 编写应用程序:你的这个例子就是在显示驱动基础上,写“Hello world”。

5 编写连接脚本:根据内存分配情况和程序存储情况写,有模板,连接时用。

开发流程:

1 编写程序;

2 编译;

3 连接;

4 加载或下载;

5 调试/运行;

6 反复执行1~5步骤,直到实现你的功能。

参考:

1 各芯片厂商的application note,有应用程序样例及代码,也可以找到相关驱动程序的样例;

2 网上搜索或看书学习开发过程;

3 可以参考uboot早期一些的代码,比较简单好懂。

你可以自己写一个汇编的程序,把Nand Flash 中的程序搬到SDRAM中。因为S3C2410有Nor Flash和Nand Flash有两种启动方式,所以在搬移过程中略有不同。如果用Nand Flash启动可以使用下面的代码,至于Nor Flash启动就相对简单了,你可以自己研究一下。

文件1heads

@ 文件 heads

@ 作用:关闭看门狗、SDRAM 的初始化设置、搬移 Nand Flash 4K 以后

@ 的代码到 SDRAM 的指定位置、执行 SDRAM 中的代码

text

global _start

_start:

ldr r0, =0x53000000 @ Close Watch Dog Timer

mov r1, #0x0

str r1, [r0]

bl memory_setup @ Initialize memory setting

bl flash_to_sdram @ Copy code to sdram

ldr sp, =0x34000000 @ Set stack pointer

ldr pc, =main @ execute the code in SDRAM

文件2:flashs

@ 文件 flashs

@ 作用:设置 Nand Flash 的控制寄存器、读取 Nand Flash

@ 中的代码到 SDRAM 的指定位置

equ NFCONF, 0x4e000000

equ NFCMD, 0x4e000004

equ NFADDR, 0x4e000008

equ NFDATA, 0x4e00000c

equ NFSTAT, 0x4e000010

equ NFECC, 0x4e000014

global flash_to_sdram

flash_to_sdram:

@ Save return addr

mov r10,lr

@ Initialize Nand Flash

mov r0,#NFCONF

ldr r1,=0xf830

str r1,[r0]

@ First reset and enable Nand Flash

ldr r1,[r0]

bic r1, r1, #0x800

str r1,[r0]

ldr r2,=NFCMD

mov r3,#0xff

str r3,[r2]

@ for delay

mov r3, #0

1:

subs r3, r3, #1

bne 1b

@ Wait until Nand Flash bit0 is 1

wait_nfstat:

ldr r2,=NFSTAT

ldr r3,[r2]

tst r3,#0x01

beq wait_nfstat

@ Disable Nand Flash

ldr r0,=NFCONF

ldr r1,[r0]

orr r1,r1,#0x8000

str r1,[r0]

@ Initialzie stack

ldr sp,=4096

@ Set arguments and call

@ function nand_read defined in nand_readc

ldr r0,=0x30000000

mov r1,#4096

mov r2,#1024

bl nand_read

@ return

mov pc,r10

文件3:interruptc

/

文件 interruptc

作用:设置并响应按键中断

/

#include "printfh"

#define GPECON ((volatile unsigned long )0x56000040)

#define GPEDAT ((volatile unsigned long )0x56000044)

#define GPEUP ((volatile unsigned long )0x56000048)

#define GPFCON ((volatile unsigned long )0x56000050)

#define GPFDAT ((volatile unsigned long )0x56000054)

#define GPFUP ((volatile unsigned long )0x56000058)

#define GPGCON ((volatile unsigned long )0x56000060)

#define GPGDAT ((volatile unsigned long )0x56000064)

#define GPGUP ((volatile unsigned long )0x56000068)

#define EINTMASK ((volatile unsigned long )0x560000a4)

#define INTMSK ((volatile unsigned long )0X4a000008)

#define PRIORITY ((volatile unsigned long )0x4a00000c)

#define EINTPEND ((volatile unsigned long )0x560000a8)

#define INTPND ((volatile unsigned long )0X4a000010)

#define SRCPND ((volatile unsigned long )0X4a000000)

#define BIT_EINT0 (0x1 << 0)

#define BIT_EINT2 (0x1 << 2)

#define BIT_EINT8_23 (0x1 << 5)

#define SET_KEY_INTERRUPT_REG() ({ \

GPGCON = (GPGCON & (~((3<<12)|(3<<4)))) | ((1<<12)|(1<<4)) ; \

GPGDAT = GPGDAT & (~((1<<6)|(1<<2))); \

GPECON = (GPECON & (~((3<<26)|(3<<22)))) | ((1<<26)|(1<<22)); \

GPEDAT = GPEDAT & (~((1<<13)|(1<<11))); \

GPGCON = (GPGCON & (~((3<<22)|(3<<6)))) | ((2<<22)|(2<<6)) ; \

GPFCON = (GPFCON & (~((3<<4)|(3<<0)))) | ((2<<4)|(2<<0)) ; \

})

__inline void ClearPending(int bit)

{

SRCPND = bit;

INTPND = bit;

}

void init_irq( ) {

GPFCON = ((0x1<<8) | (0x1 << 10) | (0x1 << 12) | (0x1 << 14)); // Set the led D9~D12 output

/

GPGCON = (GPGCON & (~((3<<12)|(3<<4)))) | ((1<<12)|(1<<4)) ; // GPGCON6,2 set output

// GPGCON6:KSCAN1

// GPGCON2:KSCAN3

GPGDAT = GPGDAT & (~((1<<6)|(1<<2))); // GPGDAT6,2 output 0

GPECON = (GPECON & (~((3<<26)|(3<<22)))) | ((1<<26)|(1<<22)); // GPECON13,11 set output

GPEDAT = GPEDAT & (~((1<<13)|(1<<11))); // GPEDAT13,11 output 0

GPGCON = (GPGCON & (~((3<<22)|(3<<6)))) | ((2<<22)|(2<<6)) ; // GPGCON11,3 set EINT

GPFCON = (GPFCON & (~((3<<4)|(3<<0)))) | ((2<<4)|(2<<0)) ; // GPFDAT2,0 set EINT

/

// Use the defined micro instead of above code

SET_KEY_INTERRUPT_REG();

GPFUP |= (1<<0) | (1<<2); // Up

GPGUP |= (1<<3) | (1<<11); // Up

EINTPEND |= (1 << 19) | (1 << 11); // Clear eint 11,19

EINTMASK &= (~((1 << 19) | (1 << 11))); // Enable EINT11,19

ClearPending(BIT_EINT0|BIT_EINT2|BIT_EINT8_23); // Enable EINT0,2 and the EINT8_23

INTMSK &= (~0x25);

return;

}

int Key_Scan( void )

{

int i;

for(i = 0; i < 1000 ;i++) ;

GPGDAT = (GPGDAT &(~((1<<6)|(1<<2)))) | (1<<6) | (0<<2) ; //GPG6,2 output 0

GPEDAT = (GPEDAT &(~((1<<13)|(1<<11)))) | (1<<13) | (1<<11) ; //GPE13,11 output 0

if( (GPFDAT&(1<< 0)) == 0 ) return 16 ;

else if( (GPFDAT&(1<< 2)) == 0 ) return 15 ;

else if( (GPGDAT&(1<< 3)) == 0 ) return 14 ;

else if( (GPGDAT&(1<<11)) == 0 ) return 13 ;

GPGDAT = (GPGDAT &(~((1<<6)|(1<<2)))) | (0<<6) | (1<<2) ; //GPG6,2 output 0

GPEDAT = (GPEDAT & (~((1<<13)|(1<<11)))) | (1<<13) | (1<<11) ; //GPE13,11 output 0

if( (GPFDAT&(1<< 0)) == 0 ) return 11 ;

else if( (GPFDAT&(1<< 2)) == 0 ) return 8 ;

else if( (GPGDAT&(1<< 3)) == 0 ) return 5 ;

else if( (GPGDAT&(1<<11)) == 0 ) return 2 ;

GPGDAT = (GPGDAT & (~((1<<6)|(1<<2)))) | (1<<6) | (1<<2) ; //GPG6,2 output 0

GPEDAT = (GPEDAT & (~((1<<13)|(1<<11)))) | (1<<13) | (0<<11) ; //GPE13,11 output 0

if( (GPFDAT&(1<< 0)) == 0 ) return 10 ;

else if( (GPFDAT&(1<< 2)) == 0 ) return 7 ;

else if( (GPGDAT&(1<< 3)) == 0 ) return 4 ;

else if( (GPGDAT&(1<<11)) == 0 ) return 1 ;

GPGDAT = (GPGDAT & (~((1<<6)|(1<<2)))) | (1<<6) | (1<<2) ; //GPG6,2 output 0

GPEDAT = (GPEDAT & (~((1<<13)|(1<<11)))) | (0<<13) | (1<<11) ; //GPE13,11 output 0

if( (GPFDAT&(1<< 0)) == 0 ) return 12 ;

else if( (GPFDAT&(1<< 2)) == 0 ) return 9 ;

else if( (GPGDAT&(1<< 3)) == 0 ) return 6 ;

else if( (GPGDAT&(1<<11)) == 0 ) return 3 ;

else return 0xff ;

}

void EINT_Handle( void ) {

GPGCON = (GPGCON & (~((3<<22)|(3<<6)))) | ((0<<22)|(0<<6)) ; //GPG11,3 set input

GPFCON = (GPFCON & (~((3<<4)|(3<<0)))) | ((0<<4)|(0<<0)) ; //GPF2, 0 set input

if(INTPND==BIT_EINT8_23) {

if(EINTPEND&(1<<11))

EINTPEND |= 1<< 11;

if(EINTPEND&(1<<19))

EINTPEND |= 1<< 19;

ClearPending(BIT_EINT8_23);

}

else if(INTPND==BIT_EINT0) {

ClearPending(BIT_EINT0);

} else if(INTPND==BIT_EINT2) {

ClearPending(BIT_EINT2);

}

int key = Key_Scan() ;

if( key != 0xff ) {

uart_printf( "K%d is pressed!\n", key ) ;

GPFDAT = ~(key << 4);

}

SET_KEY_INTERRUPT_REG();

return;

}

文件4:mems

@ 文件 mems

@ 作用:SDRAM 的初始化设置

@ 关于初始化的更多细节,请参考我的前一篇随笔

global memory_setup @ 导出 memory_setup, 使其对链接器可见

memory_setup:

mov r1, #0x48000000

adrl r2, mem_cfg_val

add r3, r1, #134

1:

@ write initial values to registers

ldr r4, [r2], #4

str r4, [r1], #4

cmp r1, r3

bne 1b

mov pc, lr

align 4

mem_cfg_val:

long 0x22111110 @ BWSCON

long 0x00000700 @ BANKCON0

long 0x00000700 @ BANKCON1

long 0x00000700 @ BANKCON2

long 0x00000700 @ BANKCON3

long 0x00000700 @ BANKCON4

long 0x00000700 @ BANKCON5

long 0x00018005 @ BANKCON6

long 0x00018005 @ BANKCON7 9bit

long 0x008e07a3 @ REFRESH

long 0x000000b2 @ BANKSIZE

long 0x00000030 @ MRSRB6

long 0x00000030 @ MRSRB7

文件5:nand_readc

/ 文件 nand_readc

作用:从 Nand Flash 中读取一块数据到 SDRAM 中的指定位置

/

#define NFCONF ((volatile unsigned long )0x4e000000)

#define NFCMD ((volatile unsigned long )0x4e000004)

#define NFADDR ((volatile unsigned long )0x4e000008)

#define NFDATA ((volatile unsigned long )0x4e00000c)

#define NFSTAT ((volatile unsigned long )0x4e000010)

#define NFECC ((volatile unsigned long )0x4e000014)

#define NAND_SECTOR_SIZE 512

#define NAND_BLOCK_MASK 0x1ff

void wait_idle() {

int i;

for (i = 0; i < 50000; ++i) ;

}

int nand_read(unsigned char buf, unsigned long start_addr, int size){

int i, j;

/

detect the argument

/

if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {

return -1;

}

/ chip Enable /

NFCONF &= ~0x800;

for (i=0; i<10; i++) {

;

}

for (i=start_addr; i < (start_addr + size); i+=NAND_SECTOR_SIZE) {

NFCMD = 0;

/ Write Address /

NFADDR = i & 0xff;

NFADDR = (i >> 9) & 0xff;

NFADDR = (i >> 17) & 0xff;

NFADDR = (i >> 25) & 0xff;

wait_idle();

for(j=0; j < NAND_SECTOR_SIZE; j++) {

buf++ = (NFDATA & 0xff);

}

}

NFCONF |= 0x800; / chip disable /

return 0;

}

文件6:sdramc

/ 文件 sdramc

作用:循环点 FS2410 开发板上的 D9、D10、D11、D12

四个发光二极管。

/

#define GPFCON ((volatile unsigned long )0x56000050)

#define GPFDAT ((volatile unsigned long )0x56000054)

int main()

{

int i,j;

while(1) {

for (i = 0; i <4; ++i) {

GPFCON = 0x1<<(8+i2);

GPFDAT = 0x0;

// for delay

for(j=0;j<50000;++j) ;

}

}

}

文件7:nandlds

SECTIONS {

first 0x00000000 : { heado memo flasho nand_reado }

second 0x30000000 : AT(4096) { sdramo }

}

文件8:Makefile

sdram:heads flashs mems sdramc

arm-linux-gcc -c -o heado heads

arm-linux-gcc -c -o memo mems

arm-linux-gcc -c -o flasho flashs

arm-linux-gcc -c -o nand_reado nand_readc

arm-linux-gcc -c -o sdramo sdramc

arm-linux-ld -Tnandlds heado memo flasho nand_reado sdramo -o sdram_tmpo

arm-linux-objcopy -O binary -S sdram_tmpo sdram

clean:

rm -f o

rm -f sdram

好了,你把这些文件拷下去,执行make命令就能生成可执行的二进制代码sdram,把sdram烧写到板子上就能运行了。祝你好运

原理

辗转相除法.

当两个数都较大时,采用辗转相除法比较方便.其方法是:

以小数除大数,如果能整除,那么小数就是所求的最大公约数.否则就用余数来除刚才的除数;再用这新除法的余数去除刚才的余数.依此类推,直到一个除法能够整除,这时作为除数的数就是所求的最大公约数.

CMP r0,r1

MOVCC r3,r0

MOVCC r0,r1

MOVCC r1,r3

S0

CMP r1,#0

BEQ S3

S1

CMP r0,r1

BCC S2

SUB r0,r0,r1

B S1

S2 MOV r3,r0

MOV r0,r1

MOV r1,r3

B S0

S3

END

没调试过,不知道程序有什么错误没有。

怎么说呢,不管是用汇编或C语言编程,都与单片机硬件结构有关,程序都要对硬件进行 *** 作,两种单片机在结构上相差较大,程序肯定也差别很大

但用C语言编程时,一些通用数学运算和硬件无关,包括一些对外部器件 *** 作的函数也可以认为与硬件无关,因此许多子程序是有通用性的,因此开发程序时,还是要分层 *** 作,就是将一些与硬件结构有关的 *** 作单独写成子程序,由这些子程序组成高一层函数,硬件变化时,底层函数要修改,而一些上层函数可以不用修改

如读写W25Q16 FLASH 基本 *** 作是发送一个字节数据和接收字一个节数据,这在不同的单片机上是不同的,但实际应用时,我们都是用其上层函数,即向某地址(或某地址开头的空间内)写入一个或多个数据,或者从某地址读出一个或多个数据,这是与单片机硬件无关的

我们将基本 *** 作过程单独编成子程序,那怕只有很少的一两条指令也要这样做,再由这些子程序组成更高级的子程序,即任意地址读写程序,这样硬件平台发生变化时,上层函数就 不用修改了

以上就是关于编写ARM汇编程序,完成两个64位数相加,结果存放在NUM单元全部的内容,包括:编写ARM汇编程序,完成两个64位数相加,结果存放在NUM单元、运用arm写程序的调用stdio.h C:\Keil\ARM\RV31\INC\stdio.h(659): error: #79: expected a type specifie、如何在ARM7上不用 *** 作系统写个最简单的类似HELLO WORLD 的程序呢等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/10091280.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-05
下一篇 2023-05-05

发表评论

登录后才能评论

评论列表(0条)

保存