1、冯·诺依曼结构
冯·诺依曼结构又称作普林斯顿体系结构(Princetionarchitecture)。
1945年,冯·诺依曼首先提出了“存储程序”的概念和二进制原理,后来,人们把利用这种概念和原理设计的电子计算机系统统称为“冯·诺依曼型结构”计算机。冯·诺依曼结构的处理器使用同一个存储器,经由同一个总线传输。
冯·诺依曼结构处理器具有以下几个特点:
必须有一个存储器;
必须有一个控制器;
必须有一个运算器,用于完成算术运算和逻辑运算;
必须有输入和输出设备,用于进行人机通信。
冯·诺依曼的主要贡献就是提出并实现了“存储程序”的概念。由于指令和数据都是二进制码,指令和操作数的地址又密切相关,因此,当初选择这种结构是自然的。但是,这种指令和数据共享同一总线的结构,使得信息流的传输成为限制计算机性能的瓶颈,影响了数据处理速度的提高。
在典型情况下,完成一条指令需要3个步骤,即:取指令、指令译码和执行指令。从指令流的定时关系也可看出冯·诺依曼结构与哈佛结构处理方式的差别。举一个最简单的对存储器进行读写操作的指令,指令1至指令3均为存、取数指令,对冯·诺依曼结构处理器,由于取指令和存取数据要从同一个存储空间存取,经由同一总线传输,因而它们无法重叠执行,只有一个完成后再进行下一个。
arm7系列的CPU有很多款,其中部分CPU没有内部cache的,比如arm7TDMI,就是纯粹的冯·诺依曼结构,其他有内部cache且数据和指令的cache分离的cpu则使用了哈弗结构。
2、哈佛结构
哈佛结构是一种将程序指令存储和数据存储分开的存储器结构,如图1所示。中央处理器首先到程序指令存储器中读取程序指令内容,解码后得到数据地址,再到相应的数据存储器中读取数据,并进行下一步的操作(通常是执行)。程序指令存储和数据存储分开,可以使指令和数据有不同的数据宽度,如Microchip公司的PIC16芯片的程序指令是14位宽度,而数据是8位宽度。
图1 哈佛体系结构框图
哈佛结构的微处理器通常具有较高的执行效率。其程序指令和数据指令分开组织和存储的,执行时可以预先读取下一条指令。
目前使用哈佛结构的中央处理器和微控制器有很多,除了Microchip公司的PIC系列芯片,还有摩托罗拉公司的MC68系列、Zilog公司的Z8系列、ATMEL公司的AVR系列和ARM公司的ARM9、ARM10和ARM11。
哈佛结构是指程序和数据空间独立的体系结构, 目的是为了减轻程序运行时的访存瓶颈。
例如最常见的卷积运算中, 一条指令同时取两个操作数, 在流水线处理时, 同时还有一个取指操作, 如果程序和数据通过一条总线访问, 取指和取数必会产生冲突, 而这对大运算量的循环的执行效率是很不利的。
哈佛结构能基本上解决取指和取数的冲突问题。
而对另一个操作数的访问, 就只能采用Enhanced哈佛结构了, 例如像TI那样,数据区再split, 并多一组总线。 或向AD那样,采用指令cache, 指令区可存放一部分数据。
在典型情况下,完成一条指令需要3个步骤,即:取指令、指令译码和执行指令。从指令流的定时关系也可看出冯·诺依曼结构与哈佛结构处理方式的差别。举一个最简单的对存储器进行读写操作的指令,指令1至指令3均为存、取数指令,对冯·诺依曼结构处理器,由于取指令和存取数据要从同一个存储空间存取,经由同一总线传输,因而它们无法重叠执行,只有一个完成后再进行下一个。
如果采用哈佛结构处理以上同样的3条存取数指令,由于取指令和存取数据分别经由不同的存储空间和不同的总线,使得各条指令可以重叠执行,这样,也就克服了数据流传输的瓶颈,提高了运算速度。
3 F2812使用的是改进的哈佛结构,其结构特点为:
1).允许数据存放在程序存储器中,并能被算术运算指令直接使用;
2).增加了高速缓冲器Cache
4 复习完以上内容,知道了F2812内部程序(即指令)空间和数据空间是分开的,地址和数据总线总共有6条:
1)3条地址总线:
1. PAB (Program Address Bus)程序地址总线,它是一个22位的总线,用于传送程序空间的读写地址。程序在运行的时候,假如执行到了某一个指令,那么需要去找到这段代码的地址,就是用PAB来传送。这条总线我们在CCS仿真时,打开view disassembly可以看到,disassembly窗口最左边0x3fxxxx即22位程序地址,见下图。
2. DRAB(Data-Read Address Bus)数据读地址总线,它是个32位的总线,用于传送数据空间的读地址。假如要读取数据空间某一个单元的内容,那么这个单元的地址就是通过DRAB来传送。
3. DWAB(Data-Write Address Bus)数据写地址总线,它也是个32位的总线,用于传送数据空间的写地址。类似的,如果我要对数据空间的某一个单元进行写操作,那么这个单元的地址就是通过DWAB来传送。
2)3条数据总线
1. PRDB(Program-Read Data Bus)程序读数据总线,它是一个32位的总线,用于传送读取程序空间时的指令或者数据。我们在执行代码的时候,首先是通过PAB传送并找到了存放该指令的存储单元,但是这个存储单元下的具体内容就要由我们的PRDB来传送了。
2. DRDB(Data-Read Data Bus)数据读数据总线,它是一个32位的总线,在读取数据空间时用来传送数据。我们在进行读操作时,先通过DRAB总线确定了需要进行读操作的数据单元的地址,接下来传送这个数据单元下面的具体内容时就需要DRDB了。
3. DWDB(Data/Program-Write Data Bus)数据写数据总线,它是一个32位的总线,在进行写操作时,向数据空间/程序空间传送相应的数据。也就是假如我们要对数据空间的某一个单元进行写操作,我们通过DWAB传送了这一个单元的地址,同时我们需要DWDB来传送写入的内容。
这里举一个实例说明:
ECanaRegs.CANRMP.all地址为0x0000600c,此为32位数据地址,内容为0xFFFFFFFF32位数据占用2个字单元。直接寻址公式为DP*0x40(DP左移7位)+偏移量。
F2812存储器映射如下图:
低64K空间等价于C240的数据空间,高64k空间等价于C240的程序空间,但这不是绝对的,具体的空间分配应该参照CMD文件。一般PAGE1为数据空间,PAGE2为程序空间。
5 关于CMD文件
在CMD文件里有两个基本的段:初始化段和非初始化段。
初始化段包含代码和常数等必须在DSP上电之后有效的数。故初始化块必须保存在如片内FLASH等非易失性存储器中;
1)已初始化的段:.text,.cinit,.const,.econst,..pinit和.switch.. 每个小段里面存储的量说明如下:
.text:所有可以执行的代码和常量
cinit:全局变量和静态变量的C初始化记录
.const:包含字符串常量和初始化的全局变量和静态变量(由const)的初始化和说明
.econst:包含字符串常量和初始化的全局变量和静态变量(由far const)的初始化和说明
.pinit:全局构造器(C++)程序列表 .switch:包含转换语气声明的列表
2)非初始化段只是保留变量的地址空间,在程序运行过程中才像变量内写数据进去,所以非初始化段必须链接到易失性存储器中如RAM。
bss,.ebss,.stack,.sysmem,和esysmem.(更好的理解就是,这些段就是存储空间而已)
每个小段里面存储的量说明如下:
.bss: 为全局变量和局部变量保留的空间,在程序上电时,cinit空间中的数据复制出来并存储在.bss空间中。
.ebss:为使用大寄存器模式时的全局变量和静态变量预留的空间,在程序上电时,cinit空间中的数据复制出来并存储在.ebss中。
.stack:为系统堆栈保留的空间,主要用于和函数传递变量或为局部变量分配空间。
.sysmem:为动态存储分配保留的空间。如果有宏函数,此空间被宏函数占用,如果没有的话,此空间保留为0
.esysmem:为动态存储分配保留的空间。如果有far函数,此空间被相应的占用,如果没有的话,此空间保留为0.
举例:
void InitPieVectTable(void)
{
int16 i;
Uint32 *Source = (void *) &PieVectTableInit;
Uint32 *Dest = (void *) &PieVectTable;
EALLOW;
for(i=0; i < 128; i++)
*Dest++ = *Source++;
EDIS;
// Enable the PIE Vector Table
PieCtrlRegs.PIECRTL.bit.ENPIE = 1;
}
1 以上的代码分配到.text作为初始化好的段,通常脱离仿真器时需要储存到非易失性(flash)中;
2 1)PieVectTable起始地址为0xd00这是TI通过DSP281x_PieVect.h头文件中
struct PIE_VECT_TABLE{
PINT PIE1_RESERVED;
PINT PIE2_RESERVED;
。。。
}
extern struct PIE_VECT_TABLE PieVectTable;
以及DSP281x_GlobalVariableDefs.c文件中
#ifdef __cplusplus
#pragma DATA_SECTION("PieVectTableFile") //C++分配数据空间方法
#else
#pragma DATA_SECTION(PieVectTable,"PieVectTableFile"); //C语言分配数据空间方法
#endif
struct PIE_VECT_TABLE PieVectTable;
最后在DSP281x_Headers_nonBIOS.cmd文件中
MEMORY
{
PAGE 0: /* Program Memory */
PAGE 1: /* Data Memory */
PIE_VECT : origin = 0x000D00, length = 0x000100 /* PIE Vector Table */
}
SECTIONS
{
PieVectTableFile : > PIE_VECT, PAGE = 1
}
将全局变量PieVectTable分配到数据空间0x000D00中,注意这里的数据空间储存的是地址!
2)PieVectTableInit起始地址为03f9500,它是通过DSP281x_PieVect.c文件中定义全局变量
const struct PIE_VECT_TABLE PieVectTableInit = {
PIE_RESERVED, // Reserved space
PIE_RESERVED,
。。。
};
以及在F2812_EzDSP_RAM_lnk.cmd文件中
MEMORY
{
PAGE 0 :
。。。。
PAGE 1 :
/* For this example, H0 is split between PAGE 0 and PAGE 1 */
RAMM1 : origin = 0x000400, length = 0x000400
DRAMH0 : origin = 0x3f9000, length = 0x001000
}
SECTIONS
{
PAGE = 0
。。。。。。。。。。
.stack : > RAMM1, PAGE = 1
.ebss : > DRAMH0, PAGE = 1
.econst : > DRAMH0, PAGE = 1
.esysmem : > DRAMH0, PAGE = 1
}
这样使得PieVectTableInit分配到数据空间0x3f9500中,这部分数据空间也是仅仅保留PieVectTableInit分配的地址,并不保留内容,属于.bss段,只有程序运行到void InitPieVectTable(void)时,PieVectTableInit才进行初始化该地址上的内容。