寄存器使用参考


1. 寄存器地址组成

1.1. 寄存器地址组成

  1. base address:寄存器对应CPU总线基地址(物理地址:0x1F000000)

  2. bank address:某一类功能外设(例如SPI,I2C)或者IP的寄存器会被划分到一个区域,这个区域被称为bank,对应的地址为bank address。

  3. offset address:具体寄存器在bank内的寻址称为offset address。

1.2. 8bit模式和16bit模式

对于offset address来说,有8bit模式和16bit模式。8bit模式offset地址范围为0x00 ~ 0xFF。16bit模式offset地址范围为0x00 ~ 0x7F。8bit与16bit模式的offset address是2倍关系。例如:8bit模式的offset地址为0x34,对应的16bit模式的offset地址为0x1A。

为何会存在两种模式?其实是为了更方便操作寄存器,16bit模式一般用来直接操作16bit的寄存器,而8bit模式则用来操作16bit寄存器的高8位(8bit模式奇数地址)或者低8位(8bit模式偶数地址)。

下图比较直观地展示CPU总线寄存器地址以及寄存器8bit模式和16bit模式的差异。

2. 寄存器工具

2.1. UBOOT的寄存器工具

2.1.1. 配置

UBOOT的寄存器工具依赖于CONFIG_SSTAR_DRIVERS宏,这个宏在配置文件中默认已经打开。

2.1.2. riu命令

  • 帮助

    在UBOOT命令行输入riu,会给出riu寄存器工具的使用方法。注意UBOOT下的riu工具的offset address是8bit模式。

  • 读取寄存器最简单的方法可以通过riu rbyte [target: bank+offset Addr(8bit mode)] 0xFF命令来读取整个bank,再去寻找需要的offset address的值。

    示例:读取bank address=0x103c的整个bank。

  • 如果要写具体的寄存器,可以通过riu wbyte [target: bank+offset Addr(8bit mode)] [value]命令来操作。

    示例:往bank address=0x103c,offset address=0xe0这个8bit寄存器写1。

2.2. Kernel的寄存器工具

Kernel下也有对应的寄存器工具,只不过Kernel下的寄存器工具的offset address是16bit模式。

2.2.1. riu_r

如果直接使用riu_r [bank address]命令,则会读取整个bank的寄存器值。

示例:读取bank address=0x103c的整个bank。

如果要读取某个offset address的寄存器值,可以通过riu_r [bank adress] [offset address]命令。

示例:读取bank address=0x103c,offset address=0x38的值。

2.2.2. riu_w

如果要修改某个寄存器的值,可以通过riu_w [bank addess] [offset address] [value]来操作。

示例:把bank address=0x103c,offset address=0x38的值改为0x1。

3. 寄存器地址

3.1. 寄存器表解析

下面以TIMER0寄存器表说明如何查看寄存器表格。

Bank=0x30:表示TIMER0寄存器的bank address=0x30。

Index 0x10:表示TIMER0寄存器16bit模式的offset address。

Index 0x003021:表示TIMER0寄存器8bit模式的offset address为0x21。

Table 1: TIMER0 Register (Bank = 30)

Index (Absolute) Mnemonic Bit Description
10h (003020h) REG003020 7:0 Default : 0x00 Access : R/W
- 7:2 Reserved.
TIMER_TRIG 1 set: Enable timer counting one time (from 0 to max, then stop).
clear: By reset itself OR set reg_timer_en.
TIMER_EN 0 set: Enable timer counting rolled (from 0 to max, then rolled).
clear: By reset itself OR set reg_timer_trig.
10h (003021h) REG003021 7:0 Default : 0x00 Access : R/W
- 7:1 Reserved.
TIMER_INT_EN 0 set: Enable interrupt.
clear: By reset itself.
11h (003022h) REG003022 7:0 Default : 0x00 Access : RO
- 7:1 Reserved.
TIMER_HIT 0 assert: When counter enabled and matches reg_timer_max.
deassert: By write 1 OR set reg_timer_en, reg_timer_once, reg_timer_max.
11h (003023 h) REG003023 7:0 Default : 0xFF Access : R/W
- 7:0 Reserved.

