or1k启动文件分析

or1k从spi flash启动文件spi_uimage_loader.S内容如下:

	/* Assembly program to go into the boot ROM */
	/* For use with simple_spi SPI master core and standard SPI flash
	   interface-compatible parts (ST M25P16 for example.)*/
	/* Currently just loads a program from SPI flash into RAM */

/* Simple SPI的基址,用于和SPI Flash通信 */
#ifndef SPI_BASE
#define SPI_BASE 0xB0000000
#endif

/* SPI Flash中24bit的地址,应用程序的起始地址 */
#ifndef BOOTROM_ADDR
#define BOOTROM_ADDR 0x000000
#endif	

/*A0-A2:代表24位地址的每个字节*/
#define HEADER_ADDR BOOTROM_ADDR + 0xc
#define A2 ((HEADER_ADDR) >> 16) & 0xFF
#define A1 ((HEADER_ADDR) >> 8) & 0xFF
#define A0  (HEADER_ADDR) & 0xFF

#ifndef INIT_DELAY
#define INIT_DELAY 1250 //FIXME 0
#endif	
	
#define SPI_SPCR 0x0
#define SPI_SPSR 0x1
#define SPI_SPDR 0x2
#define SPI_SPER 0x3
#define SPI_SPSS 0x4

#define SPI_SPCR_XFER_GO 0x51
#define SPI_SPSS_INIT 0x1
#define SPI_SPSR_RX_CHECK 0x01 /* Check bit 0 is cleared, fifo !empty*/

	/* Registers used
	r1 temp register (used in spi_xfer)
	r2 spi_xfer return value
	r3 spi_xfer tx data
	r4 Simple SPI base address
	r5 spi_xfer byte counter
	r6 temp register
	r7 temp register
	r8 temp register
	r9 return address
	r10
	r11 Image size
	r12 Load address
	r13 Reset vector
	*/	
boot_init:	
	l.movhi r0, 0
	l.movhi r2, 0
	l.movhi r5, 0

	l.movhi r1,     hi(INIT_DELAY)
	l.ori   r1, r1, lo(INIT_DELAY)
1:	l.sfeqi r1, 0
	l.bnf 1b
	l.addi r1, r1, -1
	
	l.movhi r4, hi(SPI_BASE)
	
spi_init:
	l.ori 	r2, r0, SPI_SPCR_XFER_GO /* Setup SPCR with enable bit set */
	l.sb 	SPI_SPCR(r4), r2
	l.sb  	SPI_SPSS(r4), r0         /* Clear SPI slave selects */
	l.ori 	r6, r0, SPI_SPSS_INIT
	l.sb  	SPI_SPSS(r4), r6         /* Set appropriate slave select */

	l.ori   r5, r0, 1 /*Set spi_xfer in byte mode */
	l.jal	spi_xfer
	l.ori 	r3, r0, 0x3              /* READ command opcode for SPI device*/

	l.jal 	spi_xfer

	/* Set start address in SPI Flash */
	l.ori 	r3, r0, A2
	l.jal 	spi_xfer
	l.ori 	r3, r0, A1
	l.jal 	spi_xfer
	l.ori 	r3, r0, A0

	l.ori r5, r0, 4 /* set spi_xfer in word mode */
	
	/* Load image size to r11 */
get_size:
	l.jal spi_xfer
	l.nop
	l.or r11, r2, r0

	/* Load RAM base address to r12 */
get_load_addr:
	l.jal spi_xfer
	l.nop
	l.or r12, r2, r0
	
	/* Load reset vector to r13 */
get_entry_point:
	l.jal spi_xfer
	l.nop
	l.or r13, r2, r0
	
	/* Dummy read rest of the uimage header */
	l.ori r6, r0, 0x9
get_rest:
	l.jal spi_xfer
	l.nop
	l.sfeqi r6, 0

	l.bnf get_rest
	l.addi r6, r6, -1
	
	// r6 = loop counter
	// r7 = memory store address
	// Assumes at least one 32-bit word in image
	//Fixme: Copy last remaining words in byte mode
	l.movhi r6, 0
copy:	
	l.jal 	spi_xfer         /* Read a word into r2 */
	l.add	r7, r12, r6      /* Set memory store address */
	l.sw    0(r7), r2        /* Write word */

	l.addi	r6, r6, 4        /* Increse counter */

	l.sfgeu r6, r11         /* Check if file is completely copied */
	l.bnf copy
	l.nop

