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 'h3c00003f
`define OR1200_BOOT_ADR '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 >>) - ;
pcreg_select <= '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[:];
pcreg_select <= 'b0; // select FF value
end
else if (spr_pc_we) begin
pcreg_default <= spr_dat_i[:];
end
else if (no_more_dslot | except_start | !genpc_freeze & !icpu_rty_i
& !genpc_refetch) begin
pcreg_default <= pc[:];
end always @(pcreg_boot or pcreg_default or pcreg_select)
if (pcreg_select)
// async. value is selected due to reset state
pcreg = pcreg_boot[:];
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,
l.ori r1,r0,
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中的相关代码去等:
: wb_dat_o <= 'h18000000;
: wb_dat_o <= 'h18200000;
: wb_dat_o <= 'h1880b000;
: wb_dat_o <= 'ha8400051;
: wb_dat_o <= 'hd8041000;
: wb_dat_o <= 'hd8040004;
: wb_dat_o <= 'ha8c00001;
: wb_dat_o <= 'hd8043004;
: wb_dat_o <= 'h0400001d;
: wb_dat_o <= 'ha8600003;
: wb_dat_o <= 'h0400001b;
: wb_dat_o <= 'ha860001c;
: wb_dat_o <= 'h04000019;
: wb_dat_o <= 'ha8600000;
: wb_dat_o <= 'h04000017;
: wb_dat_o <= 'ha8600000;
: wb_dat_o <= 'h18c00000;
: wb_dat_o <= 'h18e0ffff;
: wb_dat_o <= 'h04000013;
: wb_dat_o <= 'he1013000;
: wb_dat_o <= 'hd8081800;
: wb_dat_o <= 'h9cc60001;
: wb_dat_o <= 'hbc060004;
: wb_dat_o <= 'h10000007;
: wb_dat_o <= 'he4063800;
: wb_dat_o <= 'h0ffffff9;
: wb_dat_o <= 'h15000000;
: wb_dat_o <= 'ha8210100;
: wb_dat_o <= 'h44000800;
: wb_dat_o <= 'hd8040004;
: wb_dat_o <= 'h84e10000;
: wb_dat_o <= 'hb9470050;
: wb_dat_o <= 'hbc4a0200;
: wb_dat_o <= 'h13ffffdf;
: wb_dat_o <= 'h15000000;
: wb_dat_o <= 'h03ffffef;
: wb_dat_o <= 'h15000000;
: wb_dat_o <= 'hd8041802;
: wb_dat_o <= 'ha8600001;
: wb_dat_o <= 'ha4630001;
: wb_dat_o <= 'hbc030001;
: wb_dat_o <= 'h13fffffe;
: wb_dat_o <= 'h8c640001;
: wb_dat_o <= 'h44004800;
: wb_dat_o <= '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 is cleared, fifo !empty*/ #define RAM_LOAD_BASE SDRAM_BASE
#define RESET_ADDR 0x100
bootrom.S 宏定义块
boot_init:
l.movhi r0,
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,
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.jalspi_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,
l.movhi r7, 0xffff copy:
l.jal spi_xfer /* Read a byte into r3 */
l.add r8, r1, r6 /* Calculate store address */
l.sb (r8), r3 /* Write byte to memory */
l.addi r6, r6, /* 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, (r1) /* Size word is in first word of SDRAM */
l.srli r10, r7, /* 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, (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.srlir10, 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.bfboot_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,
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[]; // Interrupt enable bit
wire spe = spcr[]; // System Enable bit
wire dwom = spcr[]; // Port D Wired-OR Mode Bit
wire mstr = spcr[]; // Master Mode Select Bit
wire cpol = spcr[]; // Clock Polarity Bit
wire cpha = spcr[]; // Clock Phase Bit
wire [:] spr = spcr[:]; // 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