3.2. 寄存器地址计算

使用寄存器地址,已知寄存器的bank和offset,如何计算它的CPU物理地址(这个地址是软件编程会直接使用到的地址)。

  • 8bit模式公式

    cpu phy addr = base addr + bank addr x 0x200 + offset addr x 2 - (offset & 1)
    

    示例:

    已知bank address=0x30, offset address = 0x2
    
    cpu phy addr = 0x1F000000 + 0x30 x 0x200 + 0x2 x 2 - (0x2 & 1)
    
    cpu phy addr = 0x1F006004
    
  • 16bit模式公式

    cpu phy addr = base addr + bank addr x 0x200 + offset addr x 4
    

    示例

    已知bank address=0x30, offset address = 0x1
    
    cpu phy addr = 0x1F000000 + 0x30 x 0x200 + 0x1 x 4
    
    cpu phy addr = 0x1F006004
    

    对于UBOOT来说,physical address和virtual address是等同的,因此:

    register cpu address = register cpu physical address
    

    对于Kernel来说,由于开启了MMU,physical address和virtual address在设计上存在一个偏移值,因此:

    register cpu address = register cpu physical address + MS_IO_OFFSET
    

    注:MS_IO_OFFSET定义在./driver/sstar/include/ms_platform.h

最后,在代码里面访问寄存器的方法为:

  • 8bit模式

    (*(volatile u8*)(register cpu address))
    
  • 16bit模式

    (*(volatile u16*)(register cpu address))
    

3.3. 寄存器操作API

在UBOOT和Kernel的代码里面已经封装了一些操作寄存器的API,可以直接使用。这些API都是对前述的register cpu address地址操作的封装。

API Detail
INREG8(x) [功能] 获取8bit寄存器值
[参数] x: register cpu address
[返回] 8bit寄存器值
OUTREG8(x, y) [功能] 修改8bit寄存器值
[参数] x: register cpu address; y: 待写入寄存器的值
[返回] 无
SETREG8(x, y) [功能] 把8bit寄存器某些bit位置1
[参数] x: register cpu address; y: 指定的bit位
[返回] 无
CLRREG8(x, y) [功能] 把8bit寄存器某些bit位清零
[参数] x: register cpu address; y: 指定的bit位
[返回] 无
INREGMSK8(x, y) [功能] 按指定mask获取8bit寄存器某些bit位的值
[参数] x: register cpu address; y: 指定要获取的bit位
[返回] 8bit寄存器某些bit位的值
OUTREGMSK8(x, y, z) [功能] 清零8bit寄存器某些bit位,并重新设置这些bit位的值
[参数] x: register cpu address; y: 待写入到bit位的值; z: 指定的bit位
[返回] 无
INREG16(x) [功能] 获取16bit寄存器值
[参数] x: register cpu address
[返回] 16bit寄存器值
OUTREG16(x, y) [功能] 修改16bit寄存器值
[参数] x: register cpu address; y: 待写入寄存器的值
[返回] 无
SETREG16(x, y) [功能] 把16bit寄存器某些bit位置1
[参数] x: register cpu address; y: 指定的bit位
[返回] 无
CLRREG16(x, y) [功能] 把16bit寄存器某些bit位清零
[参数] x: register cpu address; y: 指定的bit位
[返回] 无
INREGMSK16(x, y) [功能] 按指定mask获取16bit寄存器某些bit位的值
[参数] x: register cpu address; y: 指定要获取的bit位
[返回] 16bit寄存器某些bit位的值
OUTREGMSK16(x, y, z) [功能] 清零16bit寄存器某些bit位,并重新设置这些bit位的值
[参数] x: register cpu address; y: 待设置到bit位的值; z: 指定的bit位
[返回] 无