goto_reset:
	l.jr 	r13
	l.sb  	SPI_SPSS(r4), r0 /* Clear SPI slave selects */
	
/* Write one byte, or read one to four bytes with Simple SPI
	r1 = temp register
	r2 = Data read back from SPI
	r3 = Byte to write
	r4 = Simple SPI Base address
	r5 = Number of transfers (1-4)
	*/
spi_xfer:
	l.or r1, r5, r0
	
spi_xfer_loop:	
	l.sb 	SPI_SPDR(r4), r3  /* Dummy write what's in r3 */
	l.ori 	r3, r0, SPI_SPSR_RX_CHECK /* r3 = , ensure loop just once */
spi_xfer_poll:	
	l.andi 	r3, r3, SPI_SPSR_RX_CHECK /* AND read fifo bit empty */
	l.sfeqi r3, SPI_SPSR_RX_CHECK    /* is bit set? ... */
	l.bf 	spi_xfer_poll     /* ... if so, rxfifo empty, keep polling */
	l.lbz 	r3, SPI_SPSR(r4) /* Read SPSR */

	l.lbz 	r3, SPI_SPDR(r4) /* Get data byte */

	l.slli r2, r2, 8
	l.or   r2,  r2, r3
	l.sfeqi r1, 1
	l.bnf spi_xfer_loop
	l.addi r1, r1, -1
	
	l.jr 	r9
	l.nop

大家or1k环境地址划分如下:

地址划分:

设备起始地址地址掩码大小
sdram0x0000_00000xfe00_000032MBytes
rom00xf000_00000xffff_fc001024Bytes
uart00x9000_00000xffff_ffe032Bytes
gpio00x9100_00000xffff_fffe1Bytes
gpio10x9200_00000xffff_fffe1Bytes
i2c00xa000_00000xffff_fff88Bytes
i2c10xa100_00000xffff_fff88Bytes
spi00xb000_00000xffff_fff88Bytes
spi10xb100_00000xffff_fff88Bytes
spi20xb200_00000xffff_fff88Bytes

 主要学习Linux开发,受限当前FPGA资源,只有1*uart+3*SPI+2*gpio+2*i2c+sdram

第一部分:

boot_init:	
	l.movhi r0, 0
	l.movhi r2, 0
	l.movhi r5, 0

	l.movhi r1,     hi(INIT_DELAY)
	l.ori   r1, r1, lo(INIT_DELAY)
1:	l.sfeqi r1, 0
	l.bnf 1b
	l.addi r1, r1, -1
	
	l.movhi r4, hi(SPI_BASE)

把 r0,r2,r5清零

l.movhi r1,     hi(INIT_DELAY),取出INIT_DELAY高16位放到r1中

注意:hi(INIT_DELAY) === INIT_DELAY >> 16

l.movhi    r1,k   ===    r1=(k<<16) ,为什么要这么麻烦右移后又左移,是因为指令只能携带16位立即数

l.ori   r1, r1, lo(INIT_DELAY),执行完这条指令后,r1中的内容就是INIT_DELAY,这两条指令就是把INIT_DELAY放到r1中

1:    l.sfeqi r1, 0:当r1等于0时设置flag标志

    l.bnf 1b :当flag标志没有设置时,跳到之前1处,b not flag

    l.addi r1, r1, -1:当上面r1等于0的时候,flag标志会设置,程序执行到当前行,此时r1等于1,执行减一操作后,此时r1等于0xffff_ffff

l.movhi r4, hi(SPI_BASE):把SPI_BASE高16位放到r4中

l.ori     r2, r0, SPI_SPCR_XFER_GO:把0x51放到r2中,此时r0=0,或运算的结果就是赋值

l.sb     SPI_SPCR(r4), r2:把r2的值放到 r4+SPI_SPCR 指向的地址,就是向SPI_SPCR寄存器写入0x51, l.sb是store byte

l.sb      SPI_SPSS(r4), r0:同理此时r0=0,则向SPI_SPSS写入0

l.ori     r6, r0, SPI_SPSS_INIT:此时r0=0,设置r6=SPI_SPSS_INIT=1

l.sb      SPI_SPSS(r4), r6:同理向SPI_SPSS寄存器写入r6=1

l.ori   r5, r0, 1:把r5设置为1

l.jal    spi_xfer:跳转到spi_xfer地址

本工程集成spi控制器为simple_spi,它有4个寄存器,每个寄存器8位

SPCR:控制寄存器,每位可读可写

bit7:中断使能位,1:使能中断 0:禁止中断

bit6: 控制器模块使能, 1:使能 0:禁止

bit5:保留位

bit4:设备模式选择,1:主设备 0:从设备

bit3,bit2:CPOL,CPHA

bit1-0 :SPI CLK频率选择位SPR,和ESPR配合完成分频

SPSR:状态寄存器,bit7-6:可读可写, 其它位只读

bit7:为1表示中断发生,写此位清除中断

bit6:wcol,写入冲突位,当写缓冲区满,写入时候出现此位,写入1清除此位

bit5-4:保留

bit3:写缓冲区满

bit2:写缓冲区空

bit1:接收缓冲区满

bit0:接收缓冲区空

SPDR:接收和发送缓冲区

读:接收缓冲区

写:发送缓冲区

SPER:扩展寄存器

bit7-6 : ICNT:传输完成1/2/3/4后设置中断标志

bit5-2:保留

bit1-0和控制寄存器bit1:0完成分频

从opencores下载的IPcore是没有片选的,下载的or1k添加第5个寄存器作为片选控制,每1位代表一个片选,写入1,对应片选拉低

对于上面操作

SPCR = 0x51

SPSS = 0

SPSS =1

功能,配置SPI控制器为master,并使能,spi clk为总线4分频,片选0拉低

再回头看上述汇编代码

	l.ori   r5, r0, 1 /*Set spi_xfer in byte mode */
	l.jal	spi_xfer
	l.ori 	r3, r0, 0x3              /* READ command opcode for SPI device*/

	l.jal 	spi_xfer

.......

/* Write one byte, or read one to four bytes with Simple SPI
	r1 = temp register
	r2 = Data read back from SPI
	r3 = Byte to write
	r4 = Simple SPI Base address
	r5 = Number of transfers (1-4)
	*/
spi_xfer:
	l.or r1, r5, r0
	
spi_xfer_loop:	
	l.sb 	SPI_SPDR(r4), r3  /* Dummy write what's in r3 */
	l.ori 	r3, r0, SPI_SPSR_RX_CHECK /* r3 = , ensure loop just once */
spi_xfer_poll:	
	l.andi 	r3, r3, SPI_SPSR_RX_CHECK /* AND read fifo bit empty */
	l.sfeqi r3, SPI_SPSR_RX_CHECK    /* is bit set? ... */
	l.bf 	spi_xfer_poll     /* ... if so, rxfifo empty, keep polling */
	l.lbz 	r3, SPI_SPSR(r4) /* Read SPSR */

	l.lbz 	r3, SPI_SPDR(r4) /* Get data byte */

	l.slli r2, r2, 8
	l.or   r2,  r2, r3
	l.sfeqi r1, 1
	l.bnf spi_xfer_loop
	l.addi r1, r1, -1
	
	l.jr 	r9
	l.nop

l.ori   r5, r0, 1:把r5设置为1

l.jal    spi_xfer:跳转到spi_xfer地址

l.ori     r3, r0, 0x3 :设置r3为3,注意:这条跟在跳转指令后的指令称为延迟指令,一定会被执行

l.or r1, r5, r0:设置r1 = r5=1

l.sb     SPI_SPDR(r4), r3: 设置SPI寄存器 SPDR = r3 = 3

l.ori     r3, r0, SPI_SPSR_RX_CHECK:设置r3 = 1

l.andi     r3, r3, SPI_SPSR_RX_CHECK:r3 = r3 & 1 = 1

l.sfeqi r3, SPI_SPSR_RX_CHECK:设置flag = (r3==1)?1:0

l.bf     spi_xfer_poll:跳转到 spi_xfer_poll

l.lbz     r3, SPI_SPSR(r4):读取SPI SPSR寄存器到r3, 这条是延迟指令,一定会执行

l.bf     spi_xfer_poll未发送生跳转说明接收缓冲区不为空,有数据可以读

l.lbz     r3, SPI_SPDR(r4):读取SPI数据放大r3

    l.slli r2, r2, 8
    l.or   r2,  r2, r3

把r2左移8位,把r3低8位放到r2的低8为,上一条指令读取SPI SPDR做了零扩展,所以r3高24位都为0

    l.sfeqi r1, 1
    l.bnf spi_xfer_loop
    l.addi r1, r1, -1

比较r1是否为1,不为1则跳转继续读数据,并把r1 = r1-1

    l.jr     r9
    l.nop

返回spi_xfer调用点,注意后面l.nop是延迟指令,是必需的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

jjinl

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

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

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

打赏作者

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

抵扣说明:

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

余额充值