orpsocv2 从ROM(bootrom)启动分析--以atlys板子的启动为例子

 

1 复位后的启动地址

  1) 复位后,启动地址在or1200_defines.v最后宏定义,atlys板子的目录:orpsocv2\boards\xilinx\atlys\rtl\verilog\include\or1200_defines.v 

///////////////////////////////////////////////////////////////////////////////
// Boot Address Selection                                                    //
//                                                                           //
// Allows a definable boot address, potentially different to the usual reset //
// vector to allow for power-on code to be run, if desired.                  //
//                                                                           //
// OR1200_BOOT_ADR should be the 32-bit address of the boot location         //
// OR1200_BOOT_PCREG_DEFAULT should be ((OR1200_BOOT_ADR-4)>>2)              //
//                                                                           //
// For default reset behavior uncomment the settings under the "Boot 0x100"  //
// comment below.                                                            //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
// Boot from 0xf0000100
`define OR1200_BOOT_PCREG_DEFAULT 30'h3c00003f
`define OR1200_BOOT_ADR 32'hf0000100
// Boot from 0x100
// `define OR1200_BOOT_PCREG_DEFAULT 30'h0000003f
// `define OR1200_BOOT_ADR 32'h00000100

    OR1200_BOOT_ADR[31:28] (即最高4位)是 wishbone的从机地址,对应了wishbone从机ROM设备的从机地址。

    从设备的内部地址是 0x100,即对应OR启动的地址。

 OR1200_BOOT_PCREG_DEFAULT  = ((OR1200_BOOT_ADR-4)>>2) =  (boot_adr >>2) - 4 = (f0000100>>2) - 4 =3c00003f; 

 在 genpc模块中复位时,即在复位时,当boot_adr = 0xf0000100时,pcreg_default = 3c00003f 计算得到,故在此版本中 OR1200_BOOT_PCREG_DEFAULT 宏并未用到。而在某些版本中是实现的 pcreg_default  <= `OR1200_BOOT_PCREG_DEFAULT;  //jb 参考书《深入理解OpenRisc 体系结构》中代码是这样的

//
   // PC register
   //
   always @(posedge clk or `OR1200_RST_EVENT rst)
     // default value 
     if (rst == `OR1200_RST_VALUE) begin
    pcreg_default <=  (boot_adr >>2) - 4;
    pcreg_select <=  1'b1;// select async. value due to reset state
     end
   // selected value (different from default) is written into FF after
   // reset state
     else if (pcreg_select) begin
    // dynamic value can only be assigned to FF out of reset! 
    pcreg_default <=  pcreg_boot[31:2];    
    pcreg_select <=  1'b0;        // select FF value 
     end
     else if (spr_pc_we) begin
    pcreg_default <=  spr_dat_i[31:2];
     end
     else if (no_more_dslot | except_start | !genpc_freeze & !icpu_rty_i 
          & !genpc_refetch) begin
    pcreg_default <=  pc[31:2];
     end

   always @(pcreg_boot or pcreg_default or pcreg_select)
     if (pcreg_select)
       // async. value is selected due to reset state 
       pcreg = pcreg_boot[31:2];
     else
       // FF value is selected 2nd clock after reset state 
       pcreg = pcreg_default ;

2)在文件 orpsocv2\boards\xilinx\atlys\rtl\verilog\include\orpsoc-params.v

定义了 rom 的地址宽度和从机地址,注意这里的地址宽度参数重定义为 6,在rom.v 中定义的是5,不要看错了。所以在 rom(bootrom.v)中的指令最多为 2^6 = 64条指令。

  3) 第一条指令?

    复位后PC=0X100,则传递到rom.v中后,

     则wishbone地址输入定义为: input[7:2] wb_adr_i; (共6位地址线)

在文件 orpsocv2\boards\xilinx\atlys\rtl\verilog\orpsoc_top.v 中,实例化rom时,从rom中取指令的地址截取的是 wbs_i_rom_adr_i[7:2](共6位地址线),

 

 其中wbs_i_rom0_addr_width = 6,定义在orpsoc-params .v

 

所以:在PC=0X100时,传递到ROM中取指令时,取的是 wb_adr_i = 0000_00 (PC[7:2]);

然后在不遇到异常的情况下,PC每次加4。则第二条指令PC = 0X104,传递到ROM中取指令时,取的是 wb_adr_i = 0000_01 (PC[7:2]); 所以bootrom.v 中的指令要在64条以内。

对于原rom.v 中注释指令的反汇编解释:

/*
// Zero r0 and jump to 0x00000100
0 : wb_dat_o <= 32'h18000000; //opcode=0x6; D=0; K=0x0000; --> r0=0x00000000
1 : wb_dat_o <= 32'hA8200000; //opcode=0x2a; rD=r1; A=r0; K= 0x0000; --> r1=r0|0x0000=0x00000000
2 : wb_dat_o <= 32'hA8C00100; //r6 = r0|0x0100=0x0100
3 : wb_dat_o <= 32'44003000; //opcode=0x11; B=0x06; --> PC=r6=0x00000100 (注意最高4位是Wishbone从机地址,这里不是f,即不对应ROM了,而是外部SDRAM,从机地址为0)
4 : wb_dat_o <= 32'h15000000;//opcode=0x15; nop
*/

验证,在Ubuntu虚拟机中通过编译工具查看下,先写出以下汇编代码hyexp.S:

.section .text,"ax"

    .org 0x100
.global _start
_start:
    l.movhi r0,0
    l.ori r1,r0,0
    l.ori r6,r0,0x0100
    l.jr r6
    l.nop 0x0000

汇编工具编译,再反汇编查看:

可看出汇编指令对应的 机器码 和rom中默认的是一样的。故指令的作用如下分析:

第0条:l.movhi r0,0x00  ;; 其中R0恒为0(所以一开始就清R0,

第1条:l.ori r1, r0, 0x00 ;; R1是栈指针SP也清零

第3条:l.ori r6, r0, 0x0100 ;; R6 = R0 | 0X0100 = 0X100;

第4条:l.jr r6  ;; PC = r6 强行跳转,(注意最高4位是Wishbone从机地址,这里不是f,即不对应ROM了,而是外部SDRAM,从机地址为0)

第5条:nop  ;; 由于是流水线结构,导致在跳转指令后的那条语句必被执行,所以填充一个 nop ;

综上分析可知:按默认的指令来的话,OR1200 “复位->清R0,R1(SP) ->跳到SDRAM里面的复位向量地址0x100处取指令,如果SDRAM中没有初始化数据,即为0x0,对应l.j 0 指令。

 

atlys bootrom.v 的指令,这是uboot启动的引导,应该有SPI flash 的初始代码,之后会引导PC跳转到flash中的相关代码去等:

0 : wb_dat_o <=  32'h18000000;
1 : wb_dat_o <=  32'h18200000;
2 : wb_dat_o <=  32'h1880b000;
3 : wb_dat_o <=  32'ha8400051;
4 : wb_dat_o <=  32'hd8041000;
5 : wb_dat_o <=  32'hd8040004;
6 : wb_dat_o <=  32'ha8c00001;
7 : wb_dat_o <=  32'hd8043004;
8 : wb_dat_o <=  32'h0400001d;
9 : wb_dat_o <=  32'ha8600003;
10 : wb_dat_o <=  32'h0400001b;
11 : wb_dat_o <=  32'ha860001c;
12 : wb_dat_o <=  32'h04000019;
13 : wb_dat_o <=  32'ha8600000;
14 : wb_dat_o <=  32'h04000017;
15 : wb_dat_o <=  32'ha8600000;
16 : wb_dat_o <=  32'h18c00000;
17 : wb_dat_o <=  32'h18e0ffff;
18 : wb_dat_o <=  32'h04000013;
19 : wb_dat_o <=  32'he1013000;
20 : wb_dat_o <=  32'hd8081800;
21 : wb_dat_o <=  32'h9cc60001;
22 : wb_dat_o <=  32'hbc060004;
23 : wb_dat_o <=  32'h10000007;
24 : wb_dat_o <=  32'he4063800;
25 : wb_dat_o <=  32'h0ffffff9;
26 : wb_dat_o <=  32'h15000000;
27 : wb_dat_o <=  32'ha8210100;
28 : wb_dat_o <=  32'h44000800;
29 : wb_dat_o <=  32'hd8040004;
30 : wb_dat_o <=  32'h84e10000;
31 : wb_dat_o <=  32'hb9470050;
32 : wb_dat_o <=  32'hbc4a0200;
33 : wb_dat_o <=  32'h13ffffdf;
34 : wb_dat_o <=  32'h15000000;
35 : wb_dat_o <=  32'h03ffffef;
36 : wb_dat_o <=  32'h15000000;
37 : wb_dat_o <=  32'hd8041802;
38 : wb_dat_o <=  32'ha8600001;
39 : wb_dat_o <=  32'ha4630001;
40 : wb_dat_o <=  32'hbc030001;
41 : wb_dat_o <=  32'h13fffffe;
42 : wb_dat_o <=  32'h8c640001;
43 : wb_dat_o <=  32'h44004800;
44 : wb_dat_o <=  32'h8c640002;

 以上的指令码是由 bootrom.S 文件(openrisc\trunk\orpsocv2\sw\bootrom\bootrom.S)和对应的板子 board.h (openrisc\trunk\orpsocv2\boards\xilinx\atlys\sw\board\include\board.h) 生成的。

 

BOOTROM_SPI_FLASH 部分

#include "board.h"

#ifdef BOOTROM_SPI_FLASH
    
    /* 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 */
    /* Assuming address at RAM_LOAD_BASE gets clobbered, we need
       a byte writable address somewhere!*/

#define SPI_BASE SPI0_BASE
/* simple_spi driver */    
#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*/
    
#define RAM_LOAD_BASE SDRAM_BASE
#define RESET_ADDR 0x100
bootrom.S 宏定义块

 

boot_init:    
    l.movhi r0, 0
    l.movhi r1, RAM_LOAD_BASE
    l.movhi r4, hi(SPI_BASE)

 r0 = 0;

 r1 = RAM_LOAD_BASE = SDRAM_BASE=0 ;; 其实这里是把 SDRAM 的Wishbone从机地址存在 r1 中

 r4 = hi(SPI_BASE) << 16 = hi(SPI0_BASE) << 16 = 0xb000_0000 ;; 这里是把SPI0设备的Wishbone从机地址存在 r4 中

 

SPI_INIT 部分

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.jal    spi_xfer
    l.ori     r3, r0, 0x3              /* READ command opcode for SPI device*/
    l.jal     spi_xfer
#ifdef BOOTROM_ADDR_BYTE2
    l.ori     r3, r0, BOOTROM_ADDR_BYTE2 /* Use addr if defined. MSB first */
#else    
    l.or     r3, r0, r0
#endif    
    l.jal     spi_xfer
#ifdef BOOTROM_ADDR_BYTE1
    l.ori     r3, r0, BOOTROM_ADDR_BYTE1
#else    
    l.or     r3, r0, r0
#endif    
    l.jal     spi_xfer
#ifdef BOOTROM_ADDR_BYTE0
    l.ori     r3, r0, BOOTROM_ADDR_BYTE0
#else    
    l.or     r3, r0, r0
#endif    
    l.movhi r6, 0
    l.movhi r7, 0xffff    

  r2 = r0| SPI_SPCR_XFER_GO = 0x51

  l.sb SPI_SPCR(r4), r2    ;; EA = exts(0x0)  + r4 = 0xb000_0000 , (EA)[7:0] = r2[7:0] = 0x51 这里访问的是SPI_SPCR(寄存体偏移0x0)寄存器,写入的数据为0x51。

l.sb SPI_SPSS(r4), r0    /* Clear SPI slave selects */  SPI_SPSS(寄存体偏移0x4) = r0 = 0。 SPSS应该是片选信号,且高为选中
l.ori r6, r0, SPI_SPSS_INIT   ;; r6 = r0|0x1=0x1
l.sb SPI_SPSS(r4), r6 /* Set appropriate slave select */ SPI_SPSS=0X1 使片选有效
l.jal spi_xfer   /*跳转到 spi_xfer代码块,LR=DelayInsnAddr+4,延时槽指令即跳转后的下一条,LF(R9)用于函数返回*/
l.ori r3, r0, 0x3 /* READ command opcode for SPI device*/ 传递参数到 spi_xfer 的跳转,0x3是SPI设备的读命令操作码

说明:一般SPI设备都是 写命令+数据操作(读写),这里先写入了一个 读数据的命令字

//接下来的这部分应该是 写入读数据的起始地址

//编译控制宏在头文件中均有定义

// Address bootloader should start from in FLASH
// Offset 0x1c0000
#define BOOTROM_ADDR_BYTE2 0x1c
#define BOOTROM_ADDR_BYTE1 0x00
#define BOOTROM_ADDR_BYTE0 0x00

//所以接下来的指令为分别调用了 三次 spi_xfer  ,将宏定义的地址传递进去

l.jal spi_xfer  

#ifdef BOOTROM_ADDR_BYTE2
l.ori r3, r0, BOOTROM_ADDR_BYTE2 /* Use addr if defined. MSB first */
#else
l.or r3, r0, r0
#endif


l.jal spi_xfer
#ifdef BOOTROM_ADDR_BYTE1
l.ori r3, r0, BOOTROM_ADDR_BYTE1
#else
l.or r3, r0, r0
#endif


l.jal spi_xfer
#ifdef BOOTROM_ADDR_BYTE0
l.ori r3, r0, BOOTROM_ADDR_BYTE0
#else
l.or r3, r0, r0
#endif

接下来分析下 spi_xfer 代码块的作用

spi_xfer:
    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.jr     r9
    l.lbz     r3, SPI_SPDR(r4) /* Get data byte */

spi_xfer:
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 */

// r4中存的是SPI0从设备的地址,再偏移地址SPI_SPDR,故使得SPI设备的寄存器SPDR=r3[7:0] (r3值由调用时的延时槽指令传入),这应该是数据寄存器 data regsisters

// r3 = r0|SPI_SPSR_RX_CHECK=SPI_SPSR_RX_CHECK=0x1 /* Check bit 0 is cleared, fifo !empty*/

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? ... */ SR[F]= (r3==0x1)?1:0
l.bf spi_xfer_poll /* ... if so, rxfifo empty, keep polling */ 
l.lbz r3, SPI_SPSR(r4) /* Read SPSR */   EA = (r4+SPI_SPSR(0x1) , r3[7:0]=(EA)[7:0],, r3[31:8]=0 即读取SPSR寄存器里面的低八位数值.

//循环检查 SPSR(可能为状态寄存器)里面的最低位,直到SPSR最低位为0,即表示 rxfifo 非空,则下面可以开始从SPDR读数据了,也就是写入读命令字(0x1)正常。
l.jr r9 ;; 函数返回,R9是链接寄存器(LR),里面保存着返回地址
l.lbz r3, SPI_SPDR(r4) /* Get data byte */   EA = (r4+SPI_SPDR(0x1) , r3[7:0]=(EA)[7:0],, r3[31:8]=0 即读取SPDR寄存器里面的低八位数值

综上可知:spi_xfer 函数其实是向 SPI设备写入一个字节的命令/数据,然后读取一个字节数据。都是借助 r3 来传递参数值的。

 

SPI  COPY  部分:

    l.movhi r6, 0
    l.movhi r7, 0xffff    

copy:    
    l.jal     spi_xfer         /* Read a byte into r3 */
    l.add     r8, r1, r6       /* Calculate store address */
    l.sb     0(r8), r3        /* Write byte to memory */
    l.addi     r6, r6, 1        /* Increment counter */
    l.sfeqi r6, 0x4          /* Is this the first word ?*/
    l.bf     store_sizeword   /* put sizeword in the register */
    l.sfeq     r6, r7           /* Check if we've finished loading the words */
    l.bnf     copy             /* Continue copying if not last word */
    l.nop

r6 放的是 SDRAM 数据存放起始地址,r7放的是数据结束地址(这里只是一个初始化为32位里面最大数,实际数值在后面读取)。

copy:

l.jal  spi_xfer  // 读取一个字节放到 r3

r8 = r1 + r6     // r1 放的是 SDRAM的从机地址,加上SDRAM 数据访问地址

l.sb 0(r8), r3    // EA = r8+0x0  ,,,(EA)[7:0] = r3[7:0] 把 从SPI设备读取的一字节数据 r3[7:0] 写入 SDRAM

r6 = r6 + 1      // 这里是递增 1,访问是按字节访问的

l.sfeqi r6, 0x4                 /* Is this the first word ?*/  SR[F]= (r6==0x4)?1:0 ,第一个WORD(字,4Byte)
l.bf store_sizeword          /* put sizeword in the register */  如果 SR[F]为1,则跳到 store_sizeword 代码块
l.sfeq r6, r7                   /* Check if we've finished loading the words */ SR[F]= (r6==r7)?1:0 
l.bnf copy                      /* Continue copying if not last word */ 如果 SR[F]为0,则跳到 copy 代码块
l.nop               // 延时槽指

 

先分析下 store_sizeword 部分

store_sizeword:
#ifdef SPI_RETRY_IF_INSANE_SIZEWORD
    l.lwz     r7, 0(r1)        /* Size word is in first word of SDRAM */
    l.srli    r10, r7, 16     /* Chop the sizeword we read in half */
    l.sfgtui r10, 0x0200     /* It's unlikely we'll ever load > 32MB */
    l.bf    boot_init
    l.nop
    l.j     copy
    l.nop

#else    
    l.j     copy
    l.lwz     r7, 0(r1)         /* Size word is in first word of SDRAM */
#endif

board.h 中有定义 SPI_RETRY_IF_INSANE_SIZEWORD。

#ifdef SPI_RETRY_IF_INSANE_SIZEWORD
l.lwz r7, 0(r1)                /* Size word is in first word of SDRAM */ EA=exts(0)+r1,,, r7 = (EA)[31:0],前面已经从SPI 设备(其实就是一个 FLASH)读取了开头的4个字节数据, 表示的是 数据量的大小
l.srli r10, r7, 16             /* Chop the sizeword we read in half */  r10 = r7>>16 (逻辑右移),只取高16位值
l.sfgtui r10, 0x0200       /* It's unlikely we'll ever load > 32MB */  SR[F] = (r10>0x0200)?1:0
l.bf boot_init        //如果字节数大于 32MB(0x0200_0000 = 2^25 Byte),则重启。说明超出了允许的存储空间
l.nop   //delayInsn
l.j copy   //但是注意,这里的 结束地址 r7 已经更新为实际大小了

//如果数据量在 32MB 以内,检查Size word 通过,则继续跳到 copy ,继续将 FLASH 中的数据copy 到 SDRAM 中去
l.nop  //delayInsn

#else
    l.j copy           //不作检查,直接跳到COPY继续拷贝数据到 SDRAM
    l.lwz r7, 0(r1) /* Size word is in first word of SDRAM */ 存储实际的 sizeword 到 r7
#endif

 

 跳转到SDRAM里面的复位向量:

goto_reset:
    l.ori     r1, r1, RESET_ADDR
    l.jr     r1
    l.sb      SPI_SPSS(r4), r0 /* Clear SPI slave selects */

由前面分析,r1高位存的是Wishbone从机地址对应SDRAM,再由得到 复位向量地址 0x100,经过 l.jr r1 跳到 SDRAM 的 0x100 位置处执行。延时槽指令是 关闭 SPI从机片选信号,因为前面数据已经 COPY 完毕了。

 

BOOTROM_GOTO_RESET 部分

#ifdef BOOTROM_GOTO_RESET
    /* Jump to reset vector in the SDRAM */
    l.movhi r0, 0
    l.movhi r4, SDRAM_BASE
    l.ori     r4, r4, 0x100
    l.jr     r4
    l.nop
    
#endif    
BOOTROM_GOTO_RESET

 /* Jump to reset vector in the SDRAM */

l.movhi r0, 0  ;; r0=0
l.movhi r4, SDRAM_BASE  ;;  r4 = SDRAM_BASE<<16 ,, atlys 板子头文件定义是 0x0
l.ori r4, r4, 0x100  ;;  r4 = r4|0x100 = (SDRAM_BASE<<16 | 0x0000_0100) =0x0000_0100 (atlys板子的)

l.jr r4 ;; PC = r4 ,让PC转到 SDRAM 里面的代码段去,
l.nop

注:PC地址高四位为wishbone的从机地址,对应SDRAM设备,复位初始时,在or1200_defines.v中定义的OR1200_BOOT_ADR=0xf000_0100),进入SDRAM_BASE 的代码段去。综上:由于使 PC跳到了 SDRAM里面的复位向量地址去执行,故为 BOOTROM_GOTO_RESET 。

 

BOOTROM_LOOP_AT_ZERO 部分

#ifdef BOOTROM_LOOP_AT_ZERO

    /* Don't load app via SPI, instead just put an infinite loop into bottom
    of memory and jump there.
    */
    l.movhi r0, 0
    l.movhi r4, SDRAM_BASE
    l.sw     0x0(r4), r0
    l.movhi r5, hi(0x15000001) /* A l.nop 1 so sim exits if this enabled */
    l.ori     r5, r5, lo(0x15000001)
    l.sw     0x4(r4), r5
    l.sw     0x8(r4), r5
    l.sw     0xc(r4), r5
    l.jr     r4
    l.nop

    

#endif
BOOTROM_LOOP_AT_ZERO

l.movhi r0, 0 ;; r0 = 0

l.movhi r4, SDRAM_BASE ;;  atlys 板子头文件定义是 0x0

l.sw 0x0(r4), r0 ;;   EA = exts(0)+r4 ,,  (SDRAM_BASE +0x0)[31:0] = r0
l.movhi r5, hi(0x15000001) /* A l.nop 1 so sim exits if this enabled  */
l.ori r5, r5, lo(0x15000001)  ;; r5 = 0x15000001 ,这就是 l.nop 1 的机器码
l.sw 0x4(r4), r5  ;; EA = exts(0x4)+r4 ,,  (SDRAM_BASE +0x4)[31:0] = r5
l.sw 0x8(r4), r5  ;; EA = exts(0x8)+r4 ,,  (EA)[31:0] = r5
l.sw 0xc(r4), r5  ;;  EA = exts(0xc)+r4 ,,  (EA)[31:0] = r5
l.jr r4                ;; l.jr r4 跳转到 SDRAM_BASE ,使得PC = 0x0000_0000,,跳到SDRAM_BASE后,由于RAM中起始0地址初始数据为0x0000_0000(即指令l.j 0)会执行一直在此处循环,类似 “ while(1);  ” 。上面的语句用于在SDRAM_BASE后面插入几条 nop 延时槽指令
l.nop                 ;; 延时槽指令

综上:由于使得 PC跳到了 SDRAM里面的起始0地址部分,且在0地址出LOOP。故为 BOOTROM_LOOP_AT_ZERO 

 

BOOTROM_LOOP_IN_ROM 部分 

#ifdef BOOTROM_LOOP_IN_ROM

    /* Don't load app via SPI, instead just put an infinite loop into bottom
    of memory and jump there.
    */
    l.movhi r0, 0
    l.nop     0x1
    l.j     0
    l.nop
    l.nop 
#endif

l.movhi r0,0  ;; 清零 r0

l.nop  0x1     ;;  

l.j  0            ;; PC = exts(0<<2)+本条指令的地址,故而一直在此处执行,相当于 while(1); 也没有改变最高4位wishbone从机地址的值,故一直在ROM中

l.nop           ;; 跳转指令加nop 

l.nop           ;;

 综合代码:由于这里没有跳转到 其他设备,只是在ROM里面LOOP。故为 BOOTROM_LOOP_IN_ROM 。

 

 

 SPI 控制器的 RTL 代码在目录 \orpsocv2\rtl\verilog\simple_spi\  simple_spi.v 和 fifo4.v 文件

//module simple_spi_top(
module simple_spi ( // renamed by Julius
            // 8bit WISHBONE bus slave interface
            clk_i,         // clock
            rst_i,         // reset (asynchronous active low)
            cyc_i,         // cycle
            stb_i,         // strobe
            adr_i,         // address
            we_i,          // write enable
            dat_i,         // data input
            dat_o,         // data output
            ack_o,         // normal bus termination
            inta_o,        // interrupt output
            
            
            sck_o,         // serial clock output
            ss_o, //slave select
            mosi_o,        // MasterOut SlaveIN
            miso_i         // MasterIn SlaveOut            
            );

 在上面分析SPI_Init 部分有寄存器的定义和配置,具体要从RTL 代码来分析

由 RTL 定义 可知 寄存器的功能 

 由下面的 case 语句可知 寄存器的地址偏移 

 SPCR 寄存器的位定义 

  // decode Serial Peripheral Control Register
  wire       spie = spcr[7];   // Interrupt enable bit
  wire       spe  = spcr[6];   // System Enable bit
  wire       dwom = spcr[5];   // Port D Wired-OR Mode Bit
  wire       mstr = spcr[4];   // Master Mode Select Bit
  wire       cpol = spcr[3];   // Clock Polarity Bit
  wire       cpha = spcr[2];   // Clock Phase Bit
  wire [1:0] spr  = spcr[1:0]; // Clock Rate Select Bits

所以启动配置 SPCR = 0X51 ,,,系统使能、主机模式、时钟速率选择为 01 .

 

 

 

参考:

http://blog.csdn.net/column/details/openrisc.html?&page=4

http://blog.csdn.net/leishangwen/article/details/21713357

如何添加size_word ,SPI 中软件位置的偏移 OpenRisc-54-play with OpenRISC based atlys board

SVN : http://opencores.org/ocsvn/openrisc/openrisc

posted @ 2016-11-21 18:43  .Think  阅读(1461)  评论(0编辑  收藏  